Class类

来源:互联网 发布:经纬度计算距离软件 编辑:程序博客网 时间:2024/05/29 05:11

java的Class类是java反射机制的基础,通过Class类我们可以获得关于一个类的相关信息,下面我们来了解一下有关java中Class类的相关知识!

java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。

当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象,可以通过这个Class对象对被装入类的详细信息进行访问。

简单的说,获取某一个类所对应的Class对象可以通过如下三种途径:

1. Object的getClass方法
java.lang.Object中定义有getClass方法:

public final Class getClass()

所有Java对象都具备这个方法。该方法用于返回与调用该方法对象所属类关联的Class对象,例如:

Date date1 = new Date();

Date date2 = new Date();

Class c1 = date1.getClass();

Class c2 = date2.getClass();

System.out.println(c1.getName()); // java.util.Date

System.out.println(c1 == c2); // true

上面的代码中,调用Date对象date1的getClass方法将返回用于封装Date类信息的Class对象。这里调用了Class类的getName方法:

public String getName()

这个方法的含义很直观,即返回所封装的类的名称。

需要注意的是,代码中的date1和date2的getClass方法返回了相同的Class对象(c1==c2的值为true)。这是因为,对于相同的类,JVM只会载入一次,而与该类对应的Class对象也只会存在一个,无论该类实例化了多少对象。

另外,需要强调的是,当一个对象被其父类的引用或其实现的接口类型的引用所指向的时,getClass方法返回的是与对象实际所属类关联的Class对象。例如:

List list = new ArrayList();

System.out.println(list.getClass().getName()); // java.util.ArrayList

上面的代码中,语句list.getClass()方法返回的是list所指向对象实际所属类java.util.ArrayList对应的 Class对象而并未java.util.List所对应的Class对象。有些时候可以通过这个方法了解一个对象的运行时类型,例如:

HashSet set = new HashSet();

Iterator it = set.iterator();

System.out.println(it.getClass().getName()); //java.util.HashMap$KeyIterator

从代码可以看出,HashSet的iterator方法返回的是实现了Iterator接口的HashMap内部类(KeyIterator)对象。

因为抽象类和接口不可能实例化对象,因此不能通过Object的getClass方法获得与抽象类和接口关联的Class对象。

2. 使用.class的方式
使用类名加“.class”的方式即会返回与该类对应的Class对象。例如:

Class clazz = String.class;

System.out.println(clazz.getName()); // java.lang.String

这个方法可以直接获得与指定类关联的Class对象,而并不需要有该类的对象存在。

3. 使用Class.forName方法
Class有一个著名的static方法forName:

public static Class forName(String className) throws ClassNotFoundException

该方法可以根据字符串参数所指定的类名获取与该类关联的Class对象。如果该类还没有被装入,该方法会将该类装入JVM。

该方法声明抛出ClassNotFoundException异常。顾名思义,当该方法无法获取需要装入的类时(例如,在当前类路径中不存在这个类),就会抛出这个异常。

例如,如果当前类路径中存在Foo类:

package org.whatisjava.reflect;

public class Foo {

public Foo() {

System.out.println("Foo()");

}

static {

System.out.println("Foo is initialized");

}

}

运行下面的代码:

Class clazz = Class.forName("org.whatisjava.reflect.Foo");

控制台会有如下输出:

Foo is initialized

Class.forName("org.whatisjava.reflect.Foo")首先会将reflection.Foo类装入JVM,并 返回与之关联的Class对象。JVM装入Foo类后对其进行初始化,调用了其static块中的代码。需要注意的是:forName方法的参数是类的完 整限定名(即包含包名)。

区别于前面两种获取Class对象的方法。使用Class.forName方法所要获取的与之对应的Class对象的类可以通过字符串的方式给定。该方法通常用于在程序运行时根据类名动态的载入该类并获得与之对应的Class对象。
 

