码迷,mamicode.com
首页 > 编程语言 > 详细

java反射机制

时间:2019-11-17 12:43:58      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:动态获取   结果   bsp   方法   构造   元素   uri   hang   getc   

java反射机制:
指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。
而要想解剖一个类,必须先获取该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类对象。
jdk1.6官方解释Class类:

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

乍一看有点懵,我们来看下面这张图

技术图片
这里写图片描述
我们可以看到通过编译后的class文件通过jvm使用类加载器加载到内存而Class类我们就可以理解为class文件在内存中的东东。

知道了Class是啥东西,接下来直接上代码看看它怎么用。
先给一个Person类
package reflect;

public class Person {

    private String name;
    int age;
    public String sex;

    public Person() {

    }
    Person(String name){
        this.name = name;
    }
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public Person(String name, int age, String sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    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 String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }

}




package reflect;

public class GetClass {

    /**三种方式获取字节码文件对象
     * @param args
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws ClassNotFoundException{
        //1  类名.class
        Class clazz1 = Person.class;
        System.out.println(clazz1.getName());
        //2  对象.getClass()
        Person p = new Person();
        Class clazz2 = p.getClass();
        System.out.println(clazz2.getName());
        //3 Class.forName("包名.类名"); 注意要写全
        Class clazz3 = Class.forName("reflect.Person");
        System.out.println(clazz3.getName());
    }
}

打印结果:

reflect.Person
reflect.Person
reflect.Person


获取完字节码对象到底有啥用处呢?
其实反射就是通过字节码文件对象完成的反射动作,来获取一个类的构造方法、成员变量、普通方法等操作,而不管你是public的还是private的,可以看出反射确实非常暴力。
接下来说说如何通过反射获取构造方法:
还是使用上面的Person类,在这里我们就随便用一种方式获取字节码对象了,想试试别的方式的,同学们自己回去试。
1,获取public的构造方法:

public Constructor<T> getConstructor(Class<?>... parameterTypes)
                              throws NoSuchMethodException,
                                     SecurityException

 public Constructor<?>[] getConstructors()
                                 throws SecurityException

   

上面的是有参数返回一个公共Constructor方法,而这个参数注意是指参数的数据类型的字节码文件对象(如String类型则参数是String.class,是int则参数就是int.Class ),下面的是无参数返回所有公共的构造方法(数组)。

package reflect;

import java.lang.reflect.Constructor;

public class TestReflect {

    /**通过反射获取public构造方法
     *
     * public Constructor<T> getConstructor(Class<?>... parameterTypes)
                              throws NoSuchMethodException,
                                     SecurityException

       public Constructor<?>[] getConstructors()
                                 throws SecurityException
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("reflect.Person");
        //获取无参数的构造方法
        Constructor constructor1 = clazz.getConstructor();
        //获取有参数的构造方法
        Constructor constructor2 = clazz.getConstructor(String.class,int.class);

        System.out.println(constructor1.getName());
        System.out.println(constructor2.getName());
    }
}


打印结果可以看到返回两个public的构造方法名,如果Person类中构造方法是private的会报错,同学们可以下面自己试试。

reflect.Person
reflect.Person

 

说到这插一句,可能会有同学问这个Constructor是个啥东西,
jdk 1.6中解释:
Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。
Constructor 允许在将实参与带有底层构造方法的形参的 newInstance() 匹配时进行扩展转换,但是如果发生收缩转换,则抛出 IllegalArgumentException。
其实就是相当于是构造方法的封装类。

那么获取完构造方法怎么操作呢
(1)操作无参数的 构造方法(两种方式):

package reflect;

import java.lang.reflect.Constructor;

public class TestReflect {

    /**通过反射获取public构造方法
     *
     * public Constructor<T> getConstructor(Class<?>... parameterTypes)
                              throws NoSuchMethodException,
                                     SecurityException

       public Constructor<?>[] getConstructors()
                                 throws SecurityException
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("reflect.Person");
        //获取无参数的构造方法
        Constructor constructor1 = clazz.getConstructor();

        //获取有参数的构造方法
        Constructor constructor2 = clazz.getConstructor(String.class,int.class);

/*      System.out.println(constructor1.getName());
        System.out.println(constructor2.getName());*/
        testConstructor1();

    }

    /**操作构造方法(无参数)两种方式
     * @throws Exception
     */
    public static void testConstructor1() throws Exception{
        Class clazz = Class.forName("reflect.Person");
        //1  获取到Constructor,通过construct对象实例化peron
        Constructor constructor1 = clazz.getConstructor();
        Person p1 = (Person)constructor1.newInstance();
        //2 直接通过字节码文件对象实例化person
        Person p2 = (Person) clazz.newInstance();
        //设置值
        p1.setName("李四");
        p2.setName("李四");
        System.out.println(p1.getName());
        System.out.println(p2.getName());
    }

}

  

