java类的实例化实验报告_浅谈Java类的实例化

类实例化

Java程序中,类可以被显示或者隐藏实例化。

显示实例化有4种方式

new操作符

调用Class或者java.lang.reflect.Constructor对象的newInstance()方法

调用任何现有对象的clone()方法

调用java.io.ObjectInputStream类的getObject()方法反序列化

隐藏实例化有4种方式

保存命令行参数的String对象

Java虚拟机装载每个类型,暗中会实例化Class对象表示这个类型

Java虚拟机装载了在常量池包含CONSTANT_String_info入口的类的时候,它会创建新的String对象的实例来表示这些常量字符串。(这是常量池解析CONSTANT_String_info)的过程

通过创建执行包含字符串连接符的表达式产生对象”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虚拟机创建一个类的新实例,无论是明确的还是隐含的,首先都需要在队中为对象的实例变量分配内存。所有在对象的类中和它的超类中申明的变量(包括隐藏的实例变量)都要分配内存。并立即把实例变量初始化为默认的初始值,这个类变量赋予默认的默认初始值有异曲同工之妙。

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

对象是clone(),虚拟机拷贝被克隆的实例变量值到新变量中去。

调用readObject()进行反序列化,虚拟机通过从输入流中读入的值来初始化那些非暂时性的实例变量。

如果都不是上述两种状况,虚拟机调用对象的实例初始化方法进行初始化。

Java的class文件中,将实例初始化方法称作为方法;源代码中每一个类的构造方法,都会产生一个方法。没有明确声明任何构造方法,将会产生一个默认的无参数的构造方法,相对应的class文件里面也会产生一个方法。

一个方法可能包含三种代码:调用另外一个方法,实现对任何实例变量的初始化,构造方法体的代码。我们分为三种方式讨论:

如果在构造方法里显示调用同一个类的另一个构造方法this调用,那么该构造方法就调用另外一个构造方法,不调用父类构造方法;

如果在构造方法里显示调用父类的构造方法,那么该构造方法就调用父类的构造方法;

如果在构造方法中未显示调用父类构造方法,也未显示调用本类的构造方法,就默认调用父类的无参构造方法。

举个例子:

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()。

还有一点值得说明的是方法不允许捕捉他们调用的方法抛出的异常,如果被调用的方法抛出异常终止,那么执行调用的方法也终止。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值