当前位置: 主页 > JAVA语言

反射 java-java 反射执行set方法

发布时间:2023-02-08 22:33   浏览次数:次   作者:佚名

前言

- 今天我将介绍Java的反射机制。 以前我们都是通过new的实例来获取一个类的实例。 那也太low了,今天就跟我一起学习更高级的实现方式吧。

Java文本反射机制定义反射机制的优缺点

为什么要用反射机制?直接创建对象不就好了吗? 这就涉及到动态和静态的概念

了解类和类类型

类是java.lang.Class类的实例对象,Class是所有类的一个类(有一个类叫Class)

对于普通的对象,我们一般是这样创建和表示的:

代码code1 = new Code();

但是我们看Class的源码,是这样写的:

private  Class(ClassLoader loader) { 
    classLoader = loader; 
}
 

可以看出构造函数是私有的,只有JVM可以创建Class对象,所以不能像普通类那样创建一个新的Class对象。 虽然我们不能创建一个新的Class对象,但是我们可以通过一个已经存在的类得到一个Class对象。 有以下三种方式,如下

反射 java_java反射型xss_java 反射执行set方法

这里,c1、c2、c3都是Class对象,它们一模一样,有一个学名叫做Code类类型(class type)。

给出一个简单的示例代码:

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种:Class c1 = Code.class;
        Class class1=ReflectDemo.class;
        System.out.println(class1.getName());
        //第二种:Class c2 = code1.getClass();
        ReflectDemo demo2= new ReflectDemo();
        Class c2 = demo2.getClass();
        System.out.println(c2.getName());
        //第三种:Class c3 = Class.forName("com.trigl.reflect.Code");
        Class class3 = Class.forName("com.tengj.reflect.ReflectDemo");
        System.out.println(class3.getName());
    }
}

结果:

com.tengj.reflect.ReflectDemo
com.tengj.reflect.ReflectDemo
com.tengj.reflect.ReflectDemo

Java反射相关操作

我们知道如何更早地获取Class,那么我们可以用这个Class做什么呢?

总结如下:

让我们详细介绍一下

获取成员方法信息【数据获取】

单独获取一个方法是通过Class类的以下方法获取的:

公共方法 getDeclaredMethod(字符串名称,类...

parameterTypes) // 获取本类的所有方法,不包括父类的public Method getMethod(String

name, Class... parameterTypes) // 获取该类的所有公有方法,包括父类

两个参数分别是方法名和方法参数类的类类型列表。

例如,类 A 有以下方法:

public void fun(String name,int age) {

java反射型xss_反射 java_java 反射执行set方法

System.out.println("我叫"+name+",今年"+age+"岁"); }

现在知道 A 有一个对象 a反射 java,那么你可以通过:

Class c = Class.forName(“com.tengj.reflect.Person”); // 生成类

对象 o = c。 新实例();

//newInstance可以初始化一个实例Method method = c.getMethod("fun",

String.class, int.class);//获取方法 method.invoke(o, "tengj", 10);

//通过invoke调用这个方法,第一个参数是实例对象,后面是具体的参数值

完整代码如下:

public class Person {
    private String name;
    private int age;
    private String msg="hello wrold";
 public String getName() {
        return name;
  }
    public void setName(String name) {
        this.name = name;
  }
    public int getAge() {
        return age;
  }
    public void setAge(int age) {
        this.age = age;
  }
    public Person() {
    }
    private Person(String name) {
        this.name = name;
  System.out.println(name);
  }
    public void fun() {
        System.out.println("fun");
  }
    public void fun(String name,int age) {
        System.out.println("我叫"+name+",今年"+age+"岁");
  }
}
public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");

java反射型xss_反射 java_java 反射执行set方法

Object o = c.newInstance(); Method method = c.getMethod("fun", String.class, int.class); method.invoke(o, "tengj", 10); } catch (Exception e) { e.printStackTrace(); } } }

结果:

我叫腾杰,今年10岁

怎么样,是不是感觉很厉害,只要知道这个类的路径全名,就可以在掌声中玩起来了。

有时候我们想获取一个类中所有成员方法的信息,怎么办。 这可以通过以下步骤实现:

1.获取所有方法的数组:

Class c = Class.forName(“com.tengj.reflect.Person”); 方法[]方法

= c.getDeclaredMethods(); // 获取类的所有方法,不包括父类 or: Method[] methods = c.getMethods();// 获取类的所有公共方法,包括父类

2.然后循环这个数组得到每一个方法:

对于(方法方法:方法)

完整代码如下:

person类同上,这里以后就不贴了,只贴关键代码

