2016-11-5

Java 反射机制

1. 映射类的创建三种方法

  1. String.class,
  2. Class.forName("完整类名"),
  3. new String("abc").getClass()实例创建 ;
String str ="acc";
String str2 ="accd";
System.out.println( String.class == str.getClass());//true 内存中只有一份该类的映射类,
System.out.println( String.class == str2.getClass() );//true
System.out.println( String.class == Class.forName("java.lang.String") );//true
//
System.out.println( int.class == Integer.class );//false 基本类型和它的包装类不一样的.
System.out.println( int.class == Integer.TYPE );//true,Integer.TYPE 获得包装类其基本类型映射类

2. 构造方法的反射

//映射String类的 String(StringBuffer buffer) 构造方法
Constructor constructor1 = String.class.getConstructor( StringBuffer.class );//映射成String的 String(StringBuffer buffer) 构造方法
String str3 = (String)constructor1.newInstance( new StringBuffer("abc") );//用构造方法映射类创建 String 对象.
System.out.println( str3.charAt(0) );

3. 成员变量的反射

class Point{
	private int x;
	public int y;
	
	public void abc(){
		System.out.println("x="+x+" y="+y);
	}
	
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
}
 
Point p1 = new Point(3,5);
java.lang.reflect.Field fieldY = p1.getClass().getField("y");//fieldY 仅代表Point类y的成员变量映射的对象
int p1Y = (int)fieldY.get(p1);//获得p1 对象身上的该成员变量的值
System.out.println(p1Y);
 
java.lang.reflect.Field fieldX = p1.getClass().getDeclaredField("x");//可以映射 获取私有的成员变量
fieldX.setAccessible(true);//映射后还是不能访问//设置访问私有变量(暴力反射)
int p1X = (int)fieldX.get(p1);
System.out.println(p1X);
 
//反射获取私有字段
public Object forceGet(String fieldName) throws Exception {
	Field field = this.original.getClass().getDeclaredField(fieldName);
	field.setAccessible(true);
	return field.get(this.original);
}
//替换值 void setXxx(Object obj,xxx val):将obj对象的该Field字段设置成val值, 此处的xxx表示8个基本数据类型; 若该字段的类型是引用数据类型则使用, void set(Object obj, Object value);

4. 成员方法的反射

Method m = String.class.getMethod("charAt", int.class);//映射String的charAt( int )的方法
String str3 = "abcd";
System.out.println( m.invoke(str3, 2) );//调用str3对象的该映射方法; 若对象参数为null则是静态方法

5. 反射调用方法

Method m =Point.class.getMethod("abc", null);
Point p1 = new Point(3,5);
m.invoke(p1, null);
 
 
//反射调用私有方法
public Object forceCall(String methodName, Object ... param) throws Exception {
	Method method = this.original.getClass().getDeclaredMethod(methodName);
	method.setAccessible(true);
	return method.invoke(this.original, param);
}

6. 数组的反射与Object

//具有相同的类型,相同的维度, 才算是同一个映射(字节码)
int [] a1 = new int []{1,2,3};//一维数组 int类型
int [] a2 = new int [4];	  //一维数组 int类型
int [][] a3 = new int [2][4]; //二维数组 int类型
String [] a4 = new String []{"a","b","c"}; //一维数组 String类型
 
System.out.println( a1.getClass() == a2.getClass() );//true
System.out.println( a1.getClass()  == a3.getClass() ); //编译错误,不同维度
System.out.println( a1.getClass()  == a4.getClass() ); //编译错误,不同类型
 
与Object的关系?
Object o1 = a1;//o1 是数组映射 @1
Object o2 = a4;//o2当数组 是数组映射@2
 
Object[] o3 = a1;//obj当数组 但是基本类型不是对象,不能转型,编译错误
Object[] o4 = a3;//obj当元素
Object[] o5 = a4;//obj当元素
System.out.println( a1);//I@ffffff  int类型
System.out.println( a4);//java.lang.String;@ffffff  String类型
 
综上@1;@2; 当你得到一个object反射如何区分,是当数组反射,还是当对象反射?
//答案是: class.isArray() 方法判断
 
//如何看到数组的内容?
System.out.println( Arrays.asList(a1));//a1[]转成object了
System.out.println( Arrays.asList(a4));
 

7. 获取注解

MethodInterface methodAnno = Method.getAnnotation(MethodInterface.class);

8. 参考 java.lang.Class API

注解&元注解

@Retention

Retention的英文意为保留期的意思; 当 `@Retention` 应用到一个注解上的时候, 它解释说明了这个注解的的存活时间; 
它的取值如下: 
- `RetentionPolicy.SOURCE` 注解只在源码阶段保留, 在编译器进行编译时它将被丢弃忽视;  
- `RetentionPolicy.CLASS` 注解只被保留到编译进行的时候, 它并不会被加载到 JVM 中;  
- `RetentionPolicy.RUNTIME` 注解可以保留到程序运行的时候, 它会被加载进入到 JVM 中, 所以在程序运行时可以获取到它们; 

@Target

Target 是目标的意思, @Target 指定了注解运用的地方; 
比如只能张贴到方法上, 类上, 方法参数上等等; @Target 有下面的取值
  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解, 比如类, 接口, 枚举

@Inherited

Inherited 是继承的意思, 但是它并不是说注解本身可以继承, 而是说如果一个超类被 @Inherited 注解过的注解进行注解的话, 那么如果它的子类没有被任何注解应用的话, 那么这个子类就继承了超类的注解;

@Documented

顾名思义, 这个元注解和文档有关; 它的作用是能够将注解中的元素包含到 Javadoc 中去;

示例

 
/**  
* @author yangfh  
*/  
@Retention(RetentionPolicy.RUNTIME)  
@Target(TYPE)  
public @interface ObjectDesciption {  
	String value();  
	String extra() default "";  
	long flag() default 0L;  
}