天天看点

Java反射机制笔记Java反射机制笔记反射是框架设计的灵魂

Java反射机制笔记

反射是框架设计的灵魂

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。(百度百科)

一、反射机制可以干啥

  1. 在运行过程中,能够动态的获取一个类的属性(Field)和方法(Method)
  2. 动态的调用任意一个对象的属性和方法;
  3. 框架设计的核心,通过修改配置文件动态加载类,调用类的方法和属性;

二、反射机制依赖Class类

Java反射机制依赖java.lang.Class这个类,它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。

三、Java获取Class对象的三种方法:

无论何时,只要你想在运行时使用类型信息,就必须先得到那个

Class

对象的引用。

Class.forName()

就是实现这个功能的一个便捷途径,因为使用该方法你不需要先持有这个类型 的对象。但是,如果你已经拥有了目标类的对象,那就可以通过调用

getClass()

方法来获取

Class

引用了,这个方法来自根类

Object

,它将返回表示该对象实际类型的

Class

对象的引用。《On Java 8》

方法一:Class类的静态方法

forName()

  • 方法的参数是一个完整类名字符串
  • 完整的类名还包括包名(连java.lang都不能省略)

方法二:Object类的

getClass(

)方法

Map<Integer,String> map = new HashMap<>();
Class c2 = map.getClass();
Class c3 = new String("abc").getClass();
System.out.println(c1==c3);// true
           

方法三:java语言中任意一种类型(包括基本数据类型)都有

.class

属性

Class c4 = String.class;
Class c5 = int.class;
           

四、反射机制常用类:

Java反射机制笔记Java反射机制笔记反射是框架设计的灵魂

五、通过反射机制实例化对象

在某些场景下我们可以通过修改配置文件就可以改变程序的实例对象,而不是通过修改代码

package com.kongxiao.javase.reflect;

import java.io.FileReader;
import java.util.Properties;

public class ReflectTest02 {
    public static void main(String[] args) throws Exception {
        // 传统实例化(只能创建指定类型的对象)
        User user = new User();
        System.out.println(user);

        // 通过反射机制实例化对象
        // 灵活性测试:
        // 创建一个读取配置文件的流
        FileReader reader = new FileReader("G:\\JavaXB\\ReFlect\\src\\com\\kongxiao\\javase\\reflect\\classinfo.properties");
        // 使用Properties创建一个Map对象
        Properties map = new Properties();
        // 加载配置文件到Map中
        map.load(reader);
        // 获取类名
        String className = map.getProperty("ClassName");
        reader.close();

        // 创建一个Class对象
        Class c = Class.forName(className);
        // 通过反射机制实例化对象
        // 调用无参构造
        @Deprecated(since="9")
        Object o = c.newInstance();
        System.out.println(o);

    }
}

           

classinfo.properties:

ClassName = com.kongxiao.javase.reflect.User

输出:

User{name=‘null’, age=0, no=0}

User{name=‘null’, age=0, no=0}

六、反射属性(Field)

测试类:

public class Student {
    /**
     * 四个Field分别使用不同的访问修饰符
     */
    public int no;
    private String name;
    protected int age;
    boolean sex;
}

           

实现类:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class ReflectField {
    public static void main(String[] args) throws ClassNotFoundException {
        Class studentClass = Class.forName("com.kongxiao.javase.reflect.Student");
        // 获取所有的Field(public)
        Field [] fields = studentClass.getFields();
        // 获取所有的字段(所有修饰符)
        Field [] filds2 = studentClass.getDeclaredFields();

        System.out.println(Arrays.toString(fields));
        System.out.println(Arrays.toString(filds2));

        // 单个获取(toString)
        for(Field field:filds2){
            // 获取修饰符
            // java.lang.reflect.Modifier有一个专门针对修饰符而写的类
            // 特定的修饰符有特定的编号,并且有一个静态的toString()方法
            int mod = field.getModifiers();
            System.out.print(Modifier.toString(mod)+" ");

            // 获取类型
            // 返回Class类型我想应该是应该区分基本数据类型和引用型数据类型
            Class typeClass  = field.getType();
            //System.out.println(typeClass.getName());
            System.out.print(typeClass.getSimpleName()+" ");

            //获取字段
            System.out.println(field.getName());
        }

    }
}

           

输出结果:

[public int com.kongxiao.javase.reflect.Student.no]
[public int com.kongxiao.javase.reflect.Student.no,
 private java.lang.String com.kongxiao.javase.reflect.Student.name,
 protected int com.kongxiao.javase.reflect.Student.age, 
 boolean com.kongxiao.javase.reflect.Student.sex]
 ==================================================
