泛型

泛型即参数化类型,使用的时候传入具体的参数类型,也就是说在泛型的使用过程中,操作的数据类型被定义为一个参数,视情况而定即可,此种参数类型可用于类,接口和方法中。

  • 泛型的生命周期:

泛型的生命周期只在编译阶段有效,泛型是提供给javac编译器看的,可以限定集合中
的输入类型,让编译器挡住源程序的非法输入,正确检验泛型结果后,将泛型信息抹去。

  1. 泛型类
  • 用在定义类中,通过泛型可以完成对一组类的操作对外开放相同的接口:list、set、map
  • <泛型标识>
    1. package com.Generic;
    2. public class Generic <T>{
    3. private T key;
    4. public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
    5. this.key = key;
    6. }
    7. //这个不是泛型方法,是一个普通成员方法,返回值是在声明泛型类以及声明过的泛型
    8. public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
    9. return key;
    10. }
    11. public static void main (String[] args){
    12. //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
    13. //传入的实参类型需与泛型的类型参数类型相同,即为Integer.
    14. Generic<Integer> generic = new Generic<>(123456);
    15. //传入的实参类型需与泛型的类型参数类型相同,即为String.
    16. Generic<String> generic1 = new Generic<>("sqy");
    17. //不传入任何的泛型类型参数
    18. Generic generic2 = new Generic(111);
    19. Generic generic3 = new Generic("slc");
    20. System.out.println(generic.getKey());
    21. System.out.println(generic1.getKey());
    22. System.out.println(generic2.getKey());
    23. System.out.println(generic3.getKey());
    24. }
    25. }

```
泛型、动态代理 - 图1

  • 由此可知,定义的泛型类并不一定传入泛型类型实参,在使用泛型时如果传入泛型实参,则会根据传入的类型做相关的限制,此泛型才会起到本应起的限制作用,若不传入泛型实参的话,在泛型类中使用泛型的方法或者成员变量可以定义为任何类型。
  1. 泛型方法
  • 泛型方法是在调用的时,指明泛型的基本类型
  • 泛型不存在兼容性: Ingeter是Number的一个子类,但是在使用 Generic作为形参的方法中,是不能使用Generic的实例传入的,换句话说 Generic 不能被看作为Generic的子类
  • 泛型、动态代理 - 图2
  • static方法不能访问类上定义的泛型;若静态方法要使用泛型的话,必须将static方法定义成泛型
  • 泛型上下边界,传入的泛型类型参数必须是指定类型的子类型

  • …待补充

jdk动态代理机制

Java的自带jdk动态代理机制,位于java.lang.reflect.proxy包中,其本质实现是通过反射执行invoke方法来动态获取执行方法。
<br />代理类与委托类(实现接口的类)有同样的接口,**代理类**主要负责为**委托类预处理消息**、**过滤消息、把消息转发给委托类**,以及事后处理消息等。而Java的代理机制分为静态代理和动态代理。 <br />
泛型、动态代理 - 图3

静态代理

<br />静态代理在编译使用时,定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。<br />
接口

  1. public interface Rental {
  2. public void sale();
  3. }

委托类//实现接口的类

  1. public class Entrust implements Rental{
  2. @Override
  3. public void sale() {
  4. System.out.println("出租房子");
  5. }
  6. }

代理类

  1. public class AgentRental implements Rental{
  2. private Rental target; // 被代理对象
  3. public AgentRental(Rental target) {
  4. this.target = target;
  5. }
  6. @Override
  7. public void sale() {
  8. System.out.println("房子出租价位有1k-3k"); // 增加新的操作
  9. target.sale(); // 调用Entrust委托类的sale方法
  10. }
  11. }

测试类//生成委托类的实例化对象,并将该对象传入代理类构造函数中

  1. public class Test {
  2. // 静态代理使用示例
  3. public static void consumer(Rental subject) {
  4. subject.sale();
  5. }
  6. public static void main(String[] args) {
  7. Rental test = new Entrust();
  8. System.out.println("---使用代理之前---");
  9. consumer(test);
  10. System.out.println("---使用代理之后---");
  11. consumer(new AgentRental(test));
  12. }
  13. }
  1. ![](https://cdn.nlark.com/yuque/0/2021/png/2870855/1621672925530-0ffc82fa-1c50-4a15-89fc-e41f4b392763.png#align=left&display=inline&height=165&margin=%5Bobject%20Object%5D&originHeight=165&originWidth=1051&status=done&style=none&width=1051)
  2. ![](https://cdn.nlark.com/yuque/0/2021/png/2870855/1621672925806-49656396-9174-425e-be37-d18bcfb29cf2.png#align=left&display=inline&height=547&margin=%5Bobject%20Object%5D&originHeight=547&originWidth=1183&status=done&style=none&width=1183)
  3. <a name="ev0o9"></a>
  4. ### Java动态代理
  5. > 创建动态代理用到:①java.lang.reflect.Proxy类②java.lang.reflect.InvocationHandler接口。
  • java.lang.reflect.Proxy主要用于生成动态代理类class、创建代理类实例,该类实现了java.io.Seriaizable接口
  1. > 类比于供货商发货给超市,我们去超市购买东西,超市就是一个代理类。
  2. > Java的代理模式中,我们需要定义一个接口,这个接口不可以被直接实例化,需要通过类去实现这个接口,才能实现对这个接口中的方法的调用。
  3. > 而动态代理实现了不需要中间商(类)直接“创建”某个接口的实例,对其方法进行调用,当我们调用某个动态代理对象的方法时,都会触发代理类的invoke方法,并传递对应的内容。
  4. Demo
  5. ```java
  6. import java.lang.reflect.InvocationHandler;
  7. import java.lang.reflect.Method;
  8. import java.lang.reflect.Proxy;
  9. public class Test {
  10. public static void main(String[] args){
  11. InvocationHandler handler = new InvocationHandler() {
  12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  13. System.out.println(method);
  14. if (method.getName().equals("morning")) {
  15. System.out.println("Good morning, " + args[0]);
  16. }
  17. return null;
  18. }
  19. };
  20. Hello hello = (Hello)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Hello.class},handler);
  21. hello.morning("liming");
  22. }
  23. }

