JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。
JAVA 反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言,JAVA 有着一个非常突出的动态相关机制:Reflection,用在 Java 身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的 classes。换句话说,Java 程序可以加载一个运行时才得知名称的 class,获悉其完整构造(但不包括 methods 定义),并生成其对象实体、或对其 fields 设值、或唤起其 methods。
Java 反射机制主要提供了以下功能:
1 在运行时判断任意一个对象所属的类;
2 在运行时构造任意一个类的对象;
3 在运行时判断任意一个类所具有的成员变量和方法;
4 在运行时调用任意一个对象的方法;生成动态代理。
***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
/**
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 {
// [构造函数](https://www.baidu.com/s?wd=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPvuBuh7bmvF9PjIhuHmL0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3Erj03njTkPjn1P10LPH64nHTz)
public TestClassType() {
System.out.println("----[构造函数](https://www.baidu.com/s?wd=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1dWPvuBuh7bmvF9PjIhuHmL0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3Erj03njTkPjn1P10LPH64nHTz)---");
}
// 静态的参数初始化
static {
System.out.println("---静态的参数初始化---");
}
// 非静态的参数初始化
{
System.out.println("----非静态的参数初始化---");
}
}
运行结果:
[plain] view plaincopy
---静态的参数初始化---
testForName---class TestClassType
testTypeClass---class TestClassType
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
分析:根据结果可以发现,三种生成的 Class 对象一样的,并且三种生成 Class 对象只打印一次“静态的参数初始化”。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于