当前位置: 首页 > news >正文

Java基础关键_032_反射(二)

目  录

一、反射 Class 的 Method

1.反编译 String 类的方法签名

2.通过反射调用方法

3.反编译 String 类的构造方法签名

4.通过反射调用构造方法

 二、类加载过程

1.装载(Loading)

(1)说明

(2)双亲委派机制

2.链接(Linking) 

(1)验证(Verify)

(2)准备(Prepare) 

(3)解析(Resolve)

3.初始化(initialization) 

三、类加载器获取 Class

1.说明

2.与 Class.forName() 比较

 四、反射的泛型

1.父类的泛型

2.接口的泛型 

3.属性的泛型

4.方法参数的泛型

5.方法返回值的泛型

6.构造方法参数的泛型


一、反射 Class 的 Method

1.反编译 String 类的方法签名

public class MethodTest {
    public static void main(String[] args) throws ClassNotFoundException {
        // 获取类信息
        Class<?> aClass = Class.forName("java.lang.String");

        // 获取类修饰符
        String classMod = Modifier.toString(aClass.getModifiers());

        // 获取简单类名
        String className = aClass.getSimpleName();

        // 获取简单父类名
        String classSupName = aClass.getSuperclass().getSimpleName();

        // 获取父类接口
        Class<?>[] classInterfaces = aClass.getInterfaces();

        // 获取所有方法
        Method[] declaredMethods = aClass.getDeclaredMethods();

        // 字符串拼接
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(classMod);
        stringBuilder.append(" class ");
        stringBuilder.append(className);
        stringBuilder.append(" extends ");
        stringBuilder.append(classSupName);
        if (classInterfaces.length > 0) {
            stringBuilder.append(" implements ");
            for (int i = 0; i < classInterfaces.length; i++) {
                stringBuilder.append(classInterfaces[i].getSimpleName());
                if (i != classInterfaces.length - 1) {
                    stringBuilder.append(", ");
                }
            }
        }
        stringBuilder.append(" {\n");

        for (Method declaredMethod : declaredMethods) {
            stringBuilder.append("\t");
            // 获取方法修饰符
            String methodMod = Modifier.toString(declaredMethod.getModifiers());
            stringBuilder.append(methodMod);
            stringBuilder.append(" ");

            // 获取方法返回值类型
            Class<?> returnType = declaredMethod.getReturnType();
            stringBuilder.append(returnType.getSimpleName());
            stringBuilder.append(" ");

            // 获取方法名
            String methodName = declaredMethod.getName();
            stringBuilder.append(methodName);

            // 获取方法参数类型
            stringBuilder.append(" (");
            Parameter[] parameters = declaredMethod.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                // 获取参数类型
                Class<?> parType = parameter.getType();
                stringBuilder.append(parType.getSimpleName());

                // 获取参数名
                String parName = parameter.getName();
                stringBuilder.append(" ");
                stringBuilder.append(parName);
                // 添加逗号分隔符,最后一个参数不加逗号
                if (i < parameters.length - 1) {
                    stringBuilder.append(", ");
                }
            }
            stringBuilder.append(") {}\n");
        }
        stringBuilder.append("}");

        System.out.println(stringBuilder);
    }
}


2.通过反射调用方法

  1.  四要素:对象、方法、参数、值。缺一不可;
  2. 若方法不是 public 的,运行会报【java.lang.IllegalAccessException】异常,需要通过 setAccessible(true) 打破封装;
public class Person {
    public String name;
    private int age;
    protected String sex;
    public static String country;
    public static final String job = "程序员";

    public Person() {
    }

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

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public static String getCountry() {
        return country;
    }

    public static void setCountry(String country) {
        Person.country = country;
    }

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

    private void test(String s) {
        System.out.println("test(" + s + ")方法执行完毕!");
    }
}
public class UseMethod {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Person person = new Person();
        Class<? extends Person> aClass = person.getClass();

        // 获取方法
        Method test = aClass.getDeclaredMethod("test", String.class);
        
        // 设置方法可访问
        test.setAccessible(true);

