美文网首页程序员
java注解与反射,泛型与反射

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

作者: 极微 | 来源:发表于2018-08-06 19:09 被阅读88次

    一、反射与注解

    内置注解

    java内置了3种注解,用来为编译器提供检查。

    @SuppressWarnings
    @Deprecated
    @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注解与反射,泛型与反射

        本文链接:https://www.haomeiwen.com/subject/ozpjvftx.html