该文章是看书时的一些相对自己来说较为重要的知识点,所以此博文不建议除本人外的任何人看。
栈内存的引用变量指向实例在堆内存中的首地址。
this关键字,总是指向调用该方法的对象,即谁在调用这个方法,this就代表谁。
值传递:方法里传的参数是实际值的副本。
引用传递: 方法里的参数的实际值是对象在堆内存中的引用,即内存首地址。但该参数也是将引用变量的值复制一份副本,只不过该副本也是对象的内存首地址,所以看起来传的是引用,但归根结底,也只值传递,只不过这个值是个引用。栈内存:一个方法会开辟对应的一个栈区。同一个栈区内,数据共享。如先执行
int a = 10;时,
若该栈区内还没有10这个值,则将10放进该栈中;若再执行int b=10;
时,由于第一句代码时将10放进了该栈中,些时b和a这两个变量就会在该栈区内都指向同一个10,即数据共享。
栈用来存局部变量,栈的存取速度仅次于寄存器。堆内存:堆内存用于存对象、数组、成员变量(类变量:有static修饰、实例变量:没有static修饰)。它可动态分配内存。
代码: Person p = new Person();的执行过程:
- 在堆内存中创建对象,并完成初始化。
- 调用构造器Person()。在该构造器中可以用this调用对象了。
- 将构造器返回的对象赋给引有变量p。赋的是内存首地址。
类成员(static修饰)属于类,实例成员(无static修饰)属于对象。类成员只在第1次创建对象时初始化,后面创建的对象与第1个对象共用初始化好的类成员。
重写规则:两同、两小、一大。即同名、同参数量、访问权限大于等父类。还有就是抛出异常和返回类型必须小于等于父类。
重载规则:方法名相同,参数列表不同。引用类型强转条件: 编译时类型是运行时类型的父类的对象,才可被子类(运行时类型)强转。如:Parent p = new Son();
权限允许时,子类可直接调用父类的成员变量和方法。
父类被子类重写的方法,不能再被子类对象调用用了,即使父类构造中调用了该方法。在创建子类对象时,即使调用父类构造时,执行的方法也是重写的。所以尽量不要在构造中调用方法,否则容易出问题。
组合与继承的内存开销一样,只不过组合多了个引用变量。组合既实现了复用,又保证了代码的封装性,因数继承容易破坏封装性,如重写。
构造器、初始化的执行顺序:
第一次创建对象时:- 祖宗静态初始化块
- 父类静态初始化块
- 当前类静态初始化块
- 祖宗普通初始化块
- 祖宗构造器
- 父类普通初始化块
- 父类构造器
- 当前类普通初始化块
- 当前类构造器
再次创建对象时:
- 祖宗普通初始化块
- 祖宗构造器
- 父类普通初始化块
- 父类构造器
- 当前类普通初始化块
- 当前类构造器
为什么初始化块执行在构造器之前?
因为初始化块其实是个假象,在Java编译后,初始化块代码会被还原到构造器,所以要执行在之前。
为什么静态初始化块都只执行一次?
因为静态初始化块跟类变量都是static修饰的,一样属于类,所以都只在第一次实例化对象执行时执行。
注:所有类都默认有构造器,如果自己定义了构造器,则默认的失效。