JavaEE-Java开发框架的基础-反射机制
概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
Class类
我们知道类是具有相同属性或者行为的一类事物,那么类本身也可以再被抽象,因为类们也有共同的属性和行为(比如类都有属性,都有构造器,都有方法,都能调用方法),所以把类们又抽象成了一个类Class
众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()
等。其中getClass()返回一个Class 对象
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()
被JVM调用,JVM 便自动产生一个Class 对象
在学习Class类的过程中我们还需要学习Field类,Method类,Constructor类
Field类:类属性的抽象
Method类:类方法的抽象
Constructor类:类构造器的抽象
获取指定类的属性、方法、构造器
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//List<?> list = new ArrayList();
//根据一个类的全名字符串来获得一个类的类对象
Class<?> clazz = Class.forName("java.util.HashMap");
//获得传递过来的类的所有方法
Method[] methods = clazz.getDeclaredMethods();
//System.out.println(Arrays.toString(methods));
for(Method m : methods){
System.out.println(m);
}
System.out.println("---------------------------------");
//获得类的所有属性
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
System.out.println(f);
}
System.out.println("---------------------------------");
//获得类的所有的构造器
Constructor<?>[] cs = clazz.getDeclaredConstructors();
for(Constructor c : cs){
System.out.println(c);
}
}
}
结果:
创建类对象的三种方式
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
test();
}
//第一种无参,以类的完整字符串作为参数
public static void test(){
Class<?> clazz = Class.forName("java.util.HashMap");
}
//第二种含参,参数为对象
public static void test(Object obj){
Class<?> clazz = obj.getClass();
}
//第三种无参,直接以类.class创建
public static void test(){
Class<?> clazz = Person.class;
}
}
反射必须掌握的方法
获得具体属性:
Field field = class1.getDeclaredField("address");
System.out.println(field);
获得具体方法;
红框代表可变参数,其实可以理解为数组,数组内容为要反射的方法的参数类型,如果无参数,设置一个空的Class数组即可,或者第二个参数设置为null,如果有参数,数组内容参数的类型,如String,就设置String.class
Method method = class1.getDeclaredMethod("getName", new Class[]{});
Method method1 = class1.getDeclaredMethod("setName", new Class[]{String.class});
System.out.println(method);
System.out.println(method1);
获得具体构造器:
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{Integer.class, String.class, String.class});
获取实例:
//根据类的无参构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{构造器参数});
反射调用方法:
如果底层方法是实例方法(对象方法),第一个参数就是该对象实例,一般以instance为参数即可,第二个参数是方法的参数列表,invoke的返回值就是实例方法的返回值
如果底层方法是静态的(类方法),那么可以忽略指定的 obj 参数,该参数可以为 null
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null
Method[] method = class1.getDeclaredMethod(参数);
method.invoke(instance,'方法的参数')
实例:通过反射方式赋值:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class testReflect {
public static void main(String[] args) throws Exception {
Class<?> class1 = Class.forName("com.Person");
//获得无参构造器
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
//根据类的无参构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{});
System.out.println(instance);
//获得类的所有方法
Method[] methods = class1.getDeclaredMethods();
for(Method m :methods){
//获得方法的名字
String name = m.getName();
//获得是否以set开始
boolean startsWith = name.startsWith("set");
if(startsWith){
//获得到了set字符串的后面的值
String fieldName = name.substring(3);
//获得属性的名字
fieldName = fieldName.substring(0, 1).toLowerCase()+fieldName.substring(1);
//获得方法所对应的属性
Field field = class1.getDeclaredField(fieldName);
//获得属性的具体类型,获得属性对应的类型
Class<?> type = field.getType();
if(type == Integer.class){
//反射调用set方法
m.invoke(instance, new Object[]{1});
}
if(type == String.class && "address".equals(fieldName)){
//反射调用set方法
m.invoke(instance, new Object[]{"北京"});
}
if(type == String.class && "name".equals(fieldName)){
//反射调用set方法
m.invoke(instance, new Object[]{"张三"});
}
}
}
System.out.println(instance);
}
}
实例:通过反射拷贝对象:
import com.Person;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class testReflect {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setAddress("长春");
p.setName("李四");
p.setAge(11);
Object object = copyObject(p);
System.out.println(object);
}
public static Object copyObject(Object obj) throws Exception{
//获得传递过来的对象的类对象
Class<?> class1 = obj.getClass();
//获得属性
Field[] fields = class1.getDeclaredFields();
//获得构造器
Constructor<?> constructor = class1.getConstructor(new Class[]{});
//创建一个对象
Object instance = constructor.newInstance(new Object[]{});
for(Field f :fields){
//获得属性的name
String fname = f.getName();
//获得属性的类型
Class<?> type = f.getType();
//获得属性对应的set和get方法名
String setMethodName = "set"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
String getMethodName = "get"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
//获得get方法
Method gmethod = class1.getDeclaredMethod(getMethodName, null);
//调用get方法获得被拷贝的对象的一个属性值
Object gresult = gmethod.invoke(obj, null);
//获得set方法
Method smethod = class1.getDeclaredMethod(setMethodName, new Class[]{gmethod.getReturnType()});
smethod.invoke(instance, new Object[]{gresult});
}
return instance;
}
}
高阶斗法-破坏私有属性:
由于设置了private的属性通过反射无法直接设置值,可以如下做
//获得构造器
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
//根据类的默认构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{});
//根据方法名字来获得属性对象
Field field = class1.getDeclaredField("name");
//破坏掉私有属性
field.setAccessible(true);
//设置值
field.set(instance, "张三");