Java的反射机制允许我们在运行时发现和使用类的信息。是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
一个Class对象表示了运行时的类型信息,包含了类的相关信息。Class对象用于表示一个.class文件,即类的字节码文件。
当一个类在第一次被使用时,JVM才会将其动态地加载。当这个类的Class对象被载入内存后,就能通过它来创建这个类的所有对象。
1.使用Class类的forName()静态方法:
Class c=Class.forName(目标类的文本名);
2.使用类字面常量,假设有Test类,则可通过以下方法获取Class对象:
Class c=Test.class;
3.使用从Object类集成的getClass()方法。
Test test=new Test();
Class c=test.getClass();
测试类Reflection
package com.learn.domain;
public class Reflection {
public String publicField;
private String privateField;
public String getPublicField() {
return publicField;
}
public void setPublicField(String publicField) {
this.publicField = publicField;
}
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String privateField) {
this.privateField = privateField;
}
private void privateMethod(String param){
System.out.println("我是私有方法,参数:"+param);
}
@Override
public String toString() {
return "publicField:" + publicField + " privateField:" + privateField;
}
}
主程序
public class Main {
public static void main(String[] args) {
try {
System.out.println(Class.forName("com.learn.domain.Reflection"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(Reflection.class);
System.out.println(new Reflection().getClass());
}
}
输出
class com.learn.domain.Reflection
class com.learn.domain.Reflection
class com.learn.domain.Reflection
在Java SE5之后,允许通过泛型语法对Class引用所指向的类型进行限定,从而提供了编译期的类型检查。比如使用Class extends Test>
表示Test类及其子类的Class对象,引用错误时在编译时便可发现。而如果使用普通的Class引用,则会到运行时才发现错误。
使用Class的newInstance方法
可以创建实例对象。
主程序
public class Main {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.learn.domain.Reflection");
System.out.println(clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
publicField:null privateField:null
通过Class可以获取类的字段Field,在通过Field可以对字段进行相关的操作。
主程序
public class Main {
public static void main(String[] args) {
try{
Class clazz = Class.forName("com.learn.domain.Reflection");
//获取Reflection的所有字段
Field[] fields = clazz.getDeclaredFields(); // ---- (1)
for(Field tmp:fields){
String modifier = Modifier.isPrivate(tmp.getModifiers())? // ---- (2)
"private":(Modifier.isPublic(tmp.getModifiers())?"public":"");
System.out.println("字段("+modifier+"):"+tmp.getName());
}
Reflection reflection = new Reflection();
System.out.println(reflection);
Field privateField = clazz.getDeclaredField("privateField"); // ---- (3)
privateField.setAccessible(true); // ---- (4)
privateField.set(reflection, "我是私有字段"); // ---- (5)
System.out.println(reflection);
}catch (Exception e){
e.printStackTrace();
}
}
}
输出
字段(public):publicField
字段(private):privateField
publicField:null privateField:null
publicField:null privateField:我是私有字段
getDeclaredFields方法
可以获取类的所有字段(public、private等所有字段)。如果使用getFields方法
,则只能得到public字段。注意,使用这两个方法获取的字段只是在本类中定义的字段,不能获取到父类的定义的字段。getModifiers方法
可以获取字段的修饰符信息,并借助Modifier类的静态方法进行判断。setAccessible方法
。set方法
可以对对象字段赋值。通过Class可以获取类的方法Method,在通过Method可以对方法进行相关的操作,其操作与对Field的操作类似。
主程序
public class Main {
public static void main(String[] args) {
try{
Class clazz = Class.forName("com.learn.domain.Reflection");
//获取Reflection的所有字段
Method[] methods = clazz.getDeclaredMethods();
for(Method tmp:methods){
String modifier = Modifier.isPrivate(tmp.getModifiers())?
"private":(Modifier.isPublic(tmp.getModifiers())?"public":"");
System.out.println("方法("+modifier+"):"+tmp.getName());
}
Reflection reflection = new Reflection();
Method privateMethod = clazz.getDeclaredMethod("privateMethod",String.class);
privateMethod.setAccessible(true);
privateMethod.invoke(reflection, "csdn");
}catch (Exception e){
e.printStackTrace();
}
}
}
输出
方法(public):toString
方法(public):getPrivateField
方法(private):privateMethod
方法(public):setPublicField
方法(public):setPrivateField
方法(public):getPublicField
我是私有方法,参数:csdn