百知教育 - 孙帅 - 19_反射与标注
01_类对象的概念
-
类的对象:
基于某个类new出来的对象,也称为实例对象。 -
类对象:
类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)。 -
获取类对象的方法:
- 类名.class: 如:int.class、double.class
Class c1 = ArrayList.class;
- 类的对象.getClass()
ArrayList l1 = new ArrayList(); ArrayList l2 = new ArrayList(); Class c2 = l1.getClass(); Class c3 = l2.getClass();
- Class.forName(“类的全名”): 通过类名获得类对象
Class c4 = Class.forName("java.util.ArrayList");
- 类名.class: 如:int.class、double.class
02_利用反射获取类的信息
-
java.lang.reflect中的类:
- Field: 属性
- 获取此类对象的方法:
- getFields(): 获得 公开属性 ( 包括父类 )
- getDeclaredFields(): 获得 所有属性(只包括本类)
- 获取此类对象的方法:
- Method: 方法
- 获取此类对象的方法:
- getMethods(): 获取公开方法(包括父类)
- getDeclaredMethods(): 获取所有方法(只包括本类)
- 获取此类对象的方法:
- Constructor: 构造方法
- 获取此类对象的方法:
- getConstructors(): 获取公开构造方法(包括父类)
- getDeclaredConstructors(): 获取所有构造方法(只包括本类)
- 获取此类对象的方法:
- Field: 属性
-
代码:
package day25; import java.util.ArrayList; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Constructor; public class TestClass{ public static void main(String[] args){ Class c1 = ArrayList.class; /* ArrayList l1 = new ArrayList(); ArrayList l2 = new ArrayList(); Class c2 = l1.getClass(); Class c3 = l2.getClass(); try{ Class c4 = Class.forName("java.util.ArrayList"); }catch(ClassNotFoundException e){ e.printStackTrace(); } System.out.println(c1.getName()); System.out.println(c1.getPackage().getName()); System.out.println(c2.getSuperclass().getName()); Class[] cs = c1.getInterfaces(); for(Class c : cs){ System.out.println(c.getName()); } */ /* Field[] fs = c1.getDeclaredFields(); for(Field f : fs){ System.out.println(f); } */ /* Method[] ms = c1.getDeclaredMethods(); for(Method m : ms){ System.out.println(m); } */ Constructor[] cs = c1.getDeclaredConstructors(); for(Constructor c : cs){ System.out.println(c); } } }
-
运行结果:
03_利用反射实现常规操作
-
代码:
package day25; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class TestReflection{ public static void main(String[] args) throws Exception{ //Object o = new Student(); Class c = Class.forName("day25.Student"); Object o = c.newInstance(); //Object o2 = new Student("YKY" , 20); Constructor con = c.getConstructor(String.class , int.class); Object o2 = con.newInstance("YKY" , 20); //o2.study(); Method m = c.getMethod("study"); m.invoke(o2); m.invoke(o); //o.study(); //int result = o2.study("CoreJava"); Method m2 = c.getMethod("study" , String.class); Object result = m2.invoke(o2 , "CoreJava"); System.out.println(result); } } class Student{ private String name; private int age; public Student(){ super(); System.out.println("Student()"); } public Student(String name , int age){ super(); this.name = name; this.age = age; System.out.println("Student(String , int)"); } public void study(){ System.out.println("Student "+name+" study"); } public int study(String course){ System.out.println("Student "+name+" study "+course); return 100; } }
-
运行结果:
04_利用反射访问私有成员
-
代码:
package day25; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Field; public class TestReflection{ public static void main(String[] args) throws Exception{ //Object o = new Student(); Class c = Class.forName("day25.Student"); Object o = c.newInstance(); //Object o2 = new Student("YKY" , 20); Constructor con = c.getConstructor(String.class , int.class); Object o2 = con.newInstance("YKY" , 20); //o2.study(); Method m = c.getDeclaredMethod("study"); m.setAccessible(true); m.invoke(o2); m.invoke(o); //o.study(); //int result = o2.study("CoreJava"); Method m2 = c.getMethod("study" , String.class); Object result = m2.invoke(o2 , "CoreJava"); System.out.println(result); Field f = c.getDeclaredField("name"); f.setAccessible(true); System.out.println(f.get(o)); f.set(o , "YKY"); System.out.println(f.get(o)); } } class Student{ private String name; private int age; public Student(){ super(); System.out.println("Student()"); } public Student(String name , int age){ super(); this.name = name; this.age = age; System.out.println("Student(String , int)"); } private void study(){ System.out.println("Student "+name+" study"); } public int study(String course){ System.out.println("Student "+name+" study "+course); return 100; } }
-
运行结果:
05_枚举的概念
-
概念:
可看做一个类,拥有的对象 是 特定的几个值,默认无参构造方法为私有。 -
语法:
enum 枚举名{ 枚举值, 枚举值, 枚举值 }
-
访问:
枚举名.枚举值 -
枚举值:
是枚举类中的 公开静态常量,类型为枚举类型。 -
代码(编译通过):
package day25; public class TestEnum{ public static void main(String[] args){ Order o = new Order(); o.status = State.PAYED; } } class Order{ public State status = State.UNPAY; } enum State{ //等价于类State2 UNPAY, PAYED, SENT, RECEIVED } class State2{ public static final State2 UNPAY = new State2(); public static final State2 PAYED = new State2(); public static final State2 SENT = new State2(); public static final State2 RECEIVED = new State2(); }
06_枚举的语法
-
Enum
默认是所有枚举的父类 -
代码:
package day25; import static day25.State.*; //引入静态属性、方法 import static java.lang.System.*; public class TestEnum{ public static void main(String[] args){ Order o = new Order(); o.status = PAYED; State[] states = values(); for(State state : states){ out.println(state.name()+" "+state.getComment()+" "+state.ordinal()); } out.println("nanoTime: "+nanoTime()); } } class Order{ public State status = UNPAY; } enum State{ //具有有参构造方法的枚举,等价于类State2 UNPAY("未支付"), PAYED("已支付"), SENT("已发货"), RECEIVED("已收货"); private String comment; private State(String s){ comment = s; } public String getComment(){ return comment; } } class State2{ public static final State2 UNPAY = new State2("未支付"); public static final State2 PAYED = new State2("已支付"); public static final State2 SENT = new State2("已发货"); public static final State2 RECEIVED = new State2("已收货"); private String comment; private State2(String s){ comment = s; } public String getComment(){ return comment; } } enum EnumA{ //枚举中含有抽象方法时,枚举值定义时要实现抽象方法 A1(){ public void print(){} }, A2(){ public void print(){} }; public abstract void print(); } abstract class B{ public static final B B1 = new B(){ public void print(){} }; public static final B B2 = new B(){ public void print(){} }; public abstract void print(); private B(){} }
-
运行结果:
07_自定义标注
-
概念:
表述代码的代码 -
分类:
- 标记标注: 没有属性。写法: @标注名
- 单值标注: 一个属性。写法: @标注名(属性名 = 属性值) ,如果 属性名为value,可以简写为: @标注名(属性值)
- 多值标注: 多个属性。写法: @标注名(属性名1 = 属性值1 , 属性名2 = 属性值2 …)
-
标注属性类型:
必须是具有字面值的类型(8中基本类型、String、Enum、Class以及它们的数组) -
元标注:
- Target: 描述可以为哪些程序组件添加此标注(程序组件:类、属性、构造方法、方法 …)
- Retention: 描述标注信息保留到什么时候(取值:SOURCE、CLASS、RUNTIME)
-
代码:
package day25; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.*; import static java.lang.annotation.ElementType.*; import java.lang.reflect.Method; public class TestAnnotation{ public static void main(String[] args){ Class c = MyClass.class; Method[] ms = c.getMethods(); for(Method m : ms){ if(m.isAnnotationPresent(Test.class)){ Test t = m.getAnnotation(Test.class); String v1 = t.value(); int v2 = t.value2(); System.out.println(m.getName()+" value = "+v1+" value2 = "+v2); } } } } class MyClass{ @Test public void method1(){ } @Test("HHH") public void method2(){ } @Test(value = "HHH" , value2 = 19) public void method3(){ } public void method4(){ } } @Target(METHOD) @Retention(RUNTIME) @interface Test{ String value() default "YKY"; int value2() default 20; }
-
运行结果:
08_自定义标注的案例
-
(对一个类自动测试)代码:
package day26; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import java.util.TreeMap; import java.lang.reflect.Method; import java.util.Collection; public class TestAutoTestEngine{ public static void main(String[] args){ autoTest("day26.ClassA"); } //根据className,自动创建对象,并按照Test标注,按顺序,用相应的参数,执行每个需要测试的方法 public static void autoTest(String className){ //此函数功能相当于以下代码 /* ClassA o = new ClassA(); System.out.println(o.mb("YKY")); System.out.println(o.ma("HHH")); System.out.println(o.md("LYH")); System.out.println(o.mc("YXM")); */ try{ Class c = Class.forName(className); Object o = c.newInstance(); TreeMap<Integer , Method> map = new TreeMap<>(); //拿到c类中所有公开方法 Method[] ms = c.getMethods(); for(Method m : ms){ //拿到添加了Test标注的方法中的Order if(m.isAnnotationPresent(Test.class)){ Test t = m.getAnnotation(Test.class); int order = t.order(); //利用TreeMap key:order value:Method map.put(order , m); } } //遍历TreeMap的值,依次调用每个方法 Collection<Method> values = map.values(); for(Method m : values){ Test t = m.getAnnotation(Test.class); String parameter = t.parameter(); Object result = m.invoke(o , parameter); System.out.println(result); } }catch(Exception e){ e.printStackTrace(); } } } class ClassA{ @Test(order = 2 , parameter = "HHH") public String ma(String s){ return "ma "+s; } @Test(order = 1 , parameter = "YKY") public String mb(String s){ return "mb "+s; } @Test(order = 4 , parameter = "YXM") public String mc(String s){ return "mc "+s; } @Test(order = 3 , parameter = "LYH") public String md(String s){ return "md "+s; } } @Target(METHOD) @Retention(RUNTIME) @interface Test{ int order(); String parameter(); }
-
运行结果: