本文共 13222 字,大约阅读时间需要 44 分钟。
Reflection(反射) 是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包括了完整的类的结构信息,我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法 在运行时处理注解 生成动态代理 …优点:
可以实现动态创建对象和编译,体现出很大的灵活性 缺点: 对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求,这类操作总是慢于直接执行相同的操作java.lang.Class :代表一个类
java.lang.reflect.Method :代表类的方法 java.lang.reflect.Field :代表类的成员变量 java.lang.reflect.Constructor :代表类的构造器 …package com.study.www.reflection;public class Test01 { public static void main(String[] args) throws Exception{ Class c1 = Class.forName("com.study.www.reflection.User"); System.out.println(c1); //class com.study.www.reflection.User System.out.println(c1.hashCode()); //460141958 //一个类在内存中只有一个Class对象 //一个类被加载后,类的整个结构都会被封装在Class对象中 Class c2 = Class.forName("com.study.www.reflection.User"); System.out.println(c2.hashCode()); //460141958 }}class User{ }
在Object类中定义了以下方法,此方法将被所有子类继承 :
public final Class getClass() 以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称 对象照镜子后可以得到的信息:某个类的属性,方法和构造器,某个类到底实现了哪些接口,对于每个类而言。JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定的某个结构(class/interface/enum/annotation/primitive type/void/[ ])的信息 · Class本身也是一个类 · Class对象只能由系统建立对象 · 一个加载的类在JVM中只会有一个Class实例 · 一个Class对象对应的是一个加载到JVM中的.class文件 · 每个类的实例都会记得自己是由哪个Class实例所生成 · 通过Class可以完整地得到一个类中的所有被加载的结构 · Class类是Reflection的根源,针对任何你想动态加载,运行的类,唯有先获得相应的Class对象(1)若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高:
Class c1 = Person.class; (2)已知某个类的实例对象,调用该实例对象的 getClass() 方法获取Class对象: Class c2 = person.getClass(); (3)已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName() 获取,可能会抛出ClassNotFoundException: Class c3 = Class.forName(“demo.Student”); (4)内置基本数据类型可以直接用类名.Type (5)还可以利用ClassLoaderpackage com.study.www.reflection;/** *测试Class类的创建方式有哪些? */public class Test02 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Person(); //方式一:通过对象获得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //460141958 //方式二:通过forName()获得 Class c2 = Class.forName("com.study.www.reflection.Student"); System.out.println(c2.hashCode()); //1163157884 //方式三:通过类名.class 获得 Class c3 = Student.class; System.out.println(c3.hashCode()); //1163157884 //方式四:基本内置类型的包装类都有一个Type属性 Class c4 = Integer.TYPE; System.out.println(c4); //int //获得父类类型 Class c5 = c2.getSuperclass(); System.out.println(c5); //class com.study.www.reflection.Person }}class Person{ }class Student extends Person{ }class Teacher extends Person{ }
package com.study.www.reflection;import java.lang.annotation.ElementType;public class Test03 { public static void main(String[] args) { Class c1 = Object.class; //类 Class c2 = Comparable.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; //Class System.out.println(c1); //class java.lang.Object System.out.println(c2); //interface java.lang.Comparable System.out.println(c3); //class [Ljava.lang.String; System.out.println(c4); //class [[I System.out.println(c5); //interface java.lang.Override System.out.println(c6); //class java.lang.annotation.ElementType System.out.println(c7); //class java.lang.Integer System.out.println(c8); //void System.out.println(c9); //class java.lang.Class }}
类的主动引用(一定会发生类的初始化)
· 当虚拟机启动,先初始化main方法所在的类 · new一个类的对象 · 调用类的静态成员(除了final常量)和静态方法 · 使用java.lang.reflect 包的方法对类进行反射调用 · 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类 类的被动引用(不会发生类的初始化) · 当访问一个静态域时,只有真正声明这个域的类才会被初始化,如:当通过子类引用父类的静态变量,不会导致子类初始化 · 通过数组定义类引用,不会触发此类的初始化 · 引用常量 不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中)类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的javaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象package com.study.www.reflection;public class Test05 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类的额加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2 //获取系统类加载器的父类加载器-->扩展类加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //sun.misc.Launcher$ExtClassLoader@1b6d3586 //获取扩展类加载器的父类加载器-->根加载器(c/c++) ClassLoader parent1 = parent.getParent(); System.out.println(parent1); //null //测试当前类是由哪个加载器加载的 ClassLoader classLoader = Class.forName("com.study.www.reflection.Test05").getClassLoader(); System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2 //测试JDK内置的类是谁加载的 ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader1); //null //如何获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); }}
package com.study.www.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;/** * 获得类的信息 */public class Test06 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.study.www.reflection.User"); //获得类的名字 System.out.println(c1.getName());//获得包名+类名 System.out.println(c1.getSimpleName()); // 获得类名 System.out.println("===========================>"); //获得类的属性 Field[] fields = c1.getFields(); //只能找到public属性 fields = c1.getDeclaredFields(); // 找到全部的属性 for (Field field : fields) { System.out.println(field); } //获得指定属性的值 Field name = c1.getDeclaredField("name"); System.out.println(name); System.out.println("==========================>"); //获得类的方法 Method[] methods = c1.getMethods(); //获得本类及父类的全部public方法 for (Method method : methods) { System.out.println("正常的:" + method); } Method[] methods02 = c1.getDeclaredMethods(); //获得本类的所有方法 for (Method method : methods02) { System.out.println("getDeclaredMethods :" + method); } System.out.println("==========================>"); //获得指定的方法 Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); System.out.println(setName); //获得类的构造器 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); } //获得指定的构造器 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor); }}
运行结果:
package com.study.www.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * @author Liang * @create 2021-01-27 18:37 * 通过反射,动态的创建对象 */public class Test07 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //获得Class对象 Class c1 = Class.forName("com.study.www.reflection.User"); //构造一个对象 // User user = (User) c1.newInstance(); //本质是调用了类的无参构造器 // System.out.println(user); //通过构造器创建对象 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 = (User) constructor.newInstance("Jay", 2020524, 18); System.out.println(user2); //通过反射调用普通方法 User user3 = (User)c1.newInstance(); //通过反射获取一个方法 Method setName = c1.getDeclaredMethod("setName", String.class); setName.invoke(user3, "Leehom"); //invoke :激活 System.out.println(user3.getName()); //通过反射操作属性 User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); name.setAccessible(true); //不能直接操作私有的属性,我们需要关闭程序的安全检测 属性或方法的setAccessible(true); name.set(user4, "AAA"); System.out.println(user4.getName()); }}
有时可以通过关闭安全检测来提升效率:setAccessible(true)
package com.study.www.reflection;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 Test09 { public void test01 (Mapmap , List list){ System.out.println("test01"); } public Map test02(){ System.out.println("tset02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test09.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("######" + genericParameterType); if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } method = Test09.class.getMethod("test02",null); Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } }}
运行结果:
· getAnnotations
· getAnnotationpackage com.study.www.reflection;import java.lang.annotation.*;import java.lang.reflect.Field;public class Test10 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.study.www.reflection.Student02"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); //@com.study.www.reflection.Tableschool(value=sql_student) } //获得注解的value值 Tableschool annotation = (Tableschool) c1.getAnnotation(Tableschool.class); String value = annotation.value(); System.out.println(value); //sql_student //获得类指定的注解 Field field = c1.getDeclaredField("name"); Fieldschool annotation1 = field.getAnnotation(Fieldschool.class); System.out.println(annotation1.columnName()); //sql_name System.out.println(annotation1.type()); //varchar System.out.println(annotation1.length()); //3 }}@Tableschool("sql_student")class Student02{ @Fieldschool(columnName = "sql_name", type = "varchar", length = 3) private String name; @Fieldschool(columnName = "sql_age", type = "int", length = 10) private int age; @Fieldschool(columnName = "sql_id", type = "int", length = 10) private int id; public Student02() { } public Student02(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "Student02 {name = " + this.getName() +", id = " + this.getId() + ", age = " + this.getAge() + "}"; }}//类名的注解@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface Tableschool{ String value();}//属性的注解@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface Fieldschool{ String columnName(); String type(); int length();}
转载地址:http://heqwi.baihongyu.com/