【Java语言特性学习之二】反射
一、概念
java加载class文件分两种情况:
(1)类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开(不加载)检查,称为Run- Time Type Identification 运行时类型识别
(2)从其它地方获取引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里,称为反射;
在运行状态中,动态获取类信息(属性、方法)及动态调用类对象方法的功能称为java的反射机制。
二、反射API
Java反射包:java.lang.reflect.*
1、获取类
首先获取类,获取到类之后,Class类提供了很多获取类属性,方法,构造方法的api
(1)obj.getClass(),这个是Object类里面的方法;
(2)User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类;
(3)Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类,使用最多;
package reflect; import reflect.test.model.User; public class Main { public static void main(String[] args) throws ClassNotFoundException { //1.通过Object类里面的方法getClass() User u = new User(); Class c = u.getClass(); System.out.println(c);//class reflect.test.model.User //2通过.Class属性 Class c2 = User.class; System.out.println(c2);//class reflect.test.model.User //3.Class.forName("全路径名") Class c3 = Class.forName("reflect.test.model.User"); System.out.println(c3);//class reflect.test.model.User } }
2、获取属性和方法
package reflect.test.model; public class User { private String name; private int age; public User() {} public User(String name,int age) { this.name = name; this.age = age; } public int a = 100; private String str = "123456789"; public boolean dosomething(Integer a,Float b) { System.out.println("dosomething"); return true; } }
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Main2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException { /************************获取所有的属性************************/ Class<?> c = Class.forName("reflect.test.model.User"); //getDeclaredFields 获取所有的属性 Field[] fs = c.getDeclaredFields(); // 定义可变长的字符串,用来存储属性 StringBuffer sb = new StringBuffer(); // 通过追加的方法,将每个属性拼接到此字符串中 // 最外边的public定义 sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + "{\n"); // 里边的每一个属性 for (Field field : fs) { sb.append("\t");// 空格 sb.append(Modifier.toString(field.getModifiers()) + " ");// 获得属性的修饰符,例如public,static等等 sb.append(field.getType().getSimpleName() + " ");// 属性的类型的名字 sb.append(field.getName() + ";\n");// 属性的名字+回车 } sb.append("}"); System.out.println(sb); /***************************获取指定属性***********************/ //获取id属性 Field idF = null; try { idF = c.getDeclaredField("age"); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } //实例化这个类赋给o Object o = null; try { o = c.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } //打破封装 idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。 //给o对象的id属性赋值"110" try { //set idF.set(o,110); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } //get try { System.out.println(idF.get(o)); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } /***************************获取方法****************************/ //getDeclaredMethods() 获取所有的方法(不包含构造方法) Method[] declaredMethods = c.getDeclaredMethods(); for (Method m:declaredMethods) { System.out.println(m); //getReturnType() 获得方法的放回类型 System.out.println(m.getReturnType()); //getParameterTypes() 获得方法的传入参数类型 Class<?>[] parameterTypes = m.getParameterTypes(); for(Class cc : parameterTypes) { System.out.println(cc); } } //getDeclaredMethod("方法名",参数类型.class,……) 获得特定的方法 Method declaredMethod = c.getDeclaredMethod("dosomething", Integer.class,Float.class); System.out.println(declaredMethod); Method method = c.getMethod("dosomething", Integer.class,Float.class); System.out.println(method); //getDeclaredConstructors() 获取所有的构造方法 Constructor<?>[] declaredConstructors = c.getDeclaredConstructors(); for(Constructor ccc : declaredConstructors) { System.out.println(ccc); } //getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法 Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class,int.class); System.out.println(declaredConstructor); //getSuperclass() 获取某类的父类 Class<?> superclass = c.getSuperclass(); System.out.println(superclass); //getInterfaces() 获取某类实现的接口 Class<?>[] interfaces = c.getInterfaces(); for(Class cccc: interfaces) { System.out.println(cccc); } } }
结果:
public class User{ private String name; private int age; public int a; private String str; } 110 public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float) boolean class java.lang.Integer class java.lang.Float public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float) public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float) public reflect.test.model.User() public reflect.test.model.User(java.lang.String,int) public reflect.test.model.User(java.lang.String,int) class java.lang.Object
三、反射应用--动态代理
package reflect.test.intf; public interface Interface { public void dosomething() ; }
package reflect.test.intf.impl; import reflect.test.intf.Interface; public class InterfaceImpl implements Interface { @Override public void dosomething() { System.out.println("dosomething"); } }
1、静态代理
package reflect; import reflect.test.intf.Interface; import reflect.test.intf.impl.InterfaceImpl; /** * 静态代理 */ public class HandProxy implements Interface{ Interface inter = new InterfaceImpl(); @Override public void dosomething() { System.out.println("静态代理类"); inter.dosomething(); } }
package reflect; public class TestHandProxy { public static void main(String[] args) { HandProxy p = new HandProxy(); p.dosomething(); } }
结果:
静态代理类
dosomething
2、动态代理
package reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 */ public class AutoProxy implements InvocationHandler{ private Object target; public Object bind(Object target) { this.target = target; /** * 第一个是被代理类的类构造器, * 第二个指的是被代理类的接口,也就是Interface接口, * 第三个是实现这个代理的类,这里就是本类。 * 这个方法执行了下面三步: 1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。 2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。 3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的target.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Interface类型来调用接口中定义的方法。 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("动态代理"); result = method.invoke(target, args); System.out.println("动态代理执行结束"); return result; } }
package reflect; import reflect.test.intf.Interface; import reflect.test.intf.impl.InterfaceImpl; public class TestAutoProxy { public static void main(String[] args) { Interface inter = new InterfaceImpl(); AutoProxy ap = new AutoProxy(); Interface obj = (Interface)ap.bind(inter); obj.dosomething(); } }
结果:
动态代理
dosomething
动态代理执行结束
学习技术不是用来写HelloWorld和Demo的,而是要用来解决线上系统的真实问题的.