什么是反射
对于运行阶段的一个类,可以动态的获取这个类的所有属性、方法和构造方法等信息。对于运行阶段的一个对象,也可以动态的获取这个对象的属性、方法、构造方法等信息的机制,称之为反射机制。 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法(属性)
- 生成动态代理
Class类
主要方法
getName():获得类的完整名字。 getFields():获得类的public类型的属性。 getDeclaredFields():获得类的所有属性。包括private 声明的和继承类 getMethods():获得类的public类型的方法。 getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类 getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。 getConstructors():获得类的public类型的构造方法。 getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。 newInstance():通过类的构造方法创建这个类的一个对象。 复制代码
class获取示例
public class Apple { private int price; public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public static void main(String[] args) throws Exception{ //正常的调用 Apple apple = new Apple(); apple.setPrice(5); System.out.println("Apple Price:" + apple.getPrice()); //通过.class方式调用 Class class1 = Apple.class; //使用class对象的forName方法调用 Class clz = Class.forName("com.demo.api.Apple"); Method setPriceMethod = clz.getMethod("setPrice", int.class); Constructor appleConstructor = clz.getConstructor(); Object appleObj = appleConstructor.newInstance(); setPriceMethod.invoke(appleObj, 14); Method getPriceMethod = clz.getMethod("getPrice"); System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj)); } }
从这个简单的例子可以看出,一般情况下我们使用反射获取一个对象的步骤:
- 获取类的 Class 对象实例
Class clz = Class.forName("com.demo.api.Apple");
- 根据 Class 对象实例获取 Constructor 对象
Constructor appleConstructor = clz.getConstructor();
- 使用 Constructor 对象的 newInstance 方法获取反射类对象
Object appleObj = appleConstructor.newInstance();
而如果要调用某一个方法,则需要经过下面的步骤:
- 获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
- 利用 invoke 方法调用方法
setPriceMethod.invoke(appleObj, 14); 复制代码
Class能实现的功能
1判断对象属于哪个类
Person person = new Person();
Class class2= person.getClass();
System.out.println("class2:"+class2);
输出:class2:class reflect.Person
2获取类信息
Class class1 = Person.class;
Method[] methods = class1.getMethods();
Method[] declaredMethods = class1.getDeclaredMethods();
Field[] declaredFields = class1.getDeclaredFields();
3构建对象
Person person = new Person();
Class class2= person.getClass();
Object o = class2.newInstance();
//强转前先用instanceof判断
if(o instanceof Person){undefined
((Person) o).workIng();
}
4动态执行方法
Class class1 = Class.forName("reflect.Person");
Method work = class1.getDeclaredMethod("work");
Person person = new Person();
work.invoke(person);
5动态操作属性
Class class1 = Class.forName("reflect.Person");
Person person = new Person();
Field field = class1.getDeclaredField("username");
field.set(person,"pine");
代码示例
public class Consumer { private long id;//私有的 public String name;//共有的 /*没参数构造体*/ public Consumer() { } /*有参数构造体*/ public Consumer(long id, String name) { this.id = id; this.name = name; } /*getter setter*/ public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } /*私有的无参buy方法*/ private static void buy() { System.out.println("私有的无参buy方法"); } /*共有的有参有返回值consume方法*/ public String consume(String giftName) { System.out.println("买了一件礼物: " + giftName); return giftName; } } public class TestReflect { public static void getProperty() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { try { /* 获取对象类型 */ Class<?> clazz = Class.forName("com.Dan.Consumer"); Object object = clazz.newInstance(); /* 获取到所有属性 */ Field[] field = clazz.getDeclaredFields(); for (Field f:field) { //String fieldName = f.getName();// 取到属性名字 //System.out.println(fieldName); System.out.println(f); } /* 获取到所有的方法,包括私有的,但不包括父类的 */ Method[] methods = clazz.getDeclaredMethods(); for (Method m:methods){ //String methodName = m.getName(); //System.out.println(methodName); System.out.println(m); } /* 所有的构造体 */ Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor c:constructors){ System.out.println(c); } // 调用方法 Method method = clazz.getMethod("info", String.class, long.class);//获取方法 method.invoke(object, "隔壁老王",2017032009); //得到属性 Field aField = clazz.getDeclaredField("name"); //因为name变量是private的,所以不能用getField方法 aField.setAccessible(true); aField.set(object,"二大爷"); Object obj = aField.get(object); System.out.println(obj); // 得到构造器 Constructor constructor = clazz.getDeclaredConstructor(long.class, String.class); constructor.newInstance(2016040221, "王小二"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException { getProperty(); } }
总结
- 在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象,虚拟机只会产生一份字节码, 用这份字节码可以产生多个实例对象。
- 一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示Java类的Class类显示要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。