首页 > 编程语言 >Java学习基础笔记——反射机制

Java学习基础笔记——反射机制

时间:2024-06-20 20:29:55浏览次数:22  
标签:反射 Java 对象 System 笔记 println cls Class out

第十五章 反射

15.1 反射机制

15.1.1 Java 反射机制可以完成

15.1.2 反射的优缺点

15.2 Class 类

15.2.1 基本介绍

15.2.2 Class 类常用方法

15.2.3 获取Class 类对象 6 种方式

15.3 类加载

15.3.1 基本说明

15.3.2 类加载时机

15.4 反射获取类的结构信息

15.5 反射调用性能优化

第十五章 反射

15.1 反射机制

  • 反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息(比如成员变量、构造器、成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到

  • 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射

15.1.1 Java 反射机制可以完成

  1. 在运行时判断任意一个对象所属的类

  2. 在运行时构造任意一个类得对象

  3. 在运行时得到任意一个类所具有的成员变量和方法

  4. 在运行时调用任意一个对象的成员变量和方法

  5. 生成动态代理

public class Reflection01 {
    public static void main(String[] args) throws Exception {
​
        //1. 使用 Properties 类, 读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src/re.properties"));
        String classFullPath = properties.get("classFullPath") + "";
        String method = properties.get("method").toString();
​
​
        //2. 创建对象 -> 反射机制
        //new classFullPath();
​
        //3. 使用反射机制解决
        //(1) 加载类,返回 Class 类型的对象 cls
        Class cls = Class.forName(classFullPath);//Class 指的是 一个类,类名为 Class
        //(2) 通过 cls 得到加载的类  com.ljn.Cat 的对象实例
        Object o = cls.newInstance();
        //(3) 通过 cls 得到加载的类  com.ljn.Cat 的  method "hi" 的方法对象
        //    即   在反射中,可以把方法视为  对象(万物皆对象)
        Method method1 = cls.getMethod(method);
        //(4) 通过 method1 来调用方法
        //    即   通过方法对象来实现调用方法
        method1.invoke(o);//传统方法  对象.方法(),   反射机制  方法.invoke(对象)
​
​
        //java.lang.reflect.Field:代表类的成员变量,Field 对象表示某个类的成员变量
        //得到 name 字段
        //getField 不能得到私有属性
        Field ageField = cls.getField("age");
        System.out.println(ageField.get(o));//传统方法  对象.成员变量    反射机制: 成员变量对象.get(对象)
​
​
        //java.lang.reflect.Constructor:代表类的构造方法,Constructor 对象表示 构造器
        Constructor constructor = cls.getConstructor();//()中 可以指定构造器参数类型,返回无参构造器
        System.out.println(constructor);
​
        Constructor constructor1 = cls.getConstructor(String.class, int.class);
        System.out.println(constructor1);
​
    }
}

15.1.2 反射的优缺点

  • 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑

  • 缺点:使用反射基本是解释执行,对执行速度有影响

15.2 Class 类

15.2.1 基本介绍

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

  • Class 类对象不是 new 出来的,而是系统创建的

  • 对于某个类的Class 类对象,在内存中只有一份,因为类只加载一次

  • 每个类的实例都会记得自己是由哪个 Class 实例所生成

  • 通过 Class 对象可以完整地得到一个类的完整结构,通过一系列 API

  • Class 对象是存放在 堆的

  • 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等)

15.2.2 Class 类常用方法

public class Class {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
​
        String classAllPath = "com.sty.Car";
        //1. 获取到 Car类  对应的 类对象
        //<?>  表示不确定的  java 类型
        Class<?> cls = Class.forName(classAllPath);
        //2. 输出 cls
        System.out.println(cls);//显示 cls 对象, 是哪个类的  Class 对象  
        System.out.println(cls.getClass());//运行类型  java.lang.Class
        //3. 得到包名
        System.out.println(cls.getPackage().getName());//包名
        //4. 得到全类名
        System.out.println(cls.getName());
        //5. 通过 cls 创建对象实例
        Car car = (Car) cls.newInstance();
        System.out.println(car);//toString
        //6. 通过反射 获取属性
        Field brand = cls.getField("brand");
        System.out.println(brand.get(car));
        //7. 通过反射给属性赋值
        brand.set(car, "奔驰");
        System.out.println(brand.get(car));
        //8. 希望可以得到所有的属性/字段
        Field[] fields = cls.getFields();
        for (Field f : fields) {
            System.out.println(f.getName());//属性/字段的 各个名称
        }
    }
}

