黑马程序员————反射小结(第六篇)

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

什么是反射?

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

1,反射的基石——Class类

java类的作用:用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。

Class类的作用:用于描述java类。

得到Class实例对象的三种方式:1,类名.class 2,对象.getClass() 3,Class.forName("类名")

九个预定义的Class实例对象:8个基本数据类型 + void

数组类型的Class实例对象:Class.isArray()

小结:只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…

2,反射相关的类

Constructor:代表某个类中的一个构造方法

public static void main(String[] args){

		//new String(new StringBuffer("abc"));//普通方式
		Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
		String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));
		//注:编译时只检查语法变成二进制文件,并不执行,只知道是构造方法并不知道是哪个类的什么构造方法,所以要强转并参数要传对。
		System.out.println(str2.charAt(2));
}

Filed:代表某个类中的一个成员变量

public static void main(String[] args) throws Exception {
		
	ReflectPoint pt1 = new ReflectPoint(3,5);
	Field fieldY = pt1.getClass().getField("y");
	//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
	System.out.println(fieldY.get(pt1));
	/*先用getField方法获取变量x时报错,用完getDeclardField方法后还是报错,但两者的错误不一样*/
	Field fieldX = pt1.getClass().getDeclaredField("x");//通过getDeclaredField方法可以得到类中私有的成员变量
	fieldX.setAccessible(true);//通过setAccessible方法,可以得到类中某个私有成员变量对应的实例对象上的值。称为“暴力反射”。
	System.out.println(fieldX.get(pt1));
}
练习:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。

	public static void main(String[] args){
		ReflectPoint pt1 = new ReflectPoint();
		changeStringValue(pt1);
		System.out.println(pt1);
	}
	private static void changeStringValue(Object obj) throws Exception {
		Field[] fields = obj.getClass().getFields();
		for(Field field : fields){
			//if(field.getType().equals(String.class)){	//用==比较好,因为字节码比较,只有一份。
			if(field.getType() == String.class){
				String oldValue = (String)field.get(obj);
				String newValue = oldValue.replace('b', 'a');
				field.set(obj, newValue);
			}
		}
		
	}

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

public static void main(String[] args) throws Exception {
		String str1 = "abc";
		
		//str1.charAt(1);
		Method methodCharAt = String.class.getMethod("charAt", int.class);
		System.out.println(methodCharAt.invoke(str1, 1));
		System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//jdk1.4中的调用方式。
}

综合案例:用反射的方式执行某个类的main方法

public class ReflectTest {

	public static void main(String[] args) throws Exception {
		
		//TestArguments.main(new String[]{"111","222","333"});
		String startingClassName = args[0];//需要在程序运行时传递一个参数进来,否则会发生数组角标越界。
		Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});//jdk1.5兼容jdk1.4所造成的问题
		mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
	}
}

class TestArguments{
	public static void main(String[] args){
		for(String arg : args){
			System.out.println(arg);
		}
	}
}

3,数组的反射

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

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

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

Arrays.asList()方法处理int[]和String[]时的差异。(jdk1.5为了兼容jdk1.4,如果asList方法传入的参数是Object[]类型的,就会按照jdk1.4走;如果参数类型不属于Object[]就按1.5走,即可变参数。)

4,反射的最重要作用——实现框架的功能

public static void main(String[] args) throws Exception{
		
	/*getRealPath();//金山词霸/内部
	一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。*/
		//InputStream ips = new FileInputStream("config.properties");
		
	/*一个类加载器能加载.class文件,那它当然也能加载classpath环境下的其他文件,
	既然它有如此能力,它没有理由不顺带提供这样一个方法。它也只能加载classpath环境下的那些文件。注意:直接使用类加载器时,不能以/打头。*/
		//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");

	//Class提供了一个便利方法,用加载当前类的那个类加载器去加载相同包目录下的文件
	/*Class类也提供getResourceAsStream方法的比喻:如果你每次都找我给你商店买可乐,那我还不如直接向你买可乐,即直接提供一个买可乐的方法给你。*/
		//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
		InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");

		Properties props = new Properties();
		props.load(ips);
		ips.close();
		String className = props.getProperty("className");
		Collection collections = (Collection)Class.forName(className).newInstance();
		
		//Collection collections = new HashSet();
		ReflectPoint pt1 = new ReflectPoint(3,3);
		ReflectPoint pt2 = new ReflectPoint(5,5);
		ReflectPoint pt3 = new ReflectPoint(3,3);	

		collections.add(pt1);
		collections.add(pt2);
		collections.add(pt3);
		collections.add(pt1);	
		System.out.println(collections.size());
	}

5,对JavaBean的简单内省操作(BeanUtils工具类的操作更方便,建议使用)

public static void main(String[] args) throws Exception {
	
		ReflectPoint pt1 = new ReflectPoint(3,5);
		
		String propertyName = "x";
		//"x"-->"X"-->"getX"-->MethodGetX-->	//普通反射方式
		//Object retVal = getProperty(pt1, propertyName);//抽取方法
		PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
		Method methodGetX = pd.getReadMethod();
		Object retVal = methodGetX.invoke(pt1);
		System.out.println(retVal);

		Object value = 7;
		//setProperties(pt1, propertyName, value);
		PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
		Method methodSetX = pd2.getWriteMethod();
		methodSetX.invoke(pt1,value);
		System.out.println(pt1.getX());
}



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

你可能感兴趣的:(黑马入学所需博客十篇)