类加载与反射

类加载

当程序使用某个类时,如果该类没有被装载进内存,则系统会通过加载、连接、初始化三个步骤来对类进行初始化。类加载就是类加载器将.class文件加载进JVM虚拟机中,并在虚拟机内存中产生一个Class对象。使用任何一个类虚拟机都会创建一个java.lang.Class类对象。
类加载使用的类加载器是JVM提供,采用双亲委派机制。

类加载器分为四种
  • 启动类加载起 BootStrapClassLoader 用来加载核心类库 扩展类加载器 extensionsClassLoader
  • 用来加载JRE的扩展目录 Javax. 系统类加载器 SystemClassLoader
  • 用来加载来自java命令的classpath指定的JAR包和类路径。
  • 自定义类加载器
双亲委派机制

每个类在JVM中的为一性都有类加载器和类本身决定,即使同一个类但是通过不同的类加载器加载也不是同一个类。
一个类的加载时,通过由底向上的顺序判断该类是否被该类加载器加载过,如果都没有,则自顶向下的顺序尝试进行加载。
这样做的目的是防止一个类被多份加载,可以节省空间。

类加载方式
  • 隐式加载 new
  • 显示加载 反射
类装载的过程
  1. 加载
    加载指的是将类的.class字节码文件,读入到内存中,并为之创建一个java.lang.Class对象。任何类使用之前都会为之创建一个Class对象。类加载有类加载器完成。
  2. 链接
    链接负责把类的二进制数据合并到JRE中。
    链接又分为三个阶段:
    1、验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。
    2、准备:准备阶段负责为类的静态变量分配内存,并设置默认的初始值。
    3、解析:将类的二进制数据中的符号引用替换成直接引用。
  3. 初始化
    为类的静态变量赋予正确的初始值。

反射

反射就是在运行状态中,可以获取类的

  • 名称、package、属性、方法、注解、类型、类加载器
  • 获取任意对象的属性,并改变对象的属性
  • 调用任意对象的方法
  • 判断任意对象所属的类
  • 实例化任意一个类的对象
package user;

public class User {
    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "user.User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

User user = new User();

  1. 获取类对象的方法
1)已知实例创建获取类对象
Class u = user.getClass();

2) 已知类的全路径名获取类对象
Class u = Class.forName("user.User");

3)已知类名获取类对象
Class u = User.class

2、通过类获取父类

Class fu = u.getSuperclass();

3、通过对象获取包名+类名

String name = u.getName();

4、获取类名

String name = u.getSimpleName();

5、通过类对象获取类的属性

1)只能获取public属性
Field[] fields = u.getFields();

2)获取全部属性
Field[] fields = u.getDeclaredFields();

3)获取指定属性值
Filed name = u.getField("属性名")

6、获取类的所有方法

!) 获取本类及其父类的所有public方法
Method[] methods = c1.getMethods();

2)获取本类的所有方法
Field[] declaredFields = c1.getDeclaredFields();

3)获得指定的方法, 参数为方法名和方法的参数类型(“Name”, arg1.class, arg2.class, ......)
Method setName = c1.getMethod("setName", String.class);

7、获取构造器

!) 获取本类父类的public构造器
Constructor[] constructors = c1.getConstructors();

2)获取本类的所以构造器
Constructor[] declaredConstructors = c1.getDeclaredConstructors();

3)获取指定构造器,参数为构造方法的参数列表类型
Constructor declaredConstructor = c1.getDeclaredConstructor( String.class, Integer.class);
通过反射获取对象

通过Class对象获取实例

Class c1 = Class.forName("user.Use");
本质是调用类的无参构造来创建实例,如果没有无参构造就会报错
Use u1 = (Use) c1.newInstance();

通过构造器创建对象

1)无参构造器
Constructor declaredConstructor1 = c1.getDeclaredConstructor();
Use u2 = (Use) declaredConstructor1.newInstance();
2)有参构造器
Constructor declaredConstructor = c1.getDeclaredConstructor( String.class, Integer.class);
Use u2 = (Use) declaredConstructor.newInstance("a", "1");
通过反射调用方法
Class c1 = Class.forName("user.Use");
User user = new User();
Method setAge = c1.getDeclaredMethod("setAge", Integer.class);
//对象名,参数
getAge.invoke("user", "a");
反射操作属性
Class c1 = Class.forName("user.Use");
User user = (User) c1.newInstance();
Field field = c1.getDeclaredField("name");
如果这个属性是私有属性那么在操作之前需要加上一句 name.setAccessible(true) 先关闭安全检测
name.set(user, "a");
对于反射来说操作类对象效率比较低

普通方式调用 > 关闭检测的反射 > 不关闭检测的反射

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值