public int no
private String name
protected int age
boolean sex
           

反射机制调用属性:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Field;
import java.util.Arrays;

public class ReflectFieldTest {
    public static void main(String[] args) throws Exception {
        // 传统赋值
        // 三要素:对象-属性-值
        Student student = new Student();
        student.age = 12;

        // 使用反射机制先去访问一个对象属性
        Class studentClass = Class.forName("com.kongxiao.javase.reflect.Student");
        @Deprecated(since="9")
        Object obj = studentClass.newInstance();
        // 获取属性列表
        Field [] fields = studentClass.getDeclaredFields();
        System.out.println(Arrays.toString(fields));

        // 设置指定属性值
        // 三要素:
        // 对象:obj
        // 属性: Field
        // 值: value
        int value = 12;
        Field field = studentClass.getDeclaredField("age");
        field.set(obj,value);
        // 用属性去掉对象中对应的值
        System.out.println(field.get(obj));
        
        // 访问私有属性
        Field field1 = studentClass.getDeclaredField("name");
        // 打破封装
        field1.setAccessible(true);
        field1.set(obj,"SUN");
        System.out.println(field1.get(obj));
    }
}

           

七、反射方法(Method)

测试类:

public class UserService {
    /**
     * 登录方法
     * @param name 用户名
     * @param passWord 密码
     * @return 登录成功/失败
     */
    public boolean login(String name ,String passWord){
        return "admin".equals(name)&&"123".equals(passWord);
    }

    /**
     * 退出登录
     */
    public void logout(){
        System.out.println("退出登录成功!");
    }
}

           

实现类:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectMethod {
    public static void main(String[] args) throws ClassNotFoundException {
        Class userClass = Class.forName("com.kongxiao.javase.reflect.UserService");
        // 获取所有Method(包括私有的)
        Method [] methods = userClass.getDeclaredMethods();

        // 获取各个元素
        for(Method m :methods){
            //获取修饰符列表
            System.out.print(Modifier.toString(m.getModifiers())+" ");
            // 获取返回值类型
            System.out.print(m.getReturnType().getSimpleName()+" ");
            // 获取方法名
            System.out.print(m.getName()+" ");
            // 获取参数列表
            Class [] parameterTypes = m.getParameterTypes();
            System.out.print("( ");
            for(int i = 0 ; i<parameterTypes.length;i++){
                if (i==parameterTypes.length-1){
                    System.out.print(parameterTypes[i].getSimpleName()+" a");
                }else{
                    System.out.print(parameterTypes[i].getSimpleName()+" a,");
                }
            }
            System.out.println(" )");
        }
    }
}

           

输出:

public void logout (  )
public boolean login ( String a,String a )
           

反射机制调用方法:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Method;
import java.util.Arrays;


public class ReflectMethodTest {
    public static void main(String[] args) throws Exception {
        // 传统调用方法
        // 三要素: 对象-方法名-参数列表-返回值
        UserService userService = new UserService();
        boolean status1 = userService.login("SUN","123456");
        System.out.println(status1?"登录成功!":"登陆失败!");

        //使用反射机制
        Class userServiceClass = Class.forName("com.kongxiao.javase.reflect.UserService");
        // 创建对象
        @Deprecated(since="9")
        Object obj = userServiceClass.newInstance();
        // 查看有哪些函数
        Method [] methods = userServiceClass.getDeclaredMethods();
        System.out.println(Arrays.toString(methods));
        //因为方法可能存在所以单靠方法名不能获得方法
        // getMethod(String name, Class<?>... parameterTypes) Class 对象个数可变
        Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
        // 调用方法
        // 三要素 :对象-方法名-参数列表-返回值
        //返回值:
        Object reValue = null;
        reValue  = loginMethod.invoke(obj,"admin","123456");
        System.out.println((boolean)reValue?"登录成功!":"登陆失败!");
    }
}

           

输出:

D:\Java\jdk-12.0.2\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=57995:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath G:\JavaXB\out\production\ReFlect com.kongxiao.javase.reflect.ReflectMethodTest
    
登陆失败!
[public boolean com.kongxiao.javase.reflect.UserService.login(java.lang.String,java.lang.String), 
 public void com.kongxiao.javase.reflect.UserService.logout()]
登陆失败!
           

通过以上例子我们不难发现:反射机制让代码更具有通用性,可变化的内容都写到配置文件中,可以通过修改配置文件(类似XML)这种灵活的方式来加载类、调用类方法,以及使用类属性。