注解和反射

    195

元注解

负责注解其它注解
@Target:用于描述注解的使用范围(可以用在哪个地方)
@Retention:描述注解的生命周期(SOURCE<CLASS<RUNTIME)
@Document:说明该注解将被包含再javadoc中
@Inheriteg:说明该子类可以继承父类中的该注解


反射

反射可以让Java代码动起来(动态的去创建Java对象),就好比写游戏外挂,游戏已经在运行了,我们要如何修改数据呢,就需要动态的去创建对象,也就是一个钩子,然后去修改里面的数据。

Java创建对象的方式:new、clone克隆、反射、反序列化

借助于反射API取得任何类的内部信息还可以直接操作对象的内部属性及方法。
加载完类后,在堆内存中就产生了一个Class类型的对象,包含了完整的类的结构信息,这就是反射。

Class obj = Class.forName("java.lang.String")

反射主要API
java.lang.reflect.Method:类的方法
java.lang.reflect.Field:类的成员变量
java.lang.reflect.Constructor:类的构造器

通过打印通过反射创建的类的hashcode就可以发现所有的类都是一样的。

获取Class类实例的方法

1.如果已经知道具体的类,通过类的class属性获取,该方法最为安全可靠。
Class obj = Persion.class;

2.已经知道某个类的示例,调用getClass()方法获取
Class obj = persion.getClass()

3.知道类的全类名,可以通过forName()获取
Class obj = Class.forName("java.lang.String")

类加载分析

1. 加载

  • 读取:这一阶段,类加载器从文件系统、网络或其他源读取.class文件的二进制数据。
  • 解析:将这些二进制数据转换成方法区内的运行时数据结构。在这个过程中,Java虚拟机将生成一个代表这个类的java.lang.Class对象。

2. 连接

将Java类的二进制代码合并到JVM的运行状态中

  • 验证:确保被加载的类的正确性,验证字节码是否符合Java语言的规范,以及是否不会危害虚拟机的安全。
  • 准备:为类的静态变量分配内存,并将其初始化为默认值,这个阶段不包括Java代码中定义的初始化值。
  • 解析:虚拟机将所有的符号引用转换成直接引用,这些引用来自常量池,包括类、接口、字段和方法的引用(比如创建的类是引用类型,就会去找它的真实类型)

3. 初始化

  • 执行类构造器:这一阶段,类的静态变量将被初始化为声明时指定的值,静态代码块将被执行。这个过程是按照程序代码中的顺序来执行的。(合并static和代码块,构造类信息)

先静态代码块,然后默认代码块,最后构造方法

类加载:在方法区中先生成A类的一些数据(静态变量、常量池、代码等),然后在堆中就会生成这些类对应的Class对象(此时这个对象中就包含所有的信息)

连接:栈中执行main()方法 ,给变量设置一个默认的值(就比如定义了一个int的变量,那么它的默认值就为0),然后在堆中new了一个A类的对象,和之前生成的Class对象不同 。

初始化:随后通过A类的Class对象来给new的A的栈中的变量显示的赋值


类加载器

1. 启动类加载器

  • 功能:这是虚拟机自带的类加载器,负责加载Java的核心类库,如rt.jarcharsets.jar等,这些库位于JRE的lib目录下。
  • 特点:由于启动类加载器不是Java实现的,它通常是用本地代码(如C/C++)实现的,因此在Java应用中不可见。

2. 扩展类加载器

  • 功能:加载Java的扩展库,这些库通常位于JRE的lib/ext目录或者由系统属性java.ext.dirs指定的其他目录。
  • 特点:它由Java实现,继承自ClassLoader类。

3. 应用程序类加载器

  • 功能:这是类层次结构中的默认类加载器,用于加载用户路径(classpath)上的类库。
  • 特点:如果没有自定义类加载器,那么应用程序中的类都由它来加载。

4.自定义类加载器

  • 创建方式:可以通过继承java.lang.ClassLoader类的方式来创建自己的类加载器。
  • 用途:用于特定的需要,如动态地加载网络上的类,解密加密的类文件,或者从非标准源加载类(如数据库、文件等)。
public static void main(String[] args) throws ClassNotFoundException {
        // 1.通过反射获取类的Class对象
        final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        // 2.获取系统类加载器的父类加载器-->扩展类加载器
        final ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);

        // 3.获取扩展类加载器的父类加载器-->根加载器(C/C++)
        final ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
    }

jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
jdk.internal.loader.ClassLoaders$PlatformClassLoader@27bc2616
null

Class获取类的信息

反射通常是针对类进行的(而不是实例),因为sourceFields是一个实例对象,所以要先通过getClass()获取类对象

public static <S, T> T copyClass(S sourceClass, Class<T> targetClass)  {
        try {
            if (sourceClass==null){
                throw new RuntimeException();
            }
            if (targetClass==null){
                throw new RuntimeException();
            }

            T target = targetClass.getDeclaredConstructor().newInstance();
            // 反射通常是针对类进行的(而不是实例),因为sourceFields是一个实例对象,所以要先通过getClass()获取类对象
            Field[] sourceFields = sourceClass.getClass().getDeclaredFields();
            Field[] targetFields = targetClass.getDeclaredFields();

            //外层遍历获取原对象的值
            for (Field sourceField : sourceFields) {
                sourceField.setAccessible(true);
                Object value = sourceField.get(sourceClass);

                for (Field targetField : targetFields) {
                    if (targetField.getName().equals(sourceField.getName())
                            && targetField.getType().isAssignableFrom(sourceField.getType())) {
                        targetField.setAccessible(true);
                        targetField.set(target, value);
                        break;
                    }
                }
            }
            return target;
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }
方法类型方法名返回类型用途描述
类名称和修饰符getName()String获取类的完全限定名
getSimpleName()String获取类的简单名称(不包含包名)
getModifiers()int获取类的修饰符(如public, private等)
构造函数getConstructor(Class<?>... parameterTypes)Constructor<T>获取特定的公共构造函数
getConstructors()Constructor<?>[]获取所有公共构造函数
getDeclaredConstructor(Class<?>... parameterTypes)Constructor<T>获取特定的构造函数,包括私有的
getDeclaredConstructors()Constructor<?>[]获取所有构造函数,包括私有的
方法getMethod(String name, Class<?>... parameterTypes)Method获取特定的公共方法
getMethods()Method[]获取类及其父类的所有公共方法
getDeclaredMethod(String name, Class<?>... parameterTypes)Method获取特定的方法,包括私有的
getDeclaredMethods()Method[]获取类中声明的所有方法,包括私有的
字段getField(String name)Field获取特定的公共字段
getFields()Field[]获取类及其父类的所有公共字段
getDeclaredField(String name)Field获取类中声明的特定字段,包括私有的
getDeclaredFields()Field[]获取类中声明的所有字段,包括私有的
父类和接口getSuperclass()Class<?>获取类的父类
getInterfaces()Class<?>[]获取类实现的所有接口
实例创建newInstance()Object创建类的实例(已废弃,推荐使用getDeclaredConstructor().newInstance()
类型检查isInterface()boolean检查指定的Class对象是否代表一个接口
isArray()boolean检查类是否代表一个数组
isPrimitive()boolean检查类是否为基本数据类型
消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息