Java反射机制

本文介绍了Java反射机制的背景,如servlet与Tomcat的关系,以及反射在编程中的重要作用。详细阐述了反射机制的作用,如运行时判断对象所属类、构造对象、访问成员变量和方法等。还讲解了反射涉及的主要类,包括Class、Method、Field和Constructor,并讨论了Class对象的生成和细节,以及获取Class对象的三种方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、反射出现的背景意义

servlet中并没有主方法既是main方法,因此其每次运行都需要依靠tomcat.而tomcat是用Java写的,tomcat中有主方法,servlet和tomcat中的主方法一结合就可以启动运行了。因此我们可以这样认为只有有主方法的才能自己运行,可以作为一个进程运行。而没有主方法的不能自己运行的只能作为一个线程存在。

tomcat调用servlet运行,但tomcat是如何调用servlet的?servlet也是一个类,其中也能像普通类中定义除了doget(),dopost()外的各种方法。由于servlet定义的名字五花八门,tomcat不知道各个servlet的名字于是更不可能通过new的方式创建servlet对象,那对象中的doget(),dopost()方法也是不能被调用的。

各种编程语言一般都有扫描文件的能力,但即使知道文件路径,那你是如何确定那个.class文件是servlet呢?servlet和普通类一样名字都是可以任意取的。况且也没有相应的语法知道了类文件的

因此依据之前的方式,tomcat是无法获得servlet对象的,更无法调用servlet中的各种方法

为了解决这个问题出现了反射

2、类的生命周期

在这里插入图片描述
在这里插入图片描述

3、反射机制的作用

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

2、在运行时构造任意一个类的对象

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

4、在运行时调用任何一个类所具有的成员变量和方法

5、生成动态代理

4、反射相关的主要类

1、java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象。

2、java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法

3、java.lang.reflect.Field:代表类的成员变量,Field代表某个类的成员变量

4、java.lang.reflect.Constructor:代表类的构造方法,Constructor表示某个类的构造器

5、Class类的细节

1、Class也是类,因此也继承Object类

在这里插入图片描述

2、Class类对象不是new出来的,而是系统创建的。Class类是通过类加载器ClassLoader生成的ClassLoader中有一个loadClass()方法。通过该方法生成某个类的类对象。

  • 传统new 对象的方式创建对象

在这里插入图片描述

会进入该方法中然后返回类对象

  • 反射方式创建对象仍会进入上图所示的方法
    在这里插入图片描述

3、对于某个类的Class类对象,在内存中只有一份,因为类只加载一次。创建类对象时会加锁,防止多线程环境下生成多个Class类对象

public class Test {
    public static void main(String[] args) throws Exception {
        Cat cat=new Cat();
        Class catClass=Class.forName("com.company.Cat");
    }
}

此时若在Class catClass=Class.forName(“com.company.Cat”);处打断点执行的话,就不能进入loadClass方法了,因此Cat类已经在Cat cat=new Cat()语句中执行过一次了,类对象已经加载入内存中了。

4、每个类的实例都会记得自己是由那个Class实例所产生的

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

6、Class对象是存放在堆里的

7、类的字节码二进制数据是放在方法区的,有的地方称为类的元数据。

6、Class类的方法

public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> catClass=Class.forName("com.company.Cat");
        System.out.println(catClass);//显示catClass是那个类的Class对象  运行结果:class com.company.Cat
        System.out.println(catClass.getClass());//class java.lang.Class
        //2、得到包名
        System.out.println(catClass.getPackage().getName());//com.company
        //3、得到全类名
        System.out.println(catClass.getName());//com.company.Cat
        //4、通过类对象创建对象实例
        Cat cat=(Cat)catClass.newInstance();
        //5、通过反射得到对象的属性(只能获取公有属性)
        Field name=catClass.getField("name");
        System.out.println(name.get(cat));//发财
        //6、通过反射给对象的属性赋值
        name.set(cat,"招财");
        System.out.println(name.get(cat));//招财
        //7、得到对象的所有属性
        Field[] fields=catClass.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
    }
}

7、获取Class类对象的几种方式

方式一:Class.forName(“类的全路径”)

前提: 已知道一个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()获取

应用场景: 多用于配置文件,读取类的全路径,然后加载类

实例:

Class<?> catClass=Class.forName("com.company.Cat");

方式二:类名.class

前提: 已经知道具体的类,通过类名.class获取

方式三:对象.getClass()

前提: 有具体的对象实例

8、通过反射获取类的结构信息

获取关于类的相关信息

