java知识之反射详解

因为项目中比较少用到反射,基本已经教回给老师了,前天回头学习一下,先mark一下!

一个对象在内存中只存在一个class对象

获取calss对象的三种方式:

/*
 * 获取Class对象的三种方式:
 * 
 * 1.调用Object类的getClass():任何类都会继承此方法;
 * 2.任何的数据类型(包括基本类型)都有一个:静态的class属性:
 * 		Student.class;
 * 		int.class
 * 3.调用Class类的静态方法forName(String 全名限定的类名):
 * 
 * 通过这个Class对象,可以获取Student类内部的成员属性、构造方法、成员方法的一些信息,
 * 并能够调用它们;
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		Student stu = new Student();
		
		Class stuClass1 = stu.getClass();
		
		Class stuClass2 =Student.class;
		
		Class stuClass3 = Class.forName("包名.Student");
		
		System.out.println(stuClass1 == stuClass2);
		System.out.println(stuClass1 == stuClass3);
		
		Student stu2 = new Student();
		Class stuClass4 = stu2.getClass();
		System.out.println(stuClass1 ==  stuClass4);
	}
}
觉得第三种才是解锁反射的正确姿势!

第一种:如果对象中没有无参数的构造方法(或者你不知参数的情况,是无法获取对象的)

第二种:说不上不好,但是没有第三种好!!

第三种:可以通过配置文件进行动态替换!



获取对象中的构造方法:

/*
 * 获取构造方法,并调用:
 * 
 * Class类:
 * 	--批量的:
 * 		Constructor[] getConstructors() :获取所有的"公有构造方法"
 * 		Constructor[] getDeclaredConstructors() :获取全部(包括私有)的构造方法;
 *  --获取某个构造方法
 *  	Constructor getConstructor(Class ... parameterTypes) :获取指定的"公有构造方法";
 *  	Constructor getDeclaredConstructor(Class ... parameterTypes) :获取指定的构造方法(包括私有的);
 *  
 *  --调用某个构造方法:
 *  	Constructor的 Object newInstance(Object... initargs) :调用指定构造方法,并实例化此类的对象;
 *  
 *  --暴力访问:如果私有成员,需要设置暴力访问;
 *  	Constructor的setAccessible(true):不进行权限检查;
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		//1.获取Student的Class对象
		Class stuClass = Class.forName("包名.Student");
		System.out.println("************获取所有的\"公有构造方法\"*******************");
		Constructor[] conArray = stuClass.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("************获取所有的构造方法(包括私有的)***************");
		conArray = stuClass.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("************获取\"公有构造方法\"***********************");
		Constructor con = stuClass.getConstructor(String.class);//获取的是"具有String类型形参的"公有构造方法
	//	Constructor con = stuClass.getConstructor(String.class,int.class);
		Object obj = con.newInstance("刘德华");//调用此构造方法,并传递实参:相当于:Object obj = new Student("刘德华");
		
		System.out.println("************获取\"私有构造方法\"并调用*******************");
		con = stuClass.getDeclaredConstructor();
		//设置暴力访问
		con.setAccessible(true);
		
		obj = con.newInstance();
		
	}
}

获取对象中的成员属性并调用:

/*
 * 获取成员属性,并调用:
 * 
 * Class类的方法:
 * 		--批量的:
 * 			Field[] getFields():获取所有"公有属性";
 * 			Field[] getDeclaredFields() :获取所有成员属性(包括私有):
 * 		--获取单个成员属性
 * 			Field getField(String name) :获取指定的"公有属性";
 * 			Field getDeclaredField(String name) :获取指定的属性,包括私有的;
 * 
 * 		--为成员属性赋值:(注意:1.一定要先实例化此类对象;2.访问私有属性前,要设置暴力访问)
 * 			Field的 void set(Object obj, Object value) 
 
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		//1.获取Student的Class对象
		Class stuClass = Class.forName("包名.Student");
		System.out.println("********************获取所有\"公有属性\"************************");
		Field[] fieldArray = stuClass.getFields();
		for(Field f : fieldArray){
			System.out.println(f);
		}
		System.out.println("********************获取所有属性(包括私有的)************************");
		fieldArray = stuClass.getDeclaredFields();
		for(Field f : fieldArray){
			System.out.println(f);
		}
		
		//创建一个Student对象
		Object obj = stuClass.getConstructor().newInstance();
		System.out.println("*********************获取公有属性,并调用*********************************");
		Field f = stuClass.getField("name");
		System.out.println("赋值前打印:" + obj);
		f.set(obj, "刘德华");
		System.out.println("赋值后打印:" + obj);
		
		System.out.println("*********************获取私有属性,并赋值*********************************");
		f = stuClass.getDeclaredField("score");
		//暴力访问
		f.setAccessible(true);
		
		f.set(obj, 88.5);
		System.out.println(obj);

	}
}

获取对象的成员方法并调用


/*
 * 获取成员方法:
 * 
 * Class类的方法:
 * 		--批量的:
 * 			Method[] getMethods():获取所有"公有方法"(包括继承的)
 * 			Method[] getDeclaredMethods() :获取所有成员方法(包括私有):
 * 		--获取单个成员方法
 * 			Method getMethod(String name, Class... parameterTypes) :获取指定的"公有方法";
 * 			Method getDeclaredMethod(String name, Class... parameterTypes) :获取指定的方法,包括私有的;
 * 
 * 		--调用方法:(注意:1.要先创建此类的对象;2.调用私有方法前,要先设置暴力访问)
 * 			Method:
 * 				Object invoke(Object obj, Object... args) :调用Method所代表的方法:
 * 				返回值:此Method对象调用所代表的方法,所获取的返回值;
 * 				形参:obj:方法所属对象;
 * 					args:Method所代表的那个方法的实参列表;
 * 				
 */
