Java中反射的使用详解

在使用反射前要了解的基础知识:(虽然有几个,但是每个都内容较少)
1.Java中类的加载概述和加载时机
2.Java中类加载器概述
3.Java中反射的概述

1.反射获取class文件对象的几种方式

1.Object类的getClass()方法
2.数据类型的静态属性class
3.Class类中的静态方法,public static Class forName(String className)

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式1
        Person p = new Person();
        Class c = p.getClass();

        Person p2 = new Person();
        Class c2 = p2.getClass();

        System.out.println(p == p2);// false
        System.out.println(c == c2);// true

        // 方式2
        Class c3 = Person.class;
        // int.class;
        // String.class;
        System.out.println(c == c3);//true

        // 方式3
        // ClassNotFoundException
        Class c4 = Class.forName("cn.itcast_01.Person");//这里必须为全路径名称,全路径名称指的是:包名+类名。分隔用'.'号,否则会报ClassNotFoundException异常。
        System.out.println(c == c4);//true
    }
}

总结:
这三种方式获取到的class文件对象都是一样的,是因为class文件对象只被类加载器(系统类加载器)创建一次。所以三种方式获取到的class对象都是相同的,地址和内容都一样。

当加载了class文件对象之后,就可以开工了。

2.通过构造器对象创建目标类对象

