反射,Java超详细笔记

反射概念:

         反射是啥?Java的反射机制其实就是在程序运行时去获取一个类的成员变量和方法,通过获得的这些信息去创建对象,然后我们就可以访问类的成员变量和方法。

        这个和正常创建对象的方式有什么不一样嘛?我不太理解,PPT只是说反射的这种方式可以极大的增强程序的灵活性,程序不用在编译器就能够确定,在运行期仍然可以扩展。

        希望在后面的视频中能加深这种理解。

获取Class类的对象

1、概念

        接下来敲代码演示这几种方法的使用过程。

2、案例演示

public class ReflexDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 第一种:使用类的class属性来获取该类对应的class对象
        Class<Student> sc1 = Student.class;
        System.out.println(sc1);

        // 第二种:调用对象的getClass()方法
        Student student = new Student();
        Class<? extends Student> sc2 = student.getClass();
        if (sc1==sc2)
            System.out.println(sc2);

        // 第三种:使用Class类的静态方法:forName()
        Class<?> sc3 = Class.forName("Basic.Reflex.Student");
        if (sc3==sc1)
            System.out.println(sc3);
    }
}

如何使用反射获取类的构造方法并使用呢?

        使用到两个方法:

    • Constructor<T>getConstructor(Class<?>... parameterTypes)

      返回一个 Constructor对象,该对象反映此 Class对象所表示的类的指定公共构造函数。

getConstructor()该方法返回是公共的构造器函数数组。

getConstructors()该方法返回的是所有的构造器函数数组。

案例代码:

import java.lang.reflect.Constructor;

public class ReflexDemo2 {
    public static void main(String[] args) {
        // 获取class对象
        Class<Student> c = Student.class;

        // getConstructors()
        Constructor<?>[] cons = c.getConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
        System.out.println("---------------------");

        // getDeclareConstructors()
        Constructor<?>[] conss = c.getDeclaredConstructors();
        for (Constructor constructor : conss) {
            System.out.println(constructor);
        }
    }
}

上面的这两种方法其实得到的都是数组,获得的都是数组,那反射能不能获取单个的或者指定的构造器函数呢?

答案当然是可以的!

    • Constructor<T>getConstructor(Class<?>... parameterTypes)

      返回一个 Constructor对象,该对象反映此 Class对象所表示的类的指定公共构造函数。

这两个方法可以获得单个的或者指定的构造函数,此外获得构造函数后还需要创建对象才得,需要用到Constructor类中的这个方法:

    • TnewInstance(Object... initargs)

      使用此 Constructor对象表示的构造方法,使用指定的初始化参数创建和初始化构造函数声明类的新实例。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflexDemo3 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 创建字节码对象
        Class<Student> c = Student.class;

        /*
        // 获得无参构造函数
        Constructor<Student> con = c.getConstructor();

        // 创建对象
        Student student = con.newInstance();
        */

        // 获得有参构造函数
        Constructor<Student> con = c.getConstructor(String.class, int.class);
        
        // 创建对象
        Student student = con.newInstance("奥特曼", 18);
        System.out.println(student);

    }
}

上面这个是公共的,接下来我们玩个私有的。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflexTest1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 创建反射对象
        Class<Student> c = Student.class;

        // 获得一个参数的构造函数(我们创建的Student类中有一个private Student(String name))
        Constructor<Student> con = c.getDeclaredConstructor(String.class);

        // 使用构造函数创建对象
        Student student = con.newInstance("林青霞");
        System.out.println(student);
    }
}

虽然我们使用了getDeclaredConstructor(),但是我们依然收到了错误提示:

 这是为什么呢?因为getDeclaredConstructor()仅仅是帮助我们获得了私有的构造方法,但是我们不能够拿这个私有构造去创建对象,所以编译器报错了。

那有木有什么方法能解决这个问题呢?

有的,只要Constructor类中的setAccessible()方法即可解决这个问题。

    • voidsetAccessible(boolean flag)

      将此反射对象的 accessible标志设置为指示的布尔值。设置为true就可以取消检查机制。

来吧Come on,看看效果如何:

public class ReflexTest1 {
    public static void main(String[] args) {
        // 创建反射对象
        Class<Student> c = Student.class;

        // 获得一个参数的构造函数(我们创建的Student类中有一个private Student(String name))
        Constructor<Student> con = c.getDeclaredConstructor(String.class);

        // 暴力反射
        con.setAccessible(true);
        // 使用构造函数创建对象
        Student student = con.newInstance("林青霞");
        System.out.println(student);
    }
}

