因为项目中比较少用到反射,基本已经教回给老师了,前天回头学习一下,先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);
}
}
}