下面几个方法只能够获取本类的构造方法。
涉及到的几个Class方法。
1. Constructor<T> getConstructor (Class<?>… parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
2.Constructor<?>[] getConstructors ()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
3.Constructor<T> getDeclaredConstructor (Class<?>… parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。私有成员也能获取
4. Constructor<T> [] getDeclaredConstructors ()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。私有成员也能获取
5.public void setAccessible(boolean flag)
将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
6.T newInstance(Object… initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

准备工作,这里写上一个基类。Person

public class Person {
    private String name;
    private int age;
    private String addr;
    public String gender;

    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 getAddr() {
        return addr;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", addr=" + addr + ", gender=" + gender + "]";
    }
    public Person() {
        super();
    }
    public Person(String name, int age, String addr) {
        super();
        this.name = name;
        this.age = age;
        this.addr = addr;
    }
    private Person(String name, int age){
        super();
        this.name=name;
        this.age=age;
    }
}

通过构造器类创建目标类对象:

import java.lang.reflect.Constructor;

public class reflect01 {
    public static void main(String[] args) {
        /*
         * 测试获取构造函数,创建对象
         * 有无参构造和有参构造
         */
        try {
            //公共无参构造测试
            test_wucan();

            //公共有参构造测试
            test_youcan();

            //私有 有参构造
            test_siyouwucan();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void test_siyouwucan() throws Exception {
        Class person=Class.forName("reflect.Person");
        Constructor constructor = person.getDeclaredConstructor(String.class,int.class);//一般写反射代码时都用getDeclared...获取成员。
        constructor.setAccessible(true);//这个要写上不然会报访问异常,意思是取消Java语法检查。
        Object object = constructor.newInstance("胡艺宝",19);
        System.out.println(object);
    }

    private static void test_youcan() throws Exception{
        Class person=Class.forName("reflect.Person");
        Constructor constructor=person.getDeclaredConstructor(String.class,int.class,String.class);
        Object object=constructor.newInstance("LangSheng",19,"天堂");
        System.out.println(object);
    }

    private static void test_wucan() throws Exception {
        /*
         * 但是一般写代码的时候这里都不写类型Class<Person>
         * 在这里的对象,相当于new Person();
         */
        Class<Person> person=(Class<Person>)Class.forName("reflect.Person");
        Constructor<Person> perConstructor=person.getDeclaredConstructor();
        Person p=perConstructor.newInstance();
        p.setName("FireLang");
        p.setAge(19);
        p.setAddr("天堂");
        System.out.println(p);
    }
}

结果:

Person [name=FireLang, age=19, addr=天堂]
Person [name=LangSheng, age=19, addr=天堂]
Person [name=胡艺宝, age=19, addr=null]

3.通过class文件对象来设置成员变量值

涉及到的方法:
1.Field getField(String name)
能够获取到父类的成员变量和本类的成员变量
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
2. Field[] getFields()
能够获取到父类的成员变量和本类的成员变量
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
3.Field getDeclaredField(String name)
只能够获取到本类的成员变量
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。私有成员也能获取
4.Field[] getDeclaredFields()
只能够获取到本类的成员变量
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。私有成员也能获取

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

public class Reflect02 {
    public static void main(String[] args) {
        /*
         * 用目标对象(通过反射new一个对象) 通过获取Field来设置相关对象的值
         */

        try {
            //设置公有变量
            test_setField01();

            //设置私有变量
            test_setField02();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void test_setField02() throws Exception{
        Class objeClass=Class.forName("reflect.Person");
        Constructor constructor=objeClass.getDeclaredConstructor();
        Object object=constructor.newInstance();

        Field field=objeClass.getDeclaredField("name");//这个方法能够获取所有指定变量名的成员变量

        field.setAccessible(true);//必须设置这个,因为name这个成员变量是私有成员。
        field.set(object, "CSDN");
        System.out.println(object);
    }

    private static void test_setField01() throws Exception {
        Class objClass=Class.forName("reflect.Person");
        Constructor constructor=objClass.getDeclaredConstructor();
        Object object=constructor.newInstance();


        Field field=objClass.getDeclaredField("gender");//这个方法能够获取所有指定变量名的成员变量

        //因为是公共成员变量,所以不用设置setAccessible(true);
        field.set(object, "男");
        System.out.println(object);
    }
}

作为上面的补充,这个方式能够获取到本类以及所有父类的所有私有和public方法:

    /**
     * 获取某个对象的所有属性Field对象。
     * @param target
     * @return
     */
    public static List<Field> getAllProperty(Object target){
        Class clazz = target.getClass();
        List<Field> fieldList = new LinkedList<>();
        while(clazz!=null){
            System.out.println(clazz.getName());
            fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }

4.通过class文件对象来操作类中的方法

1.Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

2.Method getMethod(String name, Class<?>… parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。能够获取父类的方法。
3.Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
4.Method getDeclaredMethod(String name, Class<?>… parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。不包括继承的方法。
注意构造方法是不能通过获取Method的方式获取。

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 获取字节码文件对象
        Class c = Class.forName("cn.itcast_01.Person");

        // 获取所有的方法
        // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
        // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法,包括私有方法
        // for (Method method : methods) {
        // System.out.println(method);
        // }

        Constructor con = c.getConstructor();
        Object obj = con.newInstance();

        /*
         * Person p = new Person(); p.show();
         */

        // 获取单个方法并使用
        // public void show()
        // public Method getMethod(String name,Class<?>... parameterTypes)
        // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
        Method m1 = c.getMethod("show");
        // obj.m1(); // 错误
        // public Object invoke(Object obj,Object... args)
        // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
        m1.invoke(obj); // 调用obj对象的m1方法

        System.out.println("----------");
        // public void method(String s)
        Method m2 = c.getMethod("method", String.class);
        m2.invoke(obj, "hello");
        System.out.println("----------");

        // public String getString(String s, int i)
        Method m3 = c.getMethod("getString", String.class, int.class);
        Object objString = m3.invoke(obj, "hello", 100);
        System.out.println(objString);
        // String s = (String)m3.invoke(obj, "hello",100);
        // System.out.println(s);
        System.out.println("----------");

        // private void function()
        Method m4 = c.getDeclaredMethod("function");
        m4.setAccessible(true);
        m4.invoke(obj);
    }
}

总结:

一.构造方法获取:

1. Constructor<T> getConstructor (Class<?>… parameterTypes)
2.Constructor<?>[] getConstructors ()
上面这两个是只能够获取本类的公共构造方法。
3.Constructor<T> getDeclaredConstructor (Class<?>… parameterTypes)
4. Constructor<T> [] getDeclaredConstructors ()
上面这两个是不仅能够获取本类的公共构造方法也能够获取本类的私有构造方法。
上面这4个构造方法是只能获取本类的构造方法,而不能够获取父类的构造方法。

5.public void setAccessible(boolean flag)//设置私有的构造方法、成员变量和普通方法是否有语法检查。
6.T newInstance(Object… initargs)

二.成员变量获取
1.Field getField(String name)
2. Field[] getFields()
上面这两个能够获取本类和父类中的变量。但是只能获取公共变量。即public修饰的。

3.Field getDeclaredField(String name)
4.Field[] getDeclaredFields()
上面这两个只能够获取本类中的变量,包括私有成员变量和公共成员变量。

三.成员方法获取

1.Method[] getMethods()
2.Method getMethod(String name, Class<?>… parameterTypes)
上面这两个能够获取本类和父类中的成员方法,但是只能够获取公共的成员方法。

3.Method[] getDeclaredMethods()
4.Method getDeclaredMethod(String name, Class<?>… parameterTypes)
上面这两个只能够获取本类中的成员方法,包括私有的成员方法和公共成员方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值