【Java学习总结】注解与反射

一、注解(Annotation)

1.概述

  • 注解(Annotation)是JDK5.0开始引用的新技术。
  • 目前大部分框架都在使用注解来简化代码。
  • 注解不同于注释,它不仅可以被人看到,同时也可以被程序所读取。
  • 注解相当于给程序添加了额外的辅助信息。
  • 注解可以使用在package ,class , method , field 等上面。

2.内置注解

是作用在代码的注解,定义在 java.lang 中。

  1. @Override:表示方法是重写父类的方法。

  2. @Deprecated:表示该方法已过时,不建议使用,但不是不能使用。

  3. @SuppressWarnings:抑制警告,可以用来关闭编译器的警告,可以传递参数。

3.元注解

作用在其他注解的注解,定义在在 java.lang.annotation 中。

  1. @Target :表示我们的注解可以用在哪些地方。
    (1).TYPE:该注解可以用于类、接口(包括注解类型)或enum声明。
    (2).FIELD:该注解可以用于字段声明(包括enum实例)。
    (3).METHOD:该注解可以用于方法声明。
    (4).PARAMETER:该注解可以用于参数声明。
    (5).CONSTRUCTOR:该注解可以用于构造器声明。
    (6).LOCAL_VARIABLE:该注解可以用于局部变量声明。
    (7).ANNOTATION_TYPE:该注解可以用于注解声明。
    (8).PACKAGE:该注解可以用于包声明。
    (9).TYPE_PARAMETER:该注解可以用于参数类型声明。1.8新加入。
    (10).TYPE_USE:该注解可以用于类型声明。1.8新加入。
  2. @Retention:表示注解在什么地方生效,用于描述注解的生命周期。源码级别(SOURCE)< 类文件级别(CLASS)< 运行时级别(RUNTIME)。
  • SOURCE:注解将被编译器丢弃。
  • CLASS:注解在class文件中可用,但会被JVM丢弃。
  • RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息。
  1. @Document:表示是否将我们的注解生成在Javadoc中。

  2. @Inherited:子类可以继承父类的注解。

4.自定义注解

二、反射(Reflection)

1.什么是反射

反射是Java被称为“准动态语言”的关键技术。反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
正常方式是通过完整的“包类”名称通过new来实例化对象。反射方式可以通过实例化对象调用getClass()方法来获得完整的“包类”名称。

2.Class类

在Object类中定义了getClass()方法,该方法的返回值是Class类,这个类是Java反射的源头。针对任何你想动态加载、运行的类,唯有先获得相应的Class对象。

    //获取Class对象的方法
    public static void main(String[] args) throws ClassNotFoundException {
    
    

        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);

        //方式二:forName获得
        Class c2 = Class.forName("包名+类名");
        System.out.println(c2);

        //方式三:通过类名.class获得
        Class c3 = Person.class;
        System.out.println(c3);
    }

