温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java基础之反射机制的示例分析

发布时间:2021-08-12 09:22:29 来源:亿速云 阅读:103 作者:小新 栏目:开发技术

小编给大家分享一下Java基础之反射机制的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

    1、什么是Java反射机制?

    在程序运行中动态地获取类的相关属性,同时调用对象的方法和获取属性,这种机制被称之为Java反射机制

    下面给出一个反射的简单例子:

    import lombok.Data;
    
    @Data
    public class User {
    
        public String username;
        private String password;
    
        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    public static void reflectionSimpleExample() throws Exception{
        User user = new User();
        System.out.println(user.toString());
    	// 获取对应类的class
        Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");
        Object obj = cls.newInstance();
        System.out.println(obj);
    	// 获取成员变量,注意要是public的
        Field field = cls.getField("username");
        System.out.println(field.get(obj));
    
    }

    2、反射机制原理

    Java反射是Java实现动态语言的关键,也就是通过反射实现类动态加载

    静态加载: 在编译时加载相关的类,如果找不到类就会报错,依赖性比较强动态加载:在运行时加载需要的类,在项目跑起来之后,调用才会报错,降低了依赖性

    例子:静态加载,如下代码,如果找不到类的情况,代码编译都不通过

    User user = new User();

    而动态加载,就是反射的情况,是可以先编译通过的,然后在调用代码时候,也就是运行时才会报错

     Class<?> cls = Class.forName("com.example.core.example.reflection.User");
    Object obj = cls.newInstance();

    Exception in thread “main” java.lang.ClassNotFoundException: com.example.core.example.reflection.User

    java中的反射允许程序在执行期借助jdk中Reflection API来获取类的内部信息,比如成员变量、成员方法、构造方法等等,并能操作类的属性和方法

    java中反射的实现和jvm和类加载机制有一定的关系,加载好类之后,在jvm的堆中会产生一个class类型的对象,这个class类包括了类的完整结构信息,通过这个class对象就可以获取到类的结构信息,所以形象地称之为java反射

    Java基础之反射机制的示例分析

    3、Class类介绍

    3.1、Class类基本介绍

    然后这个Class类是什么?看下uml类图:

    Java基础之反射机制的示例分析

    Class也是类,因此也继承Object类

    Class不是直接new出来的,而是经过系统创建的

    User user = new User();

    打个断点,debug进行看看源码,可以看到传统的直接new一个对象也是通过类加载器loadClass拿到的

    Java基础之反射机制的示例分析

    java反射方式,通用通过调试看看:

     Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");

    同样本质也是通过ClassLoad再通过类的全类名

    Java基础之反射机制的示例分析

    3.2、Class类对象的获取方法 Class.forname()

    Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");

    应用场景:多用于读取类全路径,加载类

    具体类.class
    已经知道具体类的情况,通过具体类的class属性获取

    Class u = User.class;

    应用场景:多用于用于参数传递

    对象.getClass
    已经创建好对象的情况,直接通过对象实例获取class对象

    Class cls = user.getClass();

    应用场景:通过创建好的对象,获取Class对象

    ClassLoader获取

    ClassLoader cl = user.getClass().getClassLoader();
    Class cls = cl.loadClass("com.example.core.example.reflection.domain.User");

    基本数据类型

    Class cls = int.class;

    包装类

    基本数据类型对应的包装类可以通过.TYPE得到Class类对象

    Class cls = Integer.TYPE;

    3.3 、可以获取Class对象的类型

    1、外部类,成员内部类,静态内部类,局部内部类,匿名内部类

    2、interface:接口

    3、数组

    4、enum:枚举

    5、annotation:注解

    6、基本数据类型

    7、void8、Class… ,等等

    import com.example.core.example.reflection.domain.User;
    import lombok.ToString;
    
    import java.util.List;
    
    public class GetClassObjectExample {
    
        public static void main(String[] args) {
            // 外部类
            Class<User> cls1 = User.class;
            // 接口
            Class<List> cls2 = List.class;
            // 数组
            Class<Integer[]> cls3 = Integer[].class;
            // 二维数组
            Class<String[][]> cls4 = String[][].class;
            // 注解
            Class<lombok.ToString> cls5 = ToString.class;
    
            // 枚举
            Class<Thread.State> cls6 = Thread.State.class;
            // 基本数据类型
            Class<Long> cls7 = Long.class;
            // void 数据类型
            Class<Void> cls8 = Void.class;
            // Class
            Class<Class> cls9 = Class.class;
    
            System.out.println(cls1);
            System.out.println(cls2);
            System.out.println(cls3);
            System.out.println(cls4);
            System.out.println(cls5);
            System.out.println(cls6);
            System.out.println(cls7);
            System.out.println(cls8);
            System.out.println(cls9);
        }
    }

    4、java反射的作用?

    可以通过外部类的全路径名创建对象,并使用这些类可以枚举出类的全部成员,包括构造函数、属性、方法利用反射 API 访问类的私有成员

    5、反射API主要类

    1、java.lang.Class:代表一个类,表示某个类在jvm堆中的对象

    2、 java.lang.reflect.Method:代表类的方法

    3、 java.lang.reflect.Field:代表类的成员变量

    4、 java.lang.reflect.Constructor:代表类额构造方法

    6、Java反射的优缺点

    优点:使用Java反射可以灵活动态地创建和使用对象,反射是框架的底层支撑缺点:使用Java反射,基本就是解释执行的,对执行速度是有影响的

    7、反射调用的优化方法

    前面介绍了Java反射虽然很灵活,但是缺点就是调用时候比较慢,相对直接new对象来说,情况是怎么样的?下面通过例子进行试验:

    import com.example.core.example.reflection.domain.User;
    
    import java.lang.reflect.Method;
    
    public class TestReflectionExample {
    
        private static final Integer TOTAL_COUNT = 1000000;
    
        public static void main(String[] args) throws Exception{
            test0();
            test1();
            test2();
        }
    
        public static void test0() {
            long start = System.currentTimeMillis();
            User user = new User();
            for (int i = 0 ; i < TOTAL_COUNT; i++) {
                user.hello();
            }
            System.out.println(String.format("传统调用方法执行时间:%d" , System.currentTimeMillis() - start));
        }
    
        public static void test1() throws Exception{
            long start = System.currentTimeMillis();
            Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");
            Object obj = cls.newInstance();
            Method hello = cls.getMethod("hello");
            for (int i = 0 ; i < TOTAL_COUNT; i++) {
                hello.invoke(obj);
            }
            System.out.println(String.format("反射方法调用执行时间:%d" , System.currentTimeMillis() - start));
        }
    
        public static void test2() throws Exception{
            long start = System.currentTimeMillis();
            Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");
            Object obj = cls.newInstance();
            Method hello = cls.getMethod("hello");
            // 关键,取消调用反射方法时的安全检查
            hello.setAccessible(true);
            for (int i = 0 ; i < TOTAL_COUNT; i++) {
                hello.invoke(obj);
            }
            System.out.println(String.format("优化后的反射方法调用执行时间:%d" , System.currentTimeMillis() - start));
        }
    }

    传统调用方法执行时间:19
    反射方法调用执行时间:112
    优化后的反射方法调用执行时间:50

    8、反射的基本使用例子

    java.lang.Class类

    方法名作用
    getName获取全类名
    getSimpleName获取简单类名
    getFields获取所有public修饰的属性、包括本类以及父类的
    getDeclaredFields获取本类中所有的属性
    getMethods获取所有的public修饰的方法,包括本类以及父类的
    getDeclaredMethod获取本类中所有方法
    getConstructors获取所有public修饰的构造器,只有本类
    getDeclaredConstructors获取本类中所有构造器
    getPackagePackage形式返回 包信息
    getSuperClassClass形式返回父信息
    getInterfacesClass[]形式返回父接口信息
    getAnnotationsAnnotation[]形式返回注解信息
    String allClassName = "com.example.core.example.reflection.domain.User";
    // 通过全类名获取class对象
    Class<?> cls = Class.forName(allClassName);
    System.out.println(cls);
    // 通过对象获取class
    System.out.println(cls.getClass());
    // 获取全类名
    System.out.println(cls.getName());
    // 获取包名
    System.out.println(cls.getClass().getPackage().getName());
    // 获取对象实例
    Object obj = cls.newInstance();
    System.out.println(obj);

    java.lang.reflect.Field类

    方法名作用
    getModifiers以int形式返回修饰符,默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
    getType以Class形式返回类型
    getName返回属性名称
    // 获取类属性
    Field field = cls.getField("username");
    field.set(obj , "admin");
    System.out.println(field.get(obj));
    // 获取所有类属性,private的成员变量没有权限访问
    Field[] fields = cls.getFields();
    for (Field field1 : fields) {
        System.out.println(field1.get(obj));
    }
    // 获取所有类属性包括private成员变量
    Field[] allFields = cls.getDeclaredFields();
    for (Field afield : allFields) {
        // 开放权限,私有的成员变量也能打印出来
        afield.setAccessible(true);
        System.out.println(afield.get(obj));
    }

    java.lang.reflect.Method类

    方法名作用
    getModifiers以int形式返回修饰符,默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
    getName返回方法名
    getReturnType以class形式返回类型
    getParmeterTypes以Class[] 返回参数类型数组
    // 获取class方法,同样默认情况不能获取private的方法
    Method method = cls.getMethod("hello");
    System.out.println(method.invoke(obj));

    java.lang.reflect.Constructor类

    方法名作用
    getModifiers以int形式返回修饰符,默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
    getName返回方法名
    getParmeterTypes以Class[] 返回参数类型数组
    Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");
    Constructor<?> con = cls.getDeclaredConstructor();
    con.setAccessible(true);
    Object obj = con.newInstance();
    System.out.println(obj);

    9、反射开放权限操作

    在我们使用Java反射获取class的private成员变量或者方法时,这种情况是不允许获取的,不过可以通过开放权限的方式来处理,通过设置setAccessible(true);即可

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /**
     * <pre>
     *      开放java反射权限,允许调用类的private属性或者方法
     * </pre>
     * <p>
     * <pre>
     * @author mazq
     * 修改记录
     *    修改后版本:     修改人:  修改日期: 2021/08/09 19:10  修改内容:
     * </pre>
     */
    public class AccessibleReflectionExample {
    
        public static void main(String[] args) throws Exception{
    
            test();
        }
    
        public static void test() throws Exception{
            // 创建class实例对象
            Class<?> cls = Class.forName("com.example.core.example.reflection.domain.User");
            Constructor<?> con = cls.getDeclaredConstructor();
            con.setAccessible(true);
            Object obj = con.newInstance();
    
            // 获取私有成员变量
            Field pwd = cls.getDeclaredField("password");
            // 开放私有变量的访问权限
            pwd.setAccessible(true);
            pwd.set(obj , "123456");
    
            // 私有方法调用
            Method method = cls.getDeclaredMethod("priToString");
            method.setAccessible(true);
            System.out.println(method.invoke(obj));
        }
    }

    以上是“Java基础之反射机制的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI