Java反射机制能够获取的信息,与应用
一、什么是Java反射机制?
【1】反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;
【2】对于任意一个对象,都能够调用它的任意一个属性和方法;
像这种动态获取类的信息以及动态调用对象的方法的骚操作称为java语言的反射机制。
二、Java反射机制能够获取及操作哪些信息?
【1】获取类的包名 + 类名
1 package com.zyy.test.reflect; 2 3 public class TestReflect { 4 5 public static void main(String[] args) throws ClassNotFoundException { 6 Class<?> class1 = TestReflect.class; 7 Class<?> class2 = new TestReflect().getClass(); 8 Class<?> class3 = Class.forName("com.zyy.test.reflect.TestReflect"); 9 10 System.out.println("包名+类名:" + class1.getName()); 11 System.out.println("类名" + class1.getSimpleName()); 12 System.out.println("包名+类名:" + class2.getName()); 13 System.out.println("类名" + class2.getSimpleName()); 14 System.out.println("包名+类名:" + class3.getName()); 15 System.out.println("类名" + class3.getSimpleName()); 16 17 /* 18 打印结果如下: 19 包名+类名:com.zyy.test.reflect.TestReflect 20 类名TestReflect 21 包名+类名:com.zyy.test.reflect.TestReflect 22 类名TestReflect 23 包名+类名:com.zyy.test.reflect.TestReflect 24 类名TestReflect 25 */ 26 } 27 28 }
【2】获取某个类的父类与实现的接口信息
1 package com.zyy.test.reflect; 2 3 import java.io.Serializable; 4 5 public class TestReflect implements Serializable{ 6 7 private static final long serialVersionUID = -8047590384784013451L; 8 9 public static void main(String[] args) throws ClassNotFoundException { 10 Class<?> clazz = Class.forName("com.zyy.test.reflect.TestReflect"); 11 //获取父类信息 12 System.out.println("父类:" + clazz.getSuperclass().getName()); 13 //获取实现的所有接口信息 14 Class<?>[] interfaces = clazz.getInterfaces(); 15 for (int i = 0; i < interfaces.length; i++) { 16 System.out.println("接口:" + interfaces[i].getName()); 17 } 18 19 /*打印结果如下: 20 父类:java.lang.Object 21 接口:java.io.Serializable 22 */ 23 } 24 25 }
【3】获取某个类的构造信息以及使用构造进行赋值
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.InvocationTargetException; 5 import java.math.BigDecimal; 7 8 public class TestReflect { 9 10 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, 11 IllegalArgumentException, InvocationTargetException { 12 13 Class<?> clazz = Class.forName("com.zyy.test.reflect.BookFacaed"); 14 Constructor<?>[] constructors = clazz.getConstructors(); 15 16 for (int i = 0; i < constructors.length; i++) { 17 System.out.println("构造" + i + constructors[i].getName() + "的参数为:"); 18 //获取构造的参数信息 19 Class<?>[] types = constructors[i].getParameterTypes(); 20 for (int j = 0; j < types.length; j++) { 21 System.out.println(types[j].getName() + " "); 22 } 23 } 24 25 /*打印结果: 26 构造0com.zyy.test.reflect.BookFacaed的参数为: 27 java.lang.String 28 java.math.BigDecimal 29 构造1com.zyy.test.reflect.BookFacaed的参数为: 30 java.lang.String 31 构造2com.zyy.test.reflect.BookFacaed的参数为: 32 */ 33 34 //实例化拥有2个参数的构造方法 35 BookFacaed bookFacaed = (BookFacaed)constructors[0].newInstance("《数据结构》", new BigDecimal(100)); 36 System.out.println(bookFacaed); //调用实体的toString方法打印 37 38 //通过反射机制直接实例化对象 39 BookFacaed bookFacaed2 = (BookFacaed)clazz.newInstance(); 40 bookFacaed2.setName("《数据结构》"); 41 bookFacaed2.setPrice(new BigDecimal(100)); 42 System.out.println(bookFacaed2); 43 } 44 45 } 46 47 class BookFacaed { 48 private String name; 49 50 private BigDecimal price; 51 52 public BookFacaed () {} 53 54 public BookFacaed (String name) { 55 this.name = name; 56 } 57 58 public BookFacaed (String name, BigDecimal price) { 59 this.name = name; 60 this.price = price; 61 } 62 63 public String getName() { 64 return name; 65 } 66 67 public void setName(String name) { 68 this.name = name; 69 } 70 71 public BigDecimal getPrice() { 72 return price; 73 } 74 75 public void setPrice(BigDecimal price) { 76 this.price = price; 77 } 78 79 @Override 80 public String toString() { 81 return name + "的价格为:" + price; 82 } 83 }
【4】获取某个类的所有属性信息
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Modifier;public class TestReflect { 5 6 public static void main(String[] args) throws ClassNotFoundException { 7 Class<?> clazz = Class.forName("com.zyy.test.reflect.BookFacaed"); 8 Field[] fields = clazz.getDeclaredFields(); 9 for (int i = 0; i < fields.length; i++) { 10 //获得类属性的修饰符 11 String pri = Modifier.toString(fields[i].getModifiers()); 12 //获得类属性的类型 13 Class<?> type = fields[i].getType(); 14 15 System.out.println(pri + " " + type.getSimpleName() + " " + fields[i].getName()); 16 /*打印结果: 17 private String name 18 private BigDecimal price 19 */ 20 } 21 22 /*如果要获取类的接口或者父类的属性使用下面的方法获取*/ 23 Field[] fields2 = clazz.getFields(); 24 } 25 26 }
【5】获取某个类的所有方法及其属性信息
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.Method; 4 import java.lang.reflect.Modifier; 5 import java.math.BigDecimal; 6 7 8 public class TestReflect { 9 10 public static void main(String[] args) throws ClassNotFoundException { 11 Class<?> clazz = Class.forName("com.zyy.test.reflect.BookFacaed"); 12 13 Method[] methods = clazz.getMethods(); 14 for (int i = 0; i < methods.length; i++) { 15 System.out.println("方法" + (i + 1)); 16 //获取方法的修饰符 17 String pri = Modifier.toString(methods[i].getModifiers()); 18 //获取方法的返回类型 19 Class<?> type = methods[i].getReturnType(); 20 //获取方法的持有参数 21 Class<?>[] params = methods[i].getParameterTypes(); 22 for (int j = 0; j < params.length; j++) { 23 System.out.println(params[j].getName()); 24 } 25 //获取方法的抛出异常 26 Class<?>[] excTypes = methods[i].getExceptionTypes(); 27 for (int j = 0; j < excTypes.length; j++) { 28 System.out.println(excTypes[j].getName()); 29 } 30 } 31 } 32 33 }
【6】反射机制调用某个类的某个方法
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.math.BigDecimal; 6 7 public class TestReflect { 8 9 public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, 10 IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { 11 12 Class<?> clazz = Class.forName("com.zyy.test.reflect.BookFacaed"); 13 //调用BookFacaed的addBook()方法 14 Method method = clazz.getMethod("addBook", String.class); 15 method.invoke(clazz.newInstance(), "《数据结构》"); 16 } 17 18 } 19 20 class BookFacaed { 21 private String name; 22 23 private BigDecimal price; 24 25 public BookFacaed () {} 26 27 public BookFacaed (String name) { 28 this.name = name; 29 } 30 31 public BookFacaed (String name, BigDecimal price) { 32 this.name = name; 33 this.price = price; 34 } 35 36 public void addBook(String name) { 37 System.out.println("添加书:" + name); 38 } 39 40 public String getName() { 41 return name; 42 } 43 44 public void setName(String name) { 45 this.name = name; 46 } 47 48 public BigDecimal getPrice() { 49 return price; 50 } 51 52 public void setPrice(BigDecimal price) { 53 this.price = price; 54 } 55 56 @Override 57 public String toString() { 58 return name + "的价格为:" + price; 59 } 60 }
【7】通过反射机制操作某个类的属性
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.Field; 4 import java.math.BigDecimal; 5 6 public class TestReflect { 7 8 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, 9 SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException { 10 11 Class<?> clazz = Class.forName("com.zyy.test.reflect.BookFacaed"); 12 Object obj = clazz.newInstance(); 13 //调用BookFacaed的name属性,并赋值 14 Field field = clazz.getDeclaredField("name"); 15 field.setAccessible(true); //操作属性修饰符为private则必须用此申明 16 field.set(obj, "《数据结构》"); 17 18 System.out.println(field.get(obj)); 19 } 20 21 }
三、Java反射机制能够帮助我们做什么?
【1】打破泛型的约束
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.math.BigDecimal; 6 import java.util.ArrayList; 7 import java.util.List; 8 9 public class TestReflect { 10 11 public static void main(String[] args) throws NoSuchMethodException, SecurityException, 12 IllegalAccessException, IllegalArgumentException, InvocationTargetException { 13 14 List<Integer> list = new ArrayList<Integer>(); 15 //设定了以上泛型之后,list集合中是无法插入String或者其他类型的数据的 16 //通过泛型我们便可打破这个约束,代码如下 17 Method method = list.getClass().getMethod("add", Object.class); 18 method.invoke(list, "看插入了一个String数据"); 19 20 System.out.println(list.get(0)); 21 } 22 23 }
【2】反射机制实现动态代理
Spring的一个核心设计思想便是AOP(面向切面编程),那么AOP是通过动态代理实现的,而动态代理则用到了反射机制;
用了反射机制的好处在于,一个代理就能处理所有的委托,而不用一个委托类就创建一个代理;
1 package com.zyy.test.reflect; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 8 public class TestReflect { 9 10 public static void main(String[] args) { 11 //创建代理类并绑定委托类 12 FruitProxy proxy = new FruitProxy(); 13 Fruit fruit = (Fruit) proxy.bind(new Apple()); 14 fruit.eatFruit(); 15 } 16 17 } 18 19 interface Fruit { 20 public void eatFruit(); 21 } 22 23 //委托类 24 class Apple implements Fruit { 25 public void eatFruit() { 26 System.out.println("eat Apple"); 27 } 28 } 29 30 //代理类 31 class FruitProxy implements InvocationHandler{ 32 private Object obj; 33 34 //绑定对象 35 public Object bind(Object obj) { 36 this.obj = obj; 37 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); 38 } 39 40 @Override 41 public Object invoke(Object proxy, Method method, Object[] args) 42 throws Throwable { 43 System.out.println("这里添加执行内容,<aop:before/>标签熟悉吧,作用一样"); 44 Method result = (Method) method.invoke(obj, args); 45 System.out.println("这里添加执行内容,<aop:after/>标签熟悉吧,作用一样"); 46 47 return result; 48 } 49 50 }
【3】反射机制应用于工厂模式
对于普通的工厂,新增一个子类的时候,工厂就需要进行调整,而加入反射机制后,工厂则不需要关心你有多少个子类;
1 package com.zyy.test.reflect; 2 3 public class TestReflect { 4 5 public static void main(String[] args) throws InstantiationException, 6 IllegalAccessException, ClassNotFoundException { 7 8 Fruit fruit = (Fruit) Factory.getInstance("com.zyy.test.reflect.Orange"); 9 fruit.eatFruit(); 10 } 11 12 } 13 14 interface Fruit { 15 public void eatFruit(); 16 } 17 18 class Apple implements Fruit { 19 public void eatFruit() { 20 System.out.println("eat Apple"); 21 } 22 } 23 24 class Orange implements Fruit { 25 public void eatFruit() { 26 System.out.println("eat Orange"); 27 } 28 } 29 30 class Factory { 31 public static Object getInstance (String className) throws InstantiationException, 32 IllegalAccessException, ClassNotFoundException { 33 34 Object obj = Class.forName(className).newInstance(); 35 return obj; 36 } 37 38 }