import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class ExtendedObjectPoolFactory {
//定义一个对象池,前面是对象名,后面是实际对象
private Map<String, Object> objectPool = new HashMap<>();
private Properties config = new Properties();
public static void main(String[] args) throws Exception {
ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
epf.init("extObj.txt");
epf.initPool();
epf.initProperty();
System.out.println(epf.getObject("a"));
}
//根据指定文件来初始化对象池
//根据配置文件来创建对象
public void initPool() throws Exception {
for(String name : config.stringPropertyNames()) {
System.out.println("name: " + name);
//每取出一个key-value对,如果key中不包含百分号(%)
//表明是根据value来创建一个对象
//调用createObject创建对象,并将对象添加到对象池中
if (!name.contains("%")) {
objectPool.put(name, createObject(config.getProperty(name)));
}
}
}
//根据属性文件来调用指定对象的setter方法
public void initProperty() throws Exception {
for (String name : config.stringPropertyNames()) {
//每取出一个key-value对,如果key中包含百分号(%)
//即可认为该key用于控制调用对象的setter方法设置值
//%前半为对象名字,后半控制setter方法名
if (name.contains("%")) {
//将配置文件中的key按%分割
String[] objAndProp = name.split("%");
//取出调用setter方法的参数值
Object target = getObject(objAndProp[0]);
//获取setter方法名:set+"首字母大写" + 剩下部分
String mtdName = "set" + objAndProp[1].substring(0, 1).toUpperCase()
+ objAndProp[1].substring(1);
//通过target的getClass()获取他的实现类所对应的Class对象
Class<?> targetClass = target.getClass();
//获取希望调用的setter方法
Method mtd = targetClass.getMethod(mtdName, String.class);
System.out.println(mtd);
//通过Method的invoke方法执行setter方法
//将config.getProperty(name)的值作为调用setter方法的参数
mtd.invoke(target, config.getProperty(name));
}
}
}
public Object getObject(String name) {
return objectPool.get(name);
}
//定义一个创建对象的方法
//该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象
private Object createObject(String clazzName) throws Exception {
//根据字符串来获取对应的Class对象
Class<?> clazz = Class.forName(clazzName);
//使用clazz对应类的默认构造器创建实例
return clazz.newInstance();
}
//从指定属性文件中初始化Properties对象
public void init(String fileName) {
try (FileInputStream fis = new FileInputStream(fileName))
{
config.load(fis);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
System.out.println("读取" + fileName + "异常");
}
}
}
访问成员变量值
import java.lang.reflect.Field;
public class FieldTest {
public static void main(String[] args) throws Exception {
//创建一个Person对象
Person p = new Person();
//获取Person类对应的Class对象
Class<Person> personClazz = Person.class;
//获取Person的名为name的成员变量
//使用getDeclaredField()方法声明可获取各种访问控制符的成员变量
Field nameField = personClazz.getDeclaredField("name");
//设置通过反射访问该成员变量时取消访问权限检查
nameField.setAccessible(true);
//调用set()方法为p对象的name成员变量设置值
nameField.set(p, "Jason");
//获取Person类名为age的成员变量
Field ageField = personClazz.getDeclaredField("age");
//设置通过反射访问该成员变量时取消访问权限检查
ageField.setAccessible(true);
//调用setInt()方法为p对象的age成员变量设置值
ageField.setInt(p, 30);
System.out.println(p);
}
}
class Person{
private String name;
private int age;
public String toString() {
return "Person[name:" + name +
" ,age: " + age + " ]";
}
}
getDeclaredField()方法获取了名为name的成员变量,注意此处不是使用getField()方法,因为getField()方法只能获取public访问控制的成员变量,而getDeclaredField()方法则可以获取所有的成员变量;ageField.setAccessible(true);通过反射访问该成员变量时不受访问权限的控制。
2、使用反射生成JDK动态代理
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。
使用Proxy和InvocationHandler创建动态代理
Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态的生成实现类,就可以使用Proxy来创建动态代理类;如果需要为一个或多个接口动态的创建实例,也可以使用Proxy来创建动态代理实例。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//创建一个InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler();
//使用指定的InvocationHandler来生成一个动态代理对象
Person p = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[] {Person.class}, handler);
//调用动态代理对象的walk()和sayHello()方法
p.walk();
p.sayHello("zhangsan");
}
}
class MyInvocationHandler implements InvocationHandler
{
/**
* 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
* 其中:
* proxy: 代表动态代理对象
* method: 代表正在执行的方法
* args: 代表调用目标方法时传入的实参
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----正在执行的方法: " + method);
if (args != null) {
System.out.println("下面是执行该方法时传入的实参为:");
for(Object val : args) {
System.out.println(val);
}
} else {
System.out.println("调用该方法没有实参!");
}
return null;
}
}
interface Person {
void walk();
void sayHello(String name);
}
不管程序是执行代理对象的walk()方法,还是执行代理对象的sayHello()方法,实际上都是执行InvocationHandler对象的invoke()方法。
实际上,在普通编程过程中,确实无须使用动态代理,但在编写框架或底层基础代码时,动态代理的作用就非常大。
动态代理和AOP
反射和泛型
从JDK5以后,Java的Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是Class<String>。如果Class对应的类暂时未知,则使用Class<?>。通过在反射中使用泛型,可以避免使用反射生成的对象需要强制类型转换。
import java.util.Date;
import javax.swing.JFrame;
public class ObjectFactory2 {
public static void main(String[] args) {
try {
//获取实例后无需类型转换
Date d = ObjectFactory2.GetInstance(Date.class);
JFrame f = ObjectFactory2.GetInstance(JFrame.class);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static <T> T GetInstance(Class<T> cls) throws InstantiationException, IllegalAccessException {
return cls.newInstance();
}
}
使用反射来获取泛型信息
通过指定类对应的Class对象,可以获得该类里包含的所有成员变量,不管该成员变量是使用private修饰,还是使用public修饰。获得了成员变量对应的Field对象后,就可以很容易的获得该成员变量的数据类型,即使用如下代码即可获得指定成员变量的类型。
//获取成员变量f的类型
Class<?> a = f.getType();
但这种方式只对普通类型的成员变量有效。如果该成员变量的类型是有泛型类型的类型,如Map<String, Integer>类型,则不能准确的得到该成员变量的泛型参数。
为了获得指定成员变量的泛型类型,应先使用如下方法来获取该成员变量的泛型类型。
//获取成员变量f的泛型类型
Class<?> a = f.getGenericType();
然后将Type对象强制类型转换为ParameterizedType对象,ParameterizedType代表被参数化的类型,也就是增加了泛型限制的类型。ParameterizedType类提供了如下两个方法:
getRawType(): 返回没有泛型信息的原始类型
getActualTypeArguments(): 返回泛型参数的类型。
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
public class GenericTest {
private Map<String, Integer> score;
public static void main(String[] args) {
Class<GenericTest> clazz = GenericTest.class;
try {
Field f = clazz.getDeclaredField("score");
//直接使用getType()取出类型只对普通类型的成员变量有效
Class<?> a = f.getType();
System.out.println("score的类型是: " + a);
//获得成员变量f的泛型类型
Type gType = f.getGenericType();
//如果gType类型是ParameterizedType对象
if (gType instanceof ParameterizedType) {
//强制类型转换
ParameterizedType pType = (ParameterizedType) gType;
//获取原始类型
Type rType = pType.getRawType();
System.out.println("原始类型是: " + rType);
//取得泛型类型的泛型参数
Type[] tArgs = pType.getActualTypeArguments();
System.out.println("泛型信息是: ");
for (int i = 0; i < tArgs.length; i++) {
System.out.println("第" + i + "个泛型类型是: " + tArgs[i]);
}
} else {
System.out.println("泛型类型出错!");
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Outputs:
score的类型是: interface java.util.Map
原始类型是: interface java.util.Map
泛型信息是:
第0个泛型类型是: class java.lang.String
第1个泛型类型是: class java.lang.Integer
Type也是java.lang.reflect包下的一个接口,该接口代表所有类型的公共高级接口,Class是Type接口的实现类。Type包括原始类型、参数化类型、数组类型、类型变量和基本类型等。