反射专题

news/2024/5/19 3:41:12 标签: java, jvm, 反射, 编程语言, 大数据

1 反射机制

1.1 Java程序的三阶段

image-20210526212134502.png

1.2 反射的优缺点

  • 优点:可以动态创建和使用对象(底层框架核心),使用灵活,没有反射机制,框架就失去底层支撑
  • 缺点:使用反射基本是解释执行,对执行速度有影响
java">//测试使用new,反射和优化后的反射,执行方法的速度
public class SpeedTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        m1();
        m2();
        m3();
    }

    //使用传统new对象的方式
    public static void m1() {
        Person person = new Person();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            person.sayHi();
        }
        long end = System.currentTimeMillis();
        System.out.println("m1: " + (end - start));
    }

    //使用反射的方式
    public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> personClass = Class.forName("com.yqj.domain.Person");
        Object person = personClass.newInstance();
        Method sayHi = personClass.getMethod("sayHi");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            sayHi.invoke(person);
        }
        long end = System.currentTimeMillis();
        System.out.println("m2: " + (end - start));
    }

    //使用优化后的反射
    //1.Method,Field,Constructor 对象都有 setAccessible() 方法
    //2.setAccessible 作用是启动和禁用访问安全检查的开关,true为取消访问检查,false开启
    public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> personClass = Class.forName("com.yqj.domain.Person");
        Object person = personClass.newInstance();
        Method sayHi = personClass.getMethod("sayHi");
        sayHi.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            sayHi.invoke(person);
        }
        long end = System.currentTimeMillis();
        System.out.println("m2: " + (end - start));
    }
}
  • result
m1: 5
m2: 2988
m2: 1888

2 Class类

2.1 基本说明

  • Class也是类,也继承Object类
  • Class类对象不是new出来的,而是系统创建的
java">//ClassLoader 类,不管是new还是反射的方法,第一次创建对象时候均需要通过该类创建单例的Class对象
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
  • 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
java">Person person1 = new Person();
Person person2 = new Person();
System.out.println(person1.getClass().hashCode()); //hashCode一致说明是同一个对象
System.out.println(person2.getClass().hashCode());
  • 每个类的实例都会记得自己是由哪个Class实例所生成( getClass方法)
  • 通过Class对象可以完整地得到一个类的完整结构,通过API
  • Class对象存放在堆中
  • 类的字节码二进制数据放在方法区,或称为类的元数据

2.2 Class类的常用方法

java">public class ClassBaseMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        String classPath = "com.yqj.domain.Person";
        //1.获取Person类对应的Class对象
        Class<?> personClass = Class.forName(classPath);
        //2.输出Class
        System.out.println(personClass); //显示哪个类的Class对象
        System.out.println(personClass.getClass()); //显示Class本身
        //3.得到包名
        System.out.println(personClass.getPackage().getName());
        //4.得到全类名
        System.out.println(personClass.getName());
        //5.创建对象实例
        Person person = (Person) personClass.newInstance();
        System.out.println(person);
        //6.通过反射获取属性
        //可以获取包括私有属性
        Field age = personClass.getDeclaredField("age");
        age.setAccessible(true); //允许访问私有属性
        age.set(person,24);
        System.out.println(age.get(person));
        //类似方法
//        personClass.getDeclaredMethod();
//        personClass.getMethod();
//        personClass.getDeclaredConstructor()
//        personClass.getConstructor()
    }
}

2.3 获取Class对象的方法

java">public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.已知类的全类名,且该类在类路径下,可通过Class静态方法forName获取
        //多用于配置文件,读取类全路径,加载类
        Class personClass1 = Class.forName("com.yqj.domain.Person");
        System.out.println(personClass1);
        //2.若已知具体的类,通过类的class获取,安全且程序性能最高
        //多用于参数传递,比如通过反射得到对应的构造器对象
        Class personClass2 = Person.class;
        System.out.println(personClass2);
        //3.已知某个类的实例,通过getClass方法获取Class对象
        //通过创建好的对象,获取Class对象
        Class personClass3 = new Person().getClass();
        System.out.println(personClass3);
        //4.通过类加载器获取Class对象
        Class personClass4 = new Person().getClass().getClassLoader().loadClass("com.yqj.domain.Person");
        System.out.println(personClass4);
        //5.基本数据类型通过class获取
        Class intClass = int.class;
        System.out.println(intClass);
        //6.包装类通过TYPE获取其基本类型的Class对象
        Class integerClass = Integer.TYPE;
        System.out.println(integerClass);
    }
}

2.4 具有Class对象的类型

  • 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  • interface接口
  • 数组
  • enum枚举
  • annotation注解
  • 基本数据类型
  • void

