深入理解Java面向对象三大特性
Java的三大特性:封装、继承和多态
封装:
通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只 能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自 治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们 编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐 藏的东西,只向外界提供最简单的编程接口。总结:封装主要体现在两个方 面,类是对数据和数据操作的封装,类中的方法是对实现细节的封装。
封装主要是因为Java有访问权限的控制。public>protected(继承访问权限)>package = default(包访问权限) > private。封装可以保护类中的信息,只提供想要被外界访问的信息。
注意:Java中外部类的修饰只能是public或默认,类的成员(包括内部类)的 修饰可以是以上四种。
如果不希望别人拥有访问该类的权限,可以把所有的构造器指定为private,(可以在该类的static成员内部进行创建)
如何使用这个类:采用单例模式(P122 JAVA编程思想)
**问题:在项目中的哪些地方使用过protected修饰符? **
答:Object类中对clone方法的声明即用到了protected访问修饰符,这是因为 Object类的clone方法只能实现浅克隆,而并不能实现常使用的深克隆,这就要 求子类在需要克隆对象时尽量重写clone方法,此时即声明为protected的,以 保证在需要克隆对象时,必须要求待克隆对象所在的类实现Cloneable接口并 重写clone方法。
继承:
从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父 类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化 中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要 手段。
- 为了继承一般的规则是将所有的数据成员都指定为private,而将所有方法定义为public;
- 从超类中继承方法,同名要使用关键字super;
- 继承是is-a关系,而组合是has-a关系
问题:java中关键字 final的理解
final可以用在三种情况:数据、方法和类。
修饰数据:表示变量一次赋值以后值不能被修改(常量),其名称通常大写。而用于对象的引用,final使得引用恒定不变,一旦引用被初始化指向一个对象,就无法更改,但是对象的自身可以修改的。
修饰方法:表示方法不能被重写,如Object类的getClass方法。
修饰类:表示该类不能被继承,以提高程序的安全性和可读性,如String、 System、StringBuffer类等。
final int COUNT = 1;
// COUNT = 2; // cannot assign value to final variable 'COUNT'
final Employee emp = new Employee();
emp.name = "丙子先生"; // 所引用对象的属性可变
如何初始化final所修饰的成员变量?
关键字final修饰的成员变量没有默认初始化值,其初始化方式主要有:
1.在声明时,直接对其进行显式初始化。
2.声明完后,在代码块中对其显式初始化。
3.声明完后,在构造器中对其显式初始化,但注意需要在所有构造器中均对其 进行初始化操作。
基本原则:保证在对象创建之前即需要对final修饰的属性进行初始化操作。
多态:
多态:指允许不同子类型的对象对同一消息作出不同的响应,简单来说就是 用同一对象引用调用同一方法却做了不同的事情。
方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。
- 重载发生在一个类中,==同名的方法如果有不同的参数列表(参数类型不同、参数 个数不同或者二者都不同)==则视为重载;(不能根据根据返回类型来区分重载,因为在调用方法时并不会判断方法的 返回值类型是什么,如果根据返回值类型来区分重载,则程序会不知道去调用哪 个方法。)
- 重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。
程序设计模式————状态模式:
用继承表达行为间的差异,并用字段表达状态上的变化。(java编程思想 P165)
问题: 在项目中哪些地方使用过多态?
实验室预约软件包含学生、教师和管理员三种角色,三者都有login 方法,但三者登录后进入的页面却是不同的,即在登录时会有不同的操作。三种 角色都继承父类的login方法,但对不同的对象却有不同的行为。
解析和分派:
Class 文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在 Class 文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。
解析调用:
一定是个静态过程,在编译期间就完全确定,在类加载的解析阶段就会把涉及的符号引用转化为可确定的直接引用,不会延迟到运行期再去完成。(解析阶段是虚拟机将常量池中的符号引用替换为直接引用的过程)
能在编译之前确定被调用方法的版本的方法:
静态方法 //invokestatic 构造器方法 //invokespecial 私有方法 //invokespecial 父类方法 //invokespecial
分派调用:
则可能是静态的也可能是动态的,根据分派依据的宗量数(方法的调用者和方法的参数统称为方法的宗量)又可分为单分派和多分派。两类分派方式两两组合便构成了静态单分派、静态多分派、动态单分派、动态多分派四种分派情况。
- 静态分派
静态分派的最典型应用就是多态性中的方法重载。静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。
class Human{
}
class Man extends Human{
}
class Woman extends Human{
}
public class StaticPai{
public