public class Demo {
	public static void main(String[] args) throws Exception {
		//1.获取Class对象
		Class stuClass = Class.forName("包名.Student");
		System.out.println("*************获取所有\"公有方法\"*******************");
		Method[] methodArray = stuClass.getMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		System.out.println("**************获取所有的方法(包括私有的)***************");
		methodArray = stuClass.getDeclaredMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		
		//创建Student对象
		Object obj = stuClass.getConstructor().newInstance();
		
		System.out.println("**************获取公有的,带参的show1()方法,并调用******");
		Method m = stuClass.getMethod("show1", String.class,int.class);
		Object result = m.invoke(obj, "刘德华",20);//调用show1()方法
		System.out.println("调用的返回值:" + result);
		
		System.out.println("***************获取私有的,无参的、无返回值的show4()方法,并调用****************");
		m = stuClass.getDeclaredMethod("show4");
		m.setAccessible(true);
		m.invoke(obj);
		
	}
}

通过配置文件动态修改代码:

先创建一个properties.ini

内容为一个键值对 一个classpash (包名.对象名字) 和一个方法名字(函数名字)

public class Demo {
	public static void main(String[] args) throws Exception {
		//1.获取Student的Class对象
	//	Class stuClass = Class.forName("包名.Student");
		String classPath = getValue("className");
		Class stuClass = Class.forName(classPath);
		
		//2.实例化一个Student对象
		Object obj = stuClass.getConstructor().newInstance();
		//3.调用方法
	//	Method m = stuClass.getMethod("show");
		Method m = stuClass.getMethod(getValue("methodName"));
		m.invoke(obj);
		
	}
	
	//一个方法,获取配置文件中的某个键对应的值
	public static String getValue(String key) throws IOException{
		Properties pro = new Properties();
		FileReader in = new FileReader("properties.ini");
		pro.load(in);
		in.close();
		
		return pro.getProperty(key);
	}
}

越过泛型来添加不同数据类型的数据:

泛型只存在于编译期,class对象是编译之后的,所以使用反射的时候没有泛型的说法(生成class对象之后,全都是Object类型)

/*
 * 通过反射越过泛型检查:
 * 
 * 1.定义一个具有String泛型的集合,要求成功向集合中添加一个int数据;
 */
public class Demo {
	public static void main(String[] args) throws Exception, SecurityException {
		List<String> strList = new ArrayList<>();
		strList.add("aaa");
		strList.add("bbb");
	//	strList.add(10);
		
		//通过反射
		Class listClass = strList.getClass();
		//获取add方法
		Method addMethod = listClass.getMethod("add", Object.class);
		//调用add方法
		addMethod.invoke(strList, 10);
		
		//遍历集合
		for(Object o : strList){
			System.out.println(o);
		}
		
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值