简单介绍JAVA的反射机制和配置文件properties的使用。
- 框架:半成品软件,可以在框架的基础上进行软件开发,简化编码。
- 反射:将类的各个组成成分封装为其他对象,这就是反射机制。
- 可以在程序运行中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
这里预先写一个Person类以供下面的操作。
//************Person类********************
package com.bese.domain;
public class Person {
public String name;
public int age;
protected String gender;
int weight ;
private int height;
public Person() {
}
public Person(String name, int age, String gender, int weight, int height) {
this.name = name;
this.age = age;
this.gender = gender;
this.weight = weight;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", weight=" + weight +
", height=" + height +
'}';
}
//定义成员方法
public void eat(){
System.out.println("无参方法eat执行了...");
}
public void eat(String food){
System.out.println("带参方法eat执行了:eat "+food);
}
}
- 多用于配置文件,将类名定义在配置文件中,读取文件加载类。
- 多用于参数的传递
- 多用于获取对象的字节码
//*****************获取Class对象的demo类************************
package com.bese.reflect;
import com.bese.domain.Person;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception{
//1.Class.forName("全类名")
Class cls1 = Class.forName("com.bese.domain.Person");
System.out.println(cls1);
//2.类名.class
Class cls2 = Person.class;
System.out.println(cls2);
//3.对象.getClass()
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);
//4.比较三个对象
System.out.println(cls1 == cls2);
System.out.println(cls2 == cls3);
}
}
注意:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,三种方式获取的Class对象都是同一个。
- Field[] getFields():获取所有public修饰的成员变量
- Field getField(String name) :获取指定名称的public修饰的成员变量
- Field[] getDeclaredFields() :获取所有的成员变量,不考虑权限修饰符。
- Field getDeclaredField(String name) :获取指定名称的成员变量,不考虑权限修饰符
//**********************获取成员变量**************************
package com.bese.reflect;
import com.bese.domain.Person;
import java.lang.reflect.Field;
public class ReflectDemo2{
/**
* 获取成员变量
*/
public static void main(String[] args) throws Exception{
//1.获取Person的Class对象
Class personClass = Person.class;
//2.获取全部由Public修饰的成员变量:Field[] getFields()
Field[] fileds = personClass.getFields();
for (Field field : fileds){
System.out.println(field);
}
System.out.println("------------分割线------------");
//获取指定的由Public修饰的成员变量name的值:get(Object obj)
Field name = personClass.getField("name");
Person p = new Person();
Object value = name.get(p);
System.out.println("name的值为:" + value);
//设置name的值:set(Object obj, Object value)
name.set(p,"张三");
System.out.println("name的值为:" + p.name);
System.out.println("------------分割线------------");
//Field[] getDeclaredFields() :获取所有的成员变量,不考虑权限修饰符。
Field[] declaredFields= personClass.getDeclaredFields();
for (Field declaredField : declaredFields){
System.out.println(declaredField);
}
//Field getDeclaredField(String name) Constructor getDeclaredConstructor(Class>... parameterTypes)
//获取指定名称的成员变量,不考虑权限修饰符。
Field height = personClass.getDeclaredField("height");
//忽略访问权限修饰符:暴力反射setAccessible()
height.setAccessible(true);
height.set(p,123);
Object value2 = height.get(p);
System.out.println("height的值为:" + value2);
}
}
- Constructor>[] getConstructors() :返回由Public修饰的全参构造器
- Constructor getConstructor(Class>… parameterTypes) :返回Public修饰的无参构造器
- Constructor>[] getDeclaredConstructors() :返回全参构造器,忽略权限修饰符。
- Constructor getDeclaredConstructor(Class>… parameterTypes) :返回无参构造器,忽略修饰符
//***************获取构造器,创建对象*******************************
package com.bese.reflect;
import com.bese.domain.Person;
import java.lang.reflect.Constructor;
public class ReflectDemo3 {
/**
* 获取构造方法
*/
public static void main(String[] args) throws Exception {
//1.获取Person的Class对象
Class personClass = Person.class;
//Constructor>[] getConstructors()
//获取由Public修饰的全参构造方法,需要传入所有参数的类型Class对象
Constructor constructor = personClass.getConstructor(String.class, int.class, String.class, int.class, int.class);
System.out.println(constructor);
//用构造器创建对象:newInstance()
Object person = constructor.newInstance("张三",23,"man",56,175);
System.out.println(person);
System.out.println("------------分割线------------");
//Constructor getConstructor(Class>… parameterTypes)
//获取由Public默认的无参构造
Constructor constructor1 = personClass.getConstructor(); //返回一个构造器
System.out.println(constructor1);
//用无参构造器创建对象:newInstance()
Object person1 = constructor1.newInstance();
System.out.println(person1);
//简化后的空参构造器创建对象,不需要再获取无参构造器。
Object o = personClass.newInstance();
System.out.println(o);
//如果要用私有构造器创建对象,用暴力反射的方式
constructor1.setAccessible(true);
}
}
运行结果:
注意:
获取构造器的目的是用来创建对象的,获取全参构造方法需要传入对应参数的类型对象,用全参构造器创建对象时,也需要传入对应的参数。
- Method[] getMethods() :获取全部public修饰的成员方法
- Method getMethod(String name, Class>… parameterTypes):获取指定名称且由Public修饰的方法
- Method[] getDeclaredMethods()
- Method getDeclaredMethod(String name, Class>… parameterTypes)
//************************获取成员方法和方法名*****************************
package com.bese.reflect;
import com.bese.domain.Person;
import java.lang.reflect.Method;
public class ReflectDemo4 {
/**
* 获取成员方法
*/
public static void main(String[] args) throws Exception {
//1.获取Person的Class对象
Class personClass = Person.class;
Person p = new Person();
//Method getMethod(String name, Class>... parameterTypes)
//获取指定名称且不带参数的方法
Method eat_method = personClass.getMethod("eat");
//执行方法:Object invoke(Object obj, Object... args)
eat_method.invoke(p);
//获取指定名称且带参数列表的方法
Method eat_method1 = personClass.getMethod("eat",String.class);
//调用方法
eat_method1.invoke(p,"meal");
System.out.println("--------------------分割线-----------------------");
//获取全部public修饰的成员方法
Method[] methods = personClass.getMethods();
for (Method method : methods){
System.out.println(method);
}
System.out.println("--------------------分割线-----------------------");
//只获取方法名称
for (Method method : methods){
String name = method.getName();
System.out.println(name);
}
System.out.println("--------------------分割线-----------------------");
//获取类名
String className = personClass.getName();
System.out.println("获取到的类的名称是:" + className);
}
}
运行结果:
注意:
可以看到获取到的方法全部是由Public修饰的,并且与Person类有关的方法都可以被获取到。
- String getName() :获取
- void set(Object obj, Object value)
- get(Object obj)
- setAccessible(true):暴力反射
- newInstance(Object… initargs)
如果使用无参构造方法创建对象,可以使用Class对象的方法newInstance()
- Object invoke(Object obj, Object… args)
- String getName()
- 1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 2.在程序中加载读取配置文件
- 3.使用反射技术来加载类文件进内存
- 4.创建对象
- 5.执行方法
2.1 配置文件(properties)
# 放在src根目录下的配置文件pro.properties
className=com.bese.domain.Person
methodName=eat
//************************框架类*******************
package com.bese.reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectStruct {
/*
可以创建任意对象,执行任意方法
前提:不能改变该类的任何代码
*/
public static void main(String[] args) throws Exception{
//1.加载配置文件
//1.1创建Properties对象
Properties pro = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectStruct.class.getClassLoader();//类加载器getClassLoader()
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//2.获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
注意:
在配置文件中配置好要调用的类名和该类下的方法,再到框架类中加载配置文件,就可以使用配置文件中的类和它的方法了。
时间:2019年10月14日11:04:29