java注解与反射,泛型与反射

96
极微
2018.08.06 19:09* 字数 1039

一、反射与注解

内置注解

java内置了3种注解,用来为编译器提供检查。
1、@SuppressWarnings
2、@Deprecated
3、@Override

自定义注解

元注解

元注解是用来修饰注解的注解,java提供了3种元注解。
1、@Retention
 RetentionPolicy.SOURCE 表明注解仅存在源码之中,不存在.class文件,更不能运行时可见。常见的注解为@Override, @SuppressWarnings。
 RetentionPolicy.CLASS 这是默认的注解保留策略。这种策略下,注解将存在与.class文件,但是不能被运行时访问。通常这种注解策略用来处理一些字节码级别的操作。
 RetentionPolicy.RUNTIME 这种策略下可以被运行时访问到。通常情况下,我们都会结合反射来做一些事情。
2、@Target 注解修饰的位置
3、@Inherited 注解是否可以被子类继承

自定义注解并使用

如下定义了一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.FIELD})
@Inherited
public @interface MyAnnotation {
    
    String name();
    
    String value() default "";
    
}

在user中使用了这个注解,并通过反射获取使用的注解

package testreflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

class User {
    @MyAnnotation(name = "xiaohua")
    private String name;

    public User() {

    }

    public User(String name) {
        this.name = name;
    }

    @MyAnnotation(name = "xiaoming", value = "hello")
    public void sayHi() {
        System.out.println("hi:i am " + name);
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return name.toString();
    }
}

public class GetAnnotation {
    @SuppressWarnings("unchecked")
    public static void main(String[] args)
            throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        /**
         * 获取类模板,一般用.class
         */
        Class<User> clazz = User.class;//不会初始化静态块,不会初始化非静态块,不会调用构造函数
        Object obj = new User();
                clazz=(Class<User>) Class.forName("testreflect.User");//会初始化类静态块,但不会初始化非静态的代码块,也不调用构造函数
        clazz = (Class<User>) obj.getClass();//会先初始化静态块,接着执行非静态块的初始化,最后调用构造函数
        
        /**
         * 获取类模板信息
         */
        System.out.println(clazz.getName());
        // 获取自有属性
        Field[] fields = clazz.getDeclaredFields();
        // 获取自有方法
        Method[] methods = clazz.getDeclaredMethods();
        // 获取构造器
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        /**
         * 执行方法,修改属性
         */
        // 新建对象
        Constructor<User> constructor = clazz.getDeclaredConstructor(String.class);
        User xiaoming = constructor.newInstance("xiaoming");
        System.out.println(xiaoming);
        // 调用方法
        Class<String>[] emptyClass = (Class<String>[]) new Class<?>[] {};// 泛型数组的替代解决方案
        Method method = clazz.getDeclaredMethod("sayHi", emptyClass);
        method.invoke(xiaoming, new Class<?>[] {});
        // 修改属性
        Field field = clazz.getDeclaredField("name");// public的属性
        field.setAccessible(true);field.set(xiaoming, "lihua");field.setAccessible(false);
        method.invoke(xiaoming, new Object[0]);
        /**
         * 读取注解
         */
        // 获取修饰类的注解
        Annotation[] annotations = clazz.getAnnotations();
        MyAnnotation myAnnotation = clazz.getAnnotation(MyAnnotation.class);
        // 获取方法参数注解
        Annotation[][] mAnnotations = method.getParameterAnnotations();// 二维数组,第一个代表参数个数,第二个代表参数注解
    }
}

二、反射与泛型

泛型的引入

Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是编译一旦完成,所有和泛型有关的类型全部被擦除。
为了通过反射操作这些类型以迎合实际开发的需要,Java新增了以下几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型:
 ParameterizedType:表示一种参数化的类型,比如Collection<>
 GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型,比如比如List<>[],T[]这种。
 TypeVariable:是各种类型变量的公共父接口类型变量,如参数化类型中的E、K等类型变量,表示泛指任何类,如果加上extends/super限定,则就会有相应的上限、下限。
 WildcardType:代表一种通配符类型表达式,比如?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)
加入之后java中的类型如下:

  1. raw type:原始类型,对应Class, 包括数组、接口、注解、枚举等结构。
  2. parameterized types:参数化类型,对应ParameterizedType
  3. array types:参数化数组类型,对应GenericArrayType
  4. type variables:参数化类型变量,对应TypeVariable
    分析:
    List<T ? entends>[]:这里的List就是ParameterizedType,T就是TypeVariable,T ? entends就是WildcardType(注意,WildcardType不是Java类型,而是一个表达式),整个List<T ? entends>[]就是GenericArrayType。

泛型数组?

java禁止创建泛型数组,理由是下述代码产生的安全问题:
//创建list<String>数组
List<String>[] lsa = new List<String>[10]; //1
//转化为Object数组
Object o = lsa;
Object[] oa = (Object[]) o;
//赋值list<Integer>数组
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li;
//获取第一个位置的值
String s = lsa[1].get(0); //2
如果在1出允许使用泛型数组,那么2处在运行过程中会出现类型转换异常。
泛型数组的替代解决方法是使用?,如下:
List<?>[] lsa = new List<?>[10]; //1
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li;
String s = (String) lsa[1].get(0); //2
根据通配符的定义及泛型擦除的保留上界原则,在2处返回的是Object,所以需要做显示的类型转化。
总结:要想使用泛型数组,要求程序员必须执行一次显示的类型转换,也就是将类型检查的问题从编译器交给了程序员。java的设计思想正是如此。

反射获取泛型

package testreflect;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

class User<T> {

    public void sayHi(T t) {
        System.out.println("hi,i am:" + t.toString());
    }

    public void syaHello(Map<String, Object> map) {
        for (Object str : map.values()) {
            System.out.println("hi,i am:" + str.toString());
        }
    }
}

public class GetGenerics {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Class<User> uclass = User.class;
        {
            // 获取类方法
            Method method = uclass.getMethod("sayHi", Object.class);
            // 获取指定方法参数的泛型信息
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(type);
                if (type instanceof ParameterizedType) {
                    Type[] genericTypes = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type t : genericTypes) {
                        System.out.println(t);
                    }
                }
            }
        }
        {
            // 获取类方法
            Method method = uclass.getMethod("syaHello", Map.class);
            // 获取指定方法参数的泛型信息
            Type[] types = method.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(type);
                if (type instanceof ParameterizedType) {
                    Type[] genericTypes = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type t : genericTypes) {
                        System.out.println(t);
                    }
                }
            }
        }
        /**
         * 打印结果:
         * T
         * java.util.Map<java.lang.String, java.lang.Object>
         * class java.lang.String
         * class java.lang.Object
         * 
         */
    }
}

java
Web note ad 1