注解与反射

发布时间 2023-12-06 23:37:00作者: qingshanboy

注解与反射

注解

注解:就是以@开头的

比如:@Override

内置注解

例如:

@Override:重写注解

@Deprecated:表示已过时的注解(不推荐使用某方法)

@SuppressWarnings(String[] value()):镇压警告,参数是value=一个字符串数组

元注解

修饰其他注解的注解

@Target:描述注解的使用范围

@Retention:表示在什么级别保留注解信息,用于描述注解的生命周期

(SOURCE<CLASS<RUNTIME)

......

自定义注解

//元注解修饰自定义注解
@Target(value= {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//自定义注解,写法:public @interface 注解名
public @interface MyAnotation{
    String name() default "qs";//注解参数,这里默认值为qs,写法:类型 名()
    int[] num();//注解参数
}
//由public修饰的类时,自定义注解不用写public

反射

反射机制:Java有一个很特别的类——Class,java的所有类都有一个Class对象,该对象记录关于对应的类的信息,所有类都只有一个Class对象,Class对象是由JVM(Java虚拟机)创建的,自己不能实例化class对象

通过引入java.lang.reflect.* 我们可以获取对应的类对象的构造器、方法、属性等,还可以实例化类对象对应的类从而获得一个对象

获取类对象的方式

  1. 对象.getClass()

    import java.lang.reflect.*;
    
    public class test {
        public static void main(String[] args){
            User user = new User();
            Class c = user.getClass();
            System.out.println(c);
        }
    }
    
    class User{
        public String name="qq";
        public User(String n){
            this.name = n;
    
        }
        public User(){
    
        }
    }
    
  2. Class.ForName()

    import java.lang.reflect.*;
    
    public class test {
        public static void main(String[] args) throws ClassNotFoundException{
            Class c = Class.ForName("testReflaction/User");
            System.out.println(c);
        }
    }
    
    class User{
        public String name="qq";
        public User(String n){
            this.name = n;
    
        }
        public User(){
    
        }
    }
    
  3. 类名.class

    import java.lang.reflect.*;
    
    public class test {
        public static void main(String[] args){
            Class c = User.class;
            System.out.println(c);
        }
    }
    
    class User{
        public String name="qq";
        public User(String n){
            this.name = n;
    
        }
        public User(){
    
        }
    }
    

所有类型的class对象

  1. 类有class对象:object.class
  2. 数组有class对象:String[].class
  3. 接口有class对象:Comparable.class
  4. 二维数组有class对象
  5. 注解有class对象:Override.class
  6. 枚举有class对象:ElementType.class
  7. 基本数据类型有class对象
  8. void有class对象:void.class
  9. Class类本身有class对象:class.class

类加载内存和类初始化

类的加载:把class文件的字节码读入内存,把静态数据转换为方法区运行时数据结构,并生成一个Class对象表示该类

链接:

  1. 验证:确保类信息符合JVM规范
  2. 准备:正式为静态变量(类变量)分配内存并设置默认值,这些内存在方法区分匹配
  3. 解析:把虚拟机常量池内的符号引用(常量名引用)转换为直接引用(地址引用)

初始化:执行类构造器()方法的过程,类构造器方法由编译期自动收集所有类变量的赋值和静态代码块中的语句合并产生的,类构造器方法不是构造方法。

class Test{
    static{
        ...
    }
    static int a = 100;
    public Test(){
        ...
    }
}
//如以上代码,把这里的static修饰的变量和static代码块里面的代码合并起来就是类构造器方法
//而Test()这个方法才是构造方法

初始化一个类,发现其父类没有初始化,会首先初始化父类

虚拟机会保证一个类的构造器方法在多线程环境被正确加锁和同步

什么时候类会初始化:

主动引用:

  1. new的时候
  2. 反射的时候

类加载器

类缓存:类被加载到加载器,会维持加载一段时间,JVM垃圾回收机制可以回收这些缓存的类的class对象

类加载器类型:

  1. 引导类加载器(根加载器,c++写的无法获取)

  2. 扩展类加载器

  3. 系统类加载器(常用)

package testReflaction;

public class ClassLoader {
    public static void main(String[] args){
        java.lang.ClassLoader loader1 = java.lang.ClassLoader.getSystemClassLoader();
        System.out.println(loader1);//打印系统类加载器
        java.lang.ClassLoader loader2 = loader1.getParent();
        System.out.println(loader2);//打印扩展类加载器
        java.lang.ClassLoader loader3 = loader2.getParent();
        System.out.println(loader3);//打印根类加载器,无法获取显示为空
    }
}

image-20230804092246310

获取类运行时结构

获取类名:

类对象.getName()——获取包名+类名

类对象.getSimpleName()——获取类名

获取类属性

类对象.getFields()——只获取public属性

类对象.getDeclaredFields()——获取所有属性

类对象.getField("属性名")——获得指定public属性

类对象.getDeclaredFields("属性名")——获取指定的非public属性

package testReflaction;
import java.lang.reflect.*;

public class test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{

        Class c1 = Class.forName("testReflaction.User");//获取类对象
        //获取类名
        System.out.println("获取类名:");
        System.out.println(c1.getName());//获取并打印包名+类名
        System.out.println(c1.getSimpleName());//获取并打印类名

        //获取类属性
        System.out.println("获取类属性:");
        System.out.println("___________________________________________");
        Field[] fields = c1.getFields();
        for(Field field:fields){
            System.out.println(field);
        }
        System.out.println("");
        for (Field f : c1.getDeclaredFields()){
            System.out.println(f);
        }
        Field f1 = c1.getField("name");
        Field f2 = c1.getDeclaredField("a");
        System.out.println("获取指定属性:\n" + f1 + "\n" + f2);

    }

}

class User{
    public String name="qq";
    static int a = 1;
    int b = 3;
    public User(String n){
        this.name = n;

    }
    public User(){

    }
    public String getName(){
        return this.name;
    }
    public int getA(){
        return a;
    }
    int getB(){
        return b;
    }
}

image-20230804103226028

获取类方法

类对象.getMethod()——获取指定public方法

类对象.getMethods()——获取所有public方法

类对象.getDeclaredMethod()——获取指定非Public方法

类对象.getDeclaredMethods()——获取所有非public方法

package testReflaction;
import java.lang.reflect.*;

public class test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{

        Class c1 = Class.forName("testReflaction.User");//获取类对象
       //获取类方法
        System.out.println("获取类方法:");
        Method[] methods = c1.getMethods();
        System.out.println("getMethods:");
        for (Method m : methods){
            System.out.println(m);
        }
        System.out.println("getDeclaredMethods:");
        for (Method m1 : c1.getDeclaredMethods()){
            System.out.println(m1);
        }
        Method m3 = c1.getDeclaredMethod("getB");
        System.out.println(m3);
        Method m4 = c1.getMethod("getA");
        System.out.println(m4);

    }

}

