获取Class对象引用的两种办法
添加时间:2013-6-2 点击量:
今天从头翻阅Thanking in java。发明经由过程类字面常量获得Class对象的引用和Class.forName()体式格式有些差别。特记录下。
1.Class.forName(String className):
这种体式格式要重视className必须应用全限制名(即包含完全的包名)
2.类字面常量
比如:FancyToy.class
如许做的长处是:1.编译器会对其进行搜检,不须要置于try语句块中。所以更简单,更安然。
2.铲除了对forName()办法的调用,故更高效。
类字面常量不仅可以应用于通俗的类,也可以应用于接口,数组,以及根蒂根基数据类型。
别的对于根蒂根基数据类型的包装器,有一个标准的TYPE字段,该字段是一个引用,分别指向对应的根蒂根基数据类型的Class对象,即boolean.class等价于Boolean.TYPE,void.class等价于Void.TYPE等等。然则要重视Boolean.TYPE和Boolean.class的差别,是不合的。
3.一个很首要的差别。
为了应用类,须要经过三个步调:
1. 加载: 这是由类的加载器履行的。该步调将查找字节码,并从这些字节码中创建一个Class对象。
2. 链接: 在链接阶段将验证类中的字节码,为静态域分派存储空间,并且若是须要的话,将解析这个类创建的对其他类的所有引用。
3. 初始化: 若是该类具有超类,则对其初始化,履行静态初始化器和静态初始化块。
forName()这种体式格式会完全经过这三步。然则.class体式格式,第三步会延迟,延迟到对静态办法或者很是数静态域进行初次引用时才履行,请看下面的代码:
package bells;
import java.util.Random;
/
@author bells
/
public class TestClassInitialization {
public static Random rand = new Random(47);
/
@param args
/
public static void main(String[] args) throws Exception {
Class initable = Initable.class;
System.out.println(After creating Initable ref);
System.out.println(Initable.staticFinal); //这里Initable的static块不会被初始化,因为staticFinal是编译器常量
System.out.println(Initable.staticFinal2);
System.out.println(Initable2.staticNonFinal);
Class initable3 = Class.forName(typeinfo.Initable3);
System.out.println(After creating Initable3 ref);
System.out.println(Initable3.staticNonFinal);
}
}
class Initable {
static final int staticFinal = 47;
static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
static {
System.out.println(Initializing Initable);
}
}
class Initable2 {
static int staticNonFinal = 147;
static {
System.out.println(Initaialzing Initable2);
}
}
class Initable3 {
static int staticNonFinal = 74;
static {
System.out.println(Initializing Initable3);
}
}
运行成果如下:
从成果中可以看到,仅仅应用.class语法来获得对类的引用不会引起先始化。然则Class.forName()会立即进行初始化。
还有一点:若是一个static final值是“编译期常量”,就像Initable.staticFinal那样,则这个值不须要对Initable类进行初始化就可以被读取。记住必然如果编译期常量才行。
容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永
今天从头翻阅Thanking in java。发明经由过程类字面常量获得Class对象的引用和Class.forName()体式格式有些差别。特记录下。
1.Class.forName(String className):
这种体式格式要重视className必须应用全限制名(即包含完全的包名)
2.类字面常量
比如:FancyToy.class
如许做的长处是:1.编译器会对其进行搜检,不须要置于try语句块中。所以更简单,更安然。
2.铲除了对forName()办法的调用,故更高效。
类字面常量不仅可以应用于通俗的类,也可以应用于接口,数组,以及根蒂根基数据类型。
别的对于根蒂根基数据类型的包装器,有一个标准的TYPE字段,该字段是一个引用,分别指向对应的根蒂根基数据类型的Class对象,即boolean.class等价于Boolean.TYPE,void.class等价于Void.TYPE等等。然则要重视Boolean.TYPE和Boolean.class的差别,是不合的。
3.一个很首要的差别。
为了应用类,须要经过三个步调:
1. 加载: 这是由类的加载器履行的。该步调将查找字节码,并从这些字节码中创建一个Class对象。
2. 链接: 在链接阶段将验证类中的字节码,为静态域分派存储空间,并且若是须要的话,将解析这个类创建的对其他类的所有引用。
3. 初始化: 若是该类具有超类,则对其初始化,履行静态初始化器和静态初始化块。
forName()这种体式格式会完全经过这三步。然则.class体式格式,第三步会延迟,延迟到对静态办法或者很是数静态域进行初次引用时才履行,请看下面的代码:
package bells;
import java.util.Random;
/
@author bells
/
public class TestClassInitialization {
public static Random rand = new Random(47);
/
@param args
/
public static void main(String[] args) throws Exception {
Class initable = Initable.class;
System.out.println(After creating Initable ref);
System.out.println(Initable.staticFinal); //这里Initable的static块不会被初始化,因为staticFinal是编译器常量
System.out.println(Initable.staticFinal2);
System.out.println(Initable2.staticNonFinal);
Class initable3 = Class.forName(typeinfo.Initable3);
System.out.println(After creating Initable3 ref);
System.out.println(Initable3.staticNonFinal);
}
}
class Initable {
static final int staticFinal = 47;
static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
static {
System.out.println(Initializing Initable);
}
}
class Initable2 {
static int staticNonFinal = 147;
static {
System.out.println(Initaialzing Initable2);
}
}
class Initable3 {
static int staticNonFinal = 74;
static {
System.out.println(Initializing Initable3);
}
}
运行成果如下:
从成果中可以看到,仅仅应用.class语法来获得对类的引用不会引起先始化。然则Class.forName()会立即进行初始化。
还有一点:若是一个static final值是“编译期常量”,就像Initable.staticFinal那样,则这个值不须要对Initable类进行初始化就可以被读取。记住必然如果编译期常量才行。
容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永