zoukankan      html  css  js  c++  java
  • 简介Java反射基础

    【参考资料: 疯狂Java讲义 Chapter 18】

    1、类加载、连接、初始化

      当Java程序需要某一个类时,如果该类尚未加载到内存中,系统会通过加载、连接、初始化三个步骤将该类加载到内存,并完成初始化工作。

    • 类加载:将类的class文件加载到内存,并为之创建一个java.lang.Class对象。类的加载是通过类加载器,类加载器由JVM提供,统称为系统类加载器。除了利用JVM提供的类加载器,我们还可通过继承java.lang.ClassLoader来编写自己的类加载器。一旦一个类被载入JVM,同一个类(用类的全限定名和类的类加载器作为唯一标识)就不会被重复载入了。
    • 类连接:将类的二进制数据合并到JRE中。
    • 类初始化:JVM对类进行初始化,主要是针对静态属性进行初始化。

    2、类加载器

      JVM启动时,会形成由三个类加载器类组成的初始类的加载器层次结构:

    • 根类加载器(Bootstrap classLoader):负责加载Java的核心类。根类加载器是由JVM自身实现的,并非ClassLoader的子类。
    • 扩展类加载器(Extension ClassLoader):负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs属性所指定的目录)中JAR的类包。
    • 系统类加载器(System ClassLoader):在JVM启动时,负责加载来自命令java中的-classpath或java.class.path系统属性或CLASSPATH环境变量所指定的JAR包和类路径。程序中可通过ClassLoader.getSystemClassLoader()获取该类加载器。

      三个类加载器之间的层次关系:

      

    3、通过反射操作类

    1)获取java.lang.Class对象的常用方式

    • Class类的静态方法forName(String className)。其中传入的className参数为类的全限定名。
    • 调用类的class属性来获取该类的Class对象。如Class strClass = String.class。
    • 调用对象的getClass()方法。

    2)Class类提供的接口

      获取Class对象所对应类的构造器的接口:

    1 Constructor<T> getConstructor(Class<?>... parameterTypes) //返回对应该类的public的构造器,构造器参数列表的类型声明次序符合parameterTypes类型声明次序,被封装成了Constructor对象
    2 Constructor<?>[] getConstructors() //获取所有public构造器
    3 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //返回对应parameterTypes类型声明次序的该类的构造器,与访问级别无关
    4 Constructor<?>[] getDeclaredConstructors()//返回所有的构造器,与访问级别无关

    5 Constructor<?> getEnclosingConstructor() //用于匿名类或内部类

      获取Class对象对应类的方法的接口:

    1 Method getMethod(String name, Class<?>... parameterTypes); //返回由方法名name和参数列表类型parameterTypes限定的public方法
    2 Method[] getMethods(); //所有public方法
    3 Method getDeclaredMethod(String name, Class<?>... parameterTypes); //返回由方法名和参数列表类型parameterTypes限定的方法,与访问级别无关
    4 Method[] getDeclaredMethods(); //所有方法

    5 Method getEnclosingMethod(); //用于获取内部类或匿名类的方法

      获取Class对象对应类所包含的属性的接口:

    1 Field getField(String name); //返回对应name的public 属性
    2 Field[] getFields();  //所有public属性
    3 Field getDeclaredField(String name);
    4 Field[] getDeclaredFields();

    【注:方法名中带有Declared的方法返回的构造器、方法或属性等都是忽略访问级别的;而不带有Declared的方法返回public的类成员。】

      访问Class对应类的注释的接口:

    1 <A extends Annotation> A getAnnotation(Class<A> annotationClass); //返回符合特定注解类型annotationClass的注解
    2 Annotation[] getAnnotations(); //当前Class的所有注解
    3 Annotation[] getDeclaredAnnotations(); //直接出现在当前元素上的注解

      Class中用于判断该Class是否为注释类型、数组类型、接口类型的接口:

    1 boolean isAnnotation();
    2 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); //判断是否出现了特定类型的注解
    3 boolean isAnonymousClass();
    4 boolean isArray();
    5 boolean isEnum();
    6 boolean isInstance(Object obj); //判断obj类型是否与当前Class对应的类型兼容
    7 boolean isInterface();
    8 boolean isLocalClass();
    9 boolean isPrimitive();

      其他接口:

    1 String getName();//返回该Class代表的类或接口的全称
    2 String getPackage(); //返回包名
    3 String getSimpleName(); //Class对应类的简称
    4 Class<? super T> getSuperclass(); //返回超类

      对于上述接口中出现的Class<?>... parameterTypes,是指定的参数列表的Class对象。如:

     1    public class ReflectionTest{
     2 
     3     private int privateAttribute = -1;
     4     public int publicAttribute = -2;
     5     
     6     public String publicStrAttribute = "DefaultString";
     7     
     8     
     9     public void info(){
    10         System.out.println("This is info() of class ReflectionTest");
    11     }
    12     
    13     public void info(String str){
    14         System.out.println("This is info(String) of class ReflectionTest");
    15     }
    16     
    17     public void info(String str, Integer num){
    18         System.out.println("This is info(String, Integer) of class ReflectionTest");
    19     }
    20     
    21     private void privateInfo(){
    22         System.out.println("This is privateInfo method");
    23     }
    24  
    25     public static void main(String[] args) throws Exception{
    26         Class<ReflectionTest> testClass = ReflectionTest.class;
    27   
    28         Method info1 = testClass.getMethod("info", null);
    29           System.out.println("方法参数列表长度: "+info1.getParameterTypes().length);
    30       
    31           Method info2 = testClass.getMethod("info", String.class);
    32           System.out.println("方法参数列表长度: "+info2.getParameterTypes().length);
    33       
    34           Method info3 = testClass.getMethod("info", String.class, Integer.class);
    35           System.out.println("方法参数列表长度: "+info3.getParameterTypes().length);
    36     }
    37 }

     3)通过反射生成并操作对象

    • 通过Class对象的newInstance方法
    • 通过Class对象获取对应类的Constructor,再通过Constructor对象的newInstance方法
    1         Class<ReflectionTest> testClass = ReflectionTest.class;
    2         
    3         //通过Class对象构造Class对应类的实例
    4         ReflectionTest rt1 = testClass.newInstance();
    5         Constructor constructor = testClass.getConstructor(null);
    6         ReflectionTest rt2 = (ReflectionTest)constructor.newInstance(null);  //调用默认构造函数,参数列表为空

    【注:代码基于ReflectionTest类】

    4)调用方法

    • public方法,直接通过Method对象的Object invoke(Object obj,Object... args)方法;其中obj为调用该方法的Class对应类的实例,args为方法的参数。
    1         Object newTest = constructor.newInstance(null);
    2         Method info = testClass.getMethod("info", null);
    3         info.invoke(newTest, null); 
    •  private方法,首先要调用Method类的setAccessible(boolean flag)方法,否则报错:java.lang.NoSuchMethodException

      然后调用private方法:

    1         Method privateMethod = testClass.getDeclaredMethod("privateInfo", null); //获取private方法使用getDeclaredMethod方法
    2         privateMethod.setAccessible(true);
    3         privateMethod.invoke(newTest, null);

     5)操作属性值

    • 操作8个基本类型时,使用Field的getXXX(Object obj)或setXXX(Object obj, XXX value),其中obj为被访问的Class对应的类。
    • 操作引用类型时,使用Field的get(Object obj)或set(Object obj, Object value)
     1         //操作属性
     2         Field privateField = testClass.getDeclaredField("privateAttribute"); //私有属性
     3         System.out.println(privateField.getInt(newTest));
     4         privateField.setInt(newTest, -1000);
     5         System.out.println(privateField.get(newTest));
     6         
     7         Field strField = testClass.getField("publicStrAttribute"); //公有属性
     8         System.out.println(strField.get(newTest));
     9         strField.set(newTest, "test value");
    10         System.out.println(strField.get(newTest));

     6)操作数组

      java.lang.reflect包下含有Array类,Array类提供了可以动态创建和访问Java数组的静态方法。

      主要接口:

    1 static static Object newInstance(Class<?> componentType, int... dimensions); //多维度的数组
    2 static Object newInstance(Class<?> componentType, int length); //指定数组长度的数组
    3 
    4 static XXX getXXX(Object array, int index);      //对于8中基本类型
    5 static void setXXX(Object array, int index, XXX newValue);
    6 
    7 static Object get(Object array, int index);  //对于引用类型
    8 static void setXXX(Object array, int index, Object newValue);
  • 相关阅读:
    基于docker swarm的搭建高可用web集群
    软链接和硬链接的区别
    PTA(Basic Level) Practice 刷题(部分) Python实现
    使用官方提供的方式在CentOS上安装docker
    mysql表分区的限制
    有个免费云服务器速度很快!
    PhpMyAdmin 配置文件现在需要一个短语密码的解决方法
    Django笔记:Memcached缓存系统
    Django笔记:文件上传
    Django笔记:表单验证
  • 原文地址:https://www.cnblogs.com/-crazysnail/p/3929125.html
Copyright © 2011-2022 走看看