class User{
    public String name="qq";
    static int a = 1;
    int b = 3;
    public User(String n){
        this.name = n;

    }
    public User(){

    }
    public String getName(){
        return this.name;
    }
    public int getA(){
        return a;
    }
    int getB(){
        return b;
    }
}

image-20230804103157360

获取构造方法

类对象.getConstructor():获取指定的公有构造方法

类对象.getConstructors():获取类中所有公有构造方法

类对象.getDeclaredConstructor():获取指定的构造方法

类对象.getDeclareConstructors():获取类的所有构造方法

package testReflaction;
import java.lang.reflect.*;

public class test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{

        Class c1 = Class.forName("testReflaction.User");//获取类对象
         //获取构造方法
        System.out.println("___________________________________________");
        System.out.println("获取构造方法:");
        for (Constructor c : c1.getConstructors()){
            System.out.println(c);
        }
        for (Constructor c2 : c1.getDeclaredConstructors()){
            System.out.println(c2);
        }
        System.out.println(c1.getConstructor(String.class));
        System.out.println(c1.getDeclaredConstructor());
      

    }

}

class User{
    public String name="qq";
    static int a = 1;
    int b = 3;
    public User(String n){
        this.name = n;

    }
    public User(){

    }
    public String getName(){
        return this.name;
    }
    public int getA(){
        return a;
    }
    int getB(){
        return b;
    }
}

image-20230804103125206

通过反射动态创建对象

package testReflaction;
import java.lang.reflect.*;

public class test {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException,IllegalAccessException,InstantiationException{

        Class c1 = Class.forName("testReflaction.User");//获取类对象
        //创建对象
        //newInstance()
        User user = (User)c1.newInstance();
        System.out.println(user);

        //通过构造器创建
        Constructor c = c1.getDeclaredConstructor(String.class);
        User use = (User)c.newInstance("小d");
        System.out.println(use);
        
        //调用方法
        Method getA = c1.getMethod("getA",null);
        getA.invoke(use,null);
        
      

    }

}

class User{
    public String name="qq";
    static int a = 1;
    int b = 3;
    public User(String n){
        this.name = n;

    }
    public User(){

    }
    public String getName(){
        return this.name;
    }
    public int getA(){
        return a;
    }
    int getB(){
        return b;
    }
}

image-20230804104440888

反射机制很重要,在java反序列化时会用到,可以用来获取一些自定义类的信息,还可以利用JAVA本身自带的包中的类来执行系统命令或执行代码,在框架中也会用到

接下来会去学习并记录一些JAVA反序列化的实战,以及框架方面的知识

通过反射操作泛型

通过反射获取注解