【引入】
动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
主要动态语言: Object--c、c JavaScript PHP、 Python等
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。如ava、C、C++。
虽然 java不是动态语言,但Java可以称之为“准动态语言”即java有一定的动态性我们可以利用反射机制获得类似动态语言的特性。java的动态性让编程的时候更加灵活!
反射(Reflect)是Java被视为动态语言的关键,反射机制允许程序在执行期间,通过Reflect ApI取得任何类的内部信息,同时直接操作对象的内部属性以及方法。

获取Class对象的三种方式:
- public class Reflect1 {
- public static void main(String[] args) throws ClassNotFoundException {
- //1、forName() ------> source(源代码阶段)
- Class<?> person1 = Class.forName("com.reflect.model.Person");
- System.out.println(person1);
- //2、.Class文件 ------> class (字节码阶段)
- Class<Person> person2 = Person.class;
- System.out.println(person2);
- //3、getClass ------> runtime(运行时阶段)
- Person person3=new Person();
- Class<? extends Person> person3Class = person3.getClass();
- System.out.println(person3Class);
- System.out.println("=============================");
- System.out.println(person1==person2);
- System.out.println(person2==person3Class);
- }
- }
1、获取成员变量
| Field[] getFields() | 返回一个包含Field对象的数组,反映由这个class对象表示的类或接口的所有可访问的公共字段。 |
| Field getField(String name) | 返回一个Field对象,该对象反映由这个class对象表示的类或接口的指定公共成员字段。name参数是一个String,指定所需字段的简单名称。 |
| Field[] getDeclaredFields() | 返回一个Field对象数组,反映由这个class对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承字段。 |
| Field getDeclaredField | 返回一个Field对象,该对象反映由这个class对象表示的类或接口的指定声明字段。name参数是一个String,它指定所需字段的简单名称。 |
- public class Reflect2_1 {
- public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
- Class cls = Class.forName("com.reflect.model.Person");
- //1、变量
- System.out.println("================1、变量===============");
- Field msg = cls.getField("msg");
- Person person=new Person();
- System.out.println(msg.get(person));
- msg.set(person,"hello");
- System.out.println(msg.get(person));
-
- Field age = cls.getDeclaredField("age");
- age.setAccessible(true);
- System.out.println(age.get(person));
- age.set(person,12);
- System.out.println(age.get(person));
- }
- }
2、获取成员方法
| Method getMethod(String name, Class<?>... parameterTypes) | 返回一个Method对象,该对象反映由这个class对象表示的类或接口的指定公共成员方法。name参数是一个String,用于指定所需方法的简单名称。parameterTypes参数是一个Class对象数组,按声明的顺序标识方法的形式参数类型。如果parameterTypes为空,则将其视为空数组。 |
| Method[] getMethods() | 返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有公共方法,包括由类或接口声明的方法和从超类和超接口继承的方法。 |
| Method[] getDeclaredMethods() | 返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有声明方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
| Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回一个Method对象,该对象反映由这个class对象表示的类或接口的指定声明方法。name参数是一个String,用于指定所需方法的简单名称,parameterTypes参数是一个Class对象数组,按声明的顺序标识方法的形式参数类型。 |
- public class Reflect2_2 {
- public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
- Class cls = Class.forName("com.reflect.model.Person");
- //2、方法
- System.out.println("=================2、方法==============");
- Method setAge = cls.getMethod("setAge", int.class);
- System.out.println(person.toString());
- setAge.invoke(person, 23);
- System.out.println(person.toString());
- }
- }
3、获取构造方法
| Constructor<?>[] getConstructors() | 返回一个包含构造函数对象的数组,该对象反映由这个class对象表示的类的所有公共构造函数。如果类没有公共构造函数,或者类是数组类,或者类反映了原始类型或void,则返回长度为O的数组。 |
| Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回一个构造函数对象,该对象反映由这个class对象表示的类的指定公共构造函数。parameterTypes形参是一个Class对象数组,按声明的顺序标识构造函数的形式形参类型。如果此Class对象表示在非静态上下文中声明的内部类,则形式形参类型包括显式的封闭实例作为第一个形参。 |
- public class Reflect2_3 {
- public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
- Class cls = Class.forName("com.reflect.model.Person");
- //3、构造器
- System.out.println("================3、构造器=============");
- Person person2 = (Person) cls.newInstance();
- System.out.println(person2.toString());
- Constructor constructor = cls.getConstructor();
- Person person3 = (Person) constructor.newInstance();
- System.out.println(person3.toString());
- }
- }
【需求】不改变代码,可以创建任意对象,运行任一方法
src目录下创建 info.properties文件

读取配置文件,获取对象,执行方法
- public class Reflect3 {
- public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
- //1、获取配置信息
- Properties pro=new Properties();
- ClassLoader classLoader = Reflect3.class.getClassLoader();
- InputStream input = classLoader.getResourceAsStream("info.properties");
- pro.load(input);
- //2、获取配置文件数据
- String className = pro.getProperty("className");
- String methodName = pro.getProperty("methodName");
- //3、将该类加载进入内存
- Class cls= Class.forName(className);
- //4、通过反射执行方法
- Cat cat= (Cat) cls.newInstance();
- Method method = cls.getMethod(methodName,String.class);
- method.invoke(cat,"你好!");
- }
- }
1、在运行时分析代码
Field类有一个getType方法,用来返回描述字段类型的一个对象,这个对象的类型同样是Class Method 和Constructor类有报告参数类型的方法,Method类还有一个报告返回类型的方法这三个类都有一个名为 getModifiers方法,它将返回一个整数,用不同的0/1位描述所使用的修饰符,如 public和 static另外,还可以利用javalang. reflect包中 Modifier类的静态方法分析 getModifiers返回的这个整数。例如,可以使用 Nodifier类中的 isPublic、 isPrivate或isFinal判断方法或构造器是 public、 private还是 final我们需要做的就是在 getModifiers回的整数上调用 Modifier类中适当的方法,另外,还可以利用 Modifier. toString方法将修饰符打印出来。
2、运行时检查对象
如利用Field[] getDeclaredFields() 方法,获取全部子段,编写一个通用的toString方法( )。
3、实现泛型数组操作代码
Class<?> getComponentType() :返回表示数组组件类型的Class。如果这个类不表示数组类,这个方法返回null。
由于反射的特殊性,导致很多时候,需要单例模式的场景下,反射直接回破坏单例模式。如通过getConstructors( ) 获取构造器,利用构造器方法newInstance()直接创建对象,单例模式由此失效。但是有一种对象,天生就是单例模式——枚举
- public enum SingleEnum {
- INSTANCE;
-
- private static SingleEnum singleEnum=null;
-
- private SingleEnum(){
- }
-
- static class User{
-
- private static User user=null;
-
- private User(){
-
- }
-
- public static User getInstance() {
- if(user!=null){
- user=new User();
- }
- return user;
- }
- }
-
- public SingleEnum getInstance() {
- return INSTANCE;
- }
- }
-
- class Newtest{
- public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
- Constructor<SingleEnum> userConstructor = SingleEnum.class.getDeclaredConstructor(String.class,int.class);
- userConstructor.setAccessible(true);
- SingleEnum u1 = userConstructor.newInstance();
- System.out.println(u1);
- }
- }
【运行结果】

无法通过反射创建对象。