15.2.3 获取Class 类对象 6 种方式

public class GetClass_ {
    public static void main(String[] args) throws ClassNotFoundException {
​
        //1. Class.forName()
        //应用场景
        //多用于配置文件,读取类的全路径,加载类
        String classAllPath = "com.sty.Car"; //通过读取配置文件,获取得到
        Class<?> cls1 = Class.forName(classAllPath);
        System.out.println(cls1);
​
        //2. 类名.class
        //应用场景
        //多用于参数传递
        Class<Car> cls2 = Car.class;
        System.out.println(cls2);
​
        //3. 对象.getClass()
        //有对象实例
        Car car = new Car();
        Class cls3 = car.getClass();
        System.out.println(cls3);
​
        //4. 通过类加载器【4种】来获取到类的Class 对象 
        //(1) 先得到类加载器
        ClassLoader classLoader = car.getClass().getClassLoader();
        //(2) 通过类加载器得到 Class 对象
        Class<?> cls4 = classLoader.loadClass(classAllPath);
        System.out.println(cls4);
​
​
        //cls1, cls2, cls3, cls4   是同一个 Class 对象
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
        System.out.println(cls4.hashCode());
​
​
        //5. 基本数据(int,char,boolean,short,float,double,byte,long) 按如下方式得到 Class 对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        System.out.println(integerClass);
        System.out.println(characterClass);
​
        //6. 基本数据类型对应的包装类,可以通过 .TYPE 得到 Class 对象
        Class<Integer> type1 = Integer.TYPE;
        System.out.println(type1);
        Class<Double> type2 = Double.TYPE;
        System.out.println(type2);
​
        
        System.out.println(integerClass.hashCode());
        System.out.println(type1.hashCode());
    }
}

15.3 类加载

15.3.1 基本说明

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

    1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

    2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖性

15.3.2 类加载时机

  • 当创建对象时(new)

  • 当子类被加载时,父类也加载

  • 调用类中的静态成员时

  • 通过反射

15.4 反射获取类的结构信息

  • 第一组:java.lang.Class 类

  • //第一组方法 API
    @Test
    public void api_01() throws ClassNotFoundException {
    ​
        //得到Class对象
        Class<?> personCls = Class.forName("com.sty.reflection.Person");
        //获取全类名
        System.out.println(personCls.getName());
        //获取简单类名
        System.out.println(personCls.getSimpleName());
        //获取所有 public 修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {//快捷键  fields.for
            System.out.println(field.getName());
        }
        //获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }
        //获取所有 public 修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        //获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());
        }
        //获取所有 public 修饰的构造器,包含本类的
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getName());
        }
        //获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName());
        }
        //以 Package 形式,返回包信息
        System.out.println(personCls.getPackage());
        //以 Class 形式,返回父类信息
        Class<?> superclass = personCls.getSuperclass();
        System.out.println(superclass);
        //以 Class [] 形式,返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println(anInterface);
        }
        //以 Annotation [] 形式,返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }
  • 第二组:java.lang.reflect.Field 类

  • //第二组 API
    @Test
    public void api_02() throws ClassNotFoundException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.sty.reflection.Person");
        //获取本类中所有属性
        //规定:
        /*
           默认修饰符 :0
           public :1
           private :2
           protected :4
           static :8
           final : 16
         */
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName()
            + " 该属性的修饰符值=" + declaredField.getModifiers()
            + " 该属性的类型=" + declaredField.getType());
        }
    }
  • 第三组:java.lang.reflect.Method 类

  • //获取本类中所有方法
    Method[] declaredMethods = personCls.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.println(declaredMethod.getName()
                + " 该方法的访问修饰符值=" + declaredMethod.getModifiers()
                + " 该方法返回类型=" + declaredMethod.getReturnType());
    ​
        //输出当前这个方法的形参数组情况
        Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println("该方法的形参类型=" + parameterType);
        }
    }
  • 第四组:java.lang.reflect.Constructor 类

  • //获取本类中所有构造器
    Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
    for (Constructor<?> declaredConstructor : declaredConstructors) {
        System.out.println(declaredConstructor.getName());
    ​
        输出当前这个构造器的形参数组情况
        Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println("该构造器的形参类型=" + parameterType);
        }
    }