3.类加载器

  1. 类的加载过程:
    (1)加载(Load):将class文件加载到内存中,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
    (2)链接(Link):将类的二进制数据合并到JVM中的过程。
    (3)初始化(Initialize):执行类构造器()方法的过程。由JVM负责对类进行初始化。

  2. 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

	public static void main(String[] args) throws ClassNotFoundException {
    
    
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

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

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

4.从Class对象获取信息

(1)访问 Class 对应的类所包含的属性

  1. 批量的属性:
    public Field[] getFields():获取所有public属性
    public Field[] getDeclaredFields():获取所有的属性
  2. 获取单个属性:
    public Field getField(String name): 获取单个的public属性
    public Field getDeclaredField(String name):获取任何属性

(2)访问 Class 对应的类所包含的方法

  1. 批量的方法:
    public Method[] getMethods():获取所有public构造器
    public Method[] getDeclaredMethods():获取所有的构造器
  2. 获取单个的方法:
    public Method getMethod(String name, Class… parameterTypes): 获取单个的public方法
    public Method getDeclaredMethod(String name, Class… parameterTypes):获取任何方法

(3)访问 Class 对应的类所包含的构造方法

  1. 批量的方法:
    public Constructor[] getConstructors():获取所有public构造器
    public Constructor[] getDeclaredConstructors():获取所有的构造器
  2. 获取单个的方法:
    public Constructor getConstructor(Class… parameterTypes): 获取单个的public构造器
    public Constructor getDeclaredConstructor(Class…parameterTypes):获取任何构造器

测试代码如下:

  1. 首先创建一个User实体类
class User{
    
    
    private int id;
    private int age;
    private String name;

    public User() {
    
    }

    public User(int id, int age, String name) {
    
    
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}
  1. 通过Class对象获取该实体类的方法、属性以及构造器
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
    
    
        Class c1 = Class.forName("com.carry.reflection.User");

        //获得类的名字
        System.out.println(c1.getName());//包名+类名
        System.out.println(c1.getSuperclass());//类名

        //获得类的属性
        System.out.println("=======================");
        Field[] fields = c1.getFields();//只能找到public的属性
        fields = c1.getDeclaredFields();//找到全部属性
        for(Field field : fields){
    
    
            System.out.println(field);
        }

        //获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类及其父类的所有方法
        for (Method method : methods) {
    
    
            System.out.println("正常的"+method);
        }
        methods = c1.getDeclaredMethods();//获得本类的所有方法
        for (Method method : methods) {
    
    
            System.out.println("getDeclaredMethods"+method);
        }

        //获得指定方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得类的构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
    
    
            System.out.println(constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
    
    
            System.out.println("Declared"+constructor);
        }

        //获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(int.class,int.class,String.class);
        System.out.println("指定"+declaredConstructor);
    }

5.Class动态创建对象

  1. 使用 Class 对象的 newInstance() 方法创建对象
  2. 使用 Constructor 对象创建对象

测试代码如下:

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    
    
        //获得Class对象
        Class c1 = Class.forName("com.carry.reflection.User");

        //构造一个对象
        User user = (User) c1.newInstance();//本质是调用了类的无参构造器
        System.out.println(user);

        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(int.class, int.class, String.class);
        User user2 = (User)constructor.newInstance(1, 18, "hello");
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活的意思(对象,“方法的值”)
        setName.invoke(user3,"hi");
        System.out.println(user3.getName());

        //通过反射操作属性
        System.out.println("======================");
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");

        //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
        name.setAccessible(true);//取消安全检测
        name.set(user4,"hi2");
        System.out.println(user4.getName());
    }

6.通过反射获取泛型

通过反射的方法可以获得方法中的泛型。

  1. 首先创建两个测试方法,这两个方法的返回值和参数分别为泛型。
    public void test01(Map<String,User> map, List<User> list){
    
    
        System.out.println("test01");
    }

    public Map<String,User> test02(){
    
    
        System.out.println("test02");
        return null;
    }
  1. 分别通过Class获得两个方法的泛型。.
    public static void main(String[] args) throws NoSuchMethodException {
    
    
        Method method = Test.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
    
    
            System.out.println("#"+genericParameterType);
            if (genericParameterType instanceof ParameterizedType){
    
    
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
    
    
                    System.out.println(actualTypeArgument);
                }
            }
        }

        method = Test.class.getMethod("test02",null);
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType){
    
    
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
    
    
                System.out.println(actualTypeArgument);
            }
        }
    }

7.通过反射获取注解

  1. 定义两个注解
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableHello{
    
    
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldHello{
    
    
    String columnName();
    String type();
    int length();
}
  1. 定义一个实体类,在实体类中使用这两个注解
@TableHello("db_student")
class Student{
    
    

    @FieldHello(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldHello(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldHello(columnName = "db_name",type = "varchar",length = 5)
    private String name;

    public Student2() {
    
    
    }

    public Student2(int id, int age, String name) {
    
    
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}
  1. 在主方法中获取实体类中的注解
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
    
        Class c1 = Class.forName("com.carry.reflection.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
    
    
            System.out.println(annotation);
        }

        //获得注解的value的值
        TableHello tableHello = (TableHello) c1.getAnnotation(TableHello.class);
        String value = tableHello.value();
        System.out.println(value);

        //获得类指定的注解
        Field field = c1.getDeclaredField("name");
        FieldHello annotation = field.getAnnotation(FieldHello.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }

猜你喜欢

转载自blog.csdn.net/qq_43647936/article/details/121088534