基础不够,项目来凑,遇到即学会(注解和反射)

文章目录

      • Java注解
        • 一、内置注解
        • 二、Java元注解(meta-annotation)
        • 三、Java自定义注解
      • 反射Reflection
        • 一、获取Class实例的方法
            • 已知一个类的全类名,且该类在路径下。可通过Class.forName("包名全路径+类名")获取,如果写错类名或路径会抛出ClassNotFoundException
            • 若已知具体的类,通过类的class属性来获取class实例。最可靠,性能最高
            • 已有一个类的实例,可通过实例.getClass方法来获取
            • 基本类型的包装类可以使用TYPE属性直接获取Class实例,仅限基本类型包装类内置对象
        • 二、哪些类型有Class对象
        • 三、类加载器(将class装载进内存)
        • 四、反射获取属性、方法、构造方法
        • 五、获取泛型信息
        • 六、获取注解信息

Java注解

一、内置注解

  1. @Override:(重写)定义在java.lang.Override中,此注解只可以标记在方法上,表示重写父类的方法

  2. @Deprecated:(过时)定义在java.lang.Deprecated中,此注解可以修饰方法、属性、类,表示不推荐程序员使用,通常因为被标记类使用有危险或者有更好的替代方法

  3. @SuppressWarnings:(压制警告)定义在java.lang.SuppressWarnings中,此注解用来压制编译时出现的警告信息,需要在使用时加上参数@SuppressWarnings(“参数”)

二、Java元注解(meta-annotation)

  1. @Target:标识注解可以在哪里使用,具体类型可以参考枚举类ElementType

  2. @Documented:标识生成javadoc文档

  3. @Retention:标识注解生效级别,具体类型可以参考RetentionPolicy,RUNTIME>CLASS>SOURCE

  4. @Inherited:标识子类可以继承父类的该注解

三、Java自定义注解

  1. 自定义注解使用@Interface来声明一个注解
@Target({ElementType.FIELD,ElementType.METHOD}) //标记可以使用的地方,字段、方法
@Retention(RetentionPolicy.RUNTIME) //标记生效级别,运行时
@Documented  //javadoc
public @interface AnnotationTest{}
  1. 自定义注解中的方法其实就是使用注解时所要传入的参数,方法的返回值就是参数的类型,如果只有一个参数,一般参数名为value,返回值类型只能是基本类型以及Class、String、enum
@Target({ElementType.FIELD,ElementType.METHOD}) //标记可以使用的地方,字段、方法
@Retention(RetentionPolicy.RUNTIME) //标记生效级别,运行时
@Documented  //javadoc
public @interface AnnotationTest{
    String value();//如果只有一个参数时使用value,在使用注解时可以省略"value="
}
//@AnnotationTest("参数")
  1. 可以使用default来声明一个默认值
@Target({ElementType.FIELD,ElementType.METHOD}) //标记可以使用的地方,字段、方法
@Retention(RetentionPolicy.RUNTIME) //标记生效级别,运行时
@Documented  //javadoc
public @interface AnnotaionTest{
    String name() default "names";//设置了默认值在使用注解时可以不加该参数,直接使用默认值
}
//@AnnotationTest()
  1. 参数为数据类型可以参考@Target源码定义数组参数,数组默认值"string [] arrs default {“aaa”,“bbb”}";

反射Reflection

  1. Class本身也是一个类
  2. Class对象只能由系统创建对象
  3. 一个加载的类在JVM中只有一个Class实例
  4. 一个Class对象对应是一个加载到JVM中的.class文件
  5. 每个类都可以通过Class来获取所有类信息

一、获取Class实例的方法

已知一个类的全类名,且该类在路径下。可通过Class.forName(“包名全路径+类名”)获取,如果写错类名或路径会抛出ClassNotFoundException
Class classs = Class.forName("com.test.Test");
若已知具体的类,通过类的class属性来获取class实例。最可靠,性能最高
Class classs = Test.class;
已有一个类的实例,可通过实例.getClass方法来获取
Test test = new Test();
Class classs = test.getClass();
基本类型的包装类可以使用TYPE属性直接获取Class实例,仅限基本类型包装类内置对象
Class classs = Integer.TYPE;

二、哪些类型有Class对象

