Class对象

      Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。 
      Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。 
      虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
      基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 
      每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

      一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

      Class对象是java语言反射特性,在多态中能够正确的执行相应对象的方法,也是依靠对象的Class对象提供的信息来判断的,这也就是RTTI(Runtime type identify),

举个例子:

public class classTest2 {
    public static void main(String[] args) {
        Human g=new Girl();
        System.out.println(g instanceof Girl);
        System.out.println(g.getClass().getName());  //Girl 而不是 Human
    }
}

abstract class Human{
    public Human(){

    }
}
class Girl extends Human{
    public Girl(){

    }
}


对于每一个class都对应着一个Class对象,每当你创建一个新的class,一个Class对象便会创建并存储在.class文件中。为了创建这个class的对象,JVM将调用一个类加载器(Class loader)的子系统。

类加载器系统其实就是由多个类加载器组成的一个链。类加载器使用了双亲委托模型,当一个装载器被请求装载某个类时,它首先委托自己的parent去装载,若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载。这样保证了jvm不会加载恶意的class文件。

所有的class都是只有在第一次引用该类型的静态成员时被动态加载到jvm中的。构造函数是隐式的static方法。

package test;

public class SweetShop {
	public static void main(String[] args) {
		System.out.println("inside main");
		new Candy();
		System.out.println("After creatig Candy");
		try {
			/*
			 * 加载并返回类型为Gum的Class对象,当使用Class.forName方法时,在classLoader第一次加载class文件时,对所有的static进行初始化
			 */
			Class.forName("test.Gum"); 
		} catch (Exception e) {
			System.out.println("Couldn't find Gum");
		}
		System.out.println("After Class.forName(\"Gum\")");
		new Cookie();
		System.out.println("After creating Cookie");
	}
}
class Candy{
	static{
		System.out.println("Loading Candy");
	}
}

class Cookie { 
	  static {
		  System.out.println("Loading Cookie"); 
		  } 
}

输出

inside main
Loading Candy
After creatig Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie


获取Class对象的第一种方法

          Class.forName(String className)该方法返回一个Class对象,同时对该类的static进行初始化。

获取Class对象的第二种方法

          使用字面量(literals),如Dog.class,int.class。

这两种获取Class对象的主要区别

          使用字面量获取Class对象将不会初始化static代码块或变量,这一点是和Class.forName()的区别。

其实是分为三个步骤:

1.加载(Loading),jvm找到.class文件,加载字节码到内存

2.链接(Linking),该阶段验证字节码的正确性,如果有static field话,为其分配存储空间,并处理对其他类型的引用。

3.初始化(initialization),如果有父类,就初始化它。初始化static成员。

第三个步骤-初始化,是被延迟执行的,只用当第一次应用该类型的静态成员或静态方法时,才会触发初始化(构造函数是隐式的方法)

package test;

import java.util.Random;

class Initable {
	static final int staticFinal = 47;
	static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);
	static {
		System.out.println("Initializing Initable");
	}
}

class Initable2 {
	static int staticNonFinal = 147;
	static {
		System.out.println("Initializing Initable2");
	}
}

class Initable3 {
	static int staticNonFinal = 74;
	static {
		System.out.println("Initializing Initable3");
	}
}

public class ClassInitialization {
	public static Random rand = new Random(47);
	public static void main(String[] args) throws Exception {
		Class initable = Initable.class;
		System.out.println("After creating Initable ref");
		// Does not trigger initialization:
		System.out.println(Initable.staticFinal);
		// Does trigger initialization:
		System.out.println(Initable.staticFinal2);
		// Does trigger initialization:
		System.out.println(Initable2.staticNonFinal);
		Class initable3 = Class.forName("test.Initable3");
		System.out.println("After creating Initable3 ref");
		System.out.println(Initable3.staticNonFinal);
	}
}

运行结果:

After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74

注意:如果一个static final是一个运行时常量,如 Initable.staticFinal,那么读取这个值将不会引起初始化,如果是一个static而不是final,那么访问该值,将会触发初始化,如Initable2.staticNonFinal 。


获取Class对象的第三种方法

         使用TYPE,如Integer.TYPE


待续。。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值