JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
知道一个类后,我们怎么知道这个类的所有属性和方法呢?这就需要用到Class类了。
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。
当我们编写完一个 Java 项目之后,所有的 Java 文件都会被编译成一个.class 文件,这些 Class 对象承载了这个类型的父类、接口、构造函数、方法、属性等原始信息,这些 class 文件在程序运行时会被 ClassLoader 加载到虚拟机中。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。我们通过 new 的形式创建对象实际上就是通过这些 Class 来创建,只是这个过程对于我们是不透明的而已。
Class的API很多,具体大家可以查看文档,或者这个在线中文文档。
有三种方式:
1.直接调用类的class
Class clazz = Dog.class;
2.调用对象的getClass()方法
Dog dog = new Dog("小黄");
Class clazz2 = dog.getClass();
3.使用Class类的forName(String className)方法,这里注意className要填写类的全部路径,包括包名和类名。
try {
Class clazz3 = Class.forName("com.wangjj.android_training.reflection.Dog");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
返回所有:
getConstructors(): 获取所有"公有的"构造方法,返回一个包含某些 Constructor对象的数组。
getDeclaredConstructors(): 获取所有的构造方法(包括私有、受保护、默认、公有)
返回单个:
getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法,参数是要获取的构造方法的参数Class
getDeclaredConstructor(Class... parameterTypes):获取单个的构造方法(包括私有、受保护、默认、公有),参数是要获取的构造方法的参数Class
调用构造方法:
Constructor-->newInstance(Object... args)
下面看一个例子:
public class Animal {
protected String name;
protected String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
狗类继承自动物类,有三个构造方法,分别是私有有参,公有无参,公有有参的。
public class Dog extends Animal {
private int loyalty;
private int weight;
private Dog(int loyalty){
this.loyalty = loyalty;
}
public Dog(){
}
public Dog(String name){
this.name = name;
}
public int getLoyalty() {
return loyalty;
}
public void setLoyalty(int loyalty) {
this.loyalty = loyalty;
}
public int getWeight() {
return weight;
}
private void setWeight(int weight) {
this.weight = weight;
}
}
Class clazz = Dog.class;
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、无参的构造方法*******************************");
try {
Constructor con = clazz.getConstructor(null);
System.out.println(con);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("******************获取私有构造方法,并调用*******************************");
try {
Constructor con = clazz.getDeclaredConstructor(int.class);
//调用构造方法
con.setAccessible(true);// 忽略掉访问修饰符
Dog dog1 = (Dog) con.newInstance(100);
System.out.println(con);
System.out.println("忠诚度:"+ dog1.getLoyalty());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
打印结果如下:
**********************所有公有构造方法*********************************
public com.wangjj.android_training.reflection.Dog(java.lang.String)
public com.wangjj.android_training.reflection.Dog()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
public com.wangjj.android_training.reflection.Dog(java.lang.String)
public com.wangjj.android_training.reflection.Dog()
private com.wangjj.android_training.reflection.Dog(int)
*****************获取公有、无参的构造方法*******************************
public com.wangjj.android_training.reflection.Dog()
******************获取私有构造方法,并调用*******************************
private com.wangjj.android_training.reflection.Dog(int)
忠诚度:100
返回所有:
Field[] getFields():获取所有的"公有字段",包括继承的公有字段
Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有,不包括继承的字段
返回单个:
public Field getField(String fieldName):获取某个"公有的"字段;
public Field getDeclaredField(String fieldName):获取某个字段
设置字段的值:
Field --> public void set(Object obj,Object value):
参数说明:
1.obj:要设置的字段所在的对象;
2.value:要为字段设置的值;
例如:
Field field = clazz.getDeclaredField("loyalty");
field.setAccessible(true);
field.set(dog1, 60);
System.out.println("忠诚度:"+ dog1.getLoyalty()); // 忠诚度:60
返回所有:
public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括:私有、受保护、默认、公有(不包括继承的)
返回单个:
public Method getMethod(String name,Class>... parameterTypes)
public Method getDeclaredMethod(String name,Class>... parameterTypes)
参数:
name : 方法名;
Class ... : 形参的Class类型对象
调用方法:
Method --> public Object invoke(Object obj,Object... args):
参数说明:
obj: 要调用方法的对象;
args:调用方式时所传递的实参;
如下:
Method method = clazz.getDeclaredMethod("setWeight", int.class);
method.setAccessible(true);
method.invoke(mydog, 2);
System.out.println(mydog.getWeight()); // 2
反射最重要的用途就是开发各种通用框架。很多框架(比如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。
当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射还可以用来越过泛型检查。
Java基础之—反射(非常重要)
深入解析Java反射(1) - 基础