JavaSE 16 反射

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个                   可以有多个

Class类型的对象和普通类型的对象

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


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个加载器组成的初始化加载器层次结构:
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);
  }
}

19、反射工具类【ReflectionUtils】

反射工具类【ReflectionUtils】

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值