一、Class类及其实例的理解
Java程序中的各个java类属于同一事物,描述这类事物的Java类名就是Class类。
例如
代码一:
interface PCI
{
public void open();
public void close();
}
class MainBoard
{
public void run()
{
System.out.println("mainboard run ");
}
public void usePCI(PCI p)//PCI p = new NetCard()//接口型引用指向自己的子类对象。
{
if(p!=null)
{
p.open();
p.close();
}
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
//method();
}
}
class Test5
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
}
}
在上述代码中,接口PCI,类MainBoard,类NetCard,类Test5均属于Class类。
Class类没有公共的构造方法。Class对象是在加载时由Java虚拟机及通过调用类加载器中的defineClass方法自动构造的。
那么自动构造的具体的过程:类的二进制代码编译成class文件,放在硬盘上以后,把二进制代码加载到内存中,然后才可以创建一个个的对象。即一个类被类加载器加载到内存中,暂用一片存储空间,这个空间里面的内容就是类的字节码文件(class文件)。不同类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示(注意:这一个个的对象是具有相同的类型)。简而言之,一个字节码文件对应一个class实例。Java应用程序通过编译会形成一个个的字节码文件(class文件),那么如上述代码一所示,编译该程序会产生4个字节码文件(Test5.class、 PCI.class、 MainBoard.class、 NetCard.class),即这里有4个Class实例对象。
这里为什么是4个字节码文件?
因为Class类的实例表示正在运行的Java应用程序中的类和接口。
枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,是多有具有相同元素的类型和为数的数组都共享该Class对象。基本的Java类型boolean、 byte、 char、 short、 int、 long、 float、 double和void也表示为Class对象。
二、Class实例对象的获取
获取的方法有三种:
1.类名.class 例如代码一中的MainBoard.class;适合于知道类名的情况
2.对象.getClass(); 适用于知道对象名的情况
3.Class.forName(字符串s);这种方法最灵活,只需要将完整类或者配置文件中的该项的值赋值给字符串s即可获取实例对象
下面通过代码演示
代码二
String str = "abc";
Class cls1 = str.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
该代码以常见String类的字节码文件为例。
那么Class对象cls1、 cls2、 cls3,这三个引用所指向的对象是否一致,也就是说他们是都指向的是同一块内存空间?
代码三
System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);
该代码运行结果都是true。也就是说这三个Class对象所指向的对象是一致的,所指向的是同一内存空间。
那么如果是我们自己写的类,例如代码一中的类和获取的方法呢?获取方式也是可以采用这三种。
假如是获取接口的实例对象或者字节码文件,那么第二种方法就不适用,因为我们知道接口不能创建对象。那么采取的方法就如代码五所示。
代码四
Class cls6 = PCI.class;
Class cls7 = Class.forName("PCI");
System.out.println(cls6 == cls7);
PCI是一个接口,Class类中也提供了方法isInterface()来判定指定的 Class 对象是否表示一个接口类型。
注意:Class类中静态函数forName有两种:
1. staticClass<?> forName(String className)
返回与带有给定字符串名的类或接口相关联的 Class 对象。
2. staticClass<?> forName(String name,boolean initialize, ClassLoader loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
上述代码中我们使用的是第一种,参数的值一般是我们在配置文件中设置的值,即我们会从配置文件中来获取。
三、九个预定的Class实例对象。
有九种预定义的 Class 对象,分别是八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。
这九种预定义的Class实例对象,即可以用基本类型.class等来表示,也可以用Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE(这些都是public static final 的变量)来表示。例如:int.class和Integer.class这两个实例对象不是一样的。
在API中介绍Integer 类在对象中包装了一个基本类型 int 的值。Integer 类型的对象包含一个 int 类型的字段。该类中的静态字段TYPE就表示基本类型 int 的 Class 实例。因此int.class和Integer.TYPE这两个实例对象是一样的。
此外:
在Class类中有个方法可以用来判断实例对象是否是基本类型:
public boolean isPrimitive()
判定指定的 Class 对象是否表示一个基本类型
总结:只要是源程序中出现的类型,都有各自的class实例。例如:int[]对应的实例对象是int[].class,不过int[].class是class实例对象数组,即Class[] mm=int[].class。