25_反射

反射机制(java.lang.reflect.*)框架的底层原理

Java_Java零基础进阶必备视频教程(适合Java基础,Java入门)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili

重点5.4和6.3


1. 简单介绍

### 1.1 作用?

  1. 可以直接读和修改字节码文件
  2. 反射机制可以直接操作代码片段
  3. 让程序更加灵活

1.2 相关的类在哪个包下

java.lang.reflect.*

1.3 相关的重要的类

作用
java.lang.Class代表整个字节码
java.lang.reflect.Method代表字节码中的方法字节码
java.lang.reflect.Constructor代表字节码中的构造方法字节码
java.lang.reflect.Field代表字节码中的属性字节码

2 获取Class的三种方法

2.1 Class.forName()(较为常用)

  1. 静态方法
  2. 方法的参数是一个字符串。
  3. 字符需要的是一个完整类名,完整类名必须带有包名。java.lang包也不能略。

其他:

  1. 这个方法的执行会导致类加载。(第一次加载时会执行类中的静态代码块)
Class c1 = Class.forName("java.lang.String");
Class c2 = Class.forName("java.lang.Date");
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");

2.2 对象.getClass()方法

String s = "abc";
Class x = s.getClass();

2.3 类.class 属性

Class y = String.class;
Class z = int.class;		// 基本数据类型也有 .class

3.通过Class来实例化对象

// c代表的就是Date类型
Class c = Class.forName("java.util.Date");
// 实例化一个Date对象
Object obj = c.newInstance();

newInstance()内部调用了User的无参构造方法。

当User没有无参构造方法时会抛出异常 java.lang.InstantiationException

所以,开发中,model必须有无参构造方法

4.类加载器(ClassLoader)

4.1 什么是类加载器

专门负责加载类的命令/工具

4.2 3个类加载器

  1. 启动类加载器
  2. 扩展类加载器
  3. 应用类加载器

4.3 加载顺序

  1. 启动类加载器,加载jre/lib/rt.jar。若找不到,下一步
  2. 扩展类加载器,加载jre/lib/ext/*.jar。若找不到,下一步
  3. 应用类加载器,加载classpath中的类。classpath在环境变量配置。

4.4 双亲委派机制

为了安全考虑,类加载器先从jre/lib/rt.jarjre/lib/ext/*.jar中加载。对应启动类加载器(公)和扩展类加载器(母)。

通俗易懂的双亲委派机制_吴延宝-CSDN博客_双亲委派机制

5 Field

5.1 获取Field

Class<?> studentClass = Class.forName("com.bjpowernode.java.bean.Student");
Field[] fields = studentClass.getDeclaredFields();

getDeclaredFields()可以获取所有的属性。public, protected, default (package) access, and private fields.不能获取继承的属性。

getFields()只能获取public属性。

5.2 通过Field获取属性的细节(了解一下)

for (Field field : fields) {
    System.out.print(Modifier.toString(field.getModifiers()) + " ");
    System.out.print(field.getType().getSimpleName() + " ");
    System.out.println(field.getName());
}

getModifiers()获取属性的修饰符,返回一个int,通过Modifier.toString()转换成对应的字符串。

getType()获取属性的类型。返回Class。

getName()获取属性名。

5.3 反编译Field(实际开发没用)

根据以上的方法,可以通过拼接字符串,反编译出一个.class 文件的源码。

public static void main(String[] args) throws Exception {
    StringBuilder builder = new StringBuilder();

    Class<?> studentClass = Class.forName("com.bjpowernode.java.bean.Student");

    builder.append("public class ").append(studentClass.getSimpleName()).append(" {\n");
    Field[] fields = studentClass.getDeclaredFields();
    for (Field field : fields) {
        builder.append("\t");
        builder.append(Modifier.toString(field.getModifiers())).append(" ");
        builder.append(field.getType().getSimpleName()).append(" ");
        builder.append(field.getName());
        builder.append(";\n");
    }
    builder.append("}");
    System.out.println(builder);
}

5.4 通过反射机制,set/get一个Java对象的属性(重点掌握)

Class<?> studentClass = Class.forName("com.bjpowernode.java.bean.Student");
Object obj = studentClass.newInstance();
Field no = studentClass.getDeclaredField("no");  

no.set(obj, 2222);			// 给obj的no属性赋值2222
Object o = no.get(obj);		// 获取obj的no属性
  • 以上方法不能访问private属性,需要打破封装name.setAccessible(true)
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);
name.set(obj, "2222");
System.out.println(obj);

6 Method(超级重点)

6.1 反射Method(了解)

Class<?> userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
Method[] declaredMethods = userServiceClass.getDeclaredMethods();

for (Method declaredMethod : declaredMethods) {
    // 修饰符
    System.out.println(Modifier.toString(declaredMethod.getModifiers()));
    // 返回类型
    System.out.println(declaredMethod.getReturnType());
    // 方法名
    System.out.println(declaredMethod.getName());
    // 参数类型
    Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
    for (Class<?> parameterType : parameterTypes) {
        System.out.println(parameterType.getSimpleName());
    }
    System.out.println();
}
方法作用
.getDeclaredMethods()获取Method
.getModifiers()获取修饰符
.getReturnType()获取返回值类型
.getName()获取方法名
.getParameterTypes()获取参数类型列表

6.2 Method反编译(了解)

根据以上的方法,拼接字符串。类似Field反编译。

6.3 通过反射机制获取并调用方法(重点)

Class<?> userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
Object obj = userServiceClass.newInstance();

// 获取方法
Method login = userServiceClass.getDeclaredMethod("login", String.class, String.class);

// 反射机制中最最最最重要的一个方法,调用方法
Object retValue = login.invoke(obj, "1212", "1212");
System.out.println(retValue);

.getDeclaredMethod()需要传入函数名参数类型

.invoke()调用方法

7 Constructer

7.1反编译

public static void main(String[] args) throws Exception {
    StringBuilder s = new StringBuilder();
    Class<?> studentClass = Class.forName("com.bjpowernode.java.bean.Student");

    // 类修饰符
    s.append(Modifier.toString(studentClass.getModifiers())).append(" class ");
    // 类名
    s.append(studentClass.getSimpleName()).append("{\n");

    // 获取构造方法
    Constructor<?>[] constructors = studentClass.getConstructors();
    for (Constructor<?> constructor : constructors) {
        s.append("\t");
        // 构造方法修饰符
        s.append(Modifier.toString(constructor.getModifiers())).append(" ");
        // 构造方法名与类名相同
        s.append(studentClass.getSimpleName());
        s.append("(");

        // 获取参数类型
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            s.append(parameterType.getSimpleName()).append(",");
        }
        if (parameterTypes.length != 0) {
            s.deleteCharAt(s.length() - 1);
        }

        s.append("){}\n");
    }

    s.append("}");
    System.out.println(s);

}

.getConstructors()获取构造方法

7.2 通过反射机制构造对象

// 1.获取构造方法
Constructor<?> constructor = studentClass.getDeclaredConstructor(String.class, int.class);
// 2.调用构造方法new对象
Object he = constructor.newInstance("he", 1);

无参构造直接用.newInstance()不加参数,不用先获取构造方法。

8 获取父类和实现的接口

Class<?> stringClass = Class.forName("java.lang.String");

// 获取父类
Class<?> superclass = stringClass.getSuperclass();
System.out.println(superclass.getName());

// 获取接口
Class<?>[] interfaces = stringClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
    System.out.println(anInterface.getName());
}
方法作用
.getSuperclass()获取父类
.getInterfaces()获取实现的接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

。君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值