java 反射Class类/加载类/创建对象及方法

发布于:2025-09-14 ⋅ 阅读:(17) ⋅ 点赞:(0)

基本介绍

1.子类结构图

2.父类结构图

3.基本介绍

3.2 Class类不是new出来的,而是类加载器使用loadClass生成看Class类对象

3.2.1 普通new及源码

3.2.2 使用反射方式

3.3 上面3.2的例子老师犯的错误正好也佐证了第三点,就是不管new多少次,Class类对象都只会生成一次

请看例子,明面上写了两个Cat类的class

但是最后其实是一样的

3.5 Class类常用方法

3.5.1

第六点,如果brand属性是私有的,则会报错 

3.5.2

运行结果顺利

3.7 方法区生成元数据,对Class类对象是一个指向的关系

获取Class类对象的方法

以下这些方式都能获取class对象,而且本质是同一个

类加载

1.类加载基本介绍

1.1写一段代码证明

1.2.在写代码的时候,如果不编写Dog类也会报错

运行后可以看到已经生成Dog类了,即使没有编译成功

这就说明了静态编译的特点

1.3.改一下代码,与刚才静态地直接new类不同,这里使用反射来创建一个类,是动态加载

动态加载只有执行语句的时候,才会创建此类

所以只有运行到那里却没有编写Person,才会报错

1.4.编译后可以发现只要不输入运行到的代码,是不会出错的,印证了动态加载的特性

2.类加载流程

1.“连接”步骤中,“准备”是实现默认初始化

而连接后的“初始化”步骤,时进行显式的初始化

1.1准备完成后,字节码文件将会被储存在方法区中。

类的Class对象(数据结构)将被存放至堆区,是数据的访问入口

方法区和堆区之间也存在引用,体现了反射

2.类加载阶段任务

注意这里的初始化不是对象创建的初始化,而是类加载的初始化,主要生成了静态成员(静态成员随类的加载被初始化)

前两步的加载和连接都是Jvm帮忙的,第三步初始化可以让程序员决定里边的变量等

2.1 连接阶段 验证

2.2 连接阶段 准备

静态变量在初始化阶段才会给20的值    

2.3 连接阶段 解析

在解析阶段之前,只是符号引用,因为地址还没有真正地被生成

而解析阶段拥有了地址,就可以靠地址来直接引用

2.4 连接阶段 初始化

第二点,如果直接使用类的静态属性,也会导致类的加载

2.4.1 关于第三点,追到源码可以发现有一个getClassLoadingLock()函数,正是因为此机制,才能保证内存中只有一个同样的类被正确地初始化

3.通过反射获取类的结构信息

以下是常用的关于类的kpi

具体的代码就不贴了太麻烦,需要用时回来看就行

通过反射创建对象

1. 通过无参构造器创建

class stu是学生类,有姓名和年龄,分别创建了公共无参构造器,拥有一个形参的公共有参构造器和私有的两个参数的构造器,就不摆上来了

public class ReflctionCreate {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//这里是抛出的异常

        Class<?> aclass = Class.forName("com.hspedu.stu");//获取stu的Class对象

        Object stuobj=aclass.getDeclaredConstructor().newInstance();//利用无参构造器创建stu的实例

        System.out.println(stuobj);

    }
}


注意这里需要将stu实例化,不能直接输出stu

运行结果

2. 通过有参构造器创建

由于newInstance()不能传参,所以可以通过getDeclareConstructor()来获取构造器中的name

(此函数可以获得所有不论是public还是非public的构造器内容 )

public class ReflctionCreate {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        Class<?> aclass = Class.forName("com.hspedu.stu");

        Constructor<?> con = aclass.getDeclaredConstructor(String.class);
        //创建一个构造器并返回,此构造器其实就是stu类中只有一个参数的public构造器

        Object conc = con.newInstance("小沈阳");//调用构造器重新赋值

        System.out.println(conc);

    }
}

运行结果

3. 通过非public有参构造器创建

直接使用构造器是不行的,会因为非pub构造器的属性是私有的而报错:非法

所以要使用setAccessible()来暴破,即暴力破解,破坏了封装性,绕过了安全检查,可以查看私有 构造器或属性等

注释也有重要内容,注意看

public class ReflctionCreate {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> aclass = Class.forName("com.hspedu.stu");//此处异常抛出即可

        Constructor<?> con = aclass.getDeclaredConstructor(String.class,int.class);
        //创建构造器并返回,此构造器非pub的午无参构造器

        con.setAccessible(true);//注意爆破一定要在赋值之前出现,否则访问不了

        Object conc = con.newInstance("我是非公有构造器",33);//调用构造器重新赋值

        System.out.println(conc);

    }
}

运行结果

4.通过反射访问类中成员

1.访问属性

1.1 使用属性名获取Filed对象

将stu类构造器和age属性全变成public,name属性变成Private static,然后在main函数查改age

public class ReflctionCreate {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<?> aclass = Class.forName("com.hspedu.stu");//得到stu的Class对象

        Object o = aclass.newInstance();//创建对象,此时o的运行类型已经是stu了
        System.out.println(o.getClass());
        Field field = aclass.getField("age");
        field.set(o,100);
        System.out.println(o);
    }
}

运行结果

1.2 而如果要修改私有属性,需要用getDeclaredFiled

public class ReflctionCreate {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<?> aclass = Class.forName("com.hspedu.stu");//得到stu的Class对象

        Object o = aclass.newInstance();//创建对象,此时o的运行类型已经是stu了

        Field field2 = aclass.getDeclaredField("name");

        field2.setAccessible(true);//暴破这一块

        field2.set(o,"yyy");//因为name是static属性,所以o的位置可能是null
        System.out.println(o);
    }
}

运行结果

2.访问方法

直接用老师的例子吧,写一个boss类,具体的如图

代码如下,与前面的属性、构造器都是一样的

运行结果


网站公告

今日签到

点亮在社区的每一天
去签到