05反射与注解
1. 反射
1.1获取Class对象
/** java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所以属性和方法;* 对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法称为java语言的反射机制* 想要解剖一个类,必须先要获取该类的class对象,而剖析一个类或用反射解决具体问题就是使用相关的API* (1)java.lang.Class* (2)java.lang.Reflect* 所以,class对象是反射的根源*/public static void main(String[] args) throws ClassNotFoundException {/*哪些类型可以获取class对象*/// 1.基本数据类型和voidClass<Integer> integerClass = int.class;Class<Void> voidClass = void.class;// 2.类和接口类型Class<Object> objectClass = Object.class;Class<Runnable> runnableClass = Runnable.class;// 3.枚举Class<ElementType> elementTypeClass = ElementType.class;// 4.注解Class<Override> overrideClass = Override.class;// 5.数组Class<Array> arrayClass = Array.class;/*获取class对象的四种方式* 1.类型名.class* 2.对象.getClass()* 3.Class.forName(类型全名称),通常需要配置文件配合使用,可以获取编译期间未知的类型* 4.ClassLoader的类加载器对象,loadClass(类型全名称)*/// 第一种类型名.classClass clazz = Reflect1.class;// 第二种 对象.getClass()Reflect1 r1 = new Reflect1();Class aClass = r1.getClass();// 第三种 Class.forName(类型全名称)Class clazz1 = Class.forName("Reflect.User");/** 反射的应用场景* 各个框架的设计(主要场景)* 各大框架的内部实现了大量的反射机制,想要深入了解框架,则必须要了解反射机制*/}
1.2获取类型的详细信息
public class Reflcet2 {/** 反射的应用* 通过反射获取类型的详细信息* 可以获取:包,修饰符,类型名,父类(包括泛型父类),父接口(包括泛型父接口),成员(属性,构造器,方法)* 注解(类上的,方法上的,属性上的)*/public static void main(String[] args) throws ClassNotFoundException {Class clazz = Class.forName("Reflect.User");// 1.获取类名String name = clazz.getName();System.out.println(name);// 2.获取该类实现的所有接口Class[] interfaces = clazz.getInterfaces();System.out.println(interfaces);// 3.获取该类的所有属性Field[] declaredFields = clazz.getDeclaredFields();System.out.println(declaredFields);// 4.获取父类的字节码对象Class aClass = clazz.getSuperclass();System.out.println(aClass);// 5.获取该类的所有方法Method[] declaredMethods = clazz.getDeclaredMethods();System.out.println(declaredMethods);// 6.获取该类的所有构造方法Constructor[] declaredConstructors = clazz.getDeclaredConstructors();System.out.println(declaredConstructors);}}
1.3通过反射创建任意类型对象
public class Reflcet3 {public static void main(String[] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException,NoSuchMethodException, InvocationTargetException {/*创建任意引用类型的对象* 1.直接通过class对象来实例化(要求必须有无参构造)* 2.通过获取构造器对象来进行实例化*/// 1.直接通过class对象来实例化Class<?> aClass = Class.forName("Reflect.User");// 如果类没有无参构造,就没有无参实例化方法User o = (User) aClass.newInstance();o.fn();// 2.通过获取构造器对象来进行实例化// 1.获取该类型的Class对象2.获取构造器对象3.创建对象// 已知的话,都倒是可以这样操作// 1.Class<User> u = User.class;Class<?> clazz = Class.forName("Reflect.User");// 2.获取位置类的构造函数Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class);// 3.创建对象User o1 = (User) constructor.newInstance(18, "老王");o1.fn();}}
1.4通过反射获取任意类型的属性
public class Reflcet4 {public static void main(String[] args)throws ClassNotFoundException, NoSuchFieldException, InstantiationException,IllegalAccessException {// 操作任意类型的属性Class clazz = Class.forName("Reflect.User");Object obj = clazz.newInstance();// 获取所有的属性名/*Field[] declaredFields = clazz.getDeclaredFields();for (Field item : declaredFields) {System.out.println(item);}*/// 获取已知的属性名// Field gender = clazz.getDeclaredField("gender");Field gender = clazz.getDeclaredField("age");// 如果属性值为私有的,则需要设置属性可以访问gender.setAccessible(true);// 设置属性值gender.set(obj, 18);// 获取属性值Object value = gender.get(obj);System.out.println(value);}}
1.5通过反射调用任意类型的方法
public class Reflcet5 {// 反射调用任意类型的方法public static void main(String[] args)throws ClassNotFoundException, NoSuchMethodException, InstantiationException,IllegalAccessException, InvocationTargetException {// 1.获取该类型的class对象Class clazz = Class.forName("Reflect.User");Object obj = clazz.newInstance();// 2.获取对象方法// 全部方法/*Method[] declaredMethods = clazz.getDeclaredMethods();for (Method item : declaredMethods) {System.out.println(item);}*/// 单个方法Method fn = clazz.getDeclaredMethod("fn", String.class);// 3.调用方法 =>如果需要突破权限依旧是调用setAccessible(true)fn.invoke(obj, "你好啊");}}
测试用的代码
public class User {private int age;private String name;public int gender;public User() {this.age = 0;this.name = "无";}public User(int age, String name) {this.age = age;this.name = name;}public void fn() {System.out.println(name + "今年" + age + "了");}public void fn(String str) {System.out.println(str);}}
2. 注解
public class Annotation1 {/*什么是注解* 注解是一种代码级别的说明和类,接口平级.相当于一种标记,在程序中加入注解就等于为程序打上某种标记* javac编译器,开发工具和其他程序可以通过反射来了解你的类及元素上有无标记,看你的程序有什么标记,就去干相应的是去* 标记可以加在包,类,属性,方法,方法的参数以及局部变量上定义*//** 注解的作用* 执行编译期的检查 例如@Override 代表着重写父类的方法* 分析代码(主要用途:替代配置文件); 用在框架里面,注解开发*//** JDK提供的3种基本注解* 1.@Override:描述方法的重写* 2.@SupperssWarnings:压制警告* 3.@Deprecated:标记过时*/public static void main(String[] args)throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,IllegalAccessException, InstantiationException {demo1 d = new demo1();// d.fn(); // 表现出来了/*自定义标注*/// 1.获取Demo1字节码对象Class clazz = demo1.class;// 2.获取Demo1的注解对象Annottation2 an = (Annottation2) clazz.getAnnotation(Annottation2.class);System.out.println(an);// 3.反射获得方法对象Method fn2 = clazz.getDeclaredMethod("fn2");// 想使用就得使用构造函数,给它一个对象Object o = clazz.newInstance();fn2.invoke(o);// System.out.println(fn2);}}
/*元注解* 元注解是使用在自定义的注解,为自定义的注解提供支持的* 常用的元注解* @Target:定义该注解作用在什么上面(位置),默认注解可以在任何位置,值为:ElementType的枚举值* METHOD:方法* TYPE:类型* FIELD:字段* CONSTRUCTOR:构造方法声明* @Retention:定义该注解保留到那个代码阶段,值为:RetentionPolicy类型,默认只在源码阶段保留* SOURCE:只在源码上保留* CLASS:在源码和字节码上保留* RUNTIME:在所有阶段都保留 */@Target(value = {ElementType.METHOD, ElementType.TYPE})@Retention(value = RetentionPolicy.SOURCE)public @interface Annottation2 {}
@Annottation2public class demo1 {@Deprecatedpublic void fn() {System.out.println("标记已过时");}@Annottation2 // 使用注解时给属性赋值public void fn2() {System.out.println("你好");}}
