oop三大特性:封装,继承,多态
oop一般指面向对象程序设计(一种计算机编程架构)
将东西包在一起,然后以新的完整形式呈现出来
将方法和字段一起包装到一个单元中,单元以类的形式实现
信息隐藏,隐藏对象的实现细节,不让外部直接访问到
将数据和方法包装进类中,加上具体实现的隐藏(访问修饰符),共同被称作封装,其结果是一个同时带有特征和行为的数据类型
" 定义类,定义其属性,方法的过程称为封装类"
=========================================================================
将东西包在一起,然后以新的完整形式呈现出来
将方法和字段一起包装到一个单元中,单元以类的形式实现:
这个类比我们以前写的c的结构体
定义了一个结构体,结构体里面
int age ,char *name ,double score;这些属于student的属性
这有两个函数introduce 和testFunc 这些相当于方法
类可以理解成student
java也是类似的
信息隐藏,隐藏对象的实现细节,不让外部直接访问到:
除了类比结构体以外,比c语言多了一些概念,信息隐藏
函数的实现,函数体不让人家看到,只提供了函数api的接口
将数据和方法包装进类中,加上具体实现的隐藏(访问修饰符),共同被称作封装,其结果是一个同时带有特征和行为的数据类型:
这个隐藏和前面的信息隐藏不一样,
这面的隐藏也就是访问修饰符
也就是在结构体的概念上加了一些访问修饰符,共同被称为封装
特征就是int age ;
char *name ;
double score;
行为就是那两个函数啦
void (*introduce)(int age,int name,int score);
void (*testFunc)();
" 定义类,定义其属性,方法的过程称为封装类":
我们现在封装一个结构体:它和那个c语言的结构体是非常像的,我们直接拿过来
(补充:下面的类叫Demo1)
在封装类的时候,他的语法没有struct 用class
在java中没有char *这样的指针,对于字符串有一个String这样的类型
double 是可以的
java也没有函数指针的概念,我们直接把函数名写上,
可以把int age,int name,int score去掉,不用传参
因为面向对象的特性是什么?
这个方法introduce能访问属于自己的特征属性int age; 也就不需要额外的传参
char *name;
double score;
我们c语言为什么要传参,因为c语言没有面向对象的概念,他是面向过程的编程语言,在函数调用的时候设置一些形参,调函数的时候传递这些形参int age;
char *name;
double score;
Java其实也有这些所谓的形参,只不过在下面这种情况底下,自己的成员变量进行访问的时候,就不需要额外的传参了,直接访问
刚才我们编写代码的过程就是封装了一个类
这个类里面有三个属性分别是age,name,score分别是int 型,字符型,double型
我们还分装了两个方法 , 方法=函数
封装类以后我们如何使用这个类呢?
如果用指针定义这个结构体的话
先给他分配空间,然后才可以对里面的东西进行操作
Java也一样,也需要给他分配个空间
Student stu1 =new Student();
类型 变量名 给构造方法进行传参
这句话等同于 c语言中的 struct Student *p;
p = malloc(sizeof(struct Student));
即声明了一个变量,也为这个变量分配了一个空间
那么如何给变量里面的内容赋值呢?
运行的结果
以上就是我们分装了一个类,并且使用这个类操作,这个是我们自己封装的类
之前我们用了系统的类Scanner sc = new Scanner(System.in);
多了个传递参数,如果不传参就跟刚才学到是一样的
这个参数是传给构造方法的
调用里面的方法 sc.next(); 跟我们刚才自己做的一样
那么Student stu1 =new Student(); 这句话叫什么? 实例化一个对象
我们说的这个类是一个模板,他只有一些属性和方法,属性的值是多少我们是不知道的
类不能直接使用,不能直接访问变量,需要先实例化,申请一个空间
如果我实例化对象去掉一点东西,让它直接等于null没有空间的
运行结果:没有指向内存空间的一个异常
NullPointerException基本都是由于内存访问问题,相当于java里面的段错误
stu1现在是个什么东西呢?
就是直接定义了一个指针,没有给空间直接使用
信息隐藏是oop最重要的功能之一,也是使用访问修饰符的原因
信息隐藏的原因包括:
对模块的任何实现细节所作的更改不会影响使用该模块的代码
防止用户意外修改数据
使模块易于维护和使用(就是电脑配件)
访问修饰符
private protected public 默认
这四个访问修饰符有哪些区别?
public 该类或非该类均可访问
private 只有该类可以访问
protected 该类及其子类的成员可以访问,同一个包中的类也可访问
默认 同一个包中的类可以访问
位置 private 默认 protected public
同一个类 是 是 是 是
同一个包内的类 否 是 是 是
不同包内的子类 否 否 是 是
不同包并且不是子类 否 否 否 否
我们编写的代码什么都没写,就代表他是默认的属性
(第4,5,6行就是默认的属性)
同一个类 :就是student中括号里面就是同一个类的范围
(从第2行,到14行)
同一个包内的类:
我们现在没有给这个包取名字
但是可以确定这个Student 和Demo1 是同一个包里面的类,他们都属于同一个文件
不同包并且不是子类:
新建一个包
然后起个名字
然后Test.Java 和 Demo1.Java之间的关系
是不同包内并且不是子类
public 该类或非该类均可访问
private 只有该类可以访问
protected 该类及其子类的成员可以访问,同一个包中的类也可访问
默认 同一个包中的类可以访问
位置 private 默认 protected public
同一个类 是 是 是 是
同一个包内的类 否 是 是 是
不同包内的子类 否 否 是 是
不同包并且不是子类 否 否 否 否
比如我们现在是默认的
现在这是没问题的(第8行,和第23行)
如果我们第八行加上private 呢?
visible是可视的意思
这个student 里面的sex变量是不可见的
这就是同一个包内的类 private 是不可以访问的
那么自己同一个类呢?是可以访问的
但是我们的函数是默认权限的(第10行是默认权限)
默认权限就有个问题
通过私有权限间接的访问这个变量
因为这个函数是默认权限,默认权限的作用域是同一个包内
现在我把它改成10
运行结果
属性封装的实现:
修改属性的可见性来限制对属性的访问
为每个属性创建一对赋值方法(setter)和取值(getter)方法,用于公开对这些属性的访问接口
在setter 和getter方法中,根据需要加入对属性操作的限制
我们在引用name 和age的时候,不能通过点运算符操作,可以通过共有的函数对他进行设置
刚才的代码我们可以改动一下
,把函数执行的结果当成某个函数的传参
运行结果
方法封装的目的:
隐藏方法实现细节(方法体),向外部提供公开接口(方法头),以供安全调用
简化调用,方便修改维护
根据需要,可以私有化方法,以供内部使用 ————帮助方法helper
假如别人问你多少岁,你偷偷把年龄变成18岁
age被我们设置成私密的,怎么办呢?
你其实36岁,偷偷撒谎,调用了自己的函数
运行结果
你调用getage() 它偷偷的用私有的方法撒了一个谎
那我们可以在stu1 这边 直接调用myage() 呢?
显示错误
是个非可视化的
把上面的44行的stu1.age = 18;打开呢?
提示他是一个私有化的成员,都不能通过点运算符进行操作
总结一下:对属性的封装和对方法的封装:就是对属性和方法前面加上修饰符而且
Unified Modeling Lnaguage (UML)又称统一建模语言或者标准建模语言
类的命名尽量应用领域中的术语,
因明确,无歧义,以利于相互交流和理解。
类的属性、操作中的可见性使用+、#,-分别表示public 、 protected、private
构造方法负责对象的初始化工作,为对象的属性赋合适的初始值
创建对象时,其类的构造方法确保在用户操作对象之前,系统保证初始化的进行
构造方法名与类名一致
没有返回类型
方式实现主要为字段赋初值
构造方法的调用很特别:new操作符(实例化对象的时候,自动被调用)
(Java系统保证每个类都有构造方法)
我们在new 的时候,就会自动调用这个方法,调用这个方法的目的,打印一句话,对里面的属性赋初值。
运行结果
Java语言中,方法是可重载的 函数名一样,参数列表不同,在c中是不允许
运行结果
而且实例化的对象也是有效的
总结一下:构造方法的语法规则:方法名和类名一样,
没有返回值
他的作用是为属性赋初值
什么时候被调用呢?实例化对象的时候就被调用,而且它实例化的对象也是有效的
在类的方法中,使用this 关键字代表的是调用此方法的对象的引用
this 可以看做是一个变量,他的值是当前对象的引用
使用this 可以处理方法中的成员变量和形参同名的问题
当在方法内需要用到调用到该方法的对象时,就可以用this
在类的构造方法中可以调用this ([参数列表])来调用该类的指定构造方法
第一种方法:在类的方法中,使用this 关键字代表的是调用此方法的对象的引用
是什么意思呢?
首先我们先copy一下,然后给他起个名字
可以打开这个叫this关键字的使用
然后发现复制成功
我们先把对象做出来
我们看不出this 是干什么的,但是如果去调用stu1.testThis(); 的话,就会调用this.name
19行的this 肯定是个对象,这个对象引用的是谁呢?肯定是40行的stu1
运行结果
输出了lizhaopeng
这就是第一种用法:testThis是方法,stu1是对象,是stu1这个对象调用这个方法的
调用这个方法里面有一个 this 引用的是stu1,为什么是stu1?
因为这个名字就是stu1的名字
第二种方法:this 可以看做是一个变量,他的值是当前对象的引用:
修改一下代码
运行结果
因为19行是个null,你这样做他是没有空间的
可以改正一下,这里面的this 是什么呢?
this 可以看做是一个变量,他的值是当前对象的引用
就是把当前对象赋值给stutmp
运行结果
第三种方法: 使用this 可以处理方法中的成员变量和形参同名的问题
这是最常用的一种方法
我们在实例化的时候故意将
改成
会导致一个问题,左值和右值分不清楚,如何解决
表示对象里面的age,对象里面的name ,对象里面的score,等于你传进来单独的赋值
这是非常常用的方法
整体的代码如下:
运行结果
第四种方法: 当在方法内需要用到调用到该方法的对象时,就可以用this
跟第一个一样
第五种方法: 在类的构造方法中可以调用this ([参数列表])来调用该类的指定构造方法
我现在调用的构造方法带有三个参数吧
我能不能调用一下,只有一个参数的构造方法
调用一下第7行,我们可以在三个参数的构造方法里面调用this,再加方法的列表,我什么都不调用
运行结果
是不是也能调用第11行
可以是可以
但是显示的错误Constructor call must be the first statement in a constructor(构造方法必须是第一条语句,在构造方法中)
因为27行,还有28行一共调用了两个this
改一下
这样就可以啦
运行结果
static 关键字的特点:
用来修饰类的成员——修饰成员变量的称为类变量(静态变量)
修饰成员的方法称之为类方法(静态方法)
当类被加载的时候就会被加载,优先于对象的存在
用来修饰语句块——称之为静态代码块,先于构造方法之前执行,只会执行一次,用来对静态成员做初始化
调用的时候可以直接通过类名.成员来进行访问
第一个:用来修饰类的成员——修饰成员变量的称为类变量(静态变量):
现在的代码如下
首先static可以修饰变量,如何修饰变量呢?
那我们如何访问 第八行的data 呢?
一般来说我们都需要实例化以后才能使用。
那能不能通过类名来访问呢?(第27行不行)
如果你硬要通过类名不是实例化访问的话,你这个变量就要定义成static变量(第28行)
第二个:修饰成员的方法称之为类方法(静态方法)
运行结果
那不加static可以吗?
Cannot make a static reference to the non-static method add(int, int) from the type Demo2
如果你不想用static怎么办呢?
以成员函数的方式来访问。
你必须实例化以后才能访问,你如果不想实例化就访问就用static(静态成员函数)
第三个:当类被加载的时候就会被加载,优先于对象的存在
第31 和32行优先于对象的存在
第27行的data通过类名,因为这个类(Student)被加载了,data也就同时加载,我们也就能访问了
第25行的score为什么不行呢?因为它没有static必须实例化以后才有
加上static可以不依赖于对象来访问
成员变量是这样的 第27行 Student.data =10;
成员函数也是这样的 第29行 System.out.println("ret="+add(1,3));
第四个: 用来修饰语句块——称之为静态代码块,先于构造方法之前执行,只会执行一次,用来对静态成员做初始化
看看下面执行的顺序
运行的结果
在修改一下,实例化两个对象
运行结果
静态代码块只执行了一次
构造方法执行了两次
因为我的静态变量(第8行)和(第2行)这个类就是 同时存在的,一开始就有,并且只有他一个
我们通过17行到20行对他静态代码初始化就可以啦
第五个: 调用的时候可以直接通过类名.成员来进行访问
static关键字的注意事项:
静态方法中只能访问外部静态成员
静态成员不能出现this 关键字
第一个: 静态成员不能出现this 关键字
因为this 指的是对象的引用,静态方法是先于对象之前的
Cannot use this in a static context
不能使用this 在一个静态的方法中
第二个: 静态方法中只能访问外部静态成员
静态方法中我们访问name行吗?
错误提示:Cannot make a static reference to the non-static field name
他要求这面必须是一个静态的成员
这面的静态成员是data
多数程序设计语言要求为每个方法(函数)提供一个独一无二的方法名,不存在方法重载的概念
在java中,规定方法签名是解析方法的规则而不是方法名,为方法重载开创了条件
方法重载使得在一个类中,方法名相同而参数列表不同的方法可同时存在,代表相似的行为或功能
重载overload概念:同一个类中,同名不同参的方法称为重载方法
注意:仅有返回值不同的方法不能称为重载
标准Java库是由一系列包组成,包括java.lang java.util java.net等等
标准java包就是层次型包的结构,如硬盘上嵌套的子目录一样,我们可以使用嵌套层次结构来组织包
Java的包是为了更好地规划代码,防止命名冲突和混乱,所以Java出现了打包机制
当把类组织起来放在一个包内之时,也就给包内的成员赋予了相互访问的权限,您就拥有了该包内的程序代码
包访问权限聚集在一个包内这一做法提供了意义和理由
Java程序员都可以编写属于自己的java包,为了保证包名唯一性,要求程序员在自己定义包的名字前加上唯一前缀
由于互联网上的域名称不会重复,所以推荐采用公司在互联网上的域名的倒置作为包的唯一前缀
一个类可以使用同一个包中的所有类
一个类可以使用其他包中的所有公开类
怎么使用其他包中的公开类
在每个类签名加上完整包名,例如:
java.util.Data today = new java.util.Date();
更简洁更通用的方式:使用import语句来导包(eclipse ctrl+shift+o)
import java.util.Date;
..............
Date today = new Date();
可以import特定类,也可以导入整个包。通过在源代码文件的顶部(在打包语句后)使用import语句来实现import java.util.*;
比如我们做一个scanner
它显示有错误
Multiple markers at this line
- Scanner cannot be resolved to a type
第一种方法:
然后我们点击一下ctrl +shift +o 就可以啦
这样40行的错误就没有了
发现第一行多出来这么一行话
第二种方法:
或者我们把这个第一行import ....去掉,
然后给他加上一个完整的路径
但是这种方法比较被动
那我们现在实际来建立一个包
比如我们.learn包下面的Demo3.java下面有一个main函数
它可不可以用.learn包下面的Demonew的.java 呢?
那我们同一个包底下,(.learn包)
是不是可以用他的类呢?(Demo3.java 和Demonew)
运行一下看一下结果
同样的,我们用另一个Demonew 呢?
就是.use下面的那个
记得加上访问的权限
记得加上访问的权限
给.use 下面的Demonew
这块可以用路径来访问
运行结果
在.learn 下面有Demo3.java 和Demonew.java
在use下有Demonew.java
先修改一下代码,先删掉.learn 下面的Demonew.java
然后在.learn的Demo3下面,已经变成这样了
如何解决?ctrl +shirt + o
运行一下.learn 里面的demonew
显示namenull
为什么是null,因为我们没有给这个name 赋初值
现在我们准备在.learn下面再建一个Demonew
现在有两个demonew ,对于demo3来说,我们用谁呢?
先运行看一下
他现在还是用.use 包下面的
那么如果我把import com.chenlichen.use.Demonew;这个东西去掉呢?
那么它现在就是用的.learn 下面的