java-初始化和清理
1、区别方法重载和重写:
重载:方法名称一致,通过参数列表区别不同的方法; 发生于本类或者父类、子类;
重写:方法返回值,方法名, 参数列表必须一致;发生于父类、子类
方法重载时调用的类型转换:
package com.zifuchuan; public class MyTe8 { public static void main(String[] args) { byte a=6; short b=7; int c=7; long d=7; float e=1.1f; double f=1.2d; test(a); test(b); test(c); test(d); test(e); test(f); test(1.3); test('g');//字符类型被提升为int类型 test(89);//常数89被当成int类型 int h=10; test2(h); } public static void test(byte arg) { System.out.println("test(byte arg)"); } public static void test(short arg) { System.out.println("test(short arg)"); } public static void test(int arg) { System.out.println("test(int arg)"); } public static void test(long arg) { System.out.println("test1(long arg)"); } public static void test(float arg) { System.out.println("test(float arg)"); } public static void test(double arg) { System.out.println("test(double arg)"); } public static void test2(long arg) { System.out.println("test2(long arg)"); } public static void test2(double arg) { System.out.println("test2(double arg)"); } }
可知,类型转化规则:
- 传入参数的数据类型(实际参数类型)小于方法中申明的参数类型,实际数据类型会被提升,其中字符类型比较特殊,会被提升为int类型 ;
- 传入参数的数据类型(实际参数类型)大于方法中申明的参数类型,会报错,需要强制类型转化;
- 常数89被当成int类型;
2、对象创建,初始化过程
- 首次调用Dog类的静态方法(构造器也是静态方法)/静态域首次被访问时候,java解析器查找类路径定位Dog.class文件。载入Dog.class文件(这将创建一个Class对象),静态初始化相关的动作都会执行(静态域、静态代码块按照程序中的顺序依次初始化),且在Class对象首次加载的时候执行一次。如果有父类,则先找到父类的class文件并载入,再加载子类。以此类推,最终以从基类一直到导出类的顺序,分别载入class文件和当前类的静态初始化,
- 当调用构造器创建Dog对象时候,先在堆上为Dog对象分配存储空间,并清零(也就将对象的域设置成了默认值,比如引用置为null)。如果有基类,继续为基类的对象分配存储空间并清零(导出类的构造器默认调用基类的构造器)。以此类推,最终从导出类到基类的顺序分配空间并清零。最顶层的基类对象分配存储空间并清零后,会执行本类域处的初始化操作,然后执行本类构造器。
- 基类构造器完成后,导出类依次执行所有在字段处和非静态代码块的初始化动作。以此类推,最终从基类到导出类的顺序初始化。
- 执行导出类构造器其余部分。
示例:
package com.zifuchuan; public class Beetle extends Insect{ Beetle(){ System.out.println("Beetle构造器初始化"); }
static { System.out.println("Beetle静态代码块1"); } private static int x2=print("x2"); static { System.out.println("Beetle静态代码块2"); } public static void main(String[] args) { System.out.println("main函数执行"); Beetle beetle=new Beetle(); } } class Insect{ { System.out.println("Insect非静态代码块1"); } private int first=print2("Insect非静态域"); Insect(){ System.out.println("Insect构造器初始化"); } private static int x=print("x"); { System.out.println("Insect非静态代码块2"); } public int print2(String str){ System.out.println(str); return 47; } public static int print(String str){ System.out.println(str); return 47; } }
输出结果:
x
Beetle静态代码块1
x2
Beetle静态代码块2
main函数执行
Insect非静态代码块1
Insect非静态域
Insect非静态代码块2
Insect构造器初始化
Beetle构造器初始化
3、垃圾回收器如何工作
- 引用计数--java虚拟机从未采用的垃圾回收技术
引用计数的思想?
每一个对象都含有一个引用计数器,当有新的引用连接至对象时候,引用计数加1;引用置空时候,引用计数减1。垃圾回收器在包含所有对象的列表上遍历,发现某个对象的引用计数器为0时,就是释放对象占用的资源。
缺陷:存在循环引用,可能出现本来应该被回收的对象,由于引用计数不为0无法被回收的情况
如何解决“引用计数”的缺陷?
对于一切存活的对象,一定能够最终追溯到其存活在堆栈或静态存储区中的引用,这个引用可能会穿过数个对象层次。基于此前提,从堆栈或静态存储区开始遍历所有的引用就能找到存活的对象。这解决了“引用计数”的缺陷。以下“停止-复制”、”标记-清扫”基于该思想。
- 停止-复制
先暂停程序,然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的是垃圾,被回收;对象被复制到新堆后是整齐排列的。
缺陷:
需要两个分离的堆来回复制;如果产生少量垃圾(不存活对象很少),甚至没有垃圾,垃圾回收器还是会将所有内存从一处复制另一处的堆,很浪费。
- 标记-清扫
不暂停程序,找到存活对象设置一个标记,当全部标记工作完成时候,暂停程序并清理未被标记的垃圾;剩下的堆空间不是整齐排列的。解决了“停止-复制”的缺陷。
JVM虚拟机会跟踪“停止-复制”的效果,如果对象很稳定,垃圾回收效率低,会切换到“标记-清扫”方式;JVM虚拟机会跟踪“标记-清扫”的效果,如果堆空间出现很多碎片,会切换回“停止-复制”的方式。这种方式工作方式通常称为“自适应”技术