0%

Java反射学习

概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

简单实例

获取类对象

package test;
import java.lang.Class.*;

public class reflection1 {
    public static void main(String[] args) throws Exception {
            Class.forName("test.xxx");
    }
}
class xxx{
    public void  xxx(){
        System.out.println("hello world");
    }
    static {
        System.out.println("test1");
    }
    {
        System.out.println("test2");
    }
}
  • forName方法获取一个类的时候会调用这个类的static静态代码。

WX20201115-134345@2x

获取类方法

获取全部方法

  • getMethod来获取函数的方法,执行invoke后通过newInstance来调用构造函数,但是{}的优先级会比构造方法高,所以运行结果会是先{}、构造方法、普通方法。
package test;
public class reflection1 {
    public static void main(String[] args) throws Exception {
        Class clazz=Class.forName("test.xxx");
        //实例化类,然后调用方法
        clazz.getMethod("hello").invoke(clazz.newInstance());
    }
}
class xxx{
    public   xxx(){
        System.out.println("test1");
    }
    public void hello(){
        System.out.println("hello");
    }
    static {
        System.out.println("test2");
    }
    {
        System.out.println("test3");
    }
}
  • 运行结果

WX20201115-143559@2x

获取无参数构造方法

  • 同样先需要获取到对应的类对象,然后通过getDeclaredConstructor方法来获取构造方法,这里有个细节如果获取的构造方法是私有(private)时候需要使用setAccessible,最后使用newInstance来创建实例。
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class reflection1 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("test.zzz");
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        constructor.newInstance();
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

获取含参数构造方法

  • 同样使用getDeclaredConstructor方法来获取,但是需要指定参数数据类型。然后在newInstance传参即可。
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class reflection1 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("test.zzz");
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        constructor.newInstance("黄莉荃");
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}
getDeclaredConstructors
  • getDeclaredConstructors将会返回所有构造方法的数组

WX20201115-153623@2x

  • 以获取索引为2的方法为例:
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class reflection1 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("test.zzz");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        Constructor constructor = constructors[2];
        constructor.setAccessible(true);
//      输出内容
        System.out.println(constructor);
        constructor.newInstance(18,"黄莉荃");
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

WX20201115-154252@2x

获取字段

  • 通过getDeclaredField来获取字段,如果是私有字段只需加上field.setAccessible(true);即可
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflection1 {
    public static <Feild> void main(String[] args) throws Exception {
        //获取类
        Class clazz=Class.forName("test.test");
        //获取私有方法
        Constructor c = clazz.getDeclaredConstructor();
        //获取私有字段
        Field field = clazz.getDeclaredField("age");
        System.out.println(field.get(c.newInstance()));
    }
}

class test{
    public test(){
        System.out.println("test");
    }
    public int age=222;
}

修改字段值

  • 使用set方法即可修改
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflection1 {
    public static <Feild> void main(String[] args) throws Exception {
        //获取类
        Class clazz=Class.forName("test.test");
        //获取私有方法
        Constructor c = clazz.getDeclaredConstructor();
        //获取私有字段
        Object o = c.newInstance();
        Field field = clazz.getDeclaredField("age");
        field.set(o,1111);
        System.out.println(field.get(o));
    }
}

class test{
    public test(){
        System.out.println("test");
    }
    public int age=222;
}

反射调用java.lang.Runtime

利用方法一
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflection1 {
    public static <Feild> void main(String[] args) throws Exception {
        Class clazz = Class.forName("java.lang.Runtime");
        Constructor c = clazz.getDeclaredConstructor();
        c.setAccessible(true);
        clazz.getMethod("exec", String.class).invoke(c.newInstance(),"open /Users/gqleung/Desktop/aaaa.txt");
    }
}
  • 成功打开桌面的aaaa.txt

WX20201115-160241@2x

利用方法二
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflection1 {
    public static <Feild> void main(String[] args) throws Exception {
        Class clazz=Class.forName("java.lang.Runtime");
        clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"ping y3qge8.dnslog.cn");
    }
}

WX20201115-161159@2x