注解与反射
注解:元注解与自定义注解
package Annotation; import java.lang.annotation.*; public class Test02 { @MyAnnotation public void Test(){ } } //测试元注解 //Target 表示我们的注解可以用在什么地方 @Target(value = {ElementType.METHOD,ElementType.TYPE}) //Retention 表示注解在什么地方有效 //RUNTIME>class>sources @Retention(RetentionPolicy.RUNTIME) //Documented 表示是否将我们的注解生成在JAVAdoc中 @Documented //子类可以继承父类的注解 @Inherited @interface MyAnnotation{ }
反射概述
动态语言是运行中可以改变其结构的语言,例如新的函数,对象,甚至代码可以被引进,java不是动态语言,但java可以称为准动态语言,利用反射机制可以获得类似动态语言的特性
反射机制允许程序在执行期间借助Reflection API取得类的任何内部信息,并能直接操作任意对象的内部属性与方法,加载完类以后就生成了一个class类型的对象,这个对象包含了完整的类的结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,透过这个镜子看类的结构,就被形象的称为了反射
实例化对象->getClass方法->得到完整的“包类”名称
得到class的几种方式
package Reflection; //测试class类测创建方式有哪些 public class Test03 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("这个人是:"+person.name); //方式一:通过对象获得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式二:forname Class c2 = Class.forName("Reflection.Student"); System.out.println(c2.hashCode()); //方式三:通过类名.class Class<Student> c3 = Student.class; System.out.println(c3.hashCode()); //方式四:基本内置类型的包装类都有一个Type属性 Class c4 = Integer.TYPE; System.out.println(c4); //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name="学生"; } } class Teacher extends Person{ public Teacher(){ this.name="老师"; } }
所有类型的class对象
package Reflection; import java.lang.annotation.ElementType; import java.util.Comparator; //所有类型的class对象 public class Test04 { public static void main(String[] args) { Class c1 = Object.class;//类 Class c2 = Comparator.class;//接口 Class c3 = String[].class; //数组 Class c4 = int[][].class; //二维数组 Class c5 = Override.class; //注解 Class c6 = ElementType.class; //枚举 Class c7 = Integer.class; //基本数据类型 Class c8 = void.class; //void Class c9 = Class.class; System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //只要元素类型与维度一样就是同一个Class int [] a = new int[10]; int [] b = new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } }
类的加载
package Reflection; //类加载 public class Test05 { public static void main(String[] args) { A a = new A(); System.out.println(A.m); /* 1.加载到内存的方法区中,并将这些静态数据转换成方法区运行时的数据结构,然后生成一个Class对象 2.链接,(1)先验证看是否符合jvm规范 (2)为静态变量分配内存,并赋初值为0,这里m=0,(3)虚拟机常量池内的符号引用替换为直接引用 符号引用指的是并不知道引用目标的实际地址,引用目标也不一定已经被加载到内存中了,因此只是用符号唯一标识出来 直接引用是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同,如果有了直接引用,那引用的目标必定在内存中存在。 3.初始化 将静态的方法变量合并到执行类构造器的clinit方法中,交由jvm执行 <clinit>(){ m = 100; System.out.println("A类静态代码块初始化"); m = 300; } */ } } class A{ static int m = 100 ; static { System.out.println("A类静态代码块初始化"); m = 300; } public A(){ System.out.println("A类的无参构造器"); } }
类的初始化
package Reflection; //测试类什么时候初始化 public class Test06 { static{ System.out.println("main被加载"); } public static void main(String[] args) throws ClassNotFoundException { //1.主动调用 //Son son = new Son(); //2.反射 //Class.forName("Reflection.Son"); //不会产生类的引用的方法 //1.通过子类调用父类的静态变量或方法,子类不会被加载 //System.out.println(Son.b); //2.通过数组也不会加载 Son[] array = new Son[5]; //3.调用常量也不会初始化,因为在链接阶段就已经给常量赋上值了 System.out.println(Son.M); } } class Father{ static{ System.out.println("父类被加载"); } static int b = 2; } class Son extends Father{ static{ System.out.println("子类被加载"); m = 300; } static int m=100; static final int M = 1; }
类加载器
引导类加载器:用c++编写的,是jvm自带的类加载器,负责java平台核心库,用来装载核心类库,该加载器无法直接获取
扩展类加载器:负责jre/lib/ext目录下的jar包或-D java ext.dirs 指定目录下的jar包装入工作库
系统类加载器 负责java-classpath或-D java.class.path所指目录下的jar包装入工作库,是最常用的加载器
package Reflection; public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类加载器 ClassLoader systemClassLoder = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoder); //获取系统类加载器的父类加载器->扩展类加载器 ClassLoader parent = systemClassLoder.getParent(); System.out.println(parent); //获取扩展类加载器的父类加载器->跟加载器(c/c++);由于是c编写的,java得不到这一层,会返回null ClassLoader parent1 = parent.getParent(); System.out.println(parent1); //测试当前类的加载器 ClassLoader classLoder = Class.forName("Reflection.Test07").getClassLoader(); System.out.println(classLoder); // 测试jdk内部的类是谁加载的 ClassLoader classLoder1 = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoder1); //如何获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); //双亲委派机制,保证安全性,防止同名包,类与jdk中的相冲突 //实现时,他会将任务委托给他的上级类加载器,递归这个操作,如果上级类的加载器没有加载,自己才会去加载这个类 } } **获得类的信息** ```java package Reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //获得类的信息 public class Test08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("Reflection.User"); User user = new User(); c1 = user.getClass(); //获得类的名字 System.out.println(c1.getName()); //获得包名加类名 System.out.println(c1.getSimpleName()); //获得类名 //获得类的属性 System.out.println("------------------------------------------------"); Field[] fields = c1.getFields(); //只能找到public属性 /* for (Field field : fields) { System.out.println(field); }*/ fields = c1.getDeclaredFields(); //能找到全部属性,包括私有的 for (Field field : fields) { System.out.println(field); } //获取指定属性 System.out.println("------------------------------------------------"); Field name = c1.getDeclaredField("name"); System.out.println(name); //获取类的方法 System.out.println("------------------------------------------------"); Method[] methods = c1.getMethods(); //获得本类及其父类的所有public方法 for (Method method : methods) { System.out.println("getMethods: "+method); } methods = c1.getDeclaredMethods(); //获得本类所有方法,包括私有的 for (Method method : methods) { System.out.println("getDeclaredMethods: "+method); } //获取指定方法 System.out.println("------------------------------------------------"); Method method1 = c1.getMethod("getName",null); Method method2 = c1.getMethod("setName",String.class); System.out.println(method1); System.out.println(method2); //获取所有的构造器 System.out.println("------------------------------------------------"); Constructor[] constructors = c1.getConstructors(); //获得public方法 for (Constructor constructor : constructors) { System.out.println("#" + constructor); } constructors = c1.getDeclaredConstructors(); //获得所有方法 for (Constructor constructor : constructors) { System.out.println("@" + constructor); } //获得指定的构造器 System.out.println("------------------------------------------------"); Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor); } }
通过反射,动态创建对象执行方法
package Reflection; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //通过反射,动态的创建对象 public class Test09 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { Class c1 = Class.forName("Reflection.User"); //构造一个对象 //User user = (User)c1.newInstance(); //本质上调用类的无参构造器,没有无参构造器会报错 //System.out.println(user); //通过构造器创建对象 //Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); //User user2 = (User)declaredConstructor.newInstance("xiaoming",001,18); //System.out.println(user2); //通过反射调用普通方法 User user3 = (User) c1.newInstance(); //通过反射获取方法 Method setNames = c1.getDeclaredMethod("setName", String.class); // invoke(对象,"方法的值") setNames.invoke(user3, "xiaoming"); System.out.println(user3); //通过反射操作属性 User user4 = (User)c1.newInstance(); Field name = c1.getDeclaredField("name"); //一般情况下不能操作私有属性 name.setAccessible(true); //取消安全检测,就可以操作私有属性 name.set(user4, "xiaoming3"); System.out.println(user4); } }
从性能上来说,直接new一个对象的性能,要高于反射关闭安全检查的性能,高于反射不关闭安全检测的性能
反射获取泛型信息
package Reflection; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; //通过反射获取泛型 public class Test11 { public void test01(Map<String, User> map, List<User> list){ System.out.println("test01"); } public Map<String, User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test11.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("#" + genericParameterType); if(genericParameterType instanceof ParameterizedType){ Type[] a = ((ParameterizedType)genericParameterType).getActualTypeArguments(); for(Type aa : a){ System.out.println(aa); } } } method = Test11.class.getMethod("test02",null); Type genericParameterType = method.getGenericReturnType(); if(genericParameterType instanceof ParameterizedType){ Type[] a = ((ParameterizedType)genericParameterType).getActualTypeArguments(); for(Type aa : a){ System.out.println(aa); } } } }
反射操作注解
package Reflection; import java.lang.annotation.*; import java.lang.reflect.Field; //练习反射操作注解 public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("Reflection.Student2"); Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value的值 Tablekuang tablekuang =(Tablekuang)c1.getAnnotation(Tablekuang.class); System.out.println(tablekuang.value()); //获得类型指定的注解 Field name = c1.getDeclaredField("name"); Field1 annotation = name.getAnnotation(Field1.class); System.out.println(annotation.columName()); } } @Tablekuang("db_student") class Student2{ @Field1(columName = "db_id", type =" int", length = 10) private int id; @Field1(columName = "db_age", type = "int", length = 10) private int age; @Field1(columName = "db_name", type = "varchar", length = 3) private String name; public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public Student2() { } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //类名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Tablekuang{ String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Field1{ String columName(); String type(); int length(); }