全国咨询/投诉热线:400-618-4000

java中反射的三种方法

创建时间:2018年09月18日15时38分

java中反射的三种方法:
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反射机制有一个更深入的理解!

二、代码示例
1.ClassTest.java

[java] view plaincopy
/**
* java中Class类的使用
*/
import java.io.*;
import java.lang.reflect.*;
public class ClassTest1 {
public ClassTest1(){

}
public static void main(String[] args) throws Exception{
ClassTest1 test=new ClassTest1();
ClassTest1 test1=test.getClass().newInstance();
//test1=test;
test.printMessage();
test1.printMessage();
System.out.println(test.hashCode());
System.out.println(test1.hashCode());

Method[] method=test1.getClass().getMethods();

for(Method m :method){
System.out.println(m.getDeclaringClass());
System.out.println(m.getName());
}
}
public void printMessage(){
System.out.println("Created successful!");
}
}
运行结果:

[plain] view plaincopy
Created successful!
Created successful!
14576877
12677476
class ClassTest1
printMessage
class ClassTest1
main
class java.lang.Object
wait
class java.lang.Object
wait
class java.lang.Object
wait
class java.lang.Object
hashCode
class java.lang.Object
getClass
class java.lang.Object
equals
class java.lang.Object
toString
class java.lang.Object
notify
class java.lang.Object
notifyAll
2.TestClass.java

[java] view plaincopy
/**
*
*/
public class TestClass {
public static void main(String[] args)
{
try {
// 测试Class.forName()
Class testTypeForName = Class.forName("TestClassType");
System.out.println("testForName---" + testTypeForName);
// 测试类名.class
Class testTypeClass = TestClassType.class;
System.out.println("testTypeClass---" + testTypeClass);
// 测试Object.getClass()
TestClassType testGetClass = new TestClassType();
System.out.println("testGetClass---" + testGetClass.getClass());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

class TestClassType {
// 构造函数
public TestClassType() {
System.out.println("----构造函数---");
}
// 静态的参数初始化
static {
System.out.println("---静态的参数初始化---");
}
// 非静态的参数初始化
{
System.out.println("----非静态的参数初始化---");
}
}
运行结果:
[plain] view plaincopy
---静态的参数初始化---
testForName---class TestClassType
testTypeClass---class TestClassType
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
分析:根据结果可以发现,三种生成的Class对象一样的,并且三种生成Class对象只打印一次“静态的参数初始化”。


作者:传智播客JavaEE培训学院

首发:http://java.itcast.cn