Java 类的显性实例化
Java类的实例化具有显性和隐性的区别,我们编程时一般使用new方法直接实例化,这是最简单直接的显性实例化。另外还有三种实例化,分别为反射机制中的newInstance()方法,类的Clone()方法和解串行化使用的ObjecInputStream中的getObject()方法。
在这里我主要讲一下java类显性实例化及其应注意的问题,隐性实例化的相关内容和问题会在以后补充上。
一、显的性实例化
直接使用new关键字实例化新的对象:
调用相应的构造函数完成实例化。(类中的非静态成员变量如果有初始化语句,都会被隐式的加入到构造函数中),具体如下:
public class Test {
String strA = "xyz";
String strB ;
public Test(String str){
strB = str ;
}
public static void main(String[] args){
Test t = new Test("abc");
}
}
在eclipse中装了ASM bytecode插件后,观察.class文件中的构造函数对应的字节码如下:
INVOKESPECIAL Object.<init>() : void
ALOAD 0: this
LDC "xyz"
PUTFIELD Test.strA : String
ALOAD 0: this
ALOAD 1: str
PUTFIELD Test.strB : String
RETURN
关键在于LDC“xyz”这条指令,明显可以看出,这是用于strA初始化的字符串。
由此我们可以归纳出,在没有调用本类中的其他的构造函数的情况下,每次类的构造函数都会按如下的顺序进行:
a)隐式(或显性)的调用构造函数;
b)然后执行写在构造函数外的成员变量的初始化;
c)最后在执行构造函数中的命令。
如果是有显性的调用本类其他构造函数(必须是放在构造函数的第一步执行),那么对于这个构造函数,处理过程就简单些了:
a) 调用这个构造函数;
b) 执行之后的代码。
public class Test {
String strA = "xyz";
String strB ;
public Test(String str){
this();
}
public Test(){
strB = "mno";
}
public void print(){
System.out.println(strB);
}
public static void main(String[] args){
Test t = new Test("abc");
t.print();
}
}
执行结果为:
mno
至于为什么一定要将另外一个构造函数放在构造函数的第一步:必须先处理好heap中的变量初始化后才能下一步执行。
二、显性实例化中遇到的问题及解决
以上是对java类中的显性实例化的介绍,下面看看本人在写代码中遇到的问题,进一步认识显性实例化过程中应注意的问题,当然,可能只是涉及问题的某一部分,不足之处请加以谅解。
在该程序中共有三个类,希望通过构造函数初始化的方法,把第一个类中的对象传给第二个类,第二个类再用同样的方法传给第三个类。
具体如下:(代码是模拟的,主要是为了简单明了,不保证可运行)
Public class First{
Public static void main(String []args ){
First first = new First();
first.test1();
}
//该方法实例化了一个对象,通过第二个类的构造函数传至第二个类中
Public void test1(){
String s = “student”;
System.out.println(“第一个类中的s打印值:”+s );
//初始化话第二个类,并通过构造函数传值s
Second second = new Second(s);
}
}
Public class Second{
Private String s;
Three three = new Three(s);
Public Second(String s){
This.s = s;
System.out.println(“第二个类中的s打印值:”+s );
}
}
Public class Three{
Private String s;
Public Three(String s){
this.s = s;
System.out.println(“第三个类中的s打印值:”+s );
}
}
如果运行上面的代码,则会得出下面的输出结果:
“第一个类中的s打印值:”student
“第三个类中的s打印值:”null
“第二个类中的s打印值:”student。
由此可见,测试的输出结果与我们的设计思路相反,第三个类的构造函数运行先于第二个类的构造函数,这是由于在第二个类中,由于显性实例化的缘故,Three three = new Three(s);的初始化在第二个类的构造函数之前,而此时Three的构造函数中传入的值还是空的,有与构造函数还没有执行的缘故。如此,程序虽然通过编译,但是运行时则会出现逻辑错误,而这个错误的排除,由于个人的思维定式,难度也就有所增加了。
那么,该如何去解决这个问题呢,很简单,根据显性实例化的特点,我们只需把作为第二个类中的变量 three的实例化,放到该类中的一个方法中,当需要实例化第三个类的变量,变传值的时候再调用该方法。具体如下:
Public class Second{
Private String s;
Three three;
Public Second(String s){
This.s = s;
System.out.println(“第二个类中的s打印值:”+s );
}
Public void test2(){
Three three = new Three(s);
}
}