1、反射的概念
允许程序在运行时,使用相关方法取得任何类的内部信息,并且能够直接操作任意对象的内部属性或方法等。
正常使用是通过类去创建对象,而反射则是通过对象去获取类。
静态加载:也称为编译期加载。编译的时候,将加载所有需要用到的类,如果某类不存在,则编译会报错。
动态加载:也称为运行期加载。编译的时候不用加载所有的类。当运行时,用到哪个类,则加载哪个类。
反射属于Java实现动态语言的关键。
2、反射的功能
⑴ 加载一个正在运行的类
⑵ 可以获取类的完整结构,如属性、方法、构造等
⑶ 获取具体的对象
⑷ 可以调用对象的属性、方法等
3、Class类
引入
⑴ 自定义的类,也是对象。
⑵ 自定义的类,所属的类型是:java.lang.Class
⑶ 自定义的类的对象,是通过new关键字来创建的;
Class类的对象,是系统自动创建的。
特点
⑴ Class本身也是一个类 java.lang.Class
⑵ Class对象只能由系统创建
⑶ 一个类在Java虚拟机(内存)中只会有一个对应的Class实例
⑷ 一个Class对象对应的是一个加载到Java虚拟机(内存)中的一个.class文件
⑸ 每个类的实例都知道自己是由哪个Class实例所生成的
⑹ 通过Class可以完整地得到一个类中的完整结构
Class对象和new出的对象的对比
Class类型的对象 普通类型的对象
【自定义类型的类型的实例】 【自定义类型的实例】
如何创建 通过系统创建 通过new关键字
存储的区域 方法区 堆
里面包含的内容 类的描述信息 所对应的类的完整结构
可以有几个 只有1个 可以有多个
4、获取Class类型的对象的方法
Class.forName()
public static Class<?> forName(String className) throws ClassNotFoundException {}
返回与带有给定字符串名的类或接口相关联的 Class 对象。注意:此方法为静态的,通过Class来调用。
对象.getClass()
public final native Class<?> getClass();
返回此对象的运行时类。注意:该方法在Object类中,即任何对象都有此方法。
类型.class
获取此类对应的Class类型的对象。
使用示例
public class Test {
public static void main(String[] args) {
Class c1 = null;
try {
c1 = Class.forName("java.lang.String"); // 通过调用Class类的forName方法
System.out.println(c1.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class c2 = "abc".getClass(); // 通过调用对象的getClass方法
System.out.println(c2.getName());
Class c3 = String.class; // 通过 类.class 获取类的Class类型的对象
System.out.println(c3.getName());
System.out.println("是同一个对象吗:" + (c1 == c2));
System.out.println("是同一个对象吗:" + (c3 == c2));
}
}
5、Class类的方法列举 ⑴
getName
public String getName() {}
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。注意:此方法返回全类名,即包名.类名
getSimpleName
public String getSimpleName() {}
返回类的简称。注意:此方法只返回类名,不包含包名
getFields
public Field[] getFields() throws SecurityException {}
返回本类和继承自父类的,所有访问修饰符为public的属性。返回值类型为Field数组
getDeclaredFields
public Field[] getDeclaredFields() throws SecurityException {}
返回本类中所有的属性,不管访问修饰符是不是public的。返回值类型为Field数组
getMethods
public Method[] getMethods() throws SecurityException {}
返回本类和继承自父类的,所有访问修饰符为public的方法。返回值类型为Method数组
getDeclaredMethods
public Method[] getDeclaredMethods() throws SecurityException {}
返回本类中所有的方法,不管访问修饰符是不是public的。返回值类型为Method数组
getConstructors
public Constructor<?>[] getConstructors() throws SecurityException {}
返回本类中所有访问修饰符为public的构造方法。返回值类型为Constructor数组
getDeclaredConstructors
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {}
返回本类中所有的构造方法,不管访问修饰符是不是public的。返回值类型为Constructor数组
使用示例
获取类名
Class clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String
System.out.println(clazz.getSimpleName()); // String
获取属性
class Father {
private String name;
int age;
protected double height;
public char gendar;
}
class Son extends Father {
private long time;
boolean flag;
protected float weight;
public byte data;
}
【获取公共的属性】
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class clazz = Son.class;
Field[] fields = clazz.getFields();
int len = fields.length;
for (int i = 0; i < len; i++) {
System.out.println(fields[i].getName());
}
}
}
输出结果为:父类中用public修饰的gendar和子类中用public修饰的data
【获取子类中所有的属性】
Class clazz = Son.class;
Field[] fields = clazz.getDeclaredFields();
int len = fields.length;
for (int i = 0; i < len; i++) {
System.out.println(fields[i].getName());
}
输出结果为:子类中的time、flag、weight、data
获取方法
class Father {
private void method1() {}
void method2() {}
protected void method3() {}
public void method4() {}
}
class Son extends Father {
private void function1() {}
void function2() {}
protected void function3() {}
public void function4() {}
}
【获取公共的方法】
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class clazz = Son.class;
Method[] methods = clazz.getMethods();
int len = methods.length;
for (int i = 0; i < len; i++) {
System.out.println(methods[i].getName());
}
}
}
输出结果为:祖先类【Object】中用public修饰的方法(重名是因为有重载的方法)、父类【Father】中用public修饰的method4和子类中用public修饰的function4
【获取子类中所有的方法】
Class clazz = Son.class;
Method[] methods = clazz.getDeclaredMethods();
int len = methods.length;
for (int i = 0; i < len; i++) {
System.out.println(methods[i].getName());
}
输出结果为:子类中的time、flag、weight、data
获取构造器
class MyClass {
private MyClass(){}
MyClass(String str){}
protected MyClass(int i, char c){};
public MyClass(double d, boolean b){};
}
【获取公共的构造方法】
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Constructor[] constructors = clazz.getConstructors();
int len = constructors.length;
for (int i = 0; i < len; i++) {
System.out.println(constructors[i].getName());
}
}
}
输出结果为:public MyClass(double,boolean)
【获取所有的构造方法】
Class clazz = MyClass.class;
Constructor[] constructors = clazz.getDeclaredConstructors();
int len = constructors.length;
for (int i = 0; i < len; i++) {
System.out.println(constructors[i]);
}
输出结果为:
public MyClass(double,boolean)
protected MyClass(int,char)
MyClass(java.lang.String)
private MyClass()
6、Modifier类的方法列举
toString
public static String toString(int mod) {}
将传入的int类型的修饰符转换为String类型的修饰符。注意:此方法为静态的,通过Modifier来调用。
mod 修饰符
2 private
0 【默认】
4 protected
1 public
7、Field类的方法列举 ⑴
getModifiers
public int getModifiers() {}
以整数的形式返回访问修饰符,一般使用Modifier类的toString方法进行解码
getType
public Class<?> getType() {}
返回修饰符类型。注意:此方法返回全类名,即包名.类名。可以继续通过调用getSimpleName方法,返回类型的简称。
getName
public String getName() {}
以 String 形式返回此 Field 对象表示的字段的名称。即属性名
使用示例
class MyClass {
private long time;
boolean flag;
protected float weight;
public byte data;
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Field[] fields = clazz.getDeclaredFields();
int len = fields.length;
Field field = null;
for (int i = 0; i < len; i++) {
field = fields[i];
// 修饰符
String modifier = Modifier.toString(field.getModifiers());
// 类型
String type = field.getType().getSimpleName();
// 属性名
String name = field.getName();
System.out.println(modifier + " " + type + " " + name);
}
}
}
输出结果:
private long time
boolean flag
protected float weight
public byte data
8、Method类的方法列举 ⑴
getModifiers
public int getModifiers() {}
以整数的形式返回访问修饰符,一般使用Modifier类的toString方法进行解码
getReturnType
public Class<?> getReturnType() {}
获取返回值类型。注意:此方法返回全类名,即包名.类名。可以继续通过调用getSimpleName方法,返回类型的简称。
getName
public String getName() {}
以 String 形式返回此 Method 对象表示的方法名称。即属性名
getParameterTypes
public Class<?>[] getParameterTypes() {}
按照声明时的顺序,返回此 Method 对象的所有形参的类型。返回值类型为Class数组,一般需要遍历
使用示例
class MyClass {
private void function1(String name) {}
void function2(String id, int age) {}
protected void function3(char gendar) {}
public void function4() {}
}
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Method[] methods = clazz.getDeclaredMethods();
int len = methods.length;
StringBuilder sb = null;
Method method = null;
for (int i = 0; i < len; i++) {
method = methods[i];
sb = new StringBuilder();
// 访问修饰符
String modifier = Modifier.toString(method.getModifiers());
sb.append(modifier + " ");
// 返回值类型
String returnType = method.getReturnType().getSimpleName();
sb.append(returnType + " ");
// 方法名
String name = method.getName();
sb.append(name + " (");
// 形参类型
Class[] parameterTypes = method.getParameterTypes();
int length = parameterTypes.length;
for (int j = 0; j < length; j++) {
String parametersType = parameterTypes[j].getSimpleName();
if (j < length - 1) {
sb.append(parametersType + ", ");
} else {
sb.append(parametersType);
}
}
sb.append(") {}");
System.out.println(sb);
}
}
}
输出结果:
private void function1 (String) {}
void function2 (String, int) {}
protected void function3 (char) {}
public void function4 () {}
9、Constructor类的方法列举 ⑴
getModifiers
public int getModifiers() {}
以整数的形式返回访问修饰符,一般使用Modifier类的toString方法进行解码
getName
public String getName() {}
以 String 形式返回此 Constructor 对象表示的构造方法名称。即构造器名。
提示:由于构造方法名和类名一致,所以可以用本类的Class类型的对象.getSimpleName()即可。
getParameterTypes
public Class<?>[] getParameterTypes() {}
按照声明时的顺序,返回此 Constructor 对象的所有形参的类型。返回值类型为Class数组,一般需要遍历
使用示例
class MyClass {
private MyClass(){}
MyClass(String str){}
protected MyClass(int i, char c){};
public MyClass(double d, boolean b){};
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Constructor[] constructors = clazz.getDeclaredConstructors();
int len = constructors.length;
Constructor constructor = null;
StringBuilder sb = null;
for (int i = 0; i < len; i++) {
constructor = constructors[i];
sb = new StringBuilder();
// 访问修饰符
String modifier = Modifier.toString(constructor.getModifiers());
sb.append(modifier + " ");
// 构造器名(类名)
String name = constructor.getName();
// String name = clazz.getSimpleName(); 【类名】
sb.append(name + " (");
// 形参类型
Class[] parameterTypes = constructor.getParameterTypes();
int length = parameterTypes.length;
for (int j = 0; j < length; j++) {
if (j < length - 1) {
sb.append(parameterTypes[j].getSimpleName() + ", ");
} else {
sb.append(parameterTypes[j].getSimpleName());
}
}
sb.append(") {}");
System.out.println(sb);
}
}
}
输出结果:
public MyClass (double, boolean) {}
protected MyClass (int, char) {}
MyClass (String) {}
private MyClass () {}
10、Class类的方法列举 ⑵
getSuperclass
public native Class<? super T> getSuperclass();
返回父类的 Class。返回值类型为Class
Class clazz = String.class;
System.out.println(clazz.getSuperclass().getSimpleName()); // Object
System.out.println(Object.class.getSuperclass()); // null
getInterfaces
public native Class<?>[] getInterfaces();
返回实现的接口。返回值类型为Class数组
Class clazz = String.class;
Class[] interfaces = clazz.getInterfaces();
int len = interfaces.length;
for (int i = 0; i < len; i++) {
System.out.println(interfaces[i].getName());
}
输出结果:
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
getPackage
public Package getPackage() {}
获取此类的包。返回值类型为Package
Class clazz = String.class;
Package pkg = clazz.getPackage();
System.out.println(pkg.getName()); // java.lang
getAnnotations
public Annotation[] getAnnotations() {}
返回注解。返回值类型为Annotation数组
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Annotation[] annotations = clazz.getAnnotations();
int len = annotations.length;
Annotation annotation = null;
for (int i = 0; i < len; i++) {
annotation = annotations[i];
System.out.println(annotation);
}
}
}
@MyAnnotation
@Deprecated
class MyClass {
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}
输出结果:
@MyAnnotation()
@java.lang.Deprecated()
getGenericSuperClass
public Type getGenericSuperclass() {}
获取继承的父类的泛型。返回值类型为Type
Type接口
Type 是 Java 编程语言中 所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型
ParameterizedType接口
ParameterizedType 表示参数化类型,即泛型(参数化类型)
getActualTypeArguments方法
Type[] getActualTypeArguments();
返回表示此类型实际类型参数的 Type 对象的数组。即将父类泛型的所有类型保存到一个Type数组中
Type、Class和ParameterizedType
使用示例【获取父类的泛型】
class Father<T> {
}
class Son extends Father<String> {
}
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class Test {
public static void main(String[] args) {
Class clazz = Son.class;
Type superType = clazz.getGenericSuperclass(); // 获取父类的泛型【Type】
ParameterizedType pt = (ParameterizedType) superType; // 向下转型【ParameterizedType】,以便调用泛型接口的方法
Type genericType = pt.getActualTypeArguments()[0]; // 获取父类的泛型所属的类型【Type】 这里获取首个元素,是因为父类泛型的形参列表只有一个参数
Class genericClass = (Class) genericType; // 向下转型【Class】
System.out.println(genericClass.getName()); // 获取父类的泛型【Class】
}
}
getGenericInterfaces
public Type[] getGenericInterfaces() {}
获取实现的接口的泛型。返回值类型为Type数组
使用示例【获取实现的接口的泛型】
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class Test {
public static void main(String[] args) {
Class clazz = MyClass.class;
Type[] genericTypes = clazz.getGenericInterfaces(); // 获取实现的多个接口的泛型【Type】
int len = genericTypes.length;
for (int i = 0; i < len; i++) {
Type genericType = genericTypes[i];
/*
* 判断是不是泛型接口的实现类【能不能强转】
* 若不能强转,仍然向下转型,否则会报错:
* java.lang.ClassCastException: java.lang.Class
* cannot be cast to java.lang.reflect.ParameterizedType
*
* 注意:当实现的接口没有泛型时,就不能强转,因为没有泛型参数。
*/
if (!(genericType instanceof ParameterizedType)) {
continue;
}
ParameterizedType pt = (ParameterizedType) genericType; // 强转,以便调用泛型接口的方法
Type[] typeArguments = pt.getActualTypeArguments(); // 将泛型参数的类型保存到一个Type数组中
int length = typeArguments.length;
for (int j = 0; j < length; j++) {
Class typeArgument = (Class) typeArguments[j]; // 转换为Class
System.out.println(typeArgument.getName());
}
}
}
}
interface MyInterface1<K, V> {
}
interface MyInterface2<T> {
}
interface MyInterface3 {
}
class MyClass implements MyInterface1<String, Integer>, MyInterface2<Double>, MyInterface3 {
}
11、ClassLoader类
概念
类加载器是用来把类(class)装载进内存的。
JVM在运行时会产生3个类加载器:
引导类加载器
扩展类加载器
系统类加载器(可以加载JDK中的核心类或自定义的类)
这3个加载器组成的初始化加载器层次结构:
类的加载过程
装载——链接——初始化(主要用于静态属性的初始化)
获取类加载器
public ClassLoader getClassLoader() {}
使用Class类的getClassLoader方法,得到类加载器
方法列举
loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {}
获取指定类的Class类型的对象。参数为全类名字符串
getResourceAsStream
public InputStream getResourceAsStream(String name) {}
获取指定文件的输入流。注意:该指定文件必须在src路径下面 或 和当前java文件在同一目录下,否则无法获取文件,获取时会报空指针异常
使用示例
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ClassLoader loader = Test.class.getClassLoader(); // 获取类加载器
Class clazz = loader.loadClass("abc".getClass().getName()); // 加载字符串【String】类
System.out.println(clazz.getName()); // java.lang.String
InputStream is = loader.getResourceAsStream("Test.java"); // 获取Test.java的输入流
byte[] buffer = new byte[1024];
int len;
while (-1 != (len = is.read(buffer))) {
System.out.print(new String(buffer, 0, len));
}
is.close();
}
}
12、Class类的方法列举 ⑶
getField
public Field getField(String name) throws NoSuchFieldException, SecurityException {}
获取该类的或继承自父类的指定的属性,该属性的访问修饰符必须是public。返回值类型为Field
getDeclaredField
public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException {}
获取该类的指定的属性,不管访问修饰符是不是public的。返回值类型为Field
getMethod
public Method getMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException {}
获取该类的或继承自父类的指定的方法,该方法的访问修饰符必须是public。第二个参数是可变参数,为方法形参的Class的类型,如果方法没有参数,则不用传参。返回值类型为Method
getDeclaredMethod
public Method getDeclaredMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException {}
获取该类的指定的方法,不管访问修饰符是不是public的。第二个参数是可变参数,为方法形参的Class的类型,如果方法没有参数,则不用传参。返回值类型为Method
getConstructor
public Constructor<T> getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException {}
获取该类的指定的构造方法,该方法的访问修饰符必须是public。参数是可变参数,为方法形参的Class的类型,如果方法没有参数,则不用传参。返回值类型为Constructor
getDeclaredConstructor
public Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException {}
获取该类的指定的构造方法,该不管访问修饰符是不是public的。参数是可变参数,为方法形参的Class的类型,如果方法没有参数,则不用传参。返回值类型为Constructor
newInstance
public T newInstance() throws InstantiationException, IllegalAccessException {}
创建此 Class 对象所表示的类的一个新实例。返回值类型为Object
注意:
⑴ 前提是所创建的对象的类中有无参构造。
⑵ 访问修饰符的情况:
①默认访问修饰符:
调用newInstance的类和要反射的类在同一个class文件中
②protected:
调用newInstance的类和要反射的类在同一个包中
否则报错:java.lang.InstantiationException
使用示例
见反射使用示例【获取、修改属性和调用方法】
13、Field类的方法列举 ⑵
set
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException {}
将指定的Field对象的属性值设置为指定的新值。第一个参数为通过Class对象创建的该类型的实例对象。第二个参数为新的属性值
get
public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException {}
获取指定的Field对象的属性值。参数为通过Class对象创建的该类型的实例对象
setAccessible
public void setAccessible(boolean flag) throws SecurityException {}
指示Field对象在使用时是否取消Java语言访问检查。true为取消。即可以访问private修饰的属性。该方法是Field的父类AccessibleObject的方法
使用示例
见反射使用示例【获取、修改属性和调用方法】
14、Method类的方法列举 ⑵
invoke
public Object invoke(Object obj, Object… args) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {}
调用指定的Method对象的方法。第一个参数为通过Class对象创建的该类型的实例对象。第二个参数为新的属性值。返回值为方法的返回值,如果方法没有返回值,则返回null。返回值类型为Object
tips:对于静态方法,可以用对应类型的示例对象,或类型.class或null来调用。
setAccessible
public void setAccessible(boolean flag) throws SecurityException {}
指示Method对象在使用时是否取消Java语言访问检查。true为取消。即可以访问private修饰的属性。该方法是Method的父类AccessibleObject的方法
使用示例
见反射使用示例【获取、修改属性和调用方法】
15、Constructor类的方法列举 ⑵
newInstance
public T newInstance(Object … initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {}
创建此 Class 对象所表示的类的一个新实例。参数是可变参数,为构造器形参的Class的类型,如果构造器没有参数,则不用传参。返回值类型为Object
使用示例
见反射使用示例【获取、修改属性和调用方法】
16、反射使用示例
获取、修改属性和调用方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
Class fatherClass = Father.class; // Father的Class对象
Object fatherObj = fatherClass.newInstance(); // 创建Father的实例
System.out.println(fatherObj);
Field name = fatherClass.getField("name"); // 获取Father类的name属性对象
name.set(fatherObj, "李四"); // 修改name属性值
System.out.println(name.get(fatherObj)); // 获取name属性值
System.out.println("================");
Class sonClass = Son.class; // Son的Class对象
Constructor sonConstructor = sonClass.getConstructor(Integer.class); // 获取Son类的有参构造
Object sonObj = sonConstructor.newInstance(15); // 创建Son的实例
System.out.println(sonObj);
Field ageField = sonClass.getDeclaredField("age"); // 获取Son类的age属性对象
ageField.setAccessible(true); // 暴力破解
ageField.set(sonObj, 10); // 修改age属性值
System.out.println(ageField.get(sonObj)); // 获取age属性值
// 获取Son类的setAge方法对象
Method setAgeMethod = sonClass.getDeclaredMethod("setAge", Integer.class);
setAgeMethod.setAccessible(true); // 暴破
Object returnValue = setAgeMethod.invoke(sonObj, 20); // 调用setAge方法,并得到返回值
System.out.println(returnValue);
System.out.println(sonObj);
}
}
class Father {
public String name = "张三";
@Override
public String toString() {
return name;
}
}
class Son extends Father {
private Integer age;
public Son(Integer age) {
this.age = age;
}
private String setAge(Integer age) {
this.age = age;
return "你能调用私有方法!?";
}
@Override
public String toString() {
return String.valueOf(age);
}
}
输出结果:
张三
李四
================
15
10
你能调用私有方法!?
20
将java文件保存到另外一文本文件中
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
String path = "Test.txt";
/* 常规做法
FileWriter fw = new FileWriter(path);
FileReader fr = new FileReader("Test.java");
BufferedWriter bw = new BufferedWriter(fw);
BufferedReader br = new BufferedReader(fr);
String str;
while (null != (str = br.readLine())) {
bw.write(str);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
*/
Class fileWriterClass = FileWriter.class;
Constructor fileWriterConstructor = fileWriterClass.getConstructor(String.class);
Object fw = fileWriterConstructor.newInstance(path); // 创建FileWriter实例
Class fileReaderClass = FileReader.class;
Constructor fileReaderConstructor = fileReaderClass.getConstructor(String.class);
Object fr = fileReaderConstructor.newInstance("Test.java"); // 创建FileReader实例
Class bufferedWriterClass = BufferedWriter.class;
Constructor bufferedWriterConstructor = bufferedWriterClass.getDeclaredConstructor(Writer.class);
Object bw = bufferedWriterConstructor.newInstance(fw); // 创建BufferedWriter实例
Class bufferedReaderClass = BufferedReader.class;
Constructor bufferedReaderConstructor = bufferedReaderClass.getConstructor(Reader.class);
Object br = bufferedReaderConstructor.newInstance(fr); // 创建BufferedReader实例
Class stringClass = "abc".getClass();
Object str = stringClass.newInstance(); // 创建String实例
// 创建BufferedReader的readLine方法对象
Method readLineMethod = bufferedReaderClass.getMethod("readLine");
// 创建BufferedWriter的write方法对象
Method writeMethod = bufferedWriterClass.getMethod("write", String.class);
// 创建BufferedWriter的newLine方法对象
Method newLineMethod = bufferedWriterClass.getMethod("newLine");
// 创建BufferedWriter的flush方法对象
Method flushMethod = bufferedWriterClass.getMethod("flush");
while(null != (str = (String) readLineMethod.invoke(br))) {
writeMethod.invoke(bw, str);
newLineMethod.invoke(bw);
flushMethod.invoke(bw);
}
// 创建BufferedReader的close方法对象
Method brCloseMethod = bufferedReaderClass.getMethod("close");
// 创建BufferedWriter的close方法对象
Method bwCloseMethod = bufferedWriterClass.getMethod("close");
brCloseMethod.invoke(br);
bwCloseMethod.invoke(bw);
}
}
17、泛型的保留时期
现象
⑴ 带泛型和不带泛型的集合对应的Class对象为同一个
⑵ 泛型只保留在编译时期,所以运行时不认的泛型
示例
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception {
List<String> list1 = new ArrayList<String>();
List list2 = new ArrayList();
// 带泛型和不带泛型的集合对应的Class对象为同一个
System.out.println(list1.getClass() == list2.getClass());
Class arrayListClass = list1.getClass();
Object arrayList = arrayListClass.newInstance();
/* 泛型只保留在编译时期,所以运行时不认的泛型
java.lang.NoSuchMethodException: java.util.ArrayList.add(java.lang.String)
Method addMethod = arrayListClass.getMethod("add", String.class);
addMethod.invoke(arrayList, "张三");
*/
}
}
18、动态代理
引入
之前的代理模式中,代理类和目标对象的类都是在编译时期确定下来,不利于程序的扩展。最好可以通过一个代理类完成全部的代理功能。
动态代理就是在程序运行时根据需要,动态创建目标类的代理对象。
实现步骤
⑴ 创建一个类,让其实现InvocationHandler接口,并实现invoke方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
参数一:被代理的对象;参数二:要调用的方法(被代理的对象的方法);参数三:方法调用时所需的参数,没有就写null。返回值:调用的方法的返回值,没有返回值则返回null。返回值类型:Object
⑵ 调用Proxy的静态方法:newProxyInstance。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {}
参数一:被代理类的ClassLoader对象(通过getClassLoader方法获取);参数二:被代理类的所有实现的接口(通过getInterfaces方法获取);参数三:实现了InvocationHalder接口的实现类对象。返回值:代理类对象。返回值类型:Object
示例
富士康代理Apple生产手机
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Apple apple = new Apple(); // 委托人
Class appleClass = apple.getClass(); // 委托类的Class类型对象
ClassLoader loader = appleClass.getClassLoader(); // 委托类的ClassLoader
Class[] interfaces = appleClass.getInterfaces(); // 委托类所实现的接口
InvocationHandler h = new ProxyPhoneFactory(apple); // InvocationHandler的实现类
Object proxy = Proxy.newProxyInstance(loader, interfaces, h); // 代理人
PhoneFactory fushikang = (PhoneFactory) proxy; // 向下转型
fushikang.makePhone(); // 苹果公司生产iPhone
}
}
/**
* 生产手机的厂商
*/
interface PhoneFactory {
void makePhone(); // 生产手机的方法
}
/**
* 苹果公司【委托人】
*/
class Apple implements PhoneFactory {
@Override
public void makePhone() {
System.out.println("苹果公司生产iPhone");
}
}
/**
* 代理工厂【代理人】
*/
class ProxyPhoneFactory implements InvocationHandler {
Apple apple;
public ProxyPhoneFactory(Apple apple) { // 需要通过构造器来创建委托人对象
this.apple = apple;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(apple, args);
}
}
模版
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
ConsignerClass consigner = new ConsignerClass(); // 委托对象
Object proxyObj = new ProxyClass().blind(consigner); // 获取代理对象
MethodInterface proxy = (MethodInterface) proxyObj; // 向下转型
proxy.method(); // 调用委托方法
}
}
/**
* 委托方法接口
*/
interface MethodInterface {
/**
* 委托方法
*/
void method();
}
/**
* 委托类
*/
class ConsignerClass implements MethodInterface {
@Override
public void method() {
System.out.println("我是委托类的委托方法");
}
}
/**
* 产生代理对象的类
*/
class ProxyClass implements InvocationHandler {
private Object obj;
/**
* 产生一个代理对象
* @param obj 被代理对象【委托对象】
* @return 代理对象
*/
public Object blind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(obj, args);
}
}