Hello.java(需要被代理的接口

  1. public interface Hello {
  2. void morning(String name);
  3. }

这里首先定义了一个handler,通过其实现对某接口类的调用。 接着定义了一个代理对象Hello,需要传递三个参数分别为ClassLoader、要代理的接口数组以及调用接口时触发的对应方法。 此时我调用hello.morning,就会触发handler的invoke方法,并传递三个参数进去,分别为proxy即代理对象,method即调用的方法的Method对象,args即传递的参数。

所有的handler都需要实现InvocationHandler这个接口,并实现其invoke方法来实现对接口的调用。

Proxy类的主要方法

  1. package java.lang.reflect;
  2. import java.lang.reflect.InvocationHandler;
  3. /**
  4. * Creator: yz
  5. * Date: 2020/1/15
  6. */
  7. public class Proxy implements java.io.Serializable {
  8. // 省去成员变量和部分类方法...
  9. /**
  10. * 获取动态代理处理类对象
  11. *
  12. * @param proxy 返回调用处理程序的代理实例
  13. * @return 代理实例的调用处理程序
  14. * @throws IllegalArgumentException 如果参数不是一个代理实例
  15. */
  16. public static InvocationHandler getInvocationHandler(Object proxy)
  17. throws IllegalArgumentException {
  18. ...
  19. }
  20. /**
  21. * 创建动态代理类实例
  22. *
  23. * @param loader 指定动态代理类的类加载器
  24. * @param interfaces 指定动态代理类的类需要实现的接口数组
  25. * @param h 动态代理处理类
  26. * @return 返回动态代理生成的代理类实例
  27. * @throws IllegalArgumentException 不正确的参数异常
  28. */
  29. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  30. throws IllegalArgumentException {
  31. ...
  32. }
  33. /**
  34. * 创建动态代理类
  35. *
  36. * @param loader 定义代理类的类加载器
  37. * @param interfaces 代理类要实现的接口列表
  38. * @return 用指定的类加载器定义的代理类,它可以实现指定的接口
  39. */
  40. public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {
  41. ...
  42. }
  43. /**
  44. * 检测某个类是否是动态代理类
  45. *
  46. * @param cl 要测试的类
  47. * @return 如该类为代理类,则为 true,否则为 false
  48. */
  49. public static boolean isProxyClass(Class<?> cl) {
  50. return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
  51. }
  52. /**
  53. * 向指定的类加载器中定义一个类对象
  54. *
  55. * @param loader 类加载器
  56. * @param name 类名
  57. * @param b 类字节码
  58. * @param off 截取开始位置
  59. * @param len 截取长度
  60. * @return JVM创建的类Class对象
  61. */
  62. private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);
  63. }
  1. InvocationHandler接口用于调用Proxy类生成的代理类方法,该类只有一个invoke方法。
  2. Java.lang.reflect.Proxy类有一个native方法动态向JMV创建一个类对象
  3. - 动态代理类实现方法
  4. > - 使用java.lang.reflect.Proxy动态创建类对象
  5. > - 创建代理类实例
  6. > - 动态代理添加方法
  7. - 动态代理类实例
  8. - 接口:
  9. ```java
  10. package com.proxy;
  11. import java.io.File;
  12. import java.io.Serializable;
  13. public interface FileSystem extends Serializable {
  14. String[] list(File file); //继承于Serializable的未实现的接口
  15. }
  • 实现接口的方法 ```java package com.proxy; import java.io.File; public class UnixFileSystem implements FileSystem { / — Disk usage — / public int spaceTotal = 996; //实现接口定义的方法,进行重写(参数、返回值不能改变 @Override public String[] list(File file) {
    1. System.out.println("正在执行[" + this.getClass().getName() + "]类的list方法,参数:[" + file + "]");
    2. return file.list();
    } }
  1. - 动态代理处理类
  2. ```java
  3. package com.proxy;
  4. import java.io.Serializable;
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. /**
  8. * Creator: yz
  9. * Date: 2020/1/14
  10. */public class JDKInvocationHandler implements InvocationHandler, Serializable {
  11. private final Object target;
  12. public JDKInvocationHandler(Object target) {
  13. this.target = target;
  14. }
  15. @Override //这里就实现动态代理的功能,对已经实现的接口方法进行重写添加等
  16. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  17. // 为了不影响测试Demo的输出结果,这里忽略掉toString方法
  18. if ("toString".equals(method.getName())) {
  19. return method.invoke(target, args);
  20. }
  21. System.out.println("即将调用[" + target.getClass().getName() + "]类的[" + method.getName() + "]方法...");
  22. Object obj = method.invoke(target, args);
  23. System.out.println("已完成[" + target.getClass().getName() + "]类的[" + method.getName() + "]方法调用...");
  24. return obj;
  25. }
  26. }
  • 动态代理类 ```java package com.proxy; import java.io.File; import java.lang.reflect.Proxy; import java.util.Arrays; /**
    • Creator: yz
    • Date: 2020/1/14 */public class FileSystemProxyTest { public static void main(String[] args) {
      1. // 创建UnixFileSystem类实例
      2. FileSystem fileSystem = new UnixFileSystem();
      3. // 使用JDK动态代理生成FileSystem动态代理类实例
      4. FileSystem proxyInstance = (FileSystem) Proxy.newProxyInstance(
      5. FileSystem.class.getClassLoader(),// 指定动态代理类的类加载器
      6. new Class[]{FileSystem.class}, // 定义动态代理生成的类实现的接口
      7. new JDKInvocationHandler(fileSystem)// 动态代理处理类
      8. );
      9. System.out.println("动态代理生成的类名:" + proxyInstance.getClass());
      10. System.out.println("----------------------------------------------------------------------------------------");
      11. System.out.println("动态代理生成的类名toString:" + proxyInstance.toString());
      12. System.out.println("----------------------------------------------------------------------------------------");
      13. // 使用动态代理的方式UnixFileSystem方法
      14. String[] files = proxyInstance.list(new File("."));
      15. System.out.println("----------------------------------------------------------------------------------------");
      16. System.out.println("UnixFileSystem.list方法执行结果:" + Arrays.toString(files));
      17. System.out.println("----------------------------------------------------------------------------------------");
      18. boolean isFileSystem = proxyInstance instanceof FileSystem;
      19. boolean isUnixFileSystem = proxyInstance instanceof UnixFileSystem;
      20. System.out.println("动态代理类[" + proxyInstance.getClass() + "]是否是FileSystem类的实例:" + isFileSystem);
      21. System.out.println("----------------------------------------------------------------------------------------");
      22. System.out.println("动态代理类[" + proxyInstance.getClass() + "]是否是UnixFileSystem类的实例:" + isUnixFileSystem);
      23. System.out.println("----------------------------------------------------------------------------------------");
      } }

```