JAVA学习笔记——注解与反射

本文详细介绍了Java中的注解(Annotation),包括其作用、格式、常见内置注解和元注解,以及如何自定义注解。同时,文章探讨了反射机制,阐述了反射在运行时获取类信息、动态创建对象和执行方法的功能,以及如何通过反射获取泛型和注解信息。
摘要由CSDN通过智能技术生成

笔记基于B站的教学视频:https://www.bilibili.com/video/BV1p4411P7V3?p=16&share_source=copy_web

1 注解

1.1 什么是注解?

  • Annotation的作用:

    • 不是程序本身但可以对程序做出解释
    • 可以被其他程序(例如编译器)读取
  • Annotation的格式:

    • 注解以"@注解名"在代码证存在,并且可以添加一些参数
    • 示例:@SuppressWarnings(value=“bunchecked”)。
  • Annotation在哪使用:

    • 可以附加在package,class,method或者field等上面,根据其定义来确定。可以通过反射机制来访问这些元数据

1.2 JAVA中常见的几个内置注解

  • @Override

    定义在java.lang.Override中,只用于修饰方法表示一个方法将重写超类中的另一个方法

  • @Deprecated

    定义在java.lang.Deprecated中,用于修饰方法、属性或者类,表示不推荐使用某元素

  • @SuppressWarnings

    定义在java.lang.SuppressWarnings中,用于抑制编译时的警告信息。并且此注解需要添加一个参数,可以选择使用"all"、"unchecked"等

1.3 元注解

元注解用于注解其他的注解,JAVA中定义了四个元注解(这些类型和它们所支持的类可以在java.lang.annotation包中找到):

  • @Target

    用于描述注解可以用在哪些地方(TYPE、FIELD、METHOD等)

    示例:@Target(value=ElementType.METHOD)

  • @Retention

    表示需要在什么级别保存该注释信息(SOURCE、CLASS和RUNTIME)

    示例:@Retention(RetentionPolicy.RUNTIME)

  • @Document

    用于说明该注解将被包含在javadoc中

  • @Inherited

    用于说明子类可以继承父类中的该注解

1.4 自定义注解

使用@interface来自定义注解将自动继承java.lang.annotation.Annotation接口

  • 自定义注解格式:public @interface 注解名{定义内容} (public可不加)
  • 声明参数的格式:参数类型 参数名();参数类型只能为Class,String和enum,且可以使用default来声明参数默认值。
  • 示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{
    String value() default "";
}

2 反射

2.1 反射概述

  • 类在加载完成后,便在堆内存的方法区内产生一个Class类型的对象(每个类只有一个Class对象),此对象包含完整的类结构信息。

  • 反射机制允许程序在运行阶段借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

  • 反射的优点:可以实现动态创建对象和编译有很强的灵活性;反射的缺点:会对性能产生影响。

2.2 获得反射对象

对每个类JRE都为其保留了一个不变的Class类型对象,此对象包含了类的所有被加载的结构:类的属性、方法等,Class对象只能有系统来建立,每个类的实例也都知道自己由哪一个Class对象生产。Class类也是反射的根源,对任何想动态加载的类都需要先获得对应的Class对象。

获取Class类示例的方法:

  • 已知具体类可以通过类的class属性获取
Class c1=Person.class;
  • 已知类的示例通过getClass方法获取
Class c2=person.getClass();
  • 已知一个类的全类名且该类在类路径下,通过Class类静态方法forName获取
Class c3=Class.forName("xxxxx");
  • 内置的基本数据类型可以直接使用类名.Type获取
Class c4=Integer.TYPE;

2.3 获取类的运行时结构

运用2.2中的方法获得对应对象后,调用相应方法便可获得想得到类的信息,如下列代码所示:

package Study;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Myjava {

    public static void main(String[] args) throws Exception{
        //获取Class对象
        Class c=Class.forName("Study.User");
        //获取包名+类名
        System.out.println(c.getName());
        //获取类名
        System.out.println(c.getSimpleName());

        //获取类属性
        Field[] fields1 = c.getFields();//只能找到public属性的
        Field[] fields2 = c.getDeclaredFields();//获取全部属性
        Field name = c.getDeclaredField("name");//根据参数获取指定的属性

        //获取类的方法
        Method[] methods1 = c.getMethods();//获取本类及父类的全部public方法
        Method[] methods2 = c.getDeclaredMethods();//获取本类的全部方法
        Method setId = c.getMethod("setId", int.class);//根据参数获得指定方法

        //获取类构造器,下面三行代码与获取类的方法的代码类似只是不会获取父类构造器
        Constructor[] constructors1 = c.getConstructors();
        Constructor[] constructors2 = c.getDeclaredConstructors();
        Constructor constructor = 		          c.getDeclaredConstructor(int.class,String.class);
    }

}

class User{
    private int id;
    private String name;

    public User() {}
    private void a(){}
    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }
}

2.3 动态创建对象并执行方法

创建类的对象方法:

  • 调用Class对象的newInstance()方法,这要求类必须有一个无参构造器并且构造器的访问权限足够
  • 通过getDeclaredConstructors方法获取类中指定参数的构造器,利用此构造器实例化对象

代码示例如下(继续使用上述的User类):

		//获取Class对象
        Class c=Class.forName("Study.User");
        User u1=(User)c.newInstance();//本质是调用无参构造器
        //通过构造器创建对象
        Constructor constructor = c.getDeclaredConstructor(int.class, String.class);
        User u2 = (User)constructor.newInstance(1, "JAVA");

通过反射调用普通方法:

		//通过反射调用普通方法
        Method setId = c.getDeclaredMethod("setId", int.class);
        setId.invoke(u1,1);

通过反射操作属性:

		//通过反射操作属性
        Field id = c.getDeclaredField("id");
        id.setAccessible(true);//不能直接操作私有属性需要关闭安全检查
        id.set(u1,2);

2.4 获取泛型与注解信息

JAVA采用泛型擦除机制来引入泛型,为通过反射来操作泛型,JAVA新增了四种类型:

  • ParameterizedType:表示参数化类型比如Collection
  • GenericArrayType:表示元素类型是参数化类型或类型变量的数组类型
  • TypeVariable:是各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式

通过反射获取泛型信息代码如下:

public Map<ArrayList<String>,Integer> test01(Map<String,Integer> a,ArrayList<Integer> b){
        System.out.println("test01");
        return null;
    }

    public static void main(String[] args) throws Exception{
        Method m=Myjava.class.getDeclaredMethod("test01",Map.class,ArrayList.class);
        Type[] types1 = m.getGenericParameterTypes();//获得参数泛型信息
        Type types2=m.getGenericReturnType();//获得返回值泛型信息
        //输出泛型信息
        for(Type type:types1){
            if(type instanceof ParameterizedType){
                Type[] types3=((ParameterizedType)type).getActualTypeArguments();
                for(Type type2:types3)
                    System.out.println(type2);
            }
        }
    }

通过反射获取注解信息代码如下:

@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    int i() default 0;
    String value() default "";
}

@MyAnnotation(value = "Myjava")
public class Myjava {
    @MyAnnotation(i=1)
    private int id;
    public static void main(String[] args) throws Exception{
        Class c=Class.forName("Study.Myjava");

        MyAnnotation annotation1 = (MyAnnotation)c.getAnnotation(MyAnnotation.class);//获得类注解
        String s=annotation1.value();//获得注解的值
        System.out.println(s);

        Field f=c.getDeclaredField("id");
        MyAnnotation annotation2=(MyAnnotation)f.getAnnotation(MyAnnotation.class);//获得属性的注解
        int anid=annotation2.i();
        System.out.println(anid);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值