2021-01-21

抓住规则
1.创建子类实例的时候,会先构造父类的实例(调用父类的构造方法)
2.⒉初始化顺序:先执行就地初始化,再执行代码块,再执行构造方法
New Z()这个地址没人保存,这行代码执行完毕之后就被GC判定成垃圾回收了,但还是做了一些事情:
3.构造父类实例
4.初始化成员
5.调用构造方法

class X{
     
	Y y=new Y();
	public X(){
     
		System.out.print("X");
	}
}
class Y{
     
	public Y(){
     
		System.out.print("Y");
	}
}
public class Z extends X{
     
	Y y=new Y();
	public Z(){
     
		System.out.print("Z");
	}
	public static void main(String[] args) {
     
		new Z();
	}
}

6.new Z()的时候,会先构造父类的实例进入×中执行
7.构造×实例的时候,先就地初始化,再调用构造方法,于是进入Y执行8.执行Y的构造方法,打印了Y
9.执行×的构造方法,打印X
10.父类×已经准备就绪,开始进行子类Z的初始化6.对于Z来说也是先执行就地初始化,再调用构造方法
11.就地初始化就是进入Y执行.只需要调用构造方法即可.打印Y8.执行Z自身的构造方法,打印Z
12.Java中一般都是习惯于把成员变量定义到上面,把方法定义到下面.
C++中一般习惯于把成员变量定义到下面,把方法定义到上面.
代码块的话,如果是多个代码块,这个时候定义的先后顺序就有影响了.
13.static修饰的代码块执行始终在普通代码块之前
static 代码块是在类加载的时候执行的.
普通代码块是在创建实例的时候执行的.
类加载始终是在创建实例之前(类加载只进行一次)
要是有两个static就先执行上边的static
14.对象的初始化
(0)默认的初始化
整数,浮点数 => 0 ;boolean => false ; char => ‘\u000’ ;引用类型 => null
(1)就地初始化
创建成员变量的过程中,立刻进行初始化
(2)代码块中初始化
(3)构造方法中的初始化
都是实例化的时候要进行的环节
2021-01-21_第1张图片

多态
一、向上转型
1.一个父类的引用, 指向一个子类的实例的这种写法称为 向上转型
2.向上转型发生的时机
(1)直接赋值

Cat cat = new Cat;
Animal animal = null;
animal = cat;
//将代码合并到一起
Animal animal = new Cat();

(2)方法传参
本质上就是进行“赋值”操作

public class Test {
      
   public static void main(String[] args) {
      
       Bird bird = new Bird("圆圆"); 
       feed(bird); 
  } 
   public static void feed(Animal animal) {
      
       animal.eat("谷子"); 
  } 

(3)方法返回
本质上也是赋值

public class Test {
     