程序完美的运行起来了,没有错误再出现。

反射获得成员变量并使用

        毫无疑问,肯定要使用方法来获取类中的成员变量。

来吧,代码展示:

package Basic.Reflex;

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

public class ReflexDemo4 {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 反射对象
        Class<Student> c = Student.class;

        // 获得公共的所有成员变量
        Field[] fields = c.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("-------------------");

        // 获得所有的成员变量,包括私有
        Field[] declaredFields = c.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("-------------------");

        // 获得指定的单个的成员变量
        Field age = c.getDeclaredField("age");

        // 使用构造器创建对象,并为成员变量赋值
        Constructor<Student> con = c.getConstructor();
        Student student = con.newInstance();

        // 为student中的age赋值(感觉student.age = 18)就可以了,这样子的反射是不是有些多余了?
        age.set(student, 18);

        System.out.println(student);
    }
}

最后,我们来一个反射获取成员变量的练习题:

 来吧,上代码:

package Test;

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

public class ReflexTest2 {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 反射对象
        Class<Student> c = Student.class;

        // 构造方法
        Constructor<Student> con = c.getConstructor();

        // 创建对象
        Student student = con.newInstance();

        // 成员变量
        Field name = c.getDeclaredField("name");
        Field age = c.getDeclaredField("age");
        Field address = c.getField("address");

        // 取消检查
        name.setAccessible(true);
        age.setAccessible(true);
        address.setAccessible(true);

        // 变量赋值
        name.set(student,"林青霞");
        age.set(student,18);
        address.set(student,"广西");

        System.out.println(student);
    }
}

反射获得成员方法并使用

        毫无疑问,肯定还是得上方法:

    • MehtodgetDeclaredMethod(String name, Class<?>... parameterTypes) 

      返回指定的单个的或者指定的成员方法(包括私有)

      Method[]getDeclaredMethods() 

      返回指定的单个的或者指定的所有成员方法(包括私有)

        哦,对了!还有一个方法需要学习的:

    • Objectinvoke(Object obj, Object... args)

      在具有指定参数的指定对象上调用此 方法对象表示的基础方法。

来吧,看代码学会如何使用:

        首先,在Student类中创建四个方法:一私三公

public class Student {
    private String name;
    int age;
    public String address;

    private void function(){
        System.out.println("我是private私有的");
    }

    public void show1(){
        System.out.println("show1");
    }

    public void show2(String s){
        System.out.println("show2:"+s);
    }

    public String show3(String s,int i){
        return s+","+i;
    }
}

        然后创建我们的测试类:

package Basic.Reflex;

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

public class ReflexDemo5 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 反射对象
        Class<Student> c = Student.class;

        // 所有公共方法(包括自己类中的方法、以及继承自父类的方法)
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-----------------------");

        // 所有方法,包括私有(只会包含自身类中的方法,不包含继承的方法)
        Method[] declaredMethods = c.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("-----------------------");

        // 指定的当个公共方法
        Method show1 = c.getMethod("show1");

        // 有了公共方法,那么就需要创建对象使用了
        Constructor<Student> con = c.getConstructor();
        Student student = con.newInstance();

        // Object invoke(Object obj, Object... args):在具有指定参数的指定对象上调用此方法对象表示的基础方法。
        // Object: 返回值
        // obj: 调用对象
        // ... args: 方法需要的参数

        // 调用成员方法
        show1.invoke(student);
    }
}

总结:

        

好,学完之后让我们做一道练习题巩固一下所学知识:

 来吧,代码演示:

package Test;

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

public class ReflexTest3 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 反射对象
        Class<Student> c = Student.class;

        // 构造函数
        Constructor<Student> con = c.getConstructor();

        // 创建对象
        Student student = con.newInstance();

        // 成员方法
        Method method1 = c.getMethod("method1");
        Method method2 = c.getMethod("method2", String.class);
        Method method3 = c.getMethod("method3", String.class, int.class);
        Method function = c.getDeclaredMethod("function");

        // 设置取消检查
        function.setAccessible(true);

        // 调用方法
        method1.invoke(student);
        method2.invoke(student,"奥特曼");
        Object result = method3.invoke(student, "波塞冬", 20);
        System.out.println(result);

        function.invoke(student);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值