java反射

Java反射

什么是反射

反射的作用:让java具有动态性

修改已有的属性

动态生成对象

动态调用方法

操作内部类和私有方法

通过java的反射机制,能够判断一个对象所属的类;了解任意一个类的所以属性和方法;能够调用任意一个对象的任意方法和属性

在反序列化漏洞中的应用:
定制需要的对象
通过invoke调用除了同名函数以外的函数
通过Class类创建对象,引入不能序列化的类

反射的基本使用

获取Class类对象

Class.forName 静态方法

Class.forName如果你知道某个类的名字,想获取到这个类,就可以使⽤ forName 来获取

Class class1 = Class.forName("reflection.TestReflection");

image-20230310092935475

使用类的.class 方法

任何数据类型都具备静态的属性,如果你已经加载了某个类,只是想获取到它的 java.lang.Class 对象,那么就直接使用.class拿它的 class 属性即可

但是要明确用到类的静态成员

这个⽅法其实不属于反射。

Class class2 = TestReflection.class;

image-20230310093754194

使用实例对象的 getClass() 方法。

如过上下文中存在某个类的实例obj,那么可以直接通过obj.getClass()获取它的字节码对象

TestReflection testReflection = new TestReflection();
Class class3 = testReflection.getClass();

image-20230310093922711

使用getSystemClassLoader().loadClass()方法

getSystemClassLoader().loadClass()与forName()类似。

但是forName()的静态方法JVM会装载类,并且执行static()中的代码;

而getSystemClassLoader().loadClass()不会执行static()中的代码

image-20230310094446860

反射创造对象