public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            Method[] methods = c.getDeclaredMethods();
            for(Method m:methods){
                String  methodName= m.getName();
                System.out.println(methodName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

获取名称

设定名称

设置年龄

乐趣

乐趣

获取年龄

在这里,如果 c.getDeclaredMethods(); 改为 c.getMethods(); 执行结果如下,方法多了很多,Object中的方法也打印出来了,因为Object是所有类的父类:

getNamesetNamegetAgesetAgefunfunwaitwaitwaitqualstoStringhashCodegetClassnotifynotifyAll

获取成员变量信息

想一想成员变量中包含的内容:成员变量类型+成员变量名

类的成员变量也是一个对象,是java.lang.reflect.Field的一个对象,所以我们通过java.lang.reflect.Field封装的方法获取这些信息。

通过Class类的以下方法分别获取一个成员变量:

public Field getDeclaredField(字符串名称) //

获取类自身声明的所有变量,不包括其父类的变量 public Field getField(String name) // 获取类的所有公共成员变量反射 java,包括其父类的变量

参数是成员变量的名称。

java反射型xss_java 反射执行set方法_反射 java

例如,类 A 有以下成员变量:

私人诠释 n;

如果A有一个对象a,那么它的成员变量可以这样获取:

Class c = a.getClass();Field 字段 = c.getDeclaredField("n");

完整代码如下:

public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            //获取成员变量
            Field field = c.getDeclaredField("msg"); //因为msg变量是private的,所以不能用getField方法
            Object o = c.newInstance();
            field.setAccessible(true);//设置是否允许访问,因为该变量是private的,所以要手动设置允许访问,如果msg是public的就不需要这行了。
            Object msg = field.get(o);
            System.out.println(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

3.你好世界

同样的,如果想获取所有成员变量的信息,可以使用以下步骤

1、获取所有成员变量的数组:

字段[]字段=c。 getDeclaredFields();

2.遍历变量数组,获取成员变量字段

对于(字段字段:字段)

完整代码:

public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            Field[] fields = c.getDeclaredFields();
            for(Field field :fields){
                System.out.println(field.getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

nameagemsg

获取构造函数

最后想想构造函数中包含的内容:构造函数参数

如上,一个类的构造函数也是一个对象,它是java.lang.reflect.Constructor的一个对象,所以我们通过java.lang.reflect.Constructor中封装的方法获取这些信息。

单独获取一个构造函数,通过Class类的如下方法:

公共构造函数getDeclaredConstructor(类...

parameterTypes) // 获取该类的所有构造函数,不包括其父类的构造函数 public Constructor getConstructor(Class... parameterTypes) //

java 反射执行set方法_反射 java_java反射型xss

获取该类的所有公共构造函数,包括父类

该参数是构造函数参数类的类类型列表。

例如,类 A 具有以下构造函数:

public A(String a, int b) {
    // code body
}

然后你可以通过:

构造函数 constructor = a.getDeclaredConstructor(String.class,

诠释。 班级);

得到这个构造函数。

完整代码:

public class ReflectDemo {
    public static void main(String[] args){
        try {
            Class c = Class.forName("com.tengj.reflect.Person");
            //获取构造函数
            Constructor constructor = c.getDeclaredConstructor(String.class);
            constructor.setAccessible(true);//设置是否允许访问,因为该构造器是private的,所以要手动设置允许访问,如果构造器是public的就不需要这行了。
            constructor.newInstance("tengj");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

腾杰

注意:Class的newInstance方法只能创建一个只包含无参构造函数的类。 如果一个类只有带参数的构造函数,则需要另一个方法:

fromClass.getDeclaredConstructor(String.class).newInstance("tengj");

获取所有构造函数可以通过以下步骤实现:

1.获取这个类的所有构造函数,并把它们放在一个数组中:

构造函数[] 构造函数 = c. getDeclaredConstructors();

2、遍历构造函数数组,得到某个构造函数:

对于(构造函数构造函数:构造函数)

完整代码:

public class ReflectDemo {
    public static void main(String[] args){
            Constructor[] constructors = c.getDeclaredConstructors();
            for(Constructor constructor:constructors){
                System.out.println(constructor);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

执行结果:【参考】

公共 com.tengj.reflect.Person() 公共 com.tengj.reflect.Person(java.lang.String)

通过反思理解集合泛型的本质

java反射型xss_java 反射执行set方法_反射 java

先得出结论:

Java中泛型集合是为了防止误输入,只在编译阶段有效,绕过编译,到了运行时就失效了。

下面通过实例验证:

/**
 1. 集合泛型的本质
 2. @description
 3. @author Trigl
 4. @date 2016年4月2日上午2:54:11
 */
public class GenericEssence {
    public static void main(String[] args) {
        List list1 = new ArrayList(); // 没有泛型 
        List list2 = new ArrayList(); // 有泛型
        /*
         * 1.首先观察正常添加元素方式,在编译器检查泛型,
         * 这个时候如果list2添加int类型会报错
         */
        list2.add("hello");
//      list2.add(20); // 报错!list2有泛型限制,只能添加String,添加int报错
        System.out.println("list2的长度是:" + list2.size()); // 此时list2长度为1
        /*
         * 2.然后通过反射添加元素方式,在运行期动态加载类,首先得到list1和list2
         * 的类类型相同,然后再通过方法反射绕过编译器来调用add方法,看能否插入int
         * 型的元素
         */
        Class c1 = list1.getClass();
        Class c2 = list2.getClass();
        System.out.println(c1 == c2); // 结果:true,说明类类型完全相同
        // 验证:我们可以通过方法的反射来给list2添加元素,这样可以绕过编译检查
        try {
            Method m = c2.getMethod("add", Object.class); // 通过方法反射得到add方法
            m.invoke(list2, 20); // 给list2添加一个int型的,上面显示在编译器是会报错的
            System.out.println("list2的长度是:" + list2.size()); // 结果:2,说明list2长度增加了,并没有泛型检查
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*
         * 综上可以看出,在编译器的时候,泛型会限制集合内元素类型保持一致,但是编译器结束进入
         * 运行期以后,泛型就不再起作用了,即使是不同类型的元素也可以插入集合。
         */
    }
}

结果:

list2 的长度是:1 list2 的真实长度是:​​2 摘要

至此,Java反射机制的引入就差不多完成了。 我在复习SpringMVC中的IOC/DI的时候,是通过Java反射实现的。 我希望这篇笔记对你也有用。 (更多免费Java知识请私聊)