public static void main(String[] args) {
    Class c1 = Object.class; //对象
    Class c2 = int [].class; //数组
    Class c3 = int [] [].class;
    Class c4 = Override.class;//注解
    Class c5 = ElementType.class;//枚举
    Class c6 = void.class;//空
    Class c7 = Connection.class;//接口
    Class c8 = Class.class;//Class
    //...
    System.out.println(c1);
    System.out.println(c2);
    System.out.println(c3);
    System.out.println(c4);
    System.out.println(c5);
    System.out.println(c6);
    System.out.println(c7);
    System.out.println(c8);

    //返回发现hashCode值相等,说明只要类型和维度相同,那么就是同一个Class
    //如果一维数组和二维数组,那么就不是同一个Class
    int [] arr = new int[]{1};
    int [] arrs = new int[]{1,2,3};
    System.out.println(arr.getClass().hashCode()+" "+arrs.getClass().hashCode());
}

基础不够,项目来凑,遇到即学会(注解和反射)_第1张图片

基础不够,项目来凑,遇到即学会(注解和反射)_第2张图片

三、类加载器(将class装载进内存)

  1. 引导类加载器:用C++编写,是JVM自带的类加载器,负责java平台核心库,用来装载核心类库,该加载器无法直接读取
  2. 扩展类加载器:负责jre/lib/ext目录下的jar包或- D java.ext.dirs指定目录下的jar包装入工作库
  3. 系统类加载器:负责java -classpath 或 -D java.class.path所指的目录下的类或jar包装入工作,是最常用的加载器
public static void main(String[] args) {
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//系统加载器 sun.misc.Launcher$AppClassLoader@18b4aac2
    System.out.println(systemClassLoader);
    ClassLoader parent = systemClassLoader.getParent();//扩展类加载器 sun.misc.Launcher$ExtClassLoader@5ce65a89
    System.out.println(parent);
    ClassLoader parent1 = parent.getParent();//引导类加载器 null
    System.out.println(parent1);

    Class c1 = RedisConnectionTest.class;
    ClassLoader classLoader = c1.getClassLoader();//自定义类获取到了系统加载器 sun.misc.Launcher$AppClassLoader@18b4aac2
    System.out.println(classLoader);

    Class c2 = Object.class;//jdk类获取到了引导类加载器 null
    System.out.println(c2.getClassLoader());

    //获取类加载器可以加载的路径
    String property = System.getProperty("java.class.path");
    String[] split = property.split(";");
    Arrays.asList(split).forEach(s-> System.out.println(s));
}

四、反射获取属性、方法、构造方法

public static void main(String[] args) throws Exception {
    //通过反射获取Class
    Class classs = Class.forName("com.test.demolearning.user.entity.User");
    //获取属性
    Field[] fields = classs.getFields();//getFields只能获取public修饰的属性
    Arrays.asList(fields).forEach(field -> System.out.println("getFields: "+field));
    //classs.getField("属性名");获取public修饰的指定属性名
    Field[] declaredFields = classs.getDeclaredFields();//getDeclaredFields可以获取所有的属性
    Arrays.asList(declaredFields).forEach(declaredField -> System.out.println("getDeclaredFields: "+declaredField));
    //classs.getDeclaredField("");获取指定属性名,不受修饰符控制

    Method[] methods = classs.getMethods();//获取本类public修饰的方法及父类public修饰的方法
    Arrays.asList(methods).forEach(method -> System.out.println("getMethods: "+method));
    //classs.getMethod("");获取指定public修饰的方法名,包含父类。可以获取set方法,值可以追加参数类型,classs.getMethod("",属性类型.class)
    Method[] declaredMethods = classs.getDeclaredMethods();//获取本类所有方法,不受修饰符控制,无法获取父类方法
    Arrays.asList(declaredMethods).forEach(declaredMethod -> System.out.println("declaredMethod: "+declaredMethod));
    //classs.getDeclaredMethod("");获取所有方法中指定的方法,不包含父类。获取set和method类似

    Constructor[] constructors = classs.getConstructors();//获取public的构造方法
    Arrays.asList(constructors).forEach(constructor -> System.out.println("constructor: "+constructor));
    //Constructor constructor = classs.getConstructor(String.class, int.class);//获取指定类型的public有参构造
    Constructor[] declaredConstructors = classs.getDeclaredConstructors();//获取所有的构造方法
    Arrays.asList(declaredConstructors).forEach(declaredConstructor -> System.out.println("declaredConstructor: "+declaredConstructor));
    //Constructor declaredConstructor = classs.getDeclaredConstructor(String.class);获取指定类型有参构造,包含私有
}
public static void main(String[] args) throws Exception{
    Class c1 = Class.forName("com.test.demolearning.user.entity.User");
    User user = (User)c1.newInstance();//反射获取实例,如果没有无参构造将报错。可以使用c1.getConstructor(String.class)这类方法找到对应有参构造然后调用newInstance获取实例
    System.out.println(user);
    Method setName = c1.getMethod("setName", String.class);//获取方法
    setName.invoke(user,"纳米");//执行方法
    System.out.println(user);
    Field name = c1.getDeclaredField("id");//获取字段
    name.setAccessible(true);//由于是private修饰,所以需要关闭安全检查开关,可提高反射效率
    name.set(user,"ids");
    System.out.println(user);
}

