面向对象三大基石:封装,继承,多态。面试会问到。
Overriding 覆盖 只存在于父子类之间,一定。
什么时候才是覆盖呢?
class Father{
public void run(){
}
}
class Son extends Father{
public void run(int a){
}
}
注意:这是方法的重载,不是覆盖!只是这个重载发生在父子类之间。
覆盖是,子类参数列表与返回值都与父类相同,并且子类在覆盖父类方法时,不能给出更严格的访问控制,并且子类方法例外的类型是等于父子方法抛出的异常类型,或者是其子类型。
The exceptions thrown by an overriding method must be equal to or a subset of the exceptions thrown by the overridden method.
注意构造方法根本不能继承,所以不存在覆盖的问题。
访问控制
private 本类内部可见
default 同类同包
protected 同包+不同包子类
要构造一个对象,先构造父类对象,再构造子类对象
构造一个对象的执行过程。
1.递归的构造父类对象-----------〉也就是说父类本身也要走这样的步骤。
2.顺序调用成员属性赋初值语句
3.调用本类构造方法
后来课程领悟,类加载与构造对象是两回事,类加载过程,1.static静态成员加载,2运行static一次,静态代码块,3如果有静态内部类,赋值,对静态内部类的赋值是指编译产生的Employee$SomeInner.class文件的读取。
如果类有静态变量或者静态块,而且用到时(static初始化只有在必要的时候才会进行),那么就会在第一步之前执行一遍,先静态变量,然后静态块,以后再怎么new都不会执行,回到创建父类开始。
======〉引用Think In Java
在这里有必要总结一下对象的创建过程。请考虑一个名为Dog的类:
(1) 类型为Dog的一个对象首次创建时,或者Dog类的static方法/static字段首次访问时,Java解释器必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class后(它会创建一个Class对象,这将在后面学到),它的所有static初始化模块都会运行。因此,static初始化仅发生一次——在Class对象首次载入的时候。
(3) 创建一个new Dog()时,Dog对象的构建进程首先会在内存堆(Heap)里为一个Dog对象分配足够多的存储空间。
(4) 这种存储空间会清为零,将Dog中的所有基本类型设为它们的默认值(零用于数字,以及boolean和char的等价设定)。
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。正如第6章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时候。
=====================
多态-1.编译时多态 方法重载
2.运行时多态 一个对象可能会具有多个类型
对象是客观的。
人类对对象的认识是主观的
当人看到一个不能识别的,有生命的,区别人的东西时,会类来认识该事物。
也就是Animal a = new Dog();子类对象可以使用父类对象来引用。
Animal被称为编译时类型,而a真正的对象类型是运行时类型。
3个原则:
1.对象不变(运行时类型不变)(客观的肯定不会改变)
2.只能调用编译时类型的方法,方法调用时,检查编译时类型内部是否定义了该方法。
也就是说,在你以一个一个动物来看待一只狗时,你是不会知道它有散步的方法的。
3.RTTI,运行时,动态类型判定(看运行时类型),子类覆盖了(Overriding)父类方法,那么调用运行时类型对象的方法。
a instanceof 类名(编译时类型)
a为对象变量
判断a是否被声明为后面类的对象。
用在强制类型转换之前。如果转换错了,java.lang.ClassCastException 运行时例外
记住,方法只有覆盖时,调用寻找运行时类型。而Overloading ->编译时多态->看编译时类型。
属性,重载阿,都要看编译时类型。
public class TestClass {
public void print(B b){
System.out.println("is B");
}
// public void print(A a){
// System.out.println("is A");
// }
public static void main(String[] args)
{
TestClass tc = new TestClass();
A a = new B();
tc.print(a);
}
}
class A {}
class B extends A {}
为什么子类覆盖父类方法时,访问控制符只能更宽泛。因为如果父类方法为public,子类方法为private,那么多态时,察看父类方法可以调用(可调用编译时类型所定义的方法),而动态类型判断时,调用子类方法,发现为private,完蛋了。