- 封装、继承
★★★封装
封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
封装可以隐藏实现细节,用户只需调用方法即可;封装也可以对数据进行验证,保证安全合理。
★封装的实现步骤
将属性私有化,即用户不能直接修改属性(用
private
关键字);提供一个公共的 set 方法,用于对私有属性进行判断并赋值;
1
2
3
4public void setXxx(类型 参数){
//加入数据验证的业务逻辑
属性 = 参数;
}提供一个公共的 get 方法,用于获取私有属性的值。
1
2
3
4public 数据类型 getXxx(){
//进行权限判断
return xx;
}
封装与构造器结合
- 可以在构造器中使用已有的
setXxx
方法来保证对输入的数据进行业务逻辑判断,保证了封装。
1 | class Person { |
★★★继承
继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。
继承提高了代码的复用性,也提高了代码的扩展性和维护性。
继承的基本语法:
1
2class 子类 extends 父类{
}- 子类会自动拥有父类定义的属性和方法;
- 父类又叫超类、基类,子类又叫派生类。
继承图

★继承使用细节
子类继承了父类的所有属性和方法,非私有的属性和方法可以在子类中直接访问,但是私有的属性和方法不能在子类中直接访问,要通过父类提供的公共的方法去访问。
子类必须调用父类的构造器,完成父类的初始化。当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无 参构造器(super();),如果父类没有提供无参构造器,则必须在子类的构造器中用
super
去指定使用父类的哪个构造器完成对父类的初始化工作(**super(参数列表)**),否则编译不会通过。注意:
super()
在使用时,必须放在构造器的第一行(super()
只能在构造器中使用)。super()
和this()
都只能放在构造器的第一行,因此这两个方法不能共存于一个构造器中(即当在子类的构造器中使用this()
时,就不会再调用 super() 了)。
A(){...}
中也是有super()
的,但是是Object
类的构造器,所以没有输出。Java 所有类都是 Object 类的子类,Object 类是所有类的父类。
父类构造器的调用不限于子类的直接父类,将一直往上追溯直到 Object 类(顶级父类),例如假设 C 是 B 的子类,B 是 A 的子类,A 是 Object 的子类,则在创建 C 类的对象时,构造器的调用顺序为:Object -> A -> B -> C。(全部都会调用)
子类最多只能继承一个父类,即 Java 中是单继承机制。若要 C 类既继承 A 类又继承 B 类,则可以让 C 类继承 B 类,然后让 B 类继承 A类。
不能滥用继承,子类和父类必须满足 is-a 的逻辑关系。
★★★继承本质详解
如下图所示,有
GrandPa
、Father
、Son
三个类,当在main
函数中创建Son
对象时:首先会在方法区中加载其父类的信息,但由于
Father
类也有父类GrandPa
,GrandPa
类也有父类Object
,因此会最先加载Object
类的信息,然后加载GrandPa
类的信息,再加载Father
类的信息,最后加载Son
类的信息,然后这几个类的信息是相关联的。
然后在堆中会分配一段内存空间,用于存储成员变量,由于父类的存在,所以在
Son
对象的内存空间中,有如下图所示的几个存储区。
然后在栈的
main栈
中,变量son
指向Son
对象。
由上图可以看到,在
GrandPa
、Father
和Son
类中,都有成员变量name
,那在使用son.name
时,到底是用哪个name
呢?这就要按照查找关系来返回信息。★★★查找关系:
- 首先看子类本身是否有该属性;
- 如果子类有这个属性,则返回信息;
- 如果子类没有这个属性,就看父类有没有这个属性(如果父类有这个属性,并且可以访问,就返回信息);
- 如果父类没有这个属性,就按照 3 的规则,继续找上级父类,直到 Object。
注意:假设
Father
类的age
属性是private
修饰的,那son.age
是无法访问的;此时如果在GrandPa
类中增加一个可以访问的age
属性,son.age
仍然无法访问,因为son
对象已经向上找到了Father
类中的age
属性,只是该属性是private
,无法访问,并不会跳过这个无法访问的属性继续向上找。