//第一组Api
//得到Class对象
Class personClass=Class.forName("com.company.Person");
//getName:获取全类名
System.out.println(personClass.getName());
//getSimpleName():获取简单类名
System.out.println(personClass.getSimpleName());
//getFields()获取所有public修饰的属性,包括本类以及父类的
Field[] fields=personClass.getFields();
for (Field field : fields) {
    System.out.println("本类即父类的public修饰的属性"+field.getName());
}
//获取本类的所有属性,包括私有受保护的
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println("本类的所有的属性"+declaredField.getName());
}
//获取本类以及所有父类public的所有方法
Method[] methods=personClass.getMethods();
for (Method method : methods) {
    System.out.println("本类以及所有父类public的所有方法"+method.getName());
}
//获取本类的所有方法
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println("本类的所有方法"+declaredMethod.getName());
}
//获取所有public修饰的构造器仅包括本类
Constructor[] constructors = personClass.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println("获取所有public修饰的构造器仅包括本类"+constructor.getName());
}
//获取本类所有的构造器包括私有的
Constructor[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println("本类所有的构造器"+declaredConstructor.getName());
}
//以Class的形式放回父类信息
Class superClass=personClass.getSuperclass();
System.out.println("父类的Class对象="+superClass);
//以Class[]的形式返回接口信息
Class[] interfaces=personClass.getInterfaces();
for (Class anInterface : interfaces) {
    System.out.println("接口信息"+anInterface.getName());
}
Annotation[] annotations=personClass.getAnnotations();
for (Annotation annotation : annotations) {
    System.out.println("类上的注解信息"+annotation);
}

获取关于类的成员变量的具体信息

//第二组api获取关于类的成员变量的具体信息
//getModifiers:以int的形式返回修饰符
//默认修饰符的值为0 public时1 private是2 protected是4 static是8  final是16
//如果有多个修饰符返回修饰符的int值的和
//getType()获取属性的类型
Field[] declaredFields1 = personClass.getDeclaredFields();
for (Field field : declaredFields1) {
    System.out.println("本类中的所有属性"+field.getName()
                       +"该属性的修饰符"+field.getModifiers()
                       +"该属性的类型"+field.getType());
}

获取关于方法的相关信息

//第三组Api关于类的方法
//getModifiers:以int的形式返回修饰符
//默认修饰符的值为0 public时1 private是2 protected是4 static是8  final是16
//getReturnType:以Class形式获取返回类型
//getName:放回方法名
//getAnnotations()获取方法上的注解信息
//getParameterTypes:以Class[]返回方法的参数类型数组
Method[] declaredMethods1 = personClass.getDeclaredMethods();
for (Method method : declaredMethods1) {
System.out.print("本类中的所有方法"+method.getName()
+" 该方法的修饰符"+method.getModifiers()
+" 该方法的返回类型"+method.getReturnType());
//获得该方法上的注解信息
Annotation[] annotations1 = method.getAnnotations();
for (Annotation annotation : annotations1) {
System.out.print(" 该方法上的注解"+annotation);
}
//输出当前这个方法的形参数组
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.print(" 该方法的形参类型"+parameterType);
}
System.out.println("");
}

9、通过反射创建类的实例

User类

class User{
    public int age=20;
    private String name="la";
    public static Boolean sex;

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

    public User() {
    }

    private User(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public void sayHi(){
        System.out.println("sayHi");
    }
    public String la(){
        return "mmmm";
    }
    private void sayHiHi(String name){
        System.out.println(name+"  private sayHiHi");
    }
    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
public class ReflectCreateInstance {
    public static void main(String[] args) throws Exception {
        //1、先获取类的Class对象
        Class userClass =Class.forName("com.company.User");
        //2、通过public的无参构造方法创建实例
        Object o=userClass.newInstance();
        System.out.println(o);
        //3、通过public有参构造器创建实例
        Constructor constructor=userClass.getConstructor(String.class);
        Object o1=constructor.newInstance("wu");
        System.out.println(o1);
        //4、通过非public构造器创建实例
        //得到private的构造器对象
        Constructor constructor1=userClass.getDeclaredConstructor(int.class,String.class);
        //但不能直接使用private的构造器对象创建实例,需要暴力破解
        constructor1.setAccessible(true);//不设置执行下面的创建实例的方法会报错
        Object o2=constructor1.newInstance(100,"god");
        System.out.println(o2);


    }
}

10、通过反射操作类的成员变量

		//通过反射操作类的成员
        Field age=userClass.getField("age");
        age.set(o,88);//通过反射设置属性
        System.out.println(age.get(o));

        //使用反射操作private属性
        Field name=userClass.getDeclaredField("name");
        //暴力反射
        name.setAccessible(true);
        name.set(o,"hi");
        System.out.println(name.get(o));
		
		//public static Boolean sex;
        //对于静态变量由于静态变量是属于类的。所以通过反射设置属性时。
        //对象可以为空
        Field sex=userClass.getDeclaredField("sex");
        sex.set(null,true);
        System.out.println(sex.get(null));

11、通过反射访问类中的方法

        //使用反射获取类的方法
        Method sayHi=userClass.getMethod("sayHi");
        sayHi.invoke(o);
        //使用反射调用私有方法
        Method sayHiHi=userClass.getDeclaredMethod("sayHiHi",String.class);
        //暴力反射
        sayHiHi.setAccessible(true);
        sayHiHi.invoke(o,"hi");
        //在反射中如果方法中有返回值,统一返回Object
        Method la=userClass.getMethod("la");
        Object invoke=la.invoke(o);
        System.out.println(invoke);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值