java反射

java反射

参考javassist使用全解析 - rickiyang - 博客园 (cnblogs.com)

还有b站白日梦组长的视频

环境搭建

pom.xml

<dependency>
  <groupId>org.javassist</groupId>
  <artifactId>javassist</artifactId>
  <version>3.25.0-GA</version>
</dependency>

定义

对于任意一个类,都能够得到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。

其实在 Java 中定义的一个类本身也是一个对象,即 java.lang.Class 类的实例,这个实例称为类对象

类对象表示正在运行的 Java 应用程序中的类和接口

类对象没有公共构造方法,由 Java 虚拟机自动构造 类对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法 要得到类的方法和属性,首先就要得到该类对象

假设类对象如下:

public class persons {
    public String name;
    private int age;

    public persons(){
        System.out.println("无参构造方法");
    }

    public persons(String name, int age){
        this.name = name;
        this.age = age;
    }

    public void action(String string){
        System.out.println(string);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

获取类对象

此时要获取它的类对象有如下方法:

Class.forName("reflaction.User")

User.class

new User().getClass()

最常见的是第一种,我们康康

image-20220421155759430

意思是传递一个类名返回其 Class 泛型

调用无参构造方法创建对象

当调用无参构造方法的时候,直接 newInstance 即可

public class reflac
{
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    {
        Class persons = Class.forName("persons");
        persons.newInstance();
    }
}

image-20220421160457391

调用有参构造方法创建对象

常用方法介绍

方法 说明
getConstructor(Class... parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class... parameterTypes) 获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() 获得该类所有构造方法

试着写一下

import java.beans.PersistenceDelegate;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class reflac
{
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
    {
        Class persons = Class.forName("persons");
        Constructor constructor = persons.getConstructor(String.class, int.class);
        Object thai = constructor.newInstance("thai", 20);
        System.out.println(thai);
    }
}

image-20220421163046738

以后可以照着上面的模板了

其实就是 先初始化constructor,再用其newInstance(参数);

通过反射调用方法

通过反射调用方法 方法说明
getMethod(String name, Class... parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class... parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法

在上面的“调用方法”后加上invoke才能使用

import java.beans.PersistenceDelegate;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class reflac
{
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
    {
        Class persons = Class.forName("persons");
        Constructor constructor = persons.getConstructor(String.class, int.class);
        Object thai = constructor.newInstance("thai", 20);
        //System.out.println(thai);

        Method action = persons.getMethod("action", String.class);
        action.invoke(thai,"thaii yyds");

    }
}

image-20220421164648707

当然你要两句写成一句也可以

image-20220421164540394

不推荐,因为反序列化利用链里面的invoke往往是分开的

通过反射访问属性

方法 说明
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对
getDeclaredFields() 获得所有属性对象

获取属性,赋值

Field name = persons.getDeclaredField("name");
name.set(thai,"thai admire miku233");

private属性要加上 (public也可以加,建议都加吧,这样就不用担心那么多)

field.setAccessible(true);

demo

import java.beans.PersistenceDelegate;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class reflac
{
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException
    {
        Class persons = Class.forName("persons");
        Constructor constructor = persons.getConstructor(String.class, int.class);
        Object thai = constructor.newInstance("thai", 20);
        System.out.println(thai);

        Field name = persons.getDeclaredField("name");
        name.set(thai,"thai admire miku233");
        //System.out.println(thai);

        Field name1 = persons.getDeclaredField("age");
        name1.setAccessible(true);
        name1.set(thai,21);
        System.out.println(thai);

    }
}

image-20220421171128716

可以看这个当作

也有一种Classpool的反射的方法

package com.rickiyang.learn.javassist;

import javassist.*;

/**
 * @author rickiyang
 * @date 2019-08-06
 * @Desc
 */
public class CreatePerson {

    /**
     * 创建一个Person 对象
     *
     * @throws Exception
     */
    public static void createPseson() throws Exception {
        ClassPool pool = ClassPool.getDefault();

        // 1. 创建一个空类
        CtClass cc = pool.makeClass("com.rickiyang.learn.javassist.Person");

        // 2. 新增一个字段 private String name;
        // 字段名为name
        CtField param = new CtField(pool.get("java.lang.String"), "name", cc);
        // 访问级别是 private
        param.setModifiers(Modifier.PRIVATE);
        // 初始值是 "xiaoming"
        cc.addField(param, CtField.Initializer.constant("xiaoming"));

        // 3. 生成 getter、setter 方法
        cc.addMethod(CtNewMethod.setter("setName", param));
        cc.addMethod(CtNewMethod.getter("getName", param));

        // 4. 添加无参的构造函数
        CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);
        cons.setBody("{name = \"xiaohong\";}");
        cc.addConstructor(cons);

        // 5. 添加有参的构造函数
        cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc);
        // $0=this / $1,$2,$3... 代表方法参数
        cons.setBody("{$0.name = $1;}");
        cc.addConstructor(cons);

        // 6. 创建一个名为printName方法,无参数,无返回值,输出name值
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc);
        ctMethod.setModifiers(Modifier.PUBLIC);
        ctMethod.setBody("{System.out.println(name);}");
        cc.addMethod(ctMethod);

        //这里会将这个创建的类对象编译为.class文件
        cc.writeFile("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/");
    }

    public static void main(String[] args) {
        try {
            createPseson();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