导航

Java 反射机制

Posted on 2017-10-14 17:52  耍流氓的兔兔  阅读(214)  评论(0编辑  收藏  举报

 

Java反射机制:

  参考博客:http://www.cnblogs.com/bojuetech/p/5896551.html

  Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及状态调用对象的方法的功能成为Java语言的反射机制

Class:描述类本身的类

  Class是一个类,一个描述类的类(即描述类本身),封装了 描述方法的Method,描述字段的Field,描述构造器的Contstructor等属性

  对象反射可以得到的信息:某个类的数据成员名、方法和构造器、类实现的接口

  对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个类的有关信息

  Class对象只能由系统建立对象

  一个类在JVM中只会有一个Class实例

反射机制获取类有三种方法:

  直接通过类名.class

clazz = Person.class;  

  通过对象的getClass()方法获取

    Object obj = new Person();  
    clazz = obj.getClass();  

  通过全类名获取,但可能抛出ClassNotFoundException异常

clazz = Class.forName("com.java.reflection.Person");  

clazz使用newInstance创建对象:

  使用Class类的newInstance()创建类的一个对象

  实际调用的是类的无参构造器(所以写类的时候,要写一个无参的构造器)

Class clazz = Class.forName("com.java.reflection.Person");  
  
Object obj = clazz.newInstance();  

ClassLoader加载器:

  类加载器是用于将类装入JVM的

  JVM有两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)

  JVM运行时会产生3个类加载器组成的初始化加载器层次结构:

public void testClassLoader1() throws ClassNotFoundException, IOException {  
    //1、获取一个系统的类加载器  
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();  
    System.out.println("系统的类加载器-->" + classLoader);  
  
    //2、获取系统类加载器的父类加载器(扩展类加载器(extensions classLoader))  
    classLoader = classLoader.getParent();  
    System.out.println("扩展类加载器-->" + classLoader);  
  
    //3、获取扩展类加载器的父类加载器  
    //输出为Null,无法被Java程序直接引用  
    classLoader = classLoader.getParent();  
    System.out.println("启动类加载器-->" + classLoader);  
  
  
    //4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器  
    classLoader = Class.forName("com.java.reflection.Person").getClassLoader();  
    System.out.println("当前类由哪个类加载器进行加载-->"+classLoader);  
  
    //5、测试JDK提供的Object类由哪个类加载器负责加载的  
    classLoader = Class.forName("java.lang.Object").getClassLoader();  
    System.out.println("JDK提供的Object类由哪个类加载器加载-->" + classLoader);  
}  

 Method:对应类中的方法

    Class clazz = Class.forName("com.java.reflection.Person");  
  
    //1、得到clazz 对应的类中有哪些方法,不能获取private方法  
    Method[] methods = clazz.getMethods();  
    System.out.print("\ngetMethods: ");  
    for (Method method : methods){  
        System.out.print(method.getName() + ", ");  
    }  
  
    //2、获取所有的方法(且只获取当着类声明的方法,包括private方法)  
    Method[] methods2 = clazz.getDeclaredMethods();  
    System.out.print("\ngetDeclaredMethods: ");  
    for (Method method : methods2){  
        System.out.print(method.getName() + ", ");  
    }  
  
    //3、获取指定的方法  
   //第一个参数是方法名,后面的是方法里的参数
Method method = clazz.getDeclaredMethod("setName",String.class); System.out.println("\nmethod : " + method);
   //第一个参数是方法名,后面的是方法里的参数 Method method2
= clazz.getDeclaredMethod("setName",String.class ,int.class); System.out.println("method2: " + method2); //4、执行方法! Object obj = clazz.newInstance(); method2.invoke(obj, "draco", 17);

Methos.invoke()方法:调用Method对象表示的底层方法

public Object invoke(Object obj,
                     Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

 

  obj:调用底层方法的对象(调用谁的方法就是用谁的对象)

  args:方法调用的参数

Field字段:

 Class clazz = Class.forName("com.java.reflection.Person");  
  
    //1、获取字段  
    //1.1 获取Field的数组,私有字段也能获取  
    Field[] fields = clazz.getDeclaredFields();  
    for (Field field: fields) {  
        System.out.print(field.getName() + ", ");  
    }  
  
    //1.2 获取指定名字的Field(如果是私有的,见下面的4)  
    Field field = clazz.getDeclaredField("name");  
    System.out.println("\n获取指定Field名=: " + field.getName());  
  
    Person person = new Person("draco", 17); 
//2、获取指定对象的Field的值 Object val = field.get(person); System.out.println("获取指定对象字段'name'的Field的值=: " + val); //3、设置指定对象的Field的值 field.set(person, "harry"); System.out.println("设置指定对象字段'name'的Field的值=: " + person.name); //4、若该字段是私有的,需要调用setAccessible(true)方法 Field field2 = clazz.getDeclaredField("age"); field2.setAccessible(true); System.out.println("获取指定私有字段名=: " + field2.getName());

Constructor:构造器

   String className = "com.java.reflection.Person";  
    Class<Person> clazz = (Class<Person>) Class.forName(className);  
  
    //1.获取Constructor对象  
    Constructor<Person>[] constructors =  
            (Constructor<Person>[]) Class.forName(className).getConstructors();  
  
    for (Constructor<Person> constructor: constructors) {  
        System.out.println(constructor);  
    }  
  
    Constructor<Person> constructor = clazz.getConstructor(String.class, Integer.class);  
    System.out.println("指定的-->" + constructor);  
  
    //2.调用构造器的newInstance()方法创建对象  
    Object obj= constructor.newInstance("ron", 11);  

Annotation:注解

  Annotation是代码中的特殊标记,可以在编译、类加载、运行时被读取,并执行相应的处理;通过Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入补充信息

  Annotation可以象修饰符一样被使用,可用于修饰包、类、构造器、方法、参数、成员变量、局部变量的声明,这些信息被保存在Annotation的“name=value”中

  Annotation能用于为程序元素(类、方法、成员变量等)设置元数据

  基本的Annotatio:

    使用时在前面加@

    @override:限定重写父类方法

    @Deprecated:用于表示某个程序元素(类、方法等)已过时

    @SuppressWarnings:抑制编译器警告

  自定义的Annotation:

    使用@interface关键字

    Annotation的成员变量在Annotation定义中以无参数的形式声明,其方法名和返回值定义了该成员的名字和类型

    可以在定义Annotation的成员变量时为其指定初始值,指定成员变量的初始值可以使用default关键字

    没有成员定义的Annotation称为标记,包含成员变量的Annotation称为元数据Annotation