黑马程序员 反射学习笔记

----------android培训java培训、java学习型技术博客、期待与您交流!----------

反射:

 “反射就是把Java类中的各种成分映射成相应的java类”,而在此之前,首先是必须获得类的Class对象,再调用Class的相关方法,获取实例类中的各种成分,如构造方法Constructor、域Field及包等信息。

具体过程反射就是把Java类中的各种成分映射成相应的java类。具体就是先得到一个Field(字段,通常都是变量)们映射的Class的实例对象--一份字节码。然后在通过它们操作具体的类对象。

比如:

 Constructor:得到一个Constructor[] constructors= Class.forName(“java.lang.String”).getConstructors();,通过调用它的newInstance得到这个constructors所在的类的新对象。String str =(String)constructor.newInstance(new StringBuffer(“abc”))。

 Field:得到一个类中的Field,再通过Field操作这个类中的Field对应的具体成员变量。如果这个变量是私有的,还可以通过暴力反射对这个变量进行操作。

 Method:得到一个类中的Method()包括main方法,在通过得到的method对这个类对应的一个具体对象进行操作(通过invoke方法)。

那么,常见的获取Class实例的方法有哪些呢,通过学习,一般的,有如下三种方法:

(1)对于类,格式为:类名.class,例如,System.class ,Person.class

(2)对于具体的对象,需使用getClass()方法,格式为:对象.getClass(),例如,new Date().getClass(),new Person().getClass()。

(3当然,若给定类名,则可使用Class类的静态方法forName(),格式为:Class.forName("类名"),例如,Class.forName("java.util.Date");

 

1.获取构造方法(Constructor):

通过反射可以获取到java类中的构造方法,通过构造方法可以在运行时动态的创建java对象,而不用通过new来创建。对于Class类,有四个方法可以获取构造方法,getConstructors返回的是类中所有public权限的构造方法数组,getConstructor根据参数的列表返回打个public权限的构造方法。此外,getDeclaredConstructors和getDeclaredConstructor与之前的两个类似,但是,这两个获取的是类中真正声明的除private权限的构造方法,且忽略从父类中继承下来的构造方法。构造方法获取后,便可以调用构造方法了。


import java.lang.reflect.Constructor;
public class ReflectGetConst {
	public static void main(String[] args) throws Exception{
		//反射获取构造方法
		Constructor<MathMethods> constructor = MathMethods.class.getDeclaredConstructor(String.class,String.class);
//利用构造方法创建实例对象
		MathMethods mathMethods = constructor.newInstance("myAdd","add");
		System.out.println("name:"+mathMethods.getName()+"\nforWhat:"+mathMethods.getForWhat());
	}
}

class MathMethods{
	private static String id = "001";//私有静态域
	public String name = "shinian";
	private String forWhat = "No";//私有域
	MathMethods(){}	
MathMethods(String name,String forWhat){
		this.name = name;
		this.forWhat = forWhat;
	}
	public int add(int a,int b){
		return a+b;
	}
	public double add(double ...b){
		double sum = 0.0;
		for(int i=0;i<b.length;i++){
			sum+=b[i];
		}
		return sum;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getForWhat() {
		return forWhat;
	}
	public void setForWhat(String forWhat) {
		this.forWhat = forWhat;
	}
}
}


2、     获取域(Field)

反射不仅能够获取上述的构造方法,也能获取类中public修饰的域,若是private,则需通过getDeclaredField(),再经setAccessible(true)之后进行暴力似获取。而对于getField()方法,暴力获取是无效的,其只能访问public修饰的域。请看下表

 

private

缺省

protected

public

getField()

×

×

×

getField(),再经setAccessible(true)之后

×

×

×

getDeclaredField()

×

getDeclaredField(),再经setAccessible(true)之后

 

这里需要留意的是对静态域的反射操作,静态域与非静态域的区别在于静态域使用时不需要提供具体的实例,涉及到需要实例参数时,使用null即可,


public static void main(String[] args) throws Exception{
		
		Field staticField =MathMethods.class.getDeclaredField("id");
		staticField.setAccessible(true);
		//通过反射改变id域的值
		System.out.println(staticField.get(new MathMethods()));
		
		//通过反射改变id域的值,无需创建具体对象
		staticField.set(null, "007");
		System.out.println(staticField.get(new MathMethods()));
		
		System.out.println("---分割线---");
		
		Field nameField =MathMethods.class.getDeclaredField("name");
		MathMethods mathMethods = new MathMethods();
		
		//通过反射改变id域的值,需要具体的对象
		nameField.set(mathMethods, "张三");
		System.out.println(nameField.get(mathMethods));
		
		
	}
运行结果:
001
007
---分割线---
张三


3、      获取方法(Method)

         这里需要注意两点,其一是,利用getMethod(String name,Class<?>... parameterTypes),获取某个方法的对象时,对于参数是数组或者是可变参数的,需要的是同类型的数组的Class对象。其二是对某个方法对象调用

方法Objectinvoke(Object obj,Object... args)时,务必注意该方法的返回值是Object类型,参数也均为Object类型,必要的时候是需要对参数进行类型强制转换成Object类型的。

/*获取MathMethods类中的public double add(double ...b){}方法并调用*/
public class ReflectGetConst {
	public static void main(String[] args) throws Exception{
		//反射获取类的成员方法
		Method method = MathMethods.class.getMethod("add", double[].class);
		double result = (Double) method.invoke(new MathMethods("myAdd","add"), (Object)new double[]{1.1,2.1,3.5});//第二个参数强转成Object类类型,返回值Object型强转成Double类型
		System.out.println(result);//打印结果:6.7
	}


4、      操作数组

使用反射对数组进行操作是经过专门的java.lang.reflect.Array这个工具类来实现的,

import java.lang.reflect.Array;
public class ReflectArray {
	public static void main(String[] args) {
		ArrayDemo();
		
	}
	public static void ArrayDemo(){
		//一维数组
		String[] strArr = (String[])Array.newInstance(String.class, 2);
		Array.set(strArr, 0, "张三");//反射赋值
		strArr[1] = "李四";//普通赋值
		print(strArr);
		print("---1---");
		//二维数组
		
		int[][] intArr = (int[][])Array.newInstance(int.class, 1,1);
		intArr[0][0] = 1;
		print(intArr[0][0]);
		print("---2---");
		
		//类似int[][][] intArr2 = new int[1][1][1]方式
		int[][][] intArr2 = (int[][][])Array.newInstance(int.class, 2,2,2);
		intArr2[0][0][0] = 11;
		intArr2[0][0][1] = 22;
		print(intArr2[0][0][1]);
		
		print("---3---");
		
		int[] notObject = new int[]{13,23,33}; 
		Object[] objcetes1 = strArr;
		//Object[] objcetes2 = notObject;//该句报错,原因是int等基本数据类型不是直接继承自Object
		/*那么下面这句为什么又不报错呢,因为intArr是二维数组,可以视为二维数组里面存储的元素是一维数组,
		 * 是一个对象,它默认继承Object*
		 */
		
		Object[] objectes3 = intArr;
		print(objectes3.length);//从打印结果为1也可以看出,intArr里实际存放的元素是一维数组
	}
	public static void print(Object[] obj){
		for(int i = 0;i<obj.length;i++){
			System.out.println(obj[i]);
		}
	}
	public static void print(Object obj){
		System.out.println(obj);
	}
}

总结:反射还是比较难的,要好好练习才能好好掌握。

 

----------android培训java培训、java学习型技术博客、期待与您交流!----------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值