通过上面的文章相信你对java的反射机制有了一定的认识,同时也对java中Class类的用法有了比较清晰的理解,在我们实际工作的过程中,我们不断的运用java知识来解决实际生湖中的问题的时候我们就能对java反射机制有一个更深入的理解!




      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的对象呢?有三种方法可以的获取:
    1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
    MyObject x;
    Class c1 = x.getClass();
    2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如: 
    Class c2=Class.forName("MyObject"),Employee必须是接口或者类的名字。
    3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
    Class cl1 = Manager.class;
    Class cl2 = int.class;
    Class cl3 = Double[].class;
    注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。
二、Class类的常用方法
    1、getName() 
    一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
    2、newInstance()
    Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance()。例如:
    x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。
    3、getClassLoader() 
    返回该类的类加载器。
    4、getComponentType() 
    返回表示数组组件类型的 Class。
    5、getSuperclass() 
    返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
    6、isArray() 
    判定此 Class 对象是否表示一个数组类。
三、Class的一些使用技巧
    1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如
    Object obj = Class.forName(s).newInstance();
    2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:
    if(e.getClass() == Employee.class)...

Class类(在java.lang包中,Instances of the class Classrepresent classes and interfaces in a running Javaapplication):
   在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息
   获取Class实例的三种方式:
     (1)利用对象调用getClass()方法获取该对象的Class实例;
     (2)使用Class类的静态方法forName(),用类的名字获取一个Class实例(staticClass forName(String className)  Returns the Classobject associated with the class or interface with the given stringname. );
     (3)运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例
   在newInstance()调用类中缺省的构造方法 ObjectnewInstance()(可在不知该类的名字的时候,常见这个类的实例) Creates a new instance of the class represented by this Classobject.
   在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象

复制代码
 1 public class ClassTest {
2 public static void main(String [] args)throws Exception{
3 String str1="abc";
4 Class cls1=str1.getClass();
5 Class cls2=String.class;
6 Class cls3=Class.forName("java.lang.String");
7 System.out.println(cls1==cls2);
8 System.out.println(cls1==cls3);
9 }
10 }
复制代码

返回结果为:true,true.
解释:虚拟机只会产生一份字节码, 用这份字节码可以产生多个实例对象。

 

反射

      反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java类的Class类显示要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

      一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以的得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。

构造方法的反射应用

Consturctor(构造器)类代表某个类中的一个构造方法

@1@ 得到某个类所有的构造方法:例如:Constructor [] constructors = Class.forName("java.lang.String").getConstructors();

@2@ 得到某一个构造方法:例如:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

@3@ 创建实例对象:通常方式:String str=new String(new StringBuffer("abc"));
                            反射方式:String str=(String) constructor.newInstance(new StringBuffer("abc"));

 


Class 类是在Java语言中 定义一个特定类的实现。一个类的定义包含成员变量,成员方法,还有这个类实现的接口,以及这个类的父类。Class类的对象用于表示当前运行的 Java 应用程序中的类和接口。 比如:每个数组均属于一个 Class 类对象,所有具有相同元素类型和维数的数组共享一个Class 对象。基本的 Java 类型(boolean, byte, char, short, int, long, float 和 double) 和 void 类型也可表示为 Class 对象。


以下示例使用 Class 对象显示一个对象的 Class 名: 
         void printClassName(Object obj) { 
            System.out.println("The class of " + obj + 
                               " is " + obj.getClass().getName()); 
        }


        我们都知道所有的java类都是继承了object这个类,在object这个类中有一个方法:getclass().这个方法是用来取得该类已经被实例化了的对象的该类的引用,这个引用指向的是Class类的对象(呵呵,有点别扭)。我们自己无法生成一个Class对象(构造函数为private),而 这个Class类的对象是在当各类被调入时,由 Java 虚拟机自动创建 Class 对象,或通过类装载器中的 defineClass 方法生成。我们生成的对象都会有个字段记录该对象所属类在CLass类的对象的所在位置。如下图所示:
 
             Class类
       我们可以把每个Class类的对象当做众多类的代理。而且在每个Class类对象中有会有字段记录他引用的这个类的类加载器。如果该字段为null,表示该类的加载器为bootstrap loader.具体原因见:对于类加载器的认识一文。
 
 
