一、反射
1、反射概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
2、Java 反射机制的主要用途
1、在运行时判断任意一个对象所属的类。
2、在运行时构造任意一个类的对象。
3、在运行时判断任意一个类所具有的成员变量和方法。
4、在运行时调用任意一个对象的方法。
3、三种获取Class实例对象的方式
1、Person p = new Person();
Class c = p.getClass();
已知类的对象,通过 getClass() 方法获取 Class 实例对象。
2、Class c2 = Person.class;
任意数据类型都具备一个 class 静态成员变量,看上去要比第一种方式简单。
3、将类名作为字符串传递给Class类中的静态方法 forName 即可。
Class c3 = Class.forName("Person");
1 import com.reflect.pojo.Product; 2 import org.junit.Test; 3 4 /** 5 * @author zt1994 2018/3/5 14:25 6 */ 7 public class TestReflect { 8 9 /** 10 * 测试三种获取Class对象的方法 11 * @throws Exception 12 */ 13 @Test 14 public void testGetClass() throws Exception { 15 //实例化类的三种方法 任何对象都是Class的实例 16 //第一种 对象名.getClass() 17 Product product = new Product(); 18 Class<? extends Product> aClass1 = product.getClass(); 19 System.out.println(aClass1); //class com.reflect.pojo.Product 20 //第二种 类型.class 21 Class<Product> aClass2 = Product.class; 22 System.out.println(aClass2); 23 //第三种 Class 类中的静态方法 static Class<?> forName(String className) className是类或者接口的权限定名 24 Class<?> aClass3 = Class.forName("com.reflect.pojo.Product"); 25 System.out.println(aClass3); 26 //比较 27 System.out.println(aClass1==aClass2); //true 28 System.out.println(aClass1==aClass3); //true 29 System.out.println(aClass2==aClass3); //true 30 } 31 }
4、反射的作用
1、增加程序的灵活性,避免将程序写死到代码里(解除硬编码的问题);
2、Java的反射机制它知道类的基本结构,可以动态的去获取类这样的结构的结构;
3、可以让程序员在不知道其它程序员会有什么类的时候就编写完成自己的代码;
4、反射的优点:灵活,功能强大(可以拿到私有的....);
5、反射的缺点:破坏封装,影响性能;
5、反射运用(常用 API)
1、获取构造方法
getConstructors 不能获取私有的构造方法。
getDeclaredConstructors 可以获取所有构造方法,包括私有的。
Product类:
1 public class Product { 2 private Integer id; 3 private String productName; 4 private Integer classifyId; 5 private String brand; 6 7 public Integer getId() { 8 return id; 9 } 10 11 public void setId(Integer id) { 12 this.id = id; 13 } 14 15 public String getProductName() { 16 return productName; 17 } 18 19 public void setProductName(String productName) { 20 this.productName = productName; 21 } 22 23 public Integer getClassifyId() { 24 return classifyId; 25 } 26 27 public void setClassifyId(Integer classifyId) { 28 this.classifyId = classifyId; 29 } 30 31 public String getBrand() { 32 return brand; 33 } 34 35 public void setBrand(String brand) { 36 this.brand = brand; 37 } 38 }
获取构造方法:
1 /** 2 * 测试获取构造方法 3 */ 4 @Test 5 public void testGetConstructor() throws ClassNotFoundException { 6 Class<?> aClass = Class.forName("com.reflect.pojo.Product"); 7 //获取构造器 8 Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); 9 for (Constructor<?> declaredConstructor : declaredConstructors) { 10 System.out.println("declaredConstructor: [" + declaredConstructor + "]"); 11 } 12 }
2、反射创建对象
1、 newInstance()
注意 : 只能够调用无参数的构造方法,无参数的构造方法必须是有权限被访问到的。
2、获得构造器对象之后,通过构造器来创建对象
1 /** 2 * 测试反射创建对象的两种方法 3 */ 4 @Test 5 public void testCreateInstance() throws Exception { 6 //方法一 Class类中有对应的方法 newInstance() 7 Class<?> aClass = Class.forName("com.reflect.pojo.Product"); 8 Product product = (Product) aClass.newInstance(); 9 10 //方法二 获得构造器对象之后,通过构造器来创建对象 11 Constructor<?> constructor = aClass.getDeclaredConstructor(); 12 Product product1 = (Product) constructor.newInstance(); 13 }
3、获取方法
1、获取所有方法
getMethods
getDeclaredMethods
2、获取单个方法
getMethod
getDeclaredMethod
1 /** 2 * 测试获取方法 3 */ 4 @Test 5 public void testGetMethods() throws Exception{ 6 Class<?> aClass = Class.forName("com.reflect.pojo.Product"); 7 8 //获取方法 9 Method[] declaredMethods = aClass.getDeclaredMethods(); 10 for (int i = 0; i < declaredMethods.length; i++){ 11 Method declaredMethod = declaredMethods[i]; 12 //获取方法返回类型 13 Class<?> returnType = declaredMethod.getReturnType(); 14 //输出方法返回类型 15 System.out.println("returnType: [" + returnType + "]"); 16 //获取方法参数类型 17 Class<?>[] parameterTypes = declaredMethod.getParameterTypes(); 18 for (Class parameterType: parameterTypes){ 19 System.out.println("parameterType: [" + parameterType + "]"); 20 } 21 //输出变量名称 22 System.out.println("i: " + i + " declaredMethod: ["+declaredMethod.getName() + "]"); 23 } 24 }
4、获取字段(成员变量)
1、获取所有字段
getFields、getDeclaredFields
2、获取单个字段
getField、getDeclaredField
3、修改获取字段的值
set(Object obj,Object value); 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
get(Object obj); 返回指定对象(传入的obj)上此 Field 表示的字段的值。
1 /** 2 * 获取字段 3 */ 4 @Test 5 public void testAPI() throws ClassNotFoundException { 6 //获取field 7 Class<?> aClass = Class.forName("com.reflect.pojo.Product"); 8 //获取字段 9 Field[] declaredFields = aClass.getDeclaredFields(); 10 for (Field df:declaredFields){ 11 //获取字段类型 12 Class<?> type = df.getType(); 13 System.out.println("type: [" + type + "]"); 14 System.out.println(df); 15 } 16 }
5、通过反射调用方法
1、获得类对应的Class实例;
2、通过反射得到类中的指定的方法
3、通过反射(Method类)来调用方法
Method中的方法:
Object invoke(Object obj, Object... args)
obj: 调用的对象
args: 方法参数
1 /** 2 * 反射调用方法 3 */ 4 @Test 5 public void testInvoke() throws Exception { 6 Product product = new Product(); 7 product.setId(7); 8 product.setClassifyId(3); 9 product.setBrand("联想"); 10 product.setProductName("G480笔记本"); 11 12 //1.获取字节码 13 Class<?> aClass = product.getClass(); 14 //2.获取属性 15 Field[] declaredFields = aClass.getDeclaredFields(); 16 //3.获取属性数组 17 for (Field declaredField : declaredFields) { 18 //获取属性名 19 String fieldName = declaredField.getName(); 20 //回去get方法字符串名 21 String methodName = "get" + toMethodName(fieldName); 22 //通过方法名称使用反射获取方法对象 23 Method method = aClass.getMethod(methodName); 24 //执行方法 25 Object invoke = method.invoke(product); 26 //装换字符串类型 27 String s = String.valueOf(invoke); 28 System.out.println(fieldName + "=" + s); 29 } 30 }