反射的理解与使用

反射📦

定义🍨

Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任 意一个对象,都能够调用它的任意方法和属性,既然能拿到,那么我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。

用途😋

  1. 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
  2. 用于各种通用框架(了解)

反射的基本信息🌵

如平时写一句向上转型的代码,父类引用在编译结束后可以看到父类引用的类型是父类,而运行结果却是子类.那我们通过反射就能判断一个对象到底是属于哪个类.

反射相关的类🤐

类名用途
Class类代表类的实体,在运行的java应用程序中表示类和接口
Field类代表类的成员变量或者属性
Method类代表类的方法
Constructor类代表类的构造方法

Note:一个类编译结束都会生成一个.class文件,而一个.class文件在加载到JVM中时都会被解析为一个class对象,所以说每个类对象都可以视作Class类的一个实例化对象,通过对获取到的Class类对象的读写,就可以做到对这个Class对象所对应的类对象进行添加改变属性和动作的目的!使得这个类变成一个动态的类


反射中常见的使用🍰

获取指定类的class对象👶

进行反射必不可少的一步,也是第一步.可以有三种方式进行获取

  1. Class.forName(“想获取的类全路径名称”);//forName()是一个静态方法,直接可以用Class类进行调用,该方法适用于明确指定类的全路径名称
  2. 类名.class;仅适用于编译之前就明确想操作的类是哪个类的情况
  3. 使用已有类对象的引用来调用getClass(),进而获取这个类的class对象

代码:

  1. class Student{
        private String name;
        public Student(){
            System.out.println("我是公有构造方法");
        }
        private Student(String str){
            System.out.println("我是带一个参数的私有构造方法");
        }
    }
    public class TestDemo {
        public static void main(String[] args) {
            try {
                
                //第一种
                Class<?> c1=Class.forName("Student");
                //第二种
                Class<?> c2=student.class;
                //第三种
                Student student=new Student();
                Class<?> c3=student.getClass();
                
            }catch(ClassNotFoundException e){
                e.printStackTrace();
            }
        }
    }
    
  2. 上述三种获取class对象的方法,获取到的对象只有一个

    class Student{
        private String name;
        public Student(){
            System.out.println("我是公有构造方法");
        }
        private Student(String str){
            System.out.println("我是带一个参数的私有构造方法");
        }
    }
    public class TestDemo {
        public static void main(String[] args) {
            try {
                
                //第一种
                Class<?> c1=Class.forName("Student");
                //第二种
                Class<?> c2=student.class;
                //第三种
                Student student=new Student();
                Class<?> c3=student.getClass();
                
            }catch(ClassNotFoundException e){
                e.printStackTrace();
            }
            
            System.out.println(c1==c2);//true
            System.out.println(c1==c2);//true
            System.out.println(c2==c3);//true
            
        }
    }
    

基于class对象构造一个什么都能获取的对象🦅

  1. 利用class对象中公有构造方法来构造对象

    class Student{
        private String name;
        public Student(){
            System.out.println("我是公有构造方法");
        }
        private Student(String str){
            System.out.println("我是带一个参数的私有构造方法");
        }
    }
    public class TestDemo {
        public static void main(String[] args){
            //共有构造方法的调用
            try {
    
                Class<?> c=Class.forName("Student");
                Student student=(Student) c.newInstance();
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    
  2. 利用class对象中私有构造方法来构造对象

    public class TestDemo {
        public static void main(String[] args) {
            //调用私有构造方法
            try {
    
                Class<?> c=Class.forName("Student");
                //利用参数情况来获取指定的构造方法(因为构造方法构成了重载)
                Constructor<?> constructor=c.getDeclaredConstructor(String.class);
                constructor.setAccessible(true);//对获取到的构造方法设置权限为可访问
    
                //利用上述的构造方法来构造对象
                Student student=(Student) constructor.newInstance("xixi");
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

    步骤总结:

    1. 获取class对象
    2. 如果是公有构造方法,就可以拿着这个Class类对象的引用去调用newInstance()去构造对象了,构造出来是Object,可强转为想要的那个类
    3. 如果是私有构造方法,还得多做两件事,先获取到Class对象中指定的构造方法(利用的是重载),私有公有都随便拿,然后将这个构造方法的权限设置为true,最后拿着这个"开放权限"的Constructor类对象的引用去调用newInstance(形参列表)来构造对象即可,返回的也是Object,强不强转随便你

    基于什么都能获取的对象去反射属性🚶

    直接上代码:

    class Student{
        private String name;
        public Student(){
            System.out.println("我是公有构造方法");
        }
        private Student(String str){
            System.out.println("我是带一个参数的私有构造方法");
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    public class TestDemo {
        public static void main(String[] args){
            //共有构造方法的调用
            try {
    
                //获取class对象
                Class<?> c=Class.forName("Student");
                //获取字段
                Field name=c.getDeclaredField("name");
                //开放权限
                name.setAccessible(true);
                //通过公有构造方法实例化一个name字段被开放的student对象
                Student student=(Student) c.newInstance();
                //对已经开放的name字段进行修改
                name.set(student,"大哥");
    
                System.out.println(student);
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }
    //打印:
    //我是私有构造方法
    //Student{name='大哥'}
    

    基于什么都能获取的对象去反射方法😡

    class Student{
        private String name;
        public Student(){
            System.out.println("我是公有构造方法");
        }
        private Student(String str){
            System.out.println("我是带一个参数的私有构造方法");
        }
        private void display(String str){
            System.out.println("恭喜你获取到了我这私有方法"+str);
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    public class TestDemo {
        public static void main(String[] args) {
            try {
                //获取class对象
                Class<?> c=Class.forName("Student");
                //指定方法的获取
                Method method=c.getDeclaredMethod("display", String.class);
                //对选取的方法开放权限
                method.setAccessible(true);
                //实例化一个刚才指定方法已经开放权限的对象
                Student student=(Student) c.newInstance();
                //对那个方法进行访问,注意手段invoke
                method.invoke(student,"haha");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

反射的优缺点⚙️

优点:

  1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
  2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
  3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。

缺点:.

  1. 使用反射会有效率问题。会导致程序效率降低。
  2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值