五、获取泛型信息

public static void main(String [] args) throws Exception{
    Class c1 = User1.class;
    Method method = c1.getMethod("test", Map.class, String.class);
    Type[] genericParameterTypes = method.getGenericParameterTypes();//获取泛型参数类型
    int count = 1;
    for (Type genericParameterType : genericParameterTypes) {//获取所有参数类型进行循环
        System.out.println("最外层" +count+"有: "+ genericParameterType);
        if(genericParameterType instanceof ParameterizedType){//判断如果参数是泛型参数化类型就再往里面取
            //强转参数化类型,getActualTypeArguments获取真实参数方法
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("最外层"+count+"的内层有: "+actualTypeArgument);
            }
        }
        count++;
    }

    Method methodGet = c1.getMethod("test1");
    Type genericReturnType = methodGet.getGenericReturnType();//获取泛型返回型类型
    if(genericReturnType instanceof ParameterizedType){//判断如果是参数化类型
        System.out.println(genericReturnType);
        //强转为参数化类型并获取真是类型
        Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument);
        }
    }
}

class User1{
    public void test(Map<String,Integer> map,String string){

    }
    public Map<String,Integer> test1(){
        return null;
    }
}

六、获取注解信息

@Tests.ClassAnnotation
class TestAnnotations{
    private String name;
    private Integer age;
    @Tests.FieldAnnotation("sex1")
    private Integer sex;

    public TestAnnotations(){}

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    public Integer getSex() {
        return sex;
    }

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

public static void main(String[] args) throws Exception {
    Map<String,String> datas = new HashMap<>();
    datas.put("sex1","男");
    datas.put("sex2","女");
    Class classs = TestAnnotations.class;
    TestAnnotations testAnnotations = new TestAnnotations();
    testAnnotations.setName("names");
    testAnnotations.setAge(18);
    testAnnotations.setSex(1);
    ClassAnnotation annotation = (ClassAnnotation)classs.getAnnotation(ClassAnnotation.class);//获取类上注解
    if(annotation==null){
        System.out.println("没有类注解");
        return;
    }
    Map<String,Object> map = new HashMap<>();
    Field[] fields = classs.getDeclaredFields();
    for (Field field : fields) {
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(classs, field.getName());//通过这个方法可以获取到每个属性
        Object invoke = propertyDescriptor.getReadMethod().invoke(testAnnotations);//通过属性找到它的get方法并执行,获取到对象的值
        map.put(field.getName(),invoke);//将源对象值put到map集合中
        FieldAnnotation fieldAnnotation = (FieldAnnotation)field.getAnnotation(FieldAnnotation.class);//获取字段上注解
        if(fieldAnnotation==null){
            continue;
        }
        String value = fieldAnnotation.value();//获取到字段注解都value值
        String s = datas.get(value);//返回性别
        map.put(field.getName()+fieldAnnotation.sexText(),s);
    }
    System.out.println(map);

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ClassAnnotation{
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FieldAnnotation{
    String value();
    String sexText() default "_text";
}

你可能感兴趣的:(反射及注解,反射,java,class)