2.5 类加载各阶段任务

image-20210527084625015.png
  1. 加载阶段:JVM在该阶段将字节码从不同的数据源(class文件,jar包,网络)转换为二进制字节流加载至内存中,并生成一个代表该类的Class对象
  2. 连接阶段-验证:为了确保Class文件字节流中包含的信息符合当前虚拟机的要求,包括对文件格式的验证,元数据验证,字节码验证和符号引用验证,可通过 -Xverify:none 关闭
  3. 连接阶段-准备:JVM在该阶段对静态变量分配内存并默认初始化(0,0L,null,false),这些变量所使用的内存在方法区分配
  4. 连接阶段-解析:JVM将常量池内的符号引用替换为直接引用的过程
  5. Initialization初始化:此阶段执行<clinit>() 方法,该方法依次收集类中所有静态变量的赋值动作和静态代码块中的语句,并按顺序进行合并。JVM包装该方法在多线程环境中被正确加锁同步

2.6 通过反射获取结构信息

1. Class类
getName()
getSimpleName()
getFields() 获取所有public修饰的属性,包含本类和父类
getDeclaredFields() 获取本类所有属性
getMethods()
getDeclaredMethods()
getConstructors()
getDeclaredConstructors()
getPackage()
getSuperClass()
getInterfaces()
getAnnotations()

2. Field类
getModifiers() 以int形式返回修饰符,默认修饰符0,public1,private2,protected4,static8,final16,若 public1 + static8 = 9
getType()
getName()

3. Method类
getModifiers()
getReturnType()
getName()
getParameterTypes()

4. Constructor类
getModifiers()
getName()
getParameterTypes()

http://www.niftyadmin.cn/n/1571852.html

相关文章

网络编程专题

1 InetAddress类 public class InetAddressBaseMethod {public static void main(String[] args) throws UnknownHostException {//1.获取本机 InetAddress 对象InetAddress host1 InetAddress.getLocalHost();System.out.println(host1);//2.根据主机名/域名获取 InetAddress…

正则专题

1 正则表达式的基本语法 元字符的功能&#xff1a;限定符&#xff1b;选择匹配符&#xff1b;分组组合和反向引用符&#xff1b;特殊字符&#xff1b;字符匹配符&#xff1b;定位符 1.1 转义符 说明&#xff1a;转义符(\\)用于在正则表达式中检索某些特殊字符。例如&#xff1a…

mac m1的go环境配置及使用

1 go环境配置 1.1 下载go的安装包 # 下载地址 https://golang.google.cn/dl/ image-20210716085430669.png1.2 配置环境变量 # 分别在 .bash_profile 和 .zshrc 文件后面追加go的环境变量配置 # 说明&#xff1a;GOPATH表示go的工程根目录&#xff0c;之后的go程序均写在该目录…

Ubuntu20.04LTS 搭建kubernetes集群环境

更换清华源 # 备份源 sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak# 更改源 cd /etc/apt/ sudo vim sources.list# 添加 deb https://mirror.tuna.tsinghua.edu.cn/ubuntu-ports/ focal main restricted universe multiverse deb https://mirror.tuna.tsinghua.ed…

Excel数据导入到MySQL

在进行数据管理和转移时&#xff0c;经常需要将excel中的数据导入存储至数据库中&#xff0c;本文将导入的方法细化&#xff0c;并进行描述整理。本次数据库的导入操作使用 Navicat Premium 软件。 新建数据表。使用 Navicat Premium 在选定的数据库中新建和excel表对应的字段表…

使用Java操作Docker

本人在做实验过程中&#xff0c;需要通过Java程序部署docker容器。故尝试搜集资料&#xff0c;实现在Java端可以操作部署docker容器。过程中遇到一些bug和坑&#xff0c;在此总结&#xff0c;供有需要的童鞋使用。主体配置以Ubuntu16为例。后面会附加给出mac的配置说明。 docke…

阿里云挂载新硬盘

找到 待挂载 云盘&#xff0c;在 操作 列中&#xff0c;选择 更多 > 挂载&#xff0c;刷新云盘列表&#xff0c;如果是使用中&#xff0c;表示挂载服务器成功检查阿里云服务器数据盘情况&#xff0c;这里我们可以看到有100GB数据盘没有挂载 fdisk -l 挂载阿里云数据硬盘。输…

一.Jenkins环境部署

1. Gitlab环境搭建(ubuntu) 下载依赖 sudo apt-get update sudo apt-get install -y curl openssh-server ca-certificates sudo apt-get install -y postfix # 选择 internet site 下载gitlab包 # 若之前卸载过需要删除以下存在的目录 opt/gitlab etc/gitlab var/opt/gitlab v…