• Java基础系列之(一)


      前段时间与一个新手谈论Java基础的时候提到反射,然后对反射的一些问题在这里基本介绍下。在介绍之前,这里了解几个反射的几个概念。

    Class - class是对一个类进行描述的,你可以认为它是一个类的模型。

    Constructor - constructor是一个Class的构造函数,一个Class可以允许重载多个构造函数。

    Field - Filed是用来描述Class的成员变量的。

    Method - method是描述一个Class的方法的。

    Annotation - Annotation是描述Class的注解的,注解可以作用于Class,Method,Filed,Argument之上。

    Generic - Generic指的是泛型,限制参数,返回类型的描述。

    当然其他的还有参数,访问域等一些概念。

    1、Class(类)

      有多种方式如下:

      Class clz = myobject.class;

      动态加载也可以:

      Class clz = Class.forName("类的全名");

     (1) 下面描述的是可以通过Class对象获取构造函数、方法、成员变量、注解等,这里注意的是,这里获取得都是访问范围是public。

            Class clz = Reflection1Test.class;
            
            //获取所有public的构造函数
            Constructor[] constructors = clz.getConstructors();
            //获取参数是String类型的public构造函数
            Constructor constructor = clz.getConstructor(new Class[]{String.class});
            
            //获取所有public方法
            Method[] methods = clz.getMethods();
            //获取方法名称是"test",参数类型分别是List和String,而且是public的方法
            Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});
            
            //获取指定的枚举类型的枚举
            Annotation annotation = clz.getAnnotation(Reflection1Test.class);
            //获取该类的所有枚举
            Annotation[] annotations = clz.getAnnotations();

    (2) 类的修饰范围

      

    Class clz = Reflection1Test.class;
    int modifiers = clz .getModifiers();

    这里返回的是一个int值,int里面存储的信息包含public,private,protected,final,abstract,interface,native,static,synchronized,Transient,Volatile。这里稍稍提下存储原理,基本原理采用的是二进制的占位思想,之前我的一篇文章bitmap里面也是用的是二进制占位的算法。public,private,protected,final,abstract,interface,native,static,synchronized,Transient,Volatile每个定义一个二进制的位置。例如:

        public static final int PUBLIC           = 0x00000001;
    public static final int PRIVATE = 0x00000002; public static final int PROTECTED = 0x00000004; public static final int STATIC = 0x00000008; public static final int FINAL = 0x00000010; public static final int SYNCHRONIZED = 0x00000020; public static final int VOLATILE = 0x00000040; public static final int TRANSIENT = 0x00000080; public static final int NATIVE = 0x00000100; public static final int INTERFACE = 0x00000200; public static final int ABSTRACT = 0x00000400; public static final int STRICT = 0x00000800;

    这样的话,假如一个Class既是public,又是final,这个时候她的modifier值就是public+final。

    当然你想判断它是否是public还是final,JDK提供一个modifier类专门处理,如下:

    Modifier.isAbstract(int modifiers);
    Modifier.isFinal(int modifiers);
    Modifier.isInterface(int modifiers);
    Modifier.isNative(int modifiers);
    Modifier.isPrivate(int modifiers);
    Modifier.isProtected(int modifiers);
    Modifier.isPublic(int modifiers);
    Modifier.isStatic(int modifiers);
    Modifier.isStrict(int modifiers);
    Modifier.isSynchronized(int modifiers);
    Modifier.isTransient(int modifiers);
    Modifier.isVolatile(int modifiers);

    2、Constructor(构造函数)

      (1) 获取构造函数

        上面已经提到过了。怎么获取构造函数:
             

    //获取所有public的构造函数
    Constructor[] constructors = clz.getConstructors();

      上面返回的是一个public的构造函数数组。

      如果你像返回指定的构造函数,需要提供构造函数的参数类型。

    Constructor constructor = clz.getConstructor(new Class[]{String.class});

     返回的也是public的构造函数,如果没有找到指定的构造函数,就会抛NoSuchMethodException。

    (2) 构造函数的参数类型

      

    Class[] cType = constructor.getParameterTypes();

    (3) 构造函数实例化

     我们都知道构造函数是一个对象实例化的入口,或者说是new的时候要首先调用的特殊方法。那么Constructor肯定能够实例化一个对象的。

    try {
                MyObject obj = (MyObject)constructor.newInstance(new Object[]{"123",new ArrayList<String>()});
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

    constructor.newInstance()需要提供一个可变的参数列表,提供的参数必须和声明的构造函数的值和类型都一一对应。

    3、Field(变量)

    (1)获取Field对象

            //获取所有public成员变量
            Field[] fields = clz.getFields();
            //获取名称是name的public的变量
            Field field = clz.getField("name");

    这里也一样,返回的都是public修饰符的变量,如果找不到指定匹配的变量名称,会抛NoSuchFieldException异常。

    (2)获取Field的名称和类型

            //获取变量的名称
            String name = field.getName();
            
            //获取变量的类型
            Class fieldType = field.getType();

    (3)get/set Field的值

            MyObject obj = new MyObject();
            field = clz.getField("name");
            //获取obj对象的name变量的值
            Object object = field.get(obj);
            //设置obj对象的变量name的值为123
            field.set(obj, "123");

    这里通过变量的对象来获取它的值,并且能修改它的值。当然这里依然遵照的是public的原则。

    (4)访问私有变量

     上面已经说过了,上面访问都是public的变量,那么,私有变量怎么访问呢?如下:

            //获取所有声明的变量
            Field[] declaredFields = clz.getDeclaredFields();
            Field declaredField = clz.getDeclaredField("privateString");
            //私有变量必须先将访问权限设置为true
            declaredField.setAccessible(true);
            Object o = declaredField.get(test2);

    declaredField.setAccessible(true)代码是关闭字段的访问检查。

    4、Method(方法)

    (1)获取Method对象

            //获取所有public方法
            Method[] methods = clz.getMethods();
            //获取方法名称是"test",参数类型分别是List和String,而且是public的方法
            Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});

    如果没有找到指定匹配的Method,会抛NoSuchMethodException异常。

    (2)获取Method的参数

            //获取Method的参数类型
            Class[] parameterTypes = method.getParameterTypes();

    因为一个方法的参数可以是多个,所以返回的是一个数组。

    (3)获取Method的返回值

            
            //返回Method返回值的类型
            Class returnType = method.getReturnType();

    这里有人就问,如果没有返回值呢,如果是void的呢,其实void也可以看成一个返回值,空返回值的。所以void的方法返回的直接是void。

    (4)Method调用

    定义一个test方法,有两个参数,如下:

        public void test(List s,String s1){
            System.out.println("调用了Test");
        }
        Reflection1Test test = new Reflection1Test("");
            //调用Reflection1Test对象的test方法
            Object returnValue = method.invoke(test, new Object[]{new ArrayList(),"123"});

    这里有一个小细节,如果test是null的话,调用的是方法必须是static。

    (5)访问私有方法

            Reflection1Test test3 = new Reflection1Test("");
            //获取所有声明的方法
            Method[] declaredMethods = clz.getDeclaredMethods();
            Method declaredMethod = clz.getDeclaredMethod("test", new Class[]{java.util.List.class,String.class});
            declaredMethod.setAccessible(true);
            Object returnValue2 = declaredMethod.invoke(test3, new Object[]{new ArrayList(),"123"});

    与Field一样setAccessible(true)关闭反射的权限检查。

    5、Annotation(注解)

    注解的简单理解就是在类、方法、变量上打一个标签,这个标签为了具体说明它的实际意义,对类、方法、变量没有实际应用意义。

    (1)定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Inherited
    @Documented
    public @interface AnnotationTest {
        String value() default "";
    }

    注解定义是在interface前面带一个@符号,这就说明是一个注解,一般有几个定义规则。

    @Retention - 定义注解存在的周期,RetentionPolicy有三个值,Source,Class,RUNTIME。
      RetentionPolicy.Source 表示只是在源码中存在,编译的时候就被丢弃了。
      RetentionPolicy.Class 表示编译的时候注入到Class中,但是VM加载的时候会丢弃。
      RetentionPolicy.RUNTIME 表示注解会被VM加载进去,在运行期能够调用。


    @Target - 定义注解的作用范围,一般作用于类、方法、变量、构造函数。
    • ElementType.ANNOTATION_TYPE
    • ElementType.CONSTRUCTOR
    • ElementType.FIELD
    • ElementType.LOCAL_VARIABLE
    • ElementType.METHOD
    • ElementType.PACKAGE
    • ElementType.PARAMETER
    • ElementType.TYPE

    其中,ANNOTATION_TYPE是针对注解用的,在注解定义上被应用的

      @Inherited - 能够被子类复用。

    @Inherited
    public @interface MyAnnotation {
    
    }
    @MyAnnotation
    public class MySuperClass { ... }
    
    public class MySubClass extends MySuperClass { ... }
    @Documented - 能够在文档显示的。
    @Documented
    public @interface MyAnnotation {
    
    }
    @MyAnnotation
    public class MySuperClass { ... }

    (2)使用注解

    1、类注解
    @AnnotationTest(value="chs")
    public class Reflection1Test {...}

    下面是访问类的注解的例子:
            Class clz = Reflection1Test.class;
            
            //获取类的所有注解
            Annotation[] annotations = clz.getAnnotations();
            //获取注解类型是AnnotationTest
            Annotation annotation = clz.getAnnotation(AnnotationTest.class);
            if(annotation instanceof AnnotationTest){
                AnnotationTest annotationTest = (AnnotationTest)annotation;
                System.out.println(annotationTest.value());
            }

    2、方法注解
        @AnnotationTest(value="chs2")
        public Reflection1Test(String s){
            
        }

    下面是访问方法注解的例子:

            Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});
            
            Annotation[] annotations2 = method.getAnnotations();
    
            Annotation annotation2 = method.getAnnotation(AnnotationTest.class);
            if(annotation instanceof AnnotationTest){
                AnnotationTest annotationTest = (AnnotationTest)annotation;
                System.out.println(annotationTest.value());
            }

    3、变量注解
        @AnnotationTest(value="chs2")
        private String privateString;

    下面是变量访问注解的例子:

            Field field = clz.getField("name");
            
            Annotation[] annotations3 = field.getAnnotations();
    
            Annotation annotation3 = field.getAnnotation(AnnotationTest.class);
            if(annotation instanceof AnnotationTest){
                AnnotationTest annotationTest = (AnnotationTest)annotation;
                System.out.println(annotationTest.value());
            }

    4、参数注解

        public void test(List s,@AnnotationTest String s1){
            System.out.println("调用了Test");
        }

    下面是参数访问注解的例子:

            Annotation[][] Annotations5 = method.getParameterAnnotations();
            Class[] parameterTypes = method.getParameterTypes();
            
            int i=0;
            for(Annotation[] annotations21 : Annotations5){
              Class parameterType = parameterTypes[i++];
              for(Annotation annotation12 : annotations21){
                if(annotation12 instanceof AnnotationTest){
                    AnnotationTest myAnnotation = (AnnotationTest) annotation12;
                    System.out.println("param: " + parameterType.getName());
                    System.out.println("value: " + myAnnotation.value());
                }
              }

    5、Generic(泛型)

    泛型的应用非常广,一般使用的时候,是在定义一个参数化(可变的)的类或者接口,说白了,你根本不知道运行的时候应该具体哪一种类型,但是你知道是一个可变参数。你不能再运行的时候知道被参数化的类的类型是什么,当你具体使用这个类的时候,你可以显示指定它。

    总之是,定义的时候不知道具体类型,使用的时候需要指定具体的类型。

    (1)返回值是一个泛型类型

        public List<String> getList(){
            return null;
        }

    下面是访问返回值的泛型类型的例子:

    Method method = Reflection1Test.class.getMethod("getList", null);
    
    Type return = method.getGenericReturnType();
    
    if(return instanceof ParameterizedType){
        ParameterizedType type = (ParameterizedType) return ;
        Type[] arguments = type.getActualTypeArguments();
        for(Type argument : arguments ){
            Class argClz = (Class) argument ;
            System.out.println("argClz = " + argClz );
        }
    }

    (2)方法的参数是一个泛型类型

        
        public void setList(List<String> list){
        }

    下面是一个方法参数的泛型类型访问的例子:

    Method method = Reflection1Test.class.getMethod("setList", List.class);
    
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    
    for(Type genericParameterType : genericParameterTypes){
        if(genericParameterType instanceof ParameterizedType){
            ParameterizedType pType = (ParameterizedType) genericParameterType;
            Type[] argTypes = pType.getActualTypeArguments();
            for(Type parameterType : argTypes){
                Class parameterArgClz= (Class) parameterType;
                System.out.println("parameterArgClass = " + parameterArgClz);
            }
        }
    }

    (3)变量的类型是一个泛型类型

        public List<String> list;

    下面是一个变量的泛型类型访问的例子:

    Field field = Reflection1Test.class.getField("list");
    
    Type genericType = field.getGenericType();
    
    if(genericType instanceof ParameterizedType){
        ParameterizedType pType = (ParameterizedType) genericType;
        Type[] argTypes = pType.getActualTypeArguments();
        for(Type argType : argTypes){
            Class argClz = (Class) argType;
            System.out.println("Class = " + argClz);
        }
    }
    至此,java反射基本介绍如此,下一张准备说下ArrayList、LinkedList、HashMap等数据结构的源码。 
     
     
  • 相关阅读:
    NFS-heartbeat-drbd模拟NFS高可用
    drbd
    hearbeat
    ldap
    SVN
    Nginx负载均衡
    shell-day1
    angularJS(二):作用域$scope、控制器、过滤器
    angularJS(一):表达式、指令
    nodejs、npm、 typescript、angular-cli安装
  • 原文地址:https://www.cnblogs.com/wuhuangdi/p/4140478.html
Copyright © 2020-2023  润新知