1.类对象:类是程序的一部分,每个类都有一个Class对象,每当编写并且编译了一个新类的时候,就会产生一个Class对象,为了生成这个类对象,运行这个程序的JVM将使用“类加载器”系统。
2.所有的类都是在对其第一次使用的时候动态加载到JVM的。当程序创建第一个对类的静态成员的引用的时候,就会加载类。
所以构造器也是static方法,即使在构造器之间没有static关键字。因此,使用new操作符创建类的新对象也会被当作对类的静态成员的引用。
3.Class.forName():这个方法接受一个目标类的文本名的String作输入参数,返回一个Class对象的引用,如果类没加载,就加载它。(所抛出的异常是ClassNotFoundException)。
4.使用类型信息的前提条件是你必须获得恰当的Class对象的引用。
5.获得类对象引用:
当你没有具体的对象而想获得类的引用的时候:Class.forName();
当你有了感兴趣的对象(例如A a)而想获得类的引用的时候:a.getClass();
6.方法: Class cc;
cc.getName;
cc.getSimpleName();
cc.getCanonicalName();
cc.isInterface();
cc.getInterfaces();
cc.getSuperClass();
cc.newInstance();---------cc只是一个Class引用,在编译期不具备任何更进一步的类型信息。当你newInstacnce()的时候,得到的是一个Object的引用,但是这个引用指向了具体的对象。
作特定动作的时候需要进行转型。
7.类字面常量(不仅仅可以应用于类,也可以应用于接口,数组,以及基本数据类型,对于基本数据类型的包装器类,用Integer.TYPE、Boolean.TYPE等等):
xxx.class,来生成Class对象的引用,它在编译期就会收到检查,根除了forName()方法的调用,更高效和安全。
注意,使用类字面常量来创建对类对象的引用的时候,不会自动的初始化该Class对象,而Class.forName()会自动的初始化Class对象。
8.初始化的惰性:
public class Test {
public static void main(String[] args) {
Class i = Init.class;
System.out.println(Init.value1);
System.out.println("--------------------------");
System.out.println(Init.value2);
}
}
class Init{
static Random rand = new Random();
public static final int value1 = 1;
public static final int value2 = rand.nextInt(10);
static{
System.out.println("-----------------初始化:");
}
}
1
--------------------------
-----------------初始化:
7
a.) 仅使用类字面常量.class来获得类的引用是不会引发初始化的,而使用Class.forName()则会立即就进行初始化。
b.) 如果一个被staitc final修饰的词是“编译期常量”,如value1,那么这个值不需要被初始化就可以被读取。注意:如果一个域被设置成了static 和 final的,但是它不是“编译期常量”,那么使用它的时候也会引发初始化。
c.) 如果一个static域不是final的,那么对它访问时,总是要求在它被读取之前,进行链接和初始化。
b.c的解析:在你使用final修饰数据的时候,你的目的有2点:(1)编译期常量,(2)运行期初始化的时候,我们希望它不会被改变。
关于编译期常量:它在类加载的时候就已经完成了初始化,所以当加载完后,它是不可更改,可以在编译期中代入任何的计算式,编译期常量只能用于基本数据类型。
所以一个不是基本数据类型的static final域,它不是编译期常量,使用它的时候会触发初始化。
总结:初始化被延期到了对静态方法和非编译器常量进行首次引用的时候才执行。
9.使用类的准备工作:
a) 加载:由类加载器执行,查找字节码并在字节码中创建一个class对象。
b) 链接:为静态域分配存储空间,如果必要,将解析这个类创建的对其他类的引用。
c) 初始化.
10.Interger继承自Number类,但是Ingerger Class对象不是Number Class对象的子类。