浅谈Java类的实例化

类实例化

Java程序中,类可以被显示或者隐藏实例化。
显示实例化有4种方式

  1. new操作符
  2. 调用Class或者java.lang.reflect.Constructor对象的newInstance()方法
  3. 调用任何现有对象的clone()方法
  4. 调用java.io.ObjectInputStream类的getObject()方法反序列化

隐藏实例化有4种方式

  1. 保存命令行参数的String对象
  2. Java虚拟机装载每个类型,暗中会实例化Class对象表示这个类型
  3. Java虚拟机装载了在常量池包含CONSTANT_String_info入口的类的时候,它会创建新的String对象的实例来表示这些常量字符串。(这是常量池解析CONSTANT_String_info)的过程
  4. 通过创建执行包含字符串连接符的表达式产生对象”a”+”b”
public class Example7 {
    public static void main(String[] args) {
        if (args.length<2) {
            return;
        }
        System.out.println(args[0]+args[1]);
    }
}

class文件关键部分

 0: aload_0
 1: arraylength
 2: iconst_2
 3: if_icmpge     7
 6: return
 7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
10: new           #3                  // class java/lang/StringBuilder
13: dup
14: invokespecial #4                  // Method java/lang/StringBuilder."":()V
17: aload_0
18: iconst_0
19: aaload
20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: aload_0
24: iconst_1
25: aaload
26: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
29: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: return

默认生成StringBuilder对象,创建了String对象
当Java虚拟机创建一个类的新实例,无论是明确的还是隐含的,首先都需要在队中为对象的实例变量分配内存。所有在对象的类中和它的超类中申明的变量(包括隐藏的实例变量)都要分配内存。并立即把实例变量初始化为默认的初始值,这个类变量赋予默认的默认初始值有异曲同工之妙。

一旦虚拟机为新对象分配内存和为实例变量赋予默认值后,虚拟机会为实例变量赋予正确的初始值。一般而言有三种赋初始值的技术:

  1. 对象是clone(),虚拟机拷贝被克隆的实例变量值到新变量中去。
  2. 调用readObject()进行反序列化,虚拟机通过从输入流中读入的值来初始化那些非暂时性的实例变量。
  3. 如果都不是上述两种状况,虚拟机调用对象的实例初始化方法进行初始化。

Java的class文件中,将实例初始化方法称作为方法;源代码中每一个类的构造方法,都会产生一个方法。没有明确声明任何构造方法,将会产生一个默认的无参数的构造方法,相对应的class文件里面也会产生一个方法。
一个方法可能包含三种代码:调用另外一个方法,实现对任何实例变量的初始化,构造方法体的代码。我们分为三种方式讨论:

  1. 如果在构造方法里显示调用同一个类的另一个构造方法this调用,那么该构造方法就调用另外一个构造方法,不调用父类构造方法;
  2. 如果在构造方法里显示调用父类的构造方法,那么该构造方法就调用父类的构造方法;
  3. 如果在构造方法中未显示调用父类构造方法,也未显示调用本类的构造方法,就默认调用父类的无参构造方法。

举个例子:

public class Example8 extends Example9 {

    public Example8() {
        this(1);
        System.out.println("Example8");
    }

    public Example8(int i) {
        System.out.println("Example8(int)");
    }

    public static void main(String[] args) {
        Example8 example8 = new Example8();
    }

}

public class Example9 {

    public Example9() {
        System.out.println("Example9");
    }

}

运行结果:

Example9
Example8(int)
Example8

可以看出调用顺序如下Example8()的this(1) 调用 Example8(int) , Example8(int)默认的super()调用 Example9()。我们可以查看下字节码就看的很清楚了:

Example8()
 0: aload_0
 1: iconst_1
 2: invokespecial #1                  // Method "":(I)V
 5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
 8: ldc           #3                  // String Example8
10: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: return

Example8(int)
 0: aload_0
 1: invokespecial #5                  // Method Initialization/Example9."":()V
 4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
 7: ldc           #6                  // String Example8(int)
 9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: return

Example9()
 0: aload_0
 1: invokespecial #1                  // Method java/lang/Object."":()V
 4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
 7: ldc           #3                  // String Example9
 9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: return

main函数首先调用Example8()

 0: new           #7                  // class Initialization/Example8
 3: dup
 4: invokespecial #8                  // Method "":()V
 7: astore_1
 8: return

这其实也说明了一个事实,构造函数第一行必须是this()或者super(),如果都没有,默认是super()。
还有一点值得说明的是方法不允许捕捉他们调用的方法抛出的异常,如果被调用的方法抛出异常终止,那么执行调用的方法也终止。

你可能感兴趣的:(java提高)