java之反射

反射机制可以通过reflection API取得任何类的内部信息,并能操作任意对象内部的属性和方法

1.  java.lang.class 类 类的源头,新建类之后通过编译生成.class文件,通过JVM的类加载器,加载此.class文件,此.class问价加载到内存之后,就是一个运行时类。存在缓存区。这个运行时类本身就是一个Class的实例。每一个运行时类只加载一次。

java.lang.reflect.field 类的属性

java,lang.method 类的方法

eg://1. 调用运行时类的属性

  Class<Person> clazz = Person.class;

  Person p = clazz.newInstance();

  Field f1 = p.getField("name");

  f1.set(p,"zhouxingchi");

  //获取全部属性(可以获取Person类及其父类中声明为public的全部属性)

  Field[] fs = p.getFields();

  //当属性 定义为private时 也可以调用

  Field f2 = p.getDeclaredField("age");

  //获取Person类本身所有的属性,无论声明权限时什么。。

  Field[] f4 = p.getDeclaredFields();

  //获取权限修饰符,属性类型

  for(Field f: f4){

   int i = f.getModifiers();

   String str1 = Modifir.toString(i);

  //属性类型

    Class type  = f.getType();

    type.getName();

//属性名

   f.getName();

}

  f2.setAccessible(true);

  f2.set(p,20);

  System.out.println(p);

//2. 调用运行时类的方法

  Class<Person> clazz = Person.class;

  Person p = clazz.newInstance();

  Method m1 = clazz.getMethod("show",String.class); // clazz.getMethod("方法名",参数类型);

  m1.invoke(p,"HK"); //m1.invoke(p,"参数");

//获取全部的Methods 类似于获取全部的Fileds  

//获取Methods之后,可以获取 其注解  权限修饰符  返回值类型 方法名 形参列表

//获取构造器等  不分权限和参数的数量

  Class<Person> clazz = Person.class;

  Person p = clazz.newInstance();

  Constructor[] cons = clazz.getDeclaredConstructors();

  for(constructor c: cons)

    //即可遍历出构造器

//获取运行时类的父类

  Class<Person> clazz = Person.class;

  Class super = clazz.getSuperClass(); //不带泛型

  Type type1 = clazz.getGenericSuperClass(); //带泛型(如果父类带泛型的话)

   //获取父类的泛型  

  Parameterized param =(Parameterized )type1;

  Type[] params = param.getActualTyoeArguments();

//获取实现的接口

  Class[] interfaces = clazz.getInterfaces();

//获取所在的包

  Package pack = clazz.getPackage();

//获取注解 ——类上面的@Xxx 等注解(@Retention(RetentionPolicy.RUNTIME),@Target())

 Annotation[] anns =clazz.getAnnotations(); 

扩展:1.元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention, //注解有效期
    3.@Documented,
    4.@Inherited
  这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

  1.1.@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  1.2. @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  

作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

 取值(RetentionPoicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值

  1.3 @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

  1.4 @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

   1.5 自定义注解:

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

  定义注解格式:
  public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

    1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
    2.String类型
    3.Class类型
    4.enum类型
    5.Annotation类型
    6.以上所有类型的数组

  Annotation类型里面的参数该怎么设定: 
  第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
  第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
  第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

2.  获取Class类的4种方式

1.调用运行时类本身的.class属性

Class clazz = String.class;

2,通过运行时类的对象获取

Person p = new Person();

Class clazz = p.getClass();

3.通过Class的静态方法获取:体现反射的动态性

String className = “java.util.commons”;

Class clazz = Class.forName(className);

4.通过类的加载器

String className = “java.util.commons”;

ClassLoader classLoader = this.getClass().getClassLoader();

Class clazz = classLoader.loadClass(className);

 

 

  

posted @ 2018-10-12 09:55  wsjun  阅读(167)  评论(0编辑  收藏  举报