反射的详细解析,使用、优缺点、安全性

1.初始反射

反射的定义:反射是指在Java运行状态中

    1. 给定一个类对象(Class对象),通过反射获取这个对象(Class对象)的所有成员结构;
    2. 给定一个具体的对象,能够动态的调用它的方法及对任意属性值进行获取和赋值
    3. 这种动态获取类的内容、创建对象、以及动态调用对象方法及操作属性的机制,就叫做Java的反射机制。

反射的优点:

    1. 增加程序的灵活性,避免将固有的逻辑程序写死到代码里
    2. 代码简洁,可读性强,可提高代码的复用率

反射的缺点:

    1. 相较直接调用在创建对象比较多的情 景下反射性能下降
    2. 内部暴露和安全隐患(破坏单例)

反射性能慢的原因:

    1. 寻找类Class字节码的过程,比如通过ClassName找到对应的字节码Class,然后加载、解析,会比较慢,而new的方式则无需寻找,因为在Linking的解析阶段已经将符号引用转为了直接引用
    2. 安全管理机制的权限验证等
    3. 若需要调用native方法调用时JNI接口的使用
    4. 入参校验

2.反射的基本操作

缺点:判别使用反射和不使用反射的时间损耗

/**
 * 缺点:性能损耗
 */
public class EfficMain {

    public static void main(String[] args) {

        long start = System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
//            User user = new User(); //使用构造函数创建对象
            getInstanceByRef("com.javacore.reflection.pojo.User");


        }

        long end = System.currentTimeMillis();
        System.out.println("总耗时"+(end-start));
    }

    private static void getInstanceByRef(String key){
        try {
            Class<?> clazz = Class.forName(key);
            clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

反射获取Class对象的组成:

获取Class对象的四种方式

  1. 通过ClassLoader对象的loadClass()方法
  2. 类名.class
  3. Class.forName()
  4. object.getClass()
/**
 * 获取Class文件的方式
 * 1、类名.class
 * 2、Class.forName //反射
 * 3、对象.getClass()
 * 4、通过类加载器.loadClass()
 */
public class CoreMain {
    public static void main(String[] args) throws Exception{

        //1、 不会堆类初始化
        Class<Person> clazz01 = Person.class;
        System.out.println(clazz01);
        //2、MySQL
        Class<?> clazz02 = Class.forName("com.javacore.reflection.pojo.Person");
        System.out.println(clazz02);
        //3、已知实例对象
        Class<? extends Person> clazz03 = new Person().getClass();
        System.out.println(clazz03);
        //4、通过类加载器
        Class<?> clazz04 = CoreMain.class.getClassLoader().loadClass("com.javacore.reflection.pojo.Person");
        System.out.println(clazz04);

        //通过Clazz获取基本信息;属性信息;方法信息;注解信息
        /**
         * 获取的是类的修饰符
         */
        System.out.println("--------------");
        // 类中存在的修饰符,返回的是一个整数,可以通过toString方法展示出来是哪个修饰符 
        int modifiers = clazz01.getModifiers();
        System.out.println(Modifier.toString(modifiers);
        System.out.println(clazz01.getPackage());
        System.out.println(clazz01.getName());
        System.out.println(clazz01.getSimpleName());
        System.out.println(clazz01.getClassLoader());
        System.out.println(clazz01.getInterfaces());
        System.out.println(clazz01.getSuperclass());
        System.out.println(clazz01.getAnnotations());

        /**
         * 属性基本操作
         */
        System.out.println("--------------");
        Class<User> clazz = User.class;
        User user = clazz.newInstance(); // 反射调用的无参的构造方法

        Field[] fields = clazz.getFields(); //所有public字段、包括继承来的
        for(Field field:fields){
            System.out.println(field.getName());
        }
        System.out.println("--------------");
        Field[] declaredFields = clazz.getDeclaredFields();//获取当前类中定义的
        for(Field field:declaredFields){
            System.out.println(field.getName());
        }
        System.out.println("--------------");
        Field addField = clazz.getDeclaredField("address");
        addField.setAccessible(true); //设置字段的强制访问,代表反射的不安全,private的都能访问
        addField.set(user,"北京西三旗");
        System.out.println(user.getAddress());
        System.out.println("--------------");

        Field nationalty = clazz.getDeclaredField("nationalty");
        nationalty.set(null,"中国");
        System.out.println(user.nationalty);
        System.out.println("--------------");
        // 构造函数
        clazz.getDeclaredConstructors();
        Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(String.class, String.class);
        declaredConstructor.setAccessible(true);
        User user1 = declaredConstructor.newInstance("idCard", "address");
        User user2 = clazz.newInstance(); //通过无参的构造函数反射出来的,无参的构造函数需要是public
        System.out.println(user1);

        System.out.println("--------------");
        SingleDemo instance1 = SingleDemo.getInstance();
        SingleDemo instance2 = SingleDemo.getInstance();
        System.out.println(instance1==instance2);

        Constructor<? extends SingleDemo> constructor = instance1.getClass().getDeclaredConstructor();
        constructor.setAccessible(true);
        SingleDemo instance3 = constructor.newInstance();
        System.out.println(instance1==instance3);//false

//        System.out.println("--------------");
//        ClassPathXmlApplicationContext con = new ClassPathXmlApplicationContext("spring-ioc.xml");
//        Object user2 = con.getBean("user");
//        System.out.println(user2);

        /**
         * class.newInstance();底层使用的是反射出的无参的构造器,需要可见
         * Constructor.newInstance()’;任何的构造器都能够构造出一个实例,private也可以
         */


    }
}

3.反射安全性问题

  1. 可以通过setAccessible(true)方法设置对象可被强制访问
  2. 可以破坏单例的封装性
public class SingleDemo {

    private static SingleDemo instance; //

    private SingleDemo(){
        // 防止反射直接调用构造函数
        if (instance!=null){
            throw new RuntimeException("单例,不能重复调用");
        }

    }

    public static  SingleDemo getInstance(){
        if(instance == null){
            instance = new SingleDemo();
        }
        return instance;
    }
}


public class SingleMain {

    public static void main(String[] args) throws Exception {

        SingleDemo instance = SingleDemo.getInstance();
        SingleDemo instance1 = SingleDemo.getInstance();
        // 单例肯定一样
        System.out.println(instance == instance1);  //true

        Class<? extends SingleDemo> clazz = instance.getClass();
        Constructor<? extends SingleDemo> constructor = clazz.getDeclaredConstructor();
        // 强制使私有的构造函数可以访问
        constructor.setAccessible(true);
        SingleDemo singleDemo = constructor.newInstance();
        // 通过反射破坏了单例的封装性
        System.out.println(singleDemo==instance);//false
    }
}

4.反射在Spring中的应用

    1. JDBC的封装
    2. SpringIOC

     

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Building-ui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值