打印结果:

李四
李四

   
(2)操作有参数的 构造方法

package reflect;

import java.lang.reflect.Constructor;

public class TestReflect {

    /**通过反射获取public构造方法
     *
     * public Constructor<T> getConstructor(Class<?>... parameterTypes)
                              throws NoSuchMethodException,
                                     SecurityException

       public Constructor<?>[] getConstructors()
                                 throws SecurityException
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("reflect.Person");
        //获取无参数的构造方法
        Constructor constructor1 = clazz.getConstructor();

        //获取有参数的构造方法
        Constructor constructor2 = clazz.getConstructor(String.class,int.class);

/*      System.out.println(constructor1.getName());
        System.out.println(constructor2.getName());*/
        //testConstructor1();
        testConstructor2();

    }

    /**操作构造方法(有参数)
     * @throws Exception
     */
    public static void testConstructor2() throws Exception{
        Class clazz = Class.forName("reflect.Person");
        Constructor constructor = clazz.getConstructor(String.class,int.class);
        //获取实例
        Person p = (Person)constructor.newInstance("王五",20);
        System.out.println(p.getName());
        System.out.println(p.getAge());
    }
}

 

打印结果:

王五
20


返回是数组的情况没啥区别,回头大家自己试试
说完获取public的构造方法,下面该说说非public的是如何获取的(下面才是重点,嘎嘎~)
2、 获取所有类型的构造方法(不管你公有、私有还是没有的统统拿到手)
同样有以下两个方法:

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
                                      throws NoSuchMethodException,                                        SecurityException

public Constructor<?>[] getDeclaredConstructors()
                                         throws SecurityException

 

将上面的Person类中无参的构造方法改为private修饰

    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("reflect.Person");
        Constructor constructor1 = clazz.getDeclaredConstructor();
        Constructor constructor2 = clazz.getDeclaredConstructor(String.class,int.class,String.class);
        System.out.println(constructor1.getName());
        System.out.println(constructor2.getName());

    }

 

打印结果:

reflect.Person
reflect.Person

 

同样构造方法的调用

    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("reflect.Person");
        Constructor constructor1 = clazz.getDeclaredConstructor();
        Constructor constructor2 = clazz.getDeclaredConstructor(String.class,int.class,String.class);
        /*System.out.println(constructor1.getName());
        System.out.println(constructor2.getName());*/

        //public的构造方法直接通过newInstance的方式获取实例person
        Person p = (Person) constructor2.newInstance("zhangs",16,"女");
        System.out.println(p);
        //private的构造方法需要设置可访问,之后再newInstance获取实例
        constructor1.setAccessible(true);
        Person p2 = (Person) constructor1.newInstance();
        System.out.println(p2);

    }

 

打印结果

Person [name=zhangs, age=16, sex=女]
Person [name=null, age=0, sex=null]

  
这里就要注意获取实例对象的时候公有方法可以通过constructor对象直接newInstance,而私有构造方法需要先设置可访问,constructor.setAccessible(true),之后再newInstance即可,这也是反射暴力的所在。


java反射机制

标签:动态获取   结果   bsp   方法   构造   元素   uri   hang   getc   

原文地址:https://www.cnblogs.com/gao1991/p/11875810.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!