反射

反射

概述

java反射机制是在程序运行状态 中,对于任意一个类,都能够知道这个类的所有的属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称之为java的反射机制。

要想解剖一个类,必须先要获取这个类的字节码文件对象。解剖这个类,使用的就是Class类中的方法。字节码文件对象就对应到Class类型的对象

要掌握的单词:

  • Class 类
  • Constructor 构造方法
  • Method 方法
  • Field 属性
  • Instance 实例
  • invoke 执行

获取Class对象

“ 通过类字面量:

Class<?> clazz = String.class; 

通过对象实例:

String str = "Hello";
Class<?> clazz = str.getClass();

通过 Class.forName() 方法:

Class<?> clazz = Class.forName("java.lang.String");

创建对象

可以使用反射动态创建对象:

Class<?> clazz = Class.forName("java.lang.String");
Object obj = clazz.getDeclaredConstructor().newInstance();
import java.util.ArrayList;
import java.util.List;

public class AddUserTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class对象
        //方式一
        //接口名/类名.class
        Class
<String> stringClass = String.class;
        System.out.println(stringClass);

        Class
<List> lsitclass = List.class;
        System.out.println(lsitclass);

        Class<int[]> aclass = int[].class;
        System.out.println(aclass);

        Class
<Integer> integerClass = Integer.class;
        System.out.println(integerClass);

        Class
<Double> doubleClass = Double.class;
        System.out.println(doubleClass);

        //对象名.getClass();
        //方式二

        List
<String> list = new ArrayList<String>();
        System.out.println(list.getClass());

        //方式三
        //字符串必须是全路径名

        Class<?> aClass1 = Class.forName("java.util.Date");
        System.out.println(aClass1);

        Class<?> aClass2 = Class.forName("cn.javasm.Testdemo");
        System.out.println(aClass2);
    }
}

访问字段

可以通过反射访问和修改类的字段:

Class<?> clazz = Person.class;
Field field = clazz.getDeclaredField("name");

// 如果字段是私有的,需要设置为可访问
field.setAccessible(true); 

// 获取字段值
Object value = field.get(personInstance); 
// 设置字段值
field.set(personInstance, "New Name"); 
import java.lang.reflect.Field;

public class TestDemo3 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        // 获取字符串的hash属性
        // 获取字节码文件对象
        Class
<String> stringClass = String.class;
        // 获取serialVersionUID属性
//            stringClass.getDeclaredField("serialVersionUID");
//            stringClass.getDeclaredFields();

        Field field = stringClass.getDeclaredField("hash");
        System.out.println(field);
        //暴力破解
        String str = "abc";
        field.setAccessible(true);
        field.set("str", 10);
        Object obj = field.get(str);
        System.out.println(obj);
        //获取所有的属性
        Field[] declaredFields = stringClass.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }
        //获取属性的修饰符
        int modifiers = field.getModifiers();
        System.out.println(modifiers);

        Class
<Person> personClass = Person.class;
        Field name = personClass.getDeclaredField(&quot;name&quot;);
        System.out.println(name);
        System.out.println(name.getModifiers());
    }
}

修饰符对应返回值

![image-20241030111223439.png](https://www.neet0316.com/wp-content/uploads/2025/12/image-20241030111223439.png

调用方法

可以通过反射调用类的方法:

Class<?> clazz = Person.class;
Method method = clazz.getMethod("sayHello");
method.invoke(personInstance);

Method methodWithArgs = clazz.getMethod("greet", String.class);
methodWithArgs.invoke(personInstance, "World");

获取公共方法 & 获取非公开的方法

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestDemo4 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        method1();
//        method2();
    }

    private static void method2() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        //获取字节码文件对象
        Class
<String> staringClass = String.class;
        //获取公共方法
        Method method = staringClass.getMethod("substring", int.class, int.class);
        String str = "abcd";
        // 执行方法
        // 参数一 要执行的对象
        // 参数二 方法的实参
        // 返回值就是方法的返回值
        Object invoke = method.invoke(str, 1, 3);
        System.out.println(invoke);
    }

    private static void method1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        //获取字节码文件对象
        Class
<Person> personClass = Person.class;
        //获取非公开的方法
        Method method = personClass.getDeclaredMethod("eat");
        Person person = new Person("cyz", 22);
        //暴力破解
        method.setAccessible(true);
        //执行方法
        Object invoke = method.invoke(person);
        System.out.println(invoke);
    }
}

获取枚举类

public class TestDemo5 {
    public static void main(String[] args) {
        // 获取字节码文件对象
        Class
<Level> levelClass = Level.class;
        // 获取枚举Level中的所有的枚举常量
        Level[] enumConstants = levelClass.getEnumConstants();
        for (Level enumConstant : enumConstants) {
            System.out.println(enumConstant);
        }

    }

    enum Level {
        A, B, C, D, E
    }
}

如果不是枚举 返回null

public static void method2() {
    Class
<String> stringClass = String.class;
    String[] enumConstants1 = stringClass.getEnumConstants();
    System.out.println(enumConstants1);

}

获取接口和父类

可以使用反射获取类实现的接口和父类:

Class<?> clazz = Person.class;

// 获取所有接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println("Interface: " + i.getName());
}

// 获取父类
Class<?> superClass = clazz.getSuperclass();
System.out.println("Superclass: " + superClass.getName());

获取所有接口