        // 调用方法
        Object o = test.invoke(person, "参数列表");
    }
}


3.反编译 String 类的构造方法签名

public class MethodTest2 {
    public static void main(String[] args) throws ClassNotFoundException {

        // 获取类
        Class<?> aClass = Class.forName("java.lang.String");

        // 获取类修饰符
        String classMod = Modifier.toString(aClass.getModifiers());

        // 获取简单类名
        String className = aClass.getSimpleName();

        // 获取简单父类名
        String classSupName = aClass.getSuperclass().getSimpleName();

        // 获取父类接口
        Class<?>[] classInterfaces = aClass.getInterfaces();

        // 获取构造方法
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();

        // 拼接字符串
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(classMod);
        stringBuilder.append(" class ");
        stringBuilder.append(className);
        stringBuilder.append(" extends ");
        stringBuilder.append(classSupName);
        if (classInterfaces.length > 0) {
            stringBuilder.append(" implements ");
            for (int i = 0; i < classInterfaces.length; i++) {
                stringBuilder.append(classInterfaces[i].getSimpleName());
                if (i != classInterfaces.length - 1) {
                    stringBuilder.append(", ");
                }
            }
        }
        stringBuilder.append(" {\n");

        for (Constructor<?> declaredConstructor : declaredConstructors) {

            // 获取构造方法修饰符
            String constructorMod = Modifier.toString(declaredConstructor.getModifiers());
            stringBuilder.append("\t");
            stringBuilder.append(constructorMod);

            // 获取构造方法名
            String constructorName = declaredConstructor.getName().replaceAll("java.lang.", "");
            stringBuilder.append(" ");
            stringBuilder.append(constructorName);

            // 获取构造方法参数
            Parameter[] parameters = declaredConstructor.getParameters();
            stringBuilder.append(" (");

            if (parameters.length > 0) {
                for (int i = 0; i < parameters.length; i++) {

                    // 获取参数类型
                    String paraType = parameters[i].getType().getSimpleName();
                    stringBuilder.append(paraType);

                    // 获取参数名
                    String paraName = parameters[i].getName();
                    stringBuilder.append(" ");
                    stringBuilder.append(paraName);
                    if (i != parameters.length - 1) {
                        stringBuilder.append(", ");
                    }
                }
            }
            stringBuilder.append(") {}\n");
        }

        stringBuilder.append("}");
        System.out.println(stringBuilder);
    }
}


4.通过反射调用构造方法

public class Person {
    public String name;
    private int age;
    protected String sex;
    public static String country;
    public static final String job = "程序员";

    public Person() {
    }

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

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public static String getCountry() {
        return country;
    }

    public static void setCountry(String country) {
        Person.country = country;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
public class UseConstructor {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Person person = new Person();

        // 获取Class对象
        Class<? extends Person> aClass = person.getClass();

        // 获取无参构造方法
        Constructor<? extends Person> c1 = aClass.getDeclaredConstructor();
        System.out.println(c1);
        Person p1 = c1.newInstance();
        System.out.println(p1);

        // 获取有参构造方法
        Constructor<? extends Person> c2 = aClass.getDeclaredConstructor(String.class, int.class, String.class);
        System.out.println(c2);
        Person p2 = c2.newInstance("孔明", 18, "男");
        System.out.println(p2);
    }
}


 二、类加载过程

1.装载(Loading)

(1)说明

