Struts2与OGNL的联系
Java基础 – 反射
一、作用
“反射是框架设计的灵魂”,它可以将类的各个组成部分封装为一个个的对象,通过 Java 的反射机制,程序员可以更深入地控制程序的运行过程。
二、好处
-
可以在程序运行过程中操作这些封装的对象
-
可以解耦,提高程序的可扩展性
三、使用
首先准备一个Person类
public class Person {
private String name;
private Integer age;
public String a;
protected String b;
String c;
private String d;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
private void eat(String food){
System.out.println("吃" + food);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
}
1. 获取Class对象的方式
@Test
public void test() throws ClassNotFoundException {
//1. Class.forName("全类名"):将字节码文件加入进内存,获取Class对象
Class<?> clazz1 = Class.forName("com.sjl.Person");
System.out.println(clazz1);
//2. 类名.class:通过类的属性class获取
Class<Person> clazz2 = Person.class;
System.out.println(clazz2);
//3. 类对象.getClass():通过Object中的方法getClass()获取
Person person = new Person();
Class<? extends Person> clazz3 = person.getClass();
System.out.println(clazz3);
//同一字节码文件(*.class)在程序运行过程中只被加载一次,所以无论哪种方式获得的Class对象都是同一个
System.out.println(clazz1 == clazz2); //true
System.out.println(clazz2 == clazz3); //true
}
2. Class中的API
Class类的API,大致分为一下几类(参考jdk1.8 api)
- 获取类名
- String getName()
- 获取成员变量们
- Field getField(String name) 获取指定名称的公有方法
- Field[] getFields() 获取公有方法列表
- Field getDeclaredField(String name) 获取指定名称的方法
- Field[] getDeclaredFields() 获取所有方法列表
- 获取构造方法们
- Constructor< T > getConstructor(Class<?>… parameterTypes)
- Constructor<?>[] getConstructors()
- Constructor< T > getDeclaredConstructor(Class<?>… parameterTypes)
- Constructor<?>[] getDeclaredConstructors()
- 获取成员方法们
- Method getMethod(String name, Class<?>… parameterTypes)
- Method[] getMethods()
- Method getDeclaredMethod(String name, Class<?>… parameterTypes)
- Method[] getDeclaredMethods()
3. 代码实现
@Test
public void test1(){
//获取Class对象
Class<Person> clazz = Person.class;
//获取类的全名称
String name = clazz.getName();
System.out.println("类的全名称:" + name);
}
@Test
public void test2() throws Exception {
//获取Class对象
Class<?> clazz = Class.forName("com.sjl.Person");
//获取Person的公有属性列表
Field[] fields = clazz.getFields();
for(Field field : fields){
System.out.println("公共属性:" + field);
}
//获取指定的公有属性
Field a = clazz.getField("a");
System.out.println("指定公共属性a:" + a);
System.out.println("================================");
//获取Person的所有属性列表,不论权限修饰符
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("所有属性:" + declaredField);
}
//获取指定的属性
Field d = clazz.getDeclaredField("d");
System.out.println("指定属性d:" + d);
System.out.println("================================");
//为私有属性 设置值 和 获取值
Field name = clazz.getDeclaredField("name");
//暴力反射,忽略类的权限修饰符
name.setAccessible(true);
//设值,需要传一个person对象
Person person = new Person();
name.set(person, "张三");
//取值,也需要传一个person对象
Object value = name.get(person);
System.out.println(value);
}
@Test
public void test3() throws Exception {
//获取Class对象
Class<?> clazz = Class.forName("com.sjl.Person");
//获取公有构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//获取空参构造器
Constructor<?> constructor1 = clazz.getConstructor();
//通过构造器创建对象 newInstance
Object c1 = constructor1.newInstance();
System.out.println(c1);
//如果是空参构造器还可以简写,直接用Class对象创建
Object c2 = clazz.newInstance();
System.out.println(c2);
}
@Test
public void test4() throws Exception {
//获取Class对象
Class<?> clazz = Class.forName("com.sjl.Person");
//获取成员方法
Method eat_method = clazz.getDeclaredMethod("eat", String.class);
//eat是私有方法,因此需要暴力反射
eat_method.setAccessible(true);
//执行方法,传入对象和参数
Person person = new Person();
eat_method.invoke(person, "火锅");
}
四、应用小案例
实现:在不改变当前代码的情况下,创建任意一个类的实例并调用它的方法
python接口自动化测试 – 数据驱动DDT模块的简单使用
思路:
- 编写一个配置文件存放要创建的类的全类名,方法名
- 读取配置文件内容获得对应的信息
- 通过反射,根据全类名获得Class对象,创建其实例,调用其方法
配置文件:
className=com.sjl.Person
methodName=eat
Java代码:
public class ReflectDemo {
//实现:在不改变当前代码的情况下,创建任意一个类的实例并调用它的方法
public static void main(String[] args) throws Exception {
//获取Class对象
Class<?> clazz = Class.forName(getValue("className"));
//创建实例
Object o = clazz.newInstance();
//获取方法对象
Method eat_method = clazz.getDeclaredMethod(getValue("methodName"), String.class);
//执行
eat_method.setAccessible(true);
eat_method.invoke(o, "火锅");
}
//根据key值读取配置文件内容
public static String getValue(String key) throws IOException {
Properties properties = new Properties();
InputStream is = ReflectDemo.class.getClassLoader().getResourceAsStream("config.properties");
properties.load(is);
assert is != null;
is.close();
return properties.getProperty(key);
}
}
运行结果:
吃火锅
新建一个类Person2,将eat方法的输出稍作修改,将配置文件修改为
className=com.sjl.Person2
methodName=eat
运行结果
吃火锅,我是二号选手
JVM基础快速入门篇
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END