前提:刚学习了ssm框架,对ssm框架有了初步的了解,知道框架的底层实现是基于反射机制,故而学习浅尝了反射机制,仅作为学习笔记和学习记录
反射
将类的各个组成部分封装为其他对象,即为反射机制
一、优点
- 可以在程序运行中,操作这些对象
- 可与i解耦,提高程序的可扩展性
二、获取class对象的方式
-
Class.forName(“全类名” : 将字节码文件加载进内存,返回C对象(多用于配置文件)
//1. Class.forName("全类名" Class Class1 = Class.forName("Domain.Persion");
-
类名.class : 通过类名的属性class获取(多用于参数传递)
//类名.class Class Class2 = Persion.class;
-
对象.getClass() : getClass()方法在Object类中定义(多用于对象的获取字节码文件)
//对象.getClass() Persion persion = new Persion(); Class Class3 = persion.getClass();
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一此,无论哪种一种加载方式都式获取同一个class对象,其所在内存地址都是一个
三、Class对象功能
- 获取成员变量们
- Field[ ] getFields() : 获取所有public修饰的成员变量
- Field getField(String name) :获取指定的名称的public修饰的成员变量
- Field[ ] getDeclaredFields() :获取所有成员变量,不管什么修饰符
- Field getDeclaredField(String name) :获取指定的名称成员变量,无论修饰符;因此可以通过暴力反射获取访问权限的属性值(private等)
- 获取成员方法们
- Methods [ ] getMethods()
- Methods getMethod(String name, 类<?>… parameterTypes)
- Methods[ ] getDeclaredMethods()
- Methods getDeclaredMethod(String name, 类<?>… parameterTypes)
- 获取构造方法们
- Constructor<?>[ ] getConstructors() : 获取所有public修饰的构造方法
- Constructor getConstructor(类<?>… parameterTypes) :获取指定的参数类型的public修饰的构造方法
- Constructor<?>[ ] getDeclaredConstructors() :获取所有构造方法,不管什么修饰符
- Constructor getDeclaredConstructor(类<?>… parameterTypes) : 获取指定的参数类型构造方法,无论修饰符;因此可以通过暴力反射获取访问权限的属性值(private等)
- 获取类名
- String getName()
四、Field : 成员变量
-
操作:
.setAccessible(true) : 暴力反射,忽略访问权限修饰符的安全检查
-
赋值
void set(Object obj,Object value)
-
取值
get(Object obj)
-
public class Demo02 {
public static void main(String[] args) throws Exception {
Class<Persion> persionClass = Persion.class;
Persion p = new Persion();
//----------------------------获取成员变量--------------------------------------------
System.out.println("----------------获取全部成员变量(public修饰的才能获取)---------------");
Field[] fields = persionClass.getFields();
for (Field f : fields) {
System.out.println(f);
}
System.out.println("---------------获取指定成员变量(public修饰的才能获取)--------------------");
Field address = persionClass.getField("address");
Object value = address.get(p); //获取成员变量值
System.out.println(value);
address.set(p,"earth"); //设置成员变量值
System.out.println(p);
System.out.println("---------------------获取所有成员变量,不管什么修饰符----------------------");
Field[] declaredFields = persionClass.getDeclaredFields();
for (Field f: declaredFields) {
System.out.println(f);
}
System.out.println("---------------------获取指定成员变量,不管什么修饰符----------------------");
Field name = persionClass.getDeclaredField("name");
//忽略访问权限修饰符的安全检查
name.setAccessible(true); //暴力反射
Object value2 = name.get(p);
System.out.println(value2);
}
}
五、Constructor :构造方法
-
操作:
-
创建对象
T newInstance(Object… initargs)
-
无参构造方法
使用class对象直接构造
T newInstance()
-
public class Demo03 {
public static void main(String[] args) throws Exception {
Class<Persion> persionClass = Persion.class;
Persion p = new Persion();
//----------------------------获取构造方法--------------------------------------------
System.out.println("----------------获取全部构造方法(public修饰的才能获取)---------------");
Constructor<?>[] constructors = persionClass.getConstructors();
for (Constructor c: constructors) {
System.out.println(c);
}
System.out.println("---------------获取指定构造方法(public修饰的才能获取)--------------------");
Constructor<Persion> constructor = persionClass.getConstructor(String.class, int.class, char.class);
//创建对象
Persion persion = constructor.newInstance("zhangsan", 21, '男');
System.out.println(persion);
System.out.println("---------------------获取所有构造方法,不管什么修饰符----------------------");
Constructor<?>[] declaredConstructors = persionClass.getDeclaredConstructors();
for (Constructor c: declaredConstructors) {
System.out.println(c);
}
System.out.println("---------------------获取指定构造方法,不管什么修饰符----------------------");
Constructor<Persion> declaredConstructor = persionClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
Persion persion1 = declaredConstructor.newInstance("lisi", 58);
System.out.println(persion1);
}
}
六、Method:成员方法
主要掌握方法的执行:
method.invoke(String name,Object… args)
具有有参和无参之分
public class Demo04 {
public static void main(String[] args) throws Exception {
Class<Persion> persionClass = Persion.class;
Persion p = new Persion();
System.out.println("------------------获得方法(无参)---------------");
Method say = persionClass.getMethod("say"); //传入方法名
//执行方法
say.invoke(p);
System.out.println("------------------获得方法(有参参)---------------");
Method says = persionClass.getMethod("say", String.class);//传入方法名,参数类型
//执行方法
says.invoke(p,"nothings");
System.out.println("----------------------获得所有public方法---------------");
Method[] methods = persionClass.getMethods();
for (Method m: methods) {
System.out.println(m); //将会获得全部放啊,包括persion的自身方法,包括继承的Object类的隐藏方法
System.out.println(m.getName());
}
}
}
七、实践测试
目标:编写一个"框架",要求只改变配置文件的情况下,自动创建对象,并执行相应方法。
如:
要求根据类名和方法名,自动创建方法并执行对象中的相应方法
----------------------------------------------------------实现-------------------------------------
功能:开发人员自定义类,只需在配置文件中写入类的全限定名、需执行方法名、属性名、属性值即可实现程序的自动加载创建对象,并执行相应方法
实现方法:
public class reflectTest {
public static void main(String[] args) throws Exception {
//1.加载完配置文件
Properties pro = new Properties();
//1.1获取配置路径
ClassLoader classLoader = reflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
//1.2加载文件
pro.load(resourceAsStream);
String classname = pro.getProperty("classname");
String methodname = pro.getProperty("methodname");
String proname = pro.getProperty("proname");
String provalue = pro.getProperty("provalue");
//2.获取类对象
Class aClass = Class.forName(classname);
//3.获得目标类的构造方法
Constructor constructor = aClass.getConstructor();
//4.创建对象
Object o = constructor.newInstance();
//5.设置对象属性
Field declaredField = aClass.getDeclaredField(proname);
declaredField.setAccessible(true); //暴力反射
declaredField.set(o,provalue);
//获取方法,并执行
Method method = aClass.getMethod(methodname);
method.invoke(o);
}
}
自定义类(可随意定义类):
package Domain;
public class students {
private String username;
public void sleep(){
System.out.println(this.username + " is sleeping");
}
public void eat(){
System.out.println(this.username + " is eating");
}
public String getName() {
return username;
}
public void setName(String name) {
this.username = name;
}
}
配置文件(pro.proterties):
#全类名
classname=Domain.students
#方法名
methodname=eat
#属性名
proname=username
#属性值
provalue=zhangsan
输出:
zhangsan is eating