  1. 类加载器负责将类的 class 文件读入内存;
  2. 低版本 JDK 类加载器:
    1. 引导 / 启动 类加载器:负责加载 rt.jar,即核心类库;
    2. 扩展 类加载器:负责加载 ext/*.jar ;
    3. 系统 类加载器:负责加载 classpath 中的 class 文件。
  3. jdk 9 之后的 JDK 类加载器:
    1. BootstrapClassLoader(引导 / 启动 类加载器);
    2. PlatformClassLoader(平台类加载器);
    3. AppClassLoader(应用类加载器)。
  4. 高版本 JDK 中引入模块化;
  5. 可以自定义类加载器,只要符合规范即可;
  6. 可以通过 getParent() 方法获取 当前 类加载器 的 父 类加载器。
public class ClassLoaderTest {
    public static void main(String[] args) {

        // 获取应用类加载器
        ClassLoader cl1 = Person.class.getClassLoader();
        System.out.println(cl1);

        ClassLoader cl2 = ClassLoader.getSystemClassLoader();
        System.out.println(cl2);

        ClassLoader cl3 = Thread.currentThread().getContextClassLoader();
        System.out.println(cl3);

        // 获取平台类加载器
        ClassLoader cl1Parent = cl1.getParent();
        System.out.println(cl1Parent);

        ClassLoader cl2Parent = cl2.getParent();
        System.out.println(cl2Parent);

        ClassLoader cl3Parent = cl3.getParent();
        System.out.println(cl3Parent);

        // 获取启动类加载器,启动类加载器负责加载核心类库,名称读不到,直接输出 null
        ClassLoader cl1GrandParent = cl1Parent.getParent();
        System.out.println(cl1GrandParent);

        ClassLoader cl2GrandParent = cl2Parent.getParent();
        System.out.println(cl2GrandParent);

        ClassLoader cl3GrandParent = cl3Parent.getParent();
        System.out.println(cl3GrandParent);
    }
}


(2)双亲委派机制

  1. 某个类加载器接收到加载类的任务时,通常委托给【父 类加载器】完成加载;
  2. 顶级【父 类加载器】无法加载时,逐层向下委派加载任务;
  3. 这样做的原因是,可以保证程序的安全,也可以防止类加载重复。

2.链接(Linking) 

(1)验证(Verify)

        确保类加载信息符合 JVM 规范。


(2)准备(Prepare) 

  1. 正式为静态变量在方法区开辟存储空间并赋默认值;
  2. 举例如下:
    1. public static int i = 1;        // 实际上,赋默认值 0 
    2. public static final int i = 1;        // 此时赋值 1

(3)解析(Resolve)

        将虚拟机常量池中的符号引用替换为直接引用,即替换为地址。 


3.初始化(initialization) 

  1. 为静态变量赋值;
  2. 执行静态代码块。

三、类加载器获取 Class

1.说明

        上一节谈到,通过类加载器的方式可以获取 Class 。下面将做出详细解释:

public class ReflectLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        // 获取 系统类 / 应用类 加载器,负责加载 classpath 中的 class 文件
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

        System.out.println(systemClassLoader);
        // 加载 class,只是完成了类加载过程中的装载与链接,还没有初始化
        Class<?> aClass = systemClassLoader.loadClass("reflecttest.Person");
        System.out.println(aClass);

        // 在这个类第一次被真正使用的时候,才会初始化这个类
    }
}
public class Person {
    public String name;
    private int age;
    protected String sex;
    public static String country;
    public static final String job = "程序员";

    static {
        System.out.println("Person类静态代码块执行了");
    }

    public Person() {
    }

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

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public static String getCountry() {
        return country;
    }

    public static void setCountry(String country) {
        Person.country = country;
    }

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


2.与 Class.forName() 比较

        Class.forName() 会完成类加载的全部过程,如果使用类加载器的方式,可以看出没有执行静态代码块,也就是没有执行初始化的过程。而使用 Class.forName() 的方式,可以看到静态代码块执行了。

public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass = Class.forName("reflecttest.Person");
        System.out.println(aClass);
    }
}


 四、反射的泛型

1.父类的泛型

public class Animal<A, B, C> {
}
public class Dog extends Animal<String, Integer, Boolean> {
}
public class Test {
    public static void main(String[] args) {
        // 反射获取类
        Class<Dog> dogClass = Dog.class;

        // 获取当前类的父类泛型
        Type genericSuperclass = dogClass.getGenericSuperclass();

        // 如果父类使用了泛型
        if (genericSuperclass instanceof ParameterizedType){
            // 转换为参数化类型
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            // 获取泛型数组
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            // 遍历泛型数组
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument.getTypeName());
            }
        }
    }


2.接口的泛型 

public interface Animal<T, V, K> {
}
public class Cat implements Animal<String, Integer, Boolean> {
}
public class Test {
    public static void main(String[] args) {
        // 反射获取类
        Class<Cat> catClass = Cat.class;

        // 获取接口的泛型
        Type[] genericInterfaces = catClass.getGenericInterfaces();
        
        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
}


3.属性的泛型

public class Animal {
    public Map<Integer, Boolean> name;
}
public class Test {
    public static void main(String[] args) throws NoSuchFieldException {
        // 反射获取类
        Class<Animal> animalClass = Animal.class;

        // 获取属性
        Field field = animalClass.getField("name");

        // 获取属性泛型
        Type genericType = field.getGenericType();

        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}


4.方法参数的泛型

public class Animal {
    public void eat(List<String> food) {
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        // 反射获取类
        Class<Animal> animalClass = Animal.class;

        // 获取方法
        Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);

        // 获取方法参数泛型
        Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();

        for (Type genericParameterType : genericParameterTypes) {
            if (genericParameterType instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
}


5.方法返回值的泛型

public class Animal {
    public Map<String, Integer> eat(List<String> food) {
        return null;
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        // 反射获取类
        Class<Animal> animalClass = Animal.class;

        // 获取方法
        Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);

        // 获取方法返回值的泛型
        Type genericReturnType = declaredMethod.getGenericReturnType();

        if (genericReturnType instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}


6.构造方法参数的泛型

public class Animal {
    private Map<String, Boolean> name;

    public Animal(Map<String, Boolean> name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        // 反射获取类
        Class<Animal> animalClass = Animal.class;

        // 获取构造方法
        Constructor<Animal> animal = animalClass.getDeclaredConstructor(Map.class);

        // 获取构造方法参数泛型
        Type[] genericParameterTypes = animal.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            if (genericParameterType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
}

http://www.dtcms.com/a/99107.html

相关文章:

  • 六十天前端强化训练之第三十四天之CI/CD 大师级深度解析
  • CNN+Transformer+SE注意力机制多分类模型 + SHAP特征重要性分析,pytorch框架
  • NFS挂载异常排查记录
  • 比kubectl更好用的k8s命令行客户端kube-shell
  • 信号集操作函数
  • Object结构
  • sqli-labs靶场 less 8
  • Display Serializer、Camera Deserializer(Camera Des)和SerDes‌ 加解串应用
  • 【vllm/瞎折腾】在内网wsl上安装vllm并尝试多节点部署(失败了)
  • Java并发编程面试题:线程池Fork/Join(19题)
  • 【深度学习新浪潮】具身智能及其发展前景分析
  • 万物皆可“吉卜力”,使用 AI 创建你的作品
  • 逆向中如何判断JSVMP,及如何解决?(包括实战案例)
  • OpenAI API - Agent
  • protobuf新版下载安装
  • 网络通信微服务
  • 【商城实战(95)】Ansible自动化运维,开启高效部署新篇章
  • 3D Gaussian Splatting部分原理介绍和CUDA代码解读(一)——3D/2D协方差和高斯颜色的计算
  • LeetCode 56. 合并区间 | 排序+贪心解法详解
  • 创意 Python 爱心代码分享
  • el-table 动态给每行增加class属性
  • C++ vector容器总结
  • 诠视科技MR眼镜如何使用VLC 进行RTSP投屏到电脑
  • 【从零实现Json-Rpc框架】- 项目实现 - muduo网络通信类实现篇
  • 黑盒测试的测试用例构成的八点要素
  • 突破数据迁移瓶颈!AWS Snowball如何让PB级数据“瞬间”上云?
  • 12款星光闪光污迹艺术绘画效果Clip Studio Paint笔刷画笔+闪光纹理图片 Clip Studio Glitter Texture Brushes
  • INAV电流计校准
  • sqlalchemy:将mysql切换到OpenGauss
  • 使用dumpbin和depends查看dll(exe)的依赖