15.5 反射调用性能优化

关闭访问检查

  • Method 和 Field 、Constructor 对象都有 setAccessible() 方法

  • setAccessible 作用是启动和禁用访问安全检查的开关

  • 参数值为 true 表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为false 则表示反射的对象执行访问检查

标签:反射,Java,对象,System,笔记,println,cls,Class,out
From: https://blog.csdn.net/jiangnank/article/details/139781597

相关文章

  • Java毕业设计 基于springboot vue音乐网站
    Java毕业设计基于springbootvue音乐网站SpringBoot音乐网站功能介绍首页图片轮播歌曲信息歌曲分类歌曲详情歌曲播放音乐下载评论注册登录个人中心更新信息用户后台:登录个人中心修改密码个人信息音乐下载管理员:登录个人中心修改密码个人信息用户管......
  • GitHub爆赞!终于有大佬把《Python学习手册》学习笔记分享出来了
    这份笔记的目标是为了给出一份比较精炼,但是又要浅显易懂的Python教程。《Python学习手册》中文第四版虽然比较简单,但是措辞比较罗嗦,而且一个语法点往往散落在多个章节,不方便读者总结。我在做笔记时,将一个知识点的内容都统筹在一个章节里面,因此提炼性大大提高。而且还有《Pytho......
  • JAVA基础——接口(全网最详细教程)
    概述我们已经学完了抽象类,抽象类中可以用抽象方法,也可以有普通方法,构造方法,成员变量等。那么什么是接口呢?接口是更加彻底的抽象,JDK7之前,包括JDK7,接口中全部是抽象方法。接口同样是不能创建对象的。  把特有的方法(行为)写成接口,要用的时候调用接口就行了,除了狗和青蛙......
  • 2024年 Java 面试八股文(20w字)
    第一章-Java基础篇1、你是怎样理解OOP面向对象   难度系数:⭐面向对象是利于语言对现实事物进行抽象。面向对象具有以下特征:继承:继承是从已有类得到继承信息创建新类的过程封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口多态性:多态性是指允......
  • Java面试八股文2024最新版
    一、java基础1、java有哪几种数据类型?基本数据类型:byte(1),char(2),short(2),int(4),long(8),double(8),float(4),boolean(1)引用数据类型:各种类和接口,枚举,数组2、 面向对象和面向过程的区别?面向对象和面向过程都是一种开发思想。面向过程就是根据解决问题所需要的步骤,具体化的一步一步的去实现......
  • 微信小程序源码-基于Java后端的教学质量评价系统的计算机毕业设计(附源码+论文)
    大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。......
  • Java跳动爱心代码
    1.计算爱心曲线上的点的公式计算爱心曲线上的点的公式通常基于参数方程。以下是两种常见的参数方程表示方法,用于绘制爱心曲线:1.1基于(x,y)坐标的参数方程x=a*(2*cos(θ)-sin(θ))^3y=a*(2*sin(θ)-cos(θ))^3其中,a是一个常数,用于控制爱心的大小;θ是参......
  • cmake 笔记
    一、一个完整的工程给工程起个名字加上这句:project(hello)命令:project(<PROJECT-NAME>[LANGUAGES][<language-name>...])作用:定义工程名称,设置几个变量的名字: PROJECT_NAME,PROJECT_SOURCE_DIR,<PROJECT-NAME>_SOURCE_DIR,PROJECT_BINARY_DIR,<PROJECT-NAME>_B......
  • 腾讯云部署的java服务,访问阿里云的mysql数据库,带宽异常偏高,可能是什么原因
    个人名片......
  • 【Effective Python教程】(90个有效方法)笔记——第3章:函数——23:用关键字参数来传参(位
    文章目录第3章:函数第23条用关键字参数来传参位置传递参数关键字传递参数位置和关键字传递参数混合使用另外,关键字形式与位置形式也可以混用。下面这四种写法的效果相同:==如果混用,那么位置参数必须出现在关键字参数之前,否则就会出错。==每个参数只能指定一次,不能既通过位......