java反射

反射机制:

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个 对象就包含了完整的类的结构信息。

我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透 过这个镜子看 到类的结构,所以,我们形象的称之为:反射。

Java反射机制提供的功能:

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的成员变量和方法
  6. 在运行时处理注解
  7. 生成动态代理

反射相关的主要API:

  1. java.lang.Class :代表一个类
  2. java.lang.reflect.Method :代表类的方法
  3. java.lang.reflect.Field :代表类的成员变量
  4. java.lang.reflect.Constructor :代表类的构造器

Class类

在Object类中定义了以下的方法,此方法将被所有子类继承: public final Class getClass() 方 法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好 理解,即:可以通过对象反射求出类的名称。

对象通过反射后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。

对于每 个类而言,JRE 都为其保留一个不变的 Class 类型的对象。

一个 Class 对象包含 了特定某个结构 (class/interface/enum/annotation/primitive type/void/[])的有关信息。

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在 JVM 中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个 .class 文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类的对象是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

常用方法:

 

 

 

 

复制代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @program: FirstDemo
 * @description: Java反射学习
 * @author: GuoTong
 * @create: 2020-08-25 15:47
 **/
@SuppressWarnings("all")
public class TestReflection {
    public static void main(String[] args) throws Exception {
        //获取 Person  的字节码对象,由Java虚拟机由Class创建出来的,描述 Person 类结构的对象。
        //方式一:
        Person person = new Person("郭童", 23);
        System.out.println("反射之后" + person);
        //方式二
        Class<?> person2 = Class.forName("Person");
        Object obj1 = person2.newInstance();
        //方式三:
        Constructor<?> declaredConstructor1 = person2.getDeclaredConstructor();
        Object obj2 = declaredConstructor1.newInstance();
        //方式四

        Class<? extends Person> personClass = person.getClass();

        //getDeclaredFields||getDeclaredField;获取当前类的
        //getFile|| getFiles  是获得能够根据权限修饰符拿到的数据。可以获取穿透。
        //获取里面的属性(成员变量)
       /* Field[] declaredFields = personClass.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
        }*/
        //操作成员变量:
        Field name = personClass.getDeclaredField("name");
        //成员变量赋值的时候,set的时候需要绑定当前对象。另一个参数为值。
        // name.set(person,"李四");//不过这里会报错,private修饰的。不能这样去改变
        // Class TestReflection can not access a member of class Person with modifiers "privat
        //暴力设置
        name.setAccessible(true);//private修饰的。暴力访问
        name.set(person, "李四");
        System.out.println("反射之后" + person);
        System.out.println("获取所有的方法:------------------不可穿透型");
        //获取所有的方法
        Method[] declaredMethods = personClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }
        //得到需要被调用方法
        Method sayChinese = personClass.getDeclaredMethod("sayChinese");
        sayChinese.invoke(person);//调用方法
        //带参数的,拿的话需要定制形参类型。
        Method sayChinese2 = personClass.getDeclaredMethod("sayChineseDe", String.class);
        sayChinese2.invoke(person, "李四");//调用方法
        //private修饰的方法也可以暴力访问
        //method.setAccessible(true);

        System.out.println("获取构造器------------------");
        //构造器
        Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
        for (Constructor<?> constructor : declaredConstructors) {
            System.out.println(constructor);
        }
        //获取带参数的构造器
        Constructor<? extends Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(declaredConstructor);
        //利用拿到的构造器创建对象
        Person person1 = declaredConstructor.newInstance("网吧", 32);
        System.out.println(person1);


    }


}
@SuppressWarnings("all")
class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void sayChinese() {
        System.out.println("说中文");
    }

    public void sayChineseDe(String name) {
        System.out.println("说中文" + name);
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
复制代码

类的加载过程 当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初 始化。

 

 

 

 1. 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结 构,然后生成一个代表这个类的 java.lang.Class 对象,作为方法区中类数据的访问入口(即引 用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的过程需要类加载器参 与。

2. 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。 验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方面的问题 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存 都将在 方法区中进行分配。 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。

3. 初始化: 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中 所有类变量的赋值动作 和静态代码块中的语句合并产生的。(类构造器是构造类信 息的,不是构造该类对象的构造 器)。 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类 的初始 化。 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。

 

 

 

复制代码
/**
 * @program: FirstDemo
 * @description: 类加载器
 * @author: GuoTong
 * @create: 2020-08-25 17:02
 **/
public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.获取一个系统类加载器
        ClassLoader classloader = ClassLoader.getSystemClassLoader();
        System.out.println(classloader);
        //2.获取系统类加载器的父类加载器,即扩展类加载器
        classloader = classloader.getParent();
        System.out.println(classloader);
        //3.获取扩展类加载器的父类加载器,即引导类加载器
        classloader = classloader.getParent();
        System.out.println(classloader);//null,为什么:因为它是由C++编写的
        //打印为null,是jvm提示我们,前面已经到了java世界的尽头了。
        //4.测试当前类由哪个类加载器进行加载
        classloader = Class.forName("ClassLoaderTest").getClassLoader();
        System.out.println(classloader);

    }
}
复制代码

 

 

 

 

 

 

 

 

 

posted on   白嫖老郭  阅读(94)  评论(0编辑  收藏  举报

编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示