    public static void main(String[] args) {
     
        Animal animal = findMyAnimal();
   }
    public static Animal findMyAnimal() {
     
        Bird bird = new Bird("圆圆");
        return bird;
   }
}

父类的引用,只能访问到父类中的属性和方法,访问不到子类独有的属性和方法.
3.属性是对象的一个部分
对象(实例)里面包含两类内容
(1)属性(成员变量)
(2)方法(成员函数)
二、动态绑定
1.如果父类中包含的方法在子类中有对应的同名同参数的方法,就会进行动态邦定(一般"静态"/“动态"分别指的是"编译期”/"运行时"和"static”没任何关系)
2.在运行过程中,调用对象的成员方法,JVM会将当前调用的方法和对象的实际内存进行绑定
成员属性没有动态绑定技术,在哪里声明,在哪里使用
3.animal1 和 animal2 虽然都是 Animal 类型的引用, 但是 animal1 指向 Animal 类型的实例, animal2 指向 Bird 类型的实例.
针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而 animal2.eat() 实际调用了子类的方法.
因此, 在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看 究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定
4.如果eat方法只在父类中存在,此时调用的eat就是父类的这个eat方法.(不涉及动态绑定)
如果eat方法只在子类中存在,此时调用的eat就会编译报错.(也不涉及动态绑定)
如果eat方法在父类和子类中都存在,并且参数也相同,此时调用eat就会涉及到 动态绑定
在程序运行时,看animal究竟是指向一个父类的实例还是子类的实例,指向父类实例就调用父类版本的 eat. 指向子类实例就调用子类版本的eat
animal这个引用指向的是父类还是子类的实例,是运行时才能确定的,如果eat方法在父类和子类中都存在,并且参数不相同,此时调用eat,也不涉及“动态绑定”,看起来像是重载,但是又不太一样。
根据调用方法时传入的参数类型和个数判断在父类中是否存在匹配的方法,如果不存在就编译报错.(编译期确定的)
上述的动态绑定的规则,我们是站在编译器和JVM实现者的角度来看待,实际上这个操作过程在Java的语法层次上也有一个术语,"方法重写“override”
6.方法的访问限定符是会影响到动态绑定的,如果子类中的这个方法是private,这个时候外部根本就看不到子类的这个方法,此时就不涉及动态绑定了.
7.父类的方法eat是public
子类的方法eat是 private private 比 public更低(访问的范围更窄)一般情况下实际写代码,都是两个public的方法进行动态绑定/方法重写.
8.如果eat下划波浪线,需要给子类的方法上加上注解,显式的告诉编译器,当前这个子类的方法是重写了父类的方法.如果没有这个注解,其实代码也能编译运行.
加了这个注解之后,编译器就能给我们更检查和校验工作.
9.@Override 只是注解之一,Java 中的注解是有很多的,程序猿也可以自己创建一些自定义的注解,注解主要是学会使用即可,并不研究如何实现一个自定义注解.
10.class Animal {
这个Animal类看起来没有父类,其实是有的 => Object
Java中所有的类,都是直接或者间接继承自Object(祖宗类),如果写了某个类,没写extends,默认继承自Object,toString其实就是Object的方法.
三、方法重写
1.子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).
2.关于重写的注意事项
(1)重写和重载完全不一样. 不要混淆
(2)普通方法可以重写, static 修饰的静态方法不能重写.
(3)重写中子类的方法的访问权限不能低于父类的方法访问权限.
(4)重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外)
假设父类和子类方法的返回值完全互不相干,这种情况下是会编译出错的.
如果父类和子类方法的返回值类型具有父子关系,这种情况下,就可以
实际进行重写的时候,一般都是类型相同的.一般进行重写的两个方法,功能都是类似的.所以返回值类型也是兼容的.如果返回类型完全不相干,此时就没啥意义,就不应该进行重写.
3.重载是同一个作用域中,方法名字相同,参数不同(参数的个数/类型)
重写是父类和子类之间,存在同名方法,参数相同,此时通过父类引用调用该方法,就会触发重写,此时具体执行哪个版本的方法由动态绑定规则来决定.

4.对于已经投入使用的类,尽显不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。
四、多态
1.多态是一种程序设计的思想方法,具体的语法体现,向上转型,方法重写,动态绑定.
2.多态直观的理解 => "一个引用,对应到多种形态(不同类型的实例)
3.理解多态 : 实现draw方法的这个人A和实现这几个类的人B不一定是同一个人
4.多态的好处
(1)第一个好处(本质)
多态这种设计思想,本质上是“封装”的更进一步,封装的目的是为了让类的使用者不需要知道类的实现细节,就能使用,但是使用者仍然需要知道这个类是啥类型.
使用多态的话,此时类的使用者,不仅不需要知道类的实现细节,也不需要知道这个类具体是啥类型,只要知道这个类有一个draw方法就可以了,这个时候类的使用者知道的信息更少,使用成本就更低.
(2)第二个好处,方便扩展.
未来如果需要新增一个形状,创建一个新的子类即可,并且让子类也去重写这个draw方法,类的调用者这里的代码不需要做出任何修改/或者只做出很小的修改
(3)第三个好处,减少一些分支语句(减少if / else switch / case)
如果不使用多态,实现同样的逻辑,可能就比较复杂了.

你可能感兴趣的:(笔记,java)