我们知道java中有多个加载器,每个加载器能载入多个类,所以只要取得Class类对象,就可利用其getClassLoader()方法取得该类加载器的引用。
      jvm为每种类管理者独一的Class对象。因此我们可以用双等号操作符来比较对象:a1.getClass()==A.class;应该返回的是true。  
          class类和加载器
    forName(String classname)和 forName(String classname,boolean initialze,ClassLoader loader)   方法 
      该方法返回给定串名相应的de>Classde> 对象。若给定一个类或接口的完整路径名,那么此方法将试图定位、装载和连接该类。若成功,返回该类对象。否则,抛出 ClassNotFoundException 异常。 例如,下面代码段返回名为de>java.lang.Threadde> 的运行 de>Classde> 描述器。de>Class t = Class.forName("java.lang.Thread") ; 此方法是需要指定类加载器的,当用到仅有一个String参数的 forName方法时,Class对象将默认调用当前类加载器作为加载器和将第二参数为 true。第二个参数说明:如果是false时,调用forName方法只是在命令类加载器载入该类,而不初始化该类的静态区块,只有当该类第一次实例化 时,静态区块才被调用。当为true时,则载入时就调用静态区块。 de> 
getClassLoader() 
获取该类的类装载器。 
getComponentType() 
如果当前类表示一个数组,则返回表示该数组组件的 Class 对象,否则返回 null。 
getConstructor(Class[]) 
返回当前 Class 对象表示的类的指定的公有构造子对象。 
getConstructors() 
返回当前 Class 对象表示的类的所有公有构造子对象数组。 
getDeclaredConstructor(Class[]) 
返回当前 Class 对象表示的类的指定已说明的一个构造子对象。 
getDeclaredConstructors() 
返回当前 Class 对象表示的类的所有已说明的构造子对象数组。 
getDeclaredField(String) 
返回当前 Class 对象表示的类或接口的指定已说明的一个域对象。 
getDeclaredFields() 
返回当前 Class 对象表示的类或接口的所有已说明的域对象数组。 
getDeclaredMethod(String, Class[]) 
返回当前 Class 对象表示的类或接口的指定已说明的一个方法对象。 
getDeclaredMethods() 
返回 Class 对象表示的类或接口的所有已说明的方法数组。 
getField(String) 
返回当前 Class 对象表示的类或接口的指定的公有成员域对象。 
getFields() 
返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组。 
getInterfaces() 
返回当前对象表示的类或接口实现的接口。 
getMethod(String, Class[]) 
返回当前 Class 对象表示的类或接口的指定的公有成员方法对象。 
getMethods() 
返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承的方法。 
getModifiers() 
返回该类或接口的 Java 语言修改器代码。 
getName() 
返回 Class 对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。 
getResource(String) 
按指定名查找资源。 
getResourceAsStream(String) 
用给定名查找资源。 
getSigners() 
获取类标记。 
getSuperclass() 
如果此对象表示除 Object 外的任一类, 那么返回此对象的父类对象。 
isArray() 
如果 Class 对象表示一个数组则返回 true, 否则返回 false。 
isAssignableFrom(Class) 
判定 Class 对象表示的类或接口是否同参数指定的 Class 表示的类或接口相同,或是其父类。 
isInstance(Object) 
此方法是 Java 语言 instanceof 操作的动态等价方法。 
isInterface() 
判定指定的 Class 对象是否表示一个接口类型。 
isPrimitive() 
判定指定的 Class 对象是否表示一个 Java 的基类型。 
newInstance() 
创建类的新实例。 
toString() 
将对象转换为字符串。

0 0
原创粉丝点击