`

黑马程序员_java高新(二)_反射

 
阅读更多

   ------- android培训java培训、期待与您交流! ----------

 

Class类:

 

 

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class

 

 

得到各个字节码对应的实例对象的方法:( Class类型):

 

 

1、类名.class。


例如,System.class

 


2、对象.getClass()。


例如,new Date().getClass()

 


3、Class.forName("类名")。

 

例如,Class.forName("java.util.Date");

 

 

.classClass.forName的区别:

 

 

后者可以在不确定要获得字节码的具体类的时候使用,传入的是一个字符串,经常在框架中使用。

 

 

九个预定义类型的实例对象:


 

基本的 Java 类型(booleanbytecharshortintlongfloat double)和关键字void 

 

 

表示为Class对象。基本类型的字节码获取方式只有一种就是类名.class

 

 

String str1 = "abc";
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = null;
		try {
			cls3 = Class.forName("java.lang.String");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		System.out.println(cls1 == cls2);//true
		System.out.println(cls1 == cls3);//true
		System.out.println(cls2 == cls3);//true
		
		System.out.println(int.class == Integer.class);//false
		System.out.println(int.class == Integer.TYPE);//true

 

 

反射: 

 

 

反射就是把Java类中的各种成分映射成相应的java类。

 

 

构造方法的反射:

 

 

onstructor代表某个类中的一个构造方法;

 

 

得到某个类所有的构造方法:

 

例子:

 

Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

 

 

得到某一个构造方法:

 

例子:

 

Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

 

 

获得方法时要用到类型:

 

 

创建实例对象:

 

 

通常方式:String str = new String(new StringBuffer("abc"));

 

 

反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));

 

 

调用获得的方法时要用到上面相同类型的实例对象

 

 

Class.newInstance()方法:

 

 

例子:String obj = (String)Class.forName("java.lang.String").newInstance();

 

 

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。也就是使用String类的无参构造

 

 

方法创建了一个String对象。

 

 

以下是用参数为StringBuffer类型的构造函数创建一个String类型的实例对象:

 

 

Constructor<String> con1 = String.class.getConstructor(StringBuffer.class);
		String str2 = con1.newInstance(new StringBuffer("abc"));
		System.out.println(str2.charAt(2));

 

 

Field的反射:

 

 

Field代表某个类中的一个成员变量。

 

ReflectPoint pt1 = new ReflectPoint(3,5);
		
		Field fieldY = pt1.getClass().getField("y");//获取公有的成员变量
		
		System.out.println(fieldY.get(pt1));
		
		
		Field fieldX = pt1.getClass().getDeclaredField("x");//强行获取私有的成员变量
		
		fieldX.setAccessible(true);//可以获取私有成员变量的值
		
		System.out.println(fieldX.get(pt1));

 

 

综合示例:

 

private static void changeStringValue(Object obj) throws Exception {
		
		Field[] fields = obj.getClass().getFields();//获取所有公有的成员变量
		
		for(Field field : fields) {//遍历这些成员变量
			
			if(field.getType() == String.class){//判断该变量的类型是不是String
				
				String oldValue = (String)field.get(obj);
				
				String newValue = oldValue.replace('b', 'a');//替换
				field.set(obj, newValue);//设置新值
			}
		}
	}

ReflectPoint类:

public class ReflectPoint {

	private int x;
	
	public int y;
	
	public String str1 = "ball";
	
	public String str2 = "basketball";
	
	public String str3 = "itcast";

	public ReflectPoint(int x, int y) {
		
		super();
		
		this.x = x;
		
		this.y = y;
	}

	@Override
	public String toString() {
		
		return str1+":"+str2+":"+str3;
	}

}

 

 

成员方法的反射(Method):

 

 

Method代表某个类中的一个成员方法。

 

 

得到类中的某一个方法:

 

 

例子:

 

Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

 

 

调用方法:

 

 

通常方式:System.out.println(str.charAt(1));

 

 

反射方式: System.out.println(charAt.invoke(str, 1));

 

 

如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法!

 

 

Method methodCharAt = String.class.getMethod("charAt", int.class);
		
		System.out.println(methodCharAt.invoke(str1, 1));

 

 

jdk1.4jdk1.5invoke方法的区别:

 

 

Jdk1.5public Object invoke(Object obj,Object... args) 可变参数;

 

 

Jdk1.4public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数

 

 

传递给invoke方法,数组中的每个元素分别对应被调用方法中的一个参数。

 

 

 

main方法的调用:
		String startingClassName = args[0];
		
		Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		
	mainMethod.invoke(null, (Object)new String[]{"111","222","333"});

 

 

 

 为了兼容1.4版本没有可变参数方法,传入的一个数组对象会被自动拆包,变为多个参数,因此要打包成

 

 

一个Object对象传入,避免被拆包。

 

 

数组的反射:

 

 

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

 

 

2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

 

 

3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维

 

 

数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

 

 

 

int [] a1 = new int[]{1,2,3};
		int [] a2 = new int[4];
		int[][] a3 = new int[2][3];
		String [] a4 = new String[]{"a","b","c"};
		System.out.println(a1.getClass() == a2.getClass());//true
		System.out.println(a1.getClass() == a4.getClass());//false
		System.out.println(a1.getClass() == a3.getClass());//false
		System.out.println(a1.getClass().getName());
		System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(a4.getClass().getSuperclass().getName());

 

 

无法通过反射直接获得数组中元素的类型,但可以通过其中一个元素获得类型:

 

    a[0].getClass().getName();

 

 

	private static void printObject(Object obj) {
		Class clazz = obj.getClass();//获取obj的类型字节码
		if(clazz.isArray()){//判断是不是数组类型
			int len = Array.getLength(obj);//得到数组长度
			for(int i=0;i<len;i++){//遍历打印这个数组
				System.out.println(Array.get(obj, i));
			}
		}else{
			System.out.println(obj);//如果不是数组类型,则直接打印
		}
		
	}

 

 

泛型的反射:

 

 

通过反射获取方法,再获得方法的参数列表的类型,获取其参数的实际类型。

 

 

Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
		Type[] types = applyMethod.getGenericParameterTypes();
		ParameterizedType pType = (ParameterizedType) types[0];
		
		System.out.println(pType.getActualTypeArguments()[0]);
	}
	
	public static void applyVector(Vector<Date> v1) {
		
	}

  

  

 

 ------- android培训java培训、期待与您交流! ----------

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics