反射 & 注解 & 动态代理
一、反射
-
简介
-
字节码对象
public static void main(String[] args) throws ClassNotFoundException { //获取字节码对象 //方式1: Student s = new Student(); Class clazz1 = s.getClass(); //方式2:不需要导包 软编码 Class clazz2 = Class.forName("com.itheima.demo01反射.p01字节码反射.Student"); //方式3: Class clazz3 = Student.class; //字节码对象是唯一的 System.out.println(clazz1==clazz2); System.out.println(clazz1==clazz3); //获取类名 System.out.println(clazz3.getSimpleName()); //获取全类名 System.out.println(clazz3.getName()); }
-
字段的反射
public class Test { public static void main(String[] args) throws Exception { //前提:获取字节码对象 Class clazz = Zi.class; //获取本类和父类中所有公共权限的字段 Field[] fields = clazz.getFields(); System.out.println("fields.length:"+fields.length); //获取本类中所有权限的字段 Field[] declaredFields = clazz.getDeclaredFields(); System.out.println("declaredFields.length:"+declaredFields.length); //获取本类和父类某个公共权限的字段 Field pubFuNum = clazz.getField("pubFuNum"); Field pubZiNum = clazz.getField("pubZiNum"); //Field priZiNum = clazz.getField("priZiNum");//error //获取本类中某个任意权限的字段 Field pubZiNum2 = clazz.getDeclaredField("pubZiNum"); Field priZiNum = clazz.getDeclaredField("priZiNum"); //给字段设置值 Zi z = new Zi(); pubZiNum.set(z,100); System.out.println(z.pubZiNum); //获取字段的值 System.out.println(pubZiNum.get(z)); //操作私有的内容(暴力访问) priZiNum.setAccessible(true); priZiNum.set(z,200); System.out.println(priZiNum.get(z)); } } class Fu{ public int pubFuNum; private int priFuNum; } class Zi extends Fu{ public int pubZiNum; private int priZiNum; }
-
构造方法的反射
- 注意参数是 类型.class 。
public class Test { public static void main(String[] args) throws Exception { //获取字节码对象 Class clazz = Zi.class; //获取本类所有公共权限构造器 Constructor[] cons = clazz.getConstructors(); System.out.println("cons.length:" + cons.length); //获取本类所有权限构造器 Constructor[] declaredCons = clazz.getDeclaredConstructors(); System.out.println("declaredCons.length:" + declaredCons.length); //获取本类某个公共权限构造器 Constructor con1 = clazz.getConstructor(null); Constructor con2 = clazz.getConstructor(int.class); //Constructor con3 = clazz.getConstructor(int.class,int.class);//error //获取本类某个任意权限构造器 Constructor con22 = clazz.getDeclaredConstructor(int.class); Constructor con3 = clazz.getDeclaredConstructor(int.class, int.class); //创建对象 //无参 //Object o = con1.newInstance(null); Zi z1 = (Zi) con1.newInstance(null); System.out.println(z1); //有参 Zi z2 = (Zi) con2.newInstance(100); System.out.println(z2); //私有 (暴力访问) con3.setAccessible(true); Zi z3 = (Zi) con3.newInstance(100, 200); System.out.println(z3); } } class Fu { public Fu() { } } class Zi extends Fu { public Zi() { } public Zi(int num) { System.out.println("Zi..."+num); } private Zi(int num, int num2) { System.out.println("Zi..."+num + "..." + num2); } }
-
方法的反射
- 获取没事,但是调用的时候私有方法需要暴力访问
public class Test { public static void main(String[] args) throws Exception { //获取字节码对象 Class clazz = Zi.class; //获取本类和父类所有公共权限方法(包含了Object继承下来的) Method[] methods = clazz.getMethods(); System.out.println("methods.length:"+methods.length);//12 //取本类中所有任意权限的方法 Method[] declaredMethods = clazz.getDeclaredMethods(); System.out.println("declaredMethods.length:"+declaredMethods.length);//3 //获取本类某个公共权限方法 Method pubZiMethod = clazz.getMethod("pubZiMethod",null); Method pubZiMethod2 = clazz.getMethod("pubZiMethod",int.class); //Method priZiMethod3 = clazz.getMethod("priZiMethod",null);//error //获取本类某个任意权限方法 Method pubZiMethod22 = clazz.getDeclaredMethod("pubZiMethod", int.class); Method priZiMethod3 = clazz.getDeclaredMethod("priZiMethod", null); //使用方法 //公共权限 Zi z = new Zi(); pubZiMethod.invoke(z,null); pubZiMethod2.invoke(z,100); //私有权限(暴力访问) priZiMethod3.setAccessible(true); priZiMethod3.invoke(z,null); } } //Object还有9个公共的方法 class Fu extends Object{ public void pubFuMethod(){} private void priFuMethod(){} } class Zi extends Fu{ public void pubZiMethod(){ System.out.println("pubZiMethod..."); } public void pubZiMethod(int num){ System.out.println("pubZiMethod..."+num); } private void priZiMethod(){ System.out.println("priZiMethod..."); } }
二、注解
-
JUnit单元测试
public class TestDemo { @Test public void test1() { System.out.println("test1"); } @Test public void test2() { System.out.println("test2"); } @Before public void before1() { System.out.println("before1"); } @Before public void before2() { System.out.println("before2"); } @After public void after1() { System.out.println("after1"); } @After public void after2() { System.out.println("after2"); } @BeforeClass public static void staticBefore1() { System.out.println("staticBefore1"); } @BeforeClass public static void staticBefore2() { System.out.println("staticBefore2"); } @AfterClass public static void staticAfter1() { System.out.println("staticAfter1"); } @AfterClass public static void staticAfter2() { System.out.println("staticAfter2"); } }
-
@Test 相关注解执行顺序
<1> 运行 test1 方法执行顺序的结果
<2> 运行 TestDemo 类,会自动执行所有方法
-
-
注解简介
-
注解的定义与使用
public @interface MyAnno { //注解属性 :属性类型 属性名(); //基本类型 int i(); //字符串类型 String s(); //枚举类型 Color co(); //注解类型 Override o(); //Class类 Class cl(); //一维数组类型 String[] ss(); //Demo[] ds();//error 一维数组类型只能是上述5种。 }
//使用注解 @MyAnno(i=1,s="abc",co=Color.RED,o=@Override,cl=Object.class,ss={"abc","def"}) public class Test { }
-
注解的注意事项
//注解属性若是一维数组类型,只有一个元素的值时,可以省略{} @MyAnno(ss = "abc", i2 = 100) //若注解属性名为value,且只有一个属性时,赋值时属性名可以省略 //@MyAnno2(value = {"abc"}) //@MyAnno2(value = "abc") @MyAnno2("abc") public class Test { } @interface MyAnno { String[] ss(); //注解属性可以通过default指定默认值,有默认值的属性可以不赋值 int i() default 0; //没有默认值的注解属性必须赋值 int i2(); } @interface MyAnno2 { String[] value(); }
-
元注解
@MyAnno public class Fu { @MyAnno int num; @MyAnno public void method() { } } class Zi extends Fu { } @Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) //@Retention(value = RetentionPolicy.SOURCE)//源码期间保留 //@Retention(value = RetentionPolicy.CLASS)//字节码期间保留 @Retention(value = RetentionPolicy.RUNTIME)//运行期间保留 @Inherited//当前的注解使用后,可以继承给子类 @Documented //表示当前注解将来在文档中显示 @interface MyAnno { }
-
注解解析
public class Test { public static void main(String[] args) throws Exception { //获取父类字节码对象 Class fuClazz = Fu.class; //获取父类成员上的注解 Annotation[] fuClassAnnos = fuClazz.getAnnotations(); System.out.println("fuClassAnnos.length:"+fuClassAnnos.length); Annotation[] fuClassDeclareAnnos = fuClazz.getDeclaredAnnotations(); System.out.println("fuClassDeclareAnnos.length:"+fuClassAnnos.length); //获取方法的注解 Method fuMethod = fuClazz.getMethod("method", null); Annotation[] fuMethodAnnos = fuMethod.getAnnotations(); System.out.println("annos2.length:"+fuMethodAnnos.length); Annotation[] fuMethodDeclaredAnnos = fuMethod.getDeclaredAnnotations(); System.out.println("fuMethodDeclaredAnnos.length:"+fuMethodDeclaredAnnos.length); //获取指定的注解 //类上的注解 MyAnno anno = (MyAnno) fuClazz.getAnnotation(MyAnno.class); MyAnno anno2 = (MyAnno) fuClazz.getDeclaredAnnotation(MyAnno.class); System.out.println(anno==anno2); //方法上的注解 MyAnno anno3 = fuMethod.getAnnotation(MyAnno.class); MyAnno anno4 = fuMethod.getDeclaredAnnotation(MyAnno.class); System.out.println(anno3==anno4); //获取注解属性的值 System.out.println(anno.i()); System.out.println(anno3.i()); } } @MyAnno(i=100) @MyAnno2 class Fu { @MyAnno(i=200) public void method() { } } //获取注解的时候,是在运行阶段获取的,必须保证注解有效时期是到运行时期。 @Retention(RetentionPolicy.RUNTIME) @interface MyAnno { int i(); } @Retention(RetentionPolicy.RUNTIME) @interface MyAnno2 { }
-
模拟Test注解练习
-
Demo 类
public class Demo { @MyTest public void method1(){ System.out.println("method1"); } @MyTest public void method2(){ System.out.println("method2"); } @MyTest public void method3(){ System.out.println("method3"); } public void method4(){ System.out.println("method3"); } }
-
@MyTest 注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest { }
-
测试类
//模拟Junit测试注解功能 public class Test { public static void main(String[] args) throws Exception { //获取字节码对象 Class clazz = Demo.class; //根据字节码对象创建对象 T newInstance() 创建由此 类对象表示的类的新实例。 Demo td = (Demo) clazz.newInstance(); //获取所有的方法的Method对象 Method[] methods = clazz.getMethods(); //遍历所有的Method对象 for (Method method : methods) { //判断该元素上是否包含MyTest注解(如果包含,就让这个方法运行) //default boolean isAnnotationPresent(类 annotationClass) 如果此元素上 存在指定类型的注释,则返回true,否则返回false。 //System.out.println(method.getName() + ".." + method.isAnnotationPresent(MyTest.class)); if (method.isAnnotationPresent(MyTest.class)) { //执行当前方法 method.invoke(td, null); } } } }
-
三、动态代理
-
概述 - 代理只适用于加强final修饰的类,就是那种我们没法改变的类,但是我们在它的基础上加一些东西
public class FunProxy implements TicketInterface { private Fan fan; public FunProxy(Fan fan) { this.fan = fan; } @Override public int buyTicket() { System.out.println("开启6G模式"); fan.buyTicket(); System.out.println("买了一堆票"); return 10; } }
-
静态代理模式
-
动态代理模式
public class Test { public static void main(String[] args) { Fan fan = new Fan(); //static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //准备数据 //类加载器 ClassLoader classLoader = fan.getClass().getClassLoader(); //被代理的类的所有的父接口 Class<?>[] interfaces = fan.getClass().getInterfaces(); //使用匿名内部类创建InvocationHandler实现类对象 InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //System.out.println(method.getName() + "方法被调用了"); //执行原来的任何方法都会调用加强后的方法,所以可以加个判断 if (method.getName().equals("buyTicket")) { System.out.println("开启高速通道"); System.out.println("买到票了"); return 10; } else { return null; } //method.invoke(fan,null); //不能通过proxy调用方法,会造成死循环操作。 //method.invoke(proxy,null);// error 递归调用 //如果有返回值,返回值与代理的方法返回结果不一致,可能异常。 //return null; } }; //获取代理对象 TicketInterface ti = (TicketInterface) Proxy.newProxyInstance(classLoader, interfaces, handler); //执行操作 int count = ti.buyTicket(); System.out.println(count);//10 ti.toString(); } }