Java 关于反射使用学习笔记

最近学习了Java反射知识,为了加强学到的知识,从今天开始培养自己写博客的习惯,记录自己学习的一些理解。

一、创建对象

说到反射,我们都知道新建一个对象最常用的方法就是new一个,还有两种方法,这两种都是通过反射实现的,首先写一个简单的类:

public class Stu {
    private String name;
    int age;
    public String grade;

    public Stu() {
    }

    public Stu(String name) {
        this.name = name;
    }

    public Stu(int age) {
        this.age = age;
    }

    private Stu(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }

    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 void makeToast() {
        System.out.println("你好,我是" + name);
    }

    private void MyMethod() {
        System.out.println("这是我的私有方法");
    }
}

1、通过直接反射类名获取实例

   Class<?> aClass = Class.forName("**.**.**.Stu");
   Stu stu = (Stu) aClass.newInstance();

其中aClass.newInstance()和Stu.class.newInstance()效果是一样的。

拿到Stu类的Class对象,我们知道Java是面向对象编程的,万物皆对象,我通过描述目标的属性、构造、方法,最终具体为一个对象,其实我们写的Class本身也是一个对象,知道类名后我们通过对应的Class对象就可以直接创建一个实例。

2、通过反射获取构造器

Class<?> aClass = Class.forName("**.**.**.Stu");
Constructor<?> stuConstructor = aClass.getDeclaredConstructor();
stuConstructor.setAccessible(true);
Stu stu2 = (Stu) stuConstructor.newInstance();

通过getDeclaredConstructor()方法拿到的是默认的无参数构造,如果想要拿到定义好的有参构造器就要在getDeclaredConstructor()方法内传入相应的参数类型。比如上述Stu类,如果要获取name构造器

Constructor<?> stu2Constructor = aClass.getDeclaredConstructor(String.class);
stu2Constructor.setAccessible(true);
Stu stu2 = (Stu) stuConstructor.newInstance("小沙");

这里需要注意的是,我们在类里定义的是什么类型,getDeclaredConstructor()参数就要传入什么类型,传入的类型不支持转型。

Constructor<?> stuConstructor = aClass.getDeclaredConstructor(Integer.class);
stuConstructor.setAccessible(true);
Stu stu2 = (Stu) stuConstructor.newInstance(18);
System.out.println(stu2.getAge());

打印结果:

java.lang.NoSuchMethodException: **.**.**.Stu.<init>(java.lang.Integer)
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)

 两种创建方法的区别:

    我们可以进入Class.newInstance()源码看看:

private volatile transient Constructor<T> cachedConstructor;
 
@CallerSensitive
    public T newInstance() throws InstantiationException, IllegalAccessException{
.
.
.

        Constructor<T> tmpConstructor = cachedConstructor;
.
.
.
        try {
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }

源码里主要的就2句,通过已经存在的cachedConstructor赋值给一个构造器对象tmpConstructor,然后tmpConstructor调用newInstance()方法创建对象,看到这里就明白了,跟上文的第二种创建对象的方式是一样的,第一种方法创建对象时只是封装了一下第二种的方法。

二、构造器

      获取构造器

我在Stu类新建一个私有构造器

还是拿刚才获取的aClass对象

            Class<?> aClass = Class.forName("cn.enjoyedu.test.Stu");

            Constructor<?>[] constructors = aClass.getConstructors();
            for (Constructor cos:constructors) {
                System.out.println("getConstructors---------------"+cos.toString());
            }

            Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
            for (Constructor cos:declaredConstructors) {
       System.out.println("getDeclaredConstructors---------------"+cos.toString());
            }

打印结果:

从上图可以看出,使用getDeclaredConstructors()可以获取包括私有在内的全部构造器。同样的方法也适用于获取方法getDeclaredMethods()、获取属性getDeclaredFields()。

      使用构造器

            Constructor<?> classDeclaredConstructor 
                    = aClass.getDeclaredConstructor(String.class, int.class);
            classDeclaredConstructor.setAccessible(true);
            Stu stu3 = (Stu) classDeclaredConstructor.newInstance("大刘", 28);
            stu3.makeToast();

注意在获取私有构造器使用时要授予权限

.setAccessible(true)

否则会报错。

三、属性

我们修改一下Stu类的属性

    private String name;
    int age;
    public String grade;

然后使用

            Field[] fields = aClass.getFields();
            for (Field df : fields) {
                System.out.println("getFields---------------" + df.toString());
            }

            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field df : declaredFields) {
                System.out.println("getDeclaredFields---------------" + df.toString());
            }

打印结果

getFields()方法只能获取权限为‘public’的属性,getDeclaredFields()方法能获取包括私有的所有属性。

通过反射使用Field:

Stu stuField = (Stu) aClass.newInstance();
stuField.setGrade("八年级");
//如果字段是私有的 加上权限
Field grade = aClass.getDeclaredField("grade");
System.out.println(grade.getName()+"------"+grade.get(stuField));

打印结果

 

四、方法

首先我们给Stu类里增加一个私有方法

 private void MyMethod(){
        System.out.println("这是我的私有方法");
    }
            Method[] methods = aClass.getMethods();
            for (Method method:methods ) {
                System.out.println("getMethods-----------------------"+method.getName());
            }
            Method[] declaredMethods = aClass.getDeclaredMethods();
            for (Method methodD:declaredMethods ) {
                System.out.println("getDeclaredMethods---------------"+methodD.getName());
            }

打印结果

可以看到使用getMethods()获取的方法里有好多是Stu类里没有的,这些都是继承的Object的方法,并且getMethods()也没有获取到我们定义的MyMethod()。

getDeclaredMethods()方法获取到了本类里定义的包括私有在内的所有方法。

然后就使用获取到的方法。

            //反射获取到方法
            Method setNameMethod = aClass.getDeclaredMethod("setName", String.class);
            //获取对象实例  不需要转型
            Object stuMethods =  aClass.newInstance();
            //执行方法设置属性
            setNameMethod.invoke(stuMethods, "小岳岳");
            //获取方法
            setNameMethod = aClass.getDeclaredMethod("makeToast");
            //执行方法
            setNameMethod.invoke(stuMethods);
            //获取私有方法
            setNameMethod= aClass.getDeclaredMethod("MyMethod");
            //授予权限
            setNameMethod.setAccessible(true);
            setNameMethod.invoke(stuMethods);

打印结果

上面是获取并执行的都是公有方法,在执行私有方法时要加一句

setAccessible(true)

授予权限。

 

以上就是刚学反射的笔记。

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值