通过反射创建类对象主要有两种方式:

  • 通过Class的newInstance()方法 (无参)
  • 通过Constructor的newInstance(方法。(可以有参)

eg:

先创建一个person类

public class person implements Serializable {
    public String name;
    public int age;
    public person(){

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

import java.lang.reflect.Constructor;

public class reflect {
    public static void main(String[] args)  throws Exception{
        Class class1 = Class.forName("person");
        person pe = (person) class1.newInstance();
        System.out.println(pe);
        
        Constructor constructor = class1.getConstructor();
        person pe1 = (person) constructor.newInstance();
        System.out.println(pe1);
    }
}
//person@1b6d3586
//person@4554617c

反射获取类的构造器

  • getConstructors() 获取类的所有公共的构造方法
  • getDeclaredConstructors() 获取所有的构造方法(公有和私有)
  • getConstructor(Class[] parameterTypes) 返回指定参数类型public的构造器
  • getDeclaredConstructor (Class[] parameterTypes) 返回指定参数类型的private和public的构造器

eg:

import java.lang.reflect.Constructor;

public class reflect {
    public static void main(String[] args)  throws Exception{
        Class class1 = Class.forName("person");
        Constructor[] constructor = class1.getDeclaredConstructors();
        for (int i=0;i<constructor.length;i++){
            System.out.println(constructor[i]);
        }
    }
}
//public person()
//public person(java.lang.String,int)
import java.lang.reflect.Constructor;

public class reflect {
    public static void main(String[] args)  throws Exception{
        Class class1 = Class.forName("person");
        Constructor constructor = class1.getDeclaredConstructor(new Class[]{String.class,int.class});
        System.out.println(constructor);
    }
}
//public person(java.lang.String,int)

反射获取类的成员变量

先创建一个person类

public class person implements Serializable {
    public String name;
    public int age;
    private int home;
    public person(){

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

getFields()

获取当前类或父类或父接口的 public 修饰的字段。

person person = new person();
Class<?> name = person.getClass();
Field[] getFields = name.getFields();

image-20230310100809751

getDelcaredFields()

获取当前类的所有字段,包括 protected/默认/private/public修饰的字段;但是不包括父类public修饰的字段。

person person = new person();
Class<?> name = person.getClass();
Field[] declaredFields = name.getDeclaredFields();

image-20230310100946202

getField()

getField(String name)

根据变量名,返回一个具体的具有public属性的成员变量。包括父类中的public字段

person person = new person();
Class<?> name = person.getClass();
Field  Field = name.getField("name");

image-20230310101224256

getDeclaredField()

getDeclaredField(String name)

根据变量名,返回一个成员变量,可以获取本类所有的字段,包括private的,但是不能获取继承来的字段

person person = new person();
Class<?> name = person.getClass();
Field  DeclaredField = name.getDeclaredField("home");

image-20230310101423431

修改类的属性值

getField.set()

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;


public class reflect {
    public static void main(String[] args)  throws Exception{
        person pe = new person();
        Class c = pe.getClass();
        Constructor constructor = c.getConstructor(String.class,int.class);
        person p = (person) constructor.newInstance("zzz",123);
        System.out.println(p);
        Field field = c.getField("name");

        field.set(p,"wzx");//要传一个此类的实例
        System.out.println(p);
        }
    }

//person{name=zzz,age=123}
//person{name=wzx,age=123}

field.setAccessible(true);可以让我们给private属性的成员赋值,一般配合getDeclaredField()使用

获取类属性值

Field.get()方法的功能:
获取对象的Field属性值
Field.get()方法的语法:
get(Object obj)
返回值说明
返回传入对象的值
注意事项:
如果不是静态字段,传入null的obj值,会抛出相应的错误信息
当是静态字段时,传入任何obj值都可以

反射获取类的方法

getMethods()

获取当前类或父类或父接口的所有public 方法;包含接口中 default 修饰的方法 (JDK1.8)。

Class<?> name=ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");
Method[] Methods = name.getMethods();

image-20230310095218656

getDeclaredMethods()

Class<?> name=ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");
Method[] declaredMethods = name.getDeclaredMethods();

获取当前类或接口声明的所有方法;包括 protected/默认/private/public修饰的方法;不包括父类 、接口 public 修饰的方法。

image-20230310095105850

getMethod()

getMethod(String name,Class[] parameterTypes)

只能返回一个特定的方法,一个参数为目标方法名称,第二个参数为目标方法的参数对应Class的对象

获取范围:自身能用所有的公共方法。

1.类本身的public

2.继承父类的public

3.实现接口的public

Class<?> name=Class.forName("java.lang.Runtime");
Method Method = name.getMethod("exec", String.class);

image-20230310095853300

getDeclaredMethod()

getDeclaredMethod(String name,Class[] parameterTypes)

跟getMethod()一样,只能返回一个特定的方法,一个参数为目标方法名称,第二个参数为目标方法的参数对应Class的对象

但是获取的范围不同,可以获得自身类的privatepublic特定方法

Class<?> name=Class.forName("java.lang.Runtime");
Method declaredMethod = name.getDeclaredMethod("runFinalization0", null);

image-20230310100248308

eg:

给person加一个私有方法和公有方法

import java.io.*;

public class person implements Serializable {
    public String name;
    public int age;
    private int home;
    public person(){

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

        private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException{
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");

    }
    public void test(String a) {
        System.out.println(a);
    }
}
import java.io.ObjectInputStream;
import java.lang.reflect.Method;

public class reflect {
    public static void main(String[] args)  throws Exception{
        Class class1 = Class.forName("person");
        Method method = class1.getDeclaredMethod("readObject", ObjectInputStream.class);
        System.out.println(method);
        
        Method method1 = class1.getMethod("test", String.class);
        System.out.println(method1);
    }
}
//private void person.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
//public void person.test(java.lang.String)
import java.io.ObjectInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflect {
    public static void main(String[] args)  throws Exception{
        Class class1 = Class.forName("person");
        Method [] method = class1.getDeclaredMethods();
        for (int i=0;i<method.length;i++){
            System.out.println(method[i]);
        }
        
        System.out.println("分割线================");
        
        Method[] method1 = class1.getMethods();
        for (int i=0;i<method1.length;i++){
            System.out.println(method1[i]);
        }
    }
}
//private void person.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
//public void person.test(java.lang.String)
//        分割线================
//public void person.test(java.lang.String)
//public final void java.lang.Object.wait() throws java.lang.InterruptedException
//public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//public boolean java.lang.Object.equals(java.lang.Object)
//public java.lang.String java.lang.Object.toString()
//public native int java.lang.Object.hashCode()
//public final native java.lang.Class java.lang.Object.getClass()
//public final native void java.lang.Object.notify()
//public final native void java.lang.Object.notifyAll()

调用获取的类

public Object invoke( Object obj,Object... args )

public class reflect {
    public static void main(String[] args)  throws Exception{
        person pe = new person();
        Class c = pe.getClass();
        Constructor constructor = c.getConstructor(String.class,int.class);
        person p = (person) constructor.newInstance("zzz",123);

        Method method = c.getMethod("test", String.class);
        method.invoke(p,"persontest");
        }
    }
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

v2ish1yan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值