public class TestDemo6 {
    public static void main(String[] args) {
        Class
<String> stringClass = String.class;
        Class<?>[] interfaces = stringClass.getInterfaces();
        for (Class<?> i : interfaces) {
            System.out.println(i);
        }
    }
}

// 获取父类 全路径类名 类名 包名

public class TestDemo6 {
    public static void main(String[] args) {
        Class
<String> stringClass = String.class;

        //获取父类
        Class<? super String> superclass = stringClass.getSuperclass();
        System.out.println(superclass);

        //获取全路径类名
        String name = superclass.getName();
        System.out.println(name);

        //获取简单类名
        String simpleName = superclass.getSimpleName();
        System.out.println(simpleName);

        //获取包名
        System.out.println(stringClass.getPackageName());
    }
}

获取构造方法

可以使用反射获取和调用构造函数:

Class<?> clazz = Person.class;
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("John", 30);
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestDemo2 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取字符串字节码文件对象
        Class
<String> stringClass = String.class;
        // 获取构造方法
        //public String(byte ascii[], int hibyte, int offset, int count)
        Constructor
<String> constructor = stringClass.getConstructor(byte[].class, int.class, int.class);
        // 创建对象
        String string = constructor.newInstance(new byte[]{97, 98, 99}, 0, 3);
        System.out.println(string);

        //获取所有公共的构造方法
        Constructor<?>[] constructors = stringClass.getConstructors();
        for (Constructor<?> constructor1 : constructors) {
            System.out.println(constructor1);
        }

        //获取指定的构造方法
        Constructor
<String> declaredConstructor = stringClass.getDeclaredConstructor(byte[].class, int.class, int.class);

        System.out.println(declaredConstructor);

        //暴力破解
        declaredConstructor.setAccessible(true);

        String s1 = declaredConstructor.newInstance(new byte[]{97, 98, 99});
        System.out.println(s1);

        //获取所有构造方法
        Constructor<?>[] declaredConstructors = stringClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor1 : declaredConstructors) {
            System.out.println(declaredConstructors);
        }
    }
}

反射劣势

1 反射打破了封装原则

2 可以跳过泛型检查

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    List
<String> list = new ArrayList<>();
    // 获取字节码文件对象
    Class<? extends List> aClass = list.getClass();
    // 获取add方法
    Method method = aClass.getMethod("add", Object.class);
    // 执行方法
    method.invoke(list, 12);
    System.out.println(list);
}

Method和Field相关方法

判断方法

@FirstAnno("abc")
public class TestDemo10 {

    int j = 20;

    public static void main(String[] args) {

        int i = 10;

    }
}

// 自定义注解
@interface FirstAnno {
    // 在注解中可以定义属性,默认被public static final修饰
    public static final int i = 10;

    // 在注解中定义变量 使用()
    // 注解中的属性使用public修饰
//    String str();
//    
//    double d();
    // 设置默认值
    char c() default '国';

    // 注解中的属性类型只能是基本数据类型/String/Class/注解/枚举以及它们的一维数组形式
//    Object obj();
    // 如果数组中只有一个元素, {} 可以省略
//    int[] arr();
    // 如果传递值时只有一个值,并且名称是value,那么可以省略value =
    String value();
}

注解

自定义注解

@FirstAnno("abc")
public class TestDemo10 {

    int j = 20;

    public static void main(String[] args) {

        int i = 10;

    }
}

// 自定义注解
@interface FirstAnno {
    // 在注解中可以定义属性,默认被public static final修饰
    public static final int i = 10;

    // 在注解中定义变量 使用()
    // 注解中的属性使用public修饰
//    String str();
//    
//    double d();
    // 设置默认值
    char c() default '国';

    // 注解中的属性类型只能是基本数据类型/String/Class/注解/枚举以及它们的一维数组形式
//    Object obj();
    // 如果数组中只有一个元素, {} 可以省略
//    int[] arr();
    // 如果传递值时只有一个值,并且名称是value,那么可以省略value =
    String value();
}

元注解

对注解进行注解的那些注解

@Target({ElementType.METHOD, ElementType.TYPE}) // 限定注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //限定注解的存活范围
@Inherited // 表示这个注解也要作用在子类上
@Documented // 表示这个注解会生成到java文档中

10.3 反射注解

public class TestDemo11 {
    public static void main(String[] args) throws NoSuchMethodException {
        // 获取字节码文件对象
        Class
<Teacher> teacherClass = Teacher.class;
        Method method = teacherClass.getMethod("teach");
        // 判断类或者方法或者属性上面是否有指定的注解isAnnotationPresent
        if (teacherClass.isAnnotationPresent(Anno.class)) {
            // 获取所有注解
//            teacherClass.getAnnotations();
            Anno annotation = teacherClass.getAnnotation(Anno.class);
            // 获取注解的值
            String value = annotation.value();
            if ("初级".equals(value)) {
                System.out.println("认真负责");
            } else if ("中级".equals(value)) {
                System.out.println("三尺讲台,两袖清风");
            } else if ("特级".equals(value)) {
                System.out.println("桃李满天下");
            } else {
                System.out.println("辅导员...");
            }
        } else {
            System.out.println("野鸡老师......");
        }
    }
}

@Anno("特级")
class Teacher {

    public void teach() {
        System.out.println("老师要教书育人");
    }
}

@Retention(RetentionPolicy.RUNTIME)// 保留到运行阶段
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Anno {
    String value();
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