Java 反射
###
文章目录
-
-
[@[toc]](#toc_2)
-
1、什么是反射
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
2、反射的原理
下图是类的正常加载过程、反射原理与class对象:
Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。
3、反射的优缺点
优点
-
在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
-
允许程序创建和控制任何类的对象,无需提前硬编码目标类
-
提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力
-
反射的应用领域 (开源框架,如MyBatis、Spring等)
缺点
-
性能问题
反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射
反射机制主要应用在对灵活性和扩展性要求很高的系统框架上
-
代码维护问题
反射会模糊程序内部逻辑,可读性较差.
反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题
4、反射的用途
-
反编译:.class–>.java
-
通过反射机制访问java对象的属性,方法,构造方法等
-
当我们在使用IDEA,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
-
反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
5、反射技术常用API
反射常用的Java类型
java.lang.Class<T> //可获取类和类的成员信息 java.lang.reflect.Constructor<T>//可调用类的构造方法 java.lang.reflect.Field //可访问类的属性 java.lang.reflect.Method //可调用类的方法
6、反射技术使用步骤
-
导入 java.lang.reflect.*
-
获得需要操作的类的java.lang.Class对象
-
调用Class的方法获取Field、Method等对象
-
使用反射API操作实例成员
7、反射的入口类Class
Class类是Java反射机制的起源和入口
-
每个类都有自己向关的Class对象
-
提供了获取类信息的相关方法
Class类存放类的结构信息
-
类名
-
父类﹑接口
-
构造方法﹑方法﹑属性
-
注解
-
……
获取Class实例常用方式
//方法1:对象.getClass() Student stu = new Student(); Class clazz = stu.getClass();
//方法2:类.class Class clazz = Student.class;
//方法3:Class.forName() Class clazz = Class.forName("xxx.xxx.Student");
获取类型的基本信息的常用方法:
定一个BaseClass为父类
package reflect.entity; public class BaseClass { }
定一个Person类并继承BaseClass父类实现
Serializable
接口
package reflect.entity; import java.io.Serializable; import java.io.IOException; public final class Person extends BaseClass implements Serializable { // 成员变量 private String name; static final int age = 30; protected String address; public String message; // 成员方法 public String getName() { return name; } public void setName(String name) { this.name = name; } static final int getAge() { return age; } protected String getAddress() { return address; } private void silentMethod() throws IOException, NullPointerException { System.out.println("这是悄悄话"); } /*[以下声明用于通过反射获取构造方法信息测试]*/ //无参构造函数 public Person() { } //有参构造函数 private Person(String name) { this.name = name; } protected Person(String name, String address, String message) { this.name = name; this.address = address; this.message = message; } @Override public String toString() { return "{name:" + name + ", age:" + age + ", address:" + address + ", message:" + message + "}"; } }
通过反射获取类的信息示例:
package reflect.classinfo; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 获取类型的基本信息 */ public class GetClassInfo { public static void main(String[] args) { Class clz = Person.class; String fullName = clz.getName(); String simpleName = clz.getSimpleName(); System.out.println("以下是 " + fullName + " 类的基本信息"); // 获取Person类所在的包 Package pkg = clz.getPackage(); // 获得此对象所表示的实体(类、接口、基本类型或 void)的超类的 Class // 如果此对象表示 Object 类、一个接口、一个基本类型或 void,则返回 null // 如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象 Class superClass = clz.getSuperclass(); System.out.println(simpleName + " 类的超类是:" + superClass.getName()); // 获得此对象所表示的类或接口实现的接口 // 如果此对象表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组。 // 如果此对象表示一个基本类型或 void,则此方法返回一个长度为 0 的数组。 Class[] interfaces = clz.getInterfaces(); //getModifiers()方法返回int类型值表示该字段的修饰符。其中,该修饰符是java.lang.reflect.Modifier的静态属性 int modifier = clz.getModifiers(); } }
获取构造方法信息的常用方法:
获取构造方法信息示例代码:
package reflect.classinfo; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 获取构造方法信息 */ public class GetClassConstructorsInfo { public static void main(String[] args) { // 获取Person类声明的所有构造方法 // 它们是公共、保护、默认(包)访问和私有构造方法 // 如果此 Class 实例表示一个接口、一个基本类型、一个数组类或 void,则此方法返回一个长度为 0 的数组 Constructor[] cons = Person.class.getDeclaredConstructors(); // 构造方法的一些信息 System.out.println("=========构造方法展示========="); for (Constructor con : cons) { System.out.print("访问修饰符:"); int modifier = con.getModifiers(); // 判断该构造方法的访问修饰符 if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) System.out.println("public"); else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) System.out.println("protected"); else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) System.out.println("private"); else System.out.println("default(package)"); // 获取构造方法的参数列表 Class[] params = con.getParameterTypes(); if (params.length == 0) { System.out.println("该构造方法没有参数"); } else { System.out.print("该构造方法的参数列表为:["); for (int i = 0; i < params.length; i++) { if (i != 0)System.out.print(", "); System.out.print(params[i].getName()); } System.out.println("]"); } } } }
获取属性信息的常用方法:
获取属性信息示例:
package reflect.classinfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 获取属性信息 */ public class GetClassFieldsInfo { public static void main(String[] args) { // 获取Person中的所有属性, // 包括公共、保护、默认(包)访问和私有属性,但不包括继承的属性, // 如果该类或接口不声明任何属性,或者此 Class 实例表示一个基本类型、一个数组或 void,则此方法返回一个长度为 0 的数组。 Field[] fields = Person.class.getDeclaredFields(); // 展示属性的一些信息 System.out.println("===========属性展示=========="); for (Field field : fields) { System.out.println("属性名:" + field.getName()); System.out.println("类型:" + field.getType().getName()); System.out.print("访问修饰符:"); int modifier = field.getModifiers(); // 判断该属性的访问修饰符 if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) System.out.println("public"); else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) System.out.println("protected"); else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) System.out.println("private"); else System.out.println("default(package)"); // 判断该属性是否有static修饰符 if ((modifier & Modifier.STATIC) == Modifier.STATIC) System.out.println("这是一个静态属性"); // 判断该属性是否有final修饰符 if ((modifier & Modifier.FINAL) == Modifier.FINAL) System.out.println("这是一个final属性"); } } }
获取方法信息的常用方法:
获取方法信息示例:
package reflect.classinfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 获取方法信息 */ public class GetClassMethodsInfo { public static void main(String[] args) { // 获取Person中的所有方法, // 包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法, // 如果该类或接口不声明任何方法,或者此 Class 实例表示一个基本类型、一个数组或 void,则此方法返回一个长度为 0 的数组。 Method[] methods = Person.class.getDeclaredMethods(); // 展示方法的一些信息 System.out.println("===========方法展示=========="); for (Method method : methods) { System.out.println("方法名:" + method.getName()); System.out.println("返回值类型:" + method.getReturnType().getName()); // 获取方法的参数列表 Class[] params = method.getParameterTypes(); if (params.length == 0) { System.out.println("该方法没有参数"); } else { System.out.print("该方法的参数列表为:["); for (int i = 0; i < params.length; i++) { if (i != 0) System.out.print(", "); System.out.print(params[i].getName()); } System.out.println("]"); } System.out.print("访问修饰符:"); int modifier = method.getModifiers(); // 判断该方法的访问修饰符 if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) System.out.println("public"); else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) System.out.println("protected"); else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) System.out.println("private"); else System.out.println("default(package)"); // 判断该方法是否有static修饰符 if ((modifier & Modifier.STATIC) == Modifier.STATIC) System.out.println("这是一个静态方法"); // 判断该方法是否有final修饰符 if ((modifier & Modifier.FINAL) == Modifier.FINAL) System.out.println("这是一个final方法"); // 判断该方法是否有abstract修饰符 if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) System.out.println("这是一个抽象方法"); // 判断该方法是否有synchronized修饰符 if ((modifier & Modifier.SYNCHRONIZED) == Modifier.SYNCHRONIZED) System.out.println("这是一个同步方法"); // 获取方法所属的类或接口的Class实例 Class declaringClass = method.getDeclaringClass(); System.out.println("方法声明在:" + declaringClass.getName() + " 中"); // 获取方法抛出的异常类型,即throws子句中声明的异常 Class[] exceptions = method.getExceptionTypes(); if (exceptions.length > 0) { System.out.print("该方法抛出的异常有:["); for (int i = 0; i < exceptions.length; i++) { if (i != 0) System.out.print(", "); System.out.print(exceptions[i].getName()); } System.out.println("]"); } System.out.println("----------------------------"); } } }
8、反射实现类的实例化
java.lang.Class public T newInstance()
//关键代码: Class clazz = Class.forName("reflect.entity.Person"); Object obj = clazz.newInstance();
java.lang.reflect.Constructor public T newInstance(Object… initargs)
Constructor cons = clazz.getDeclaredConstructor(String.class); cons.setAccessible(true); Object obj = cons.newInstance("New Person");
package reflect.access; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class AccessPersonConstructors { // 测试反射调用构造方法 public static void main(String[] args) { try { Class clz = Class.forName("reflect.entity.Person"); Object obj = clz.newInstance(); System.out.println(obj); // 获取Person的无参构造 Constructor c1 = clz.getDeclaredConstructor(); // Person的无参构造为public,这里可以直接访问 obj = c1.newInstance(); System.out.println(obj); // 获取Person的单参构造 Constructor c2 = clz.getDeclaredConstructor(String.class); // Person的单参构造为private,这里已超出其访问范围,不能直接访问 // 通过setAccessable方法,设定为可以访问 c2.setAccessible(true); obj = c2.newInstance("New Person"); System.out.println(obj); // 获取Person的三参构造 Constructor c3 = clz.getDeclaredConstructor(String.class, String.class, String.class); // Person的三参构造为protected,这里已超出其访问范围,不能直接访问 // 通过setAccessable方法,设定为可以访问 c3.setAccessible(true); obj = c3.newInstance("New Person", "beijing", "Hello!"); System.out.println(obj); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
9、反射访问实例的字段
java.lang.reflect.Field
package reflect.access; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 通过反射方式访问属性 */ public class AccessPersonFields { // 通过反射操作Person的属性 public static void main(String[] args) { try { // 通过反射加载一个Person实例 Class cls = Class.forName("reflect.entity.Person"); Object person = cls.newInstance(); // 获取name属性 Field name = cls.getDeclaredField("name"); // name属性为private,这里已超出其访问范围,不能直接访问 // 通过setAccessable方法,设定为可以访问 name.setAccessible(true); // 先取值看一下 System.out.println("赋值前的name:" + name.get(person)); // 为name属性赋值 name.set(person, "New Person"); // 展示一下赋值效果 System.out.println("赋值后的name:" + name.get(person)); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }
10、反射调用实例的方法
java.lang.reflect.Method
public Object invoke( Object obj, Object...args)
package reflect.access; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import reflect.entity.Person; /** * 反射调用实例的方法 */ public class AccessPersonMethods { public static void main(String[] args) { //反射操作Person的方法 try { //通过反射加载Person类 Class clz = Class.forName("reflect.entity.Person"); //根据方法名和参数列表获取static final int getAge()方法,无参可以不写或用null表示 Method getAge = clz.getDeclaredMethod("getAge", null); //getAge方法为default(package),这里已超出其访问范围,不能直接访问 //通过setAccessable方法,设定为可以访问 getAge.setAccessible(true); //调用getAge方法并传参,没有参数可以不写或用null表示 //getAge方法为静态方法,调用时可以不指定具体Person实例 Object returnAge = getAge.invoke(null, null); System.out.println("年龄是:" + returnAge); Object person = clz.newInstance(); //创建Person实例 //根据方法名和参数列表获取private void silentMethod()方法 Method silentMethod = clz.getDeclaredMethod("silentMethod", null); //silentMethod方法为private,这里已超出其访问范围,不能直接访问 //通过setAccessable方法,设定为可以访问 silentMethod.setAccessible(true); //调用silentMethod方法并传参,没有参数可以不写或用null表示 silentMethod.invoke(person, null); //根据方法名和参数列表获取public void setName(String)方法 Method setName = clz.getDeclaredMethod("setName", String.class); //setName方法为public,这里可以直接访问 //调用setName方法并传参 setName.invoke(person, "New Person"); //验证一下结果,调用public String getName()方法得到name的值 Object returnName = clz.getDeclaredMethod("getName").invoke(person); System.out.println("刚才设定的name是:" + returnName); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
11、反射总结
文章知识点与官方知识档案匹配,可进一步学习相关知识
本文转自 Java 反射_if((modifier & modifier.public) == modifier.public_众生云海,一念初见的博客-CSDN博客,如有侵权,请联系删除。