泛型
泛型即参数化类型,使用的时候传入具体的参数类型,也就是说在泛型的使用过程中,操作的数据类型被定义为一个参数,视情况而定即可,此种参数类型可用于类,接口和方法中。
- 泛型的生命周期:
泛型的生命周期只在编译阶段有效,泛型是提供给javac编译器看的,可以限定集合中
的输入类型,让编译器挡住源程序的非法输入,正确检验泛型结果后,将泛型信息抹去。
- 泛型类
- 用在定义类中,通过泛型可以完成对一组类的操作对外开放相同的接口:list、set、map
- <泛型标识>
package com.Generic;public class Generic <T>{private T key;public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定this.key = key;}//这个不是泛型方法,是一个普通成员方法,返回值是在声明泛型类以及声明过的泛型public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定return key;}public static void main (String[] args){//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型//传入的实参类型需与泛型的类型参数类型相同,即为Integer.Generic<Integer> generic = new Generic<>(123456);//传入的实参类型需与泛型的类型参数类型相同,即为String.Generic<String> generic1 = new Generic<>("sqy");//不传入任何的泛型类型参数Generic generic2 = new Generic(111);Generic generic3 = new Generic("slc");System.out.println(generic.getKey());System.out.println(generic1.getKey());System.out.println(generic2.getKey());System.out.println(generic3.getKey());}}
```
- 由此可知,定义的泛型类并不一定传入泛型类型实参,在使用泛型时如果传入泛型实参,则会根据传入的类型做相关的限制,此泛型才会起到本应起的限制作用,若不传入泛型实参的话,在泛型类中使用泛型的方法或者成员变量可以定义为任何类型。
- 泛型方法
- 泛型方法是在调用的时,指明泛型的基本类型
- 泛型不存在兼容性: Ingeter是Number的一个子类,但是在使用 Generic
作为形参的方法中,是不能使用Generic 的实例传入的,换句话说 Generic 不能被看作为Generic 的子类 - static方法不能访问类上定义的泛型;若静态方法要使用泛型的话,必须将static方法定义成泛型
- 泛型上下边界,传入的泛型类型参数必须是指定类型的子类型
- …待补充
jdk动态代理机制
Java的自带jdk动态代理机制,位于java.lang.reflect.proxy包中,其本质实现是通过反射执行invoke方法来动态获取执行方法。<br />代理类与委托类(实现接口的类)有同样的接口,**代理类**主要负责为**委托类预处理消息**、**过滤消息、把消息转发给委托类**,以及事后处理消息等。而Java的代理机制分为静态代理和动态代理。 <br />
静态代理
<br />静态代理在编译使用时,定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。<br />
接口
public interface Rental {public void sale();}
委托类//实现接口的类
public class Entrust implements Rental{@Overridepublic void sale() {System.out.println("出租房子");}}
代理类
public class AgentRental implements Rental{private Rental target; // 被代理对象public AgentRental(Rental target) {this.target = target;}@Overridepublic void sale() {System.out.println("房子出租价位有1k-3k"); // 增加新的操作target.sale(); // 调用Entrust委托类的sale方法}}
测试类//生成委托类的实例化对象,并将该对象传入代理类构造函数中
public class Test {// 静态代理使用示例public static void consumer(Rental subject) {subject.sale();}public static void main(String[] args) {Rental test = new Entrust();System.out.println("---使用代理之前---");consumer(test);System.out.println("---使用代理之后---");consumer(new AgentRental(test));}}
<a name="ev0o9"></a>### Java动态代理> 创建动态代理用到:①java.lang.reflect.Proxy类②java.lang.reflect.InvocationHandler接口。
- java.lang.reflect.Proxy主要用于生成动态代理类class、创建代理类实例,该类实现了java.io.Seriaizable接口
> 类比于供货商发货给超市,我们去超市购买东西,超市就是一个代理类。> 在Java的代理模式中,我们需要定义一个接口,这个接口不可以被直接实例化,需要通过类去实现这个接口,才能实现对这个接口中的方法的调用。> 而动态代理实现了不需要中间商(类)直接“创建”某个接口的实例,对其方法进行调用,当我们调用某个动态代理对象的方法时,都会触发代理类的invoke方法,并传递对应的内容。Demo:```javaimport java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Test {public static void main(String[] args){InvocationHandler handler = new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method);if (method.getName().equals("morning")) {System.out.println("Good morning, " + args[0]);}return null;}};Hello hello = (Hello)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Hello.class},handler);hello.morning("liming");}}
Hello.java(需要被代理的接口
public interface Hello {void morning(String name);}
这里首先定义了一个handler,通过其实现对某接口类的调用。 接着定义了一个代理对象Hello,需要传递三个参数分别为ClassLoader、要代理的接口数组以及调用接口时触发的对应方法。 此时我调用hello.morning,就会触发handler的invoke方法,并传递三个参数进去,分别为proxy即代理对象,method即调用的方法的Method对象,args即传递的参数。
所有的handler都需要实现InvocationHandler这个接口,并实现其invoke方法来实现对接口的调用。
Proxy类的主要方法
package java.lang.reflect;import java.lang.reflect.InvocationHandler;/*** Creator: yz* Date: 2020/1/15*/public class Proxy implements java.io.Serializable {// 省去成员变量和部分类方法.../*** 获取动态代理处理类对象** @param proxy 返回调用处理程序的代理实例* @return 代理实例的调用处理程序* @throws IllegalArgumentException 如果参数不是一个代理实例*/public static InvocationHandler getInvocationHandler(Object proxy)throws IllegalArgumentException {...}/*** 创建动态代理类实例** @param loader 指定动态代理类的类加载器* @param interfaces 指定动态代理类的类需要实现的接口数组* @param h 动态代理处理类* @return 返回动态代理生成的代理类实例* @throws IllegalArgumentException 不正确的参数异常*/public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException {...}/*** 创建动态代理类** @param loader 定义代理类的类加载器* @param interfaces 代理类要实现的接口列表* @return 用指定的类加载器定义的代理类,它可以实现指定的接口*/public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) {...}/*** 检测某个类是否是动态代理类** @param cl 要测试的类* @return 如该类为代理类,则为 true,否则为 false*/public static boolean isProxyClass(Class<?> cl) {return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);}/*** 向指定的类加载器中定义一个类对象** @param loader 类加载器* @param name 类名* @param b 类字节码* @param off 截取开始位置* @param len 截取长度* @return JVM创建的类Class对象*/private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);}
InvocationHandler接口用于调用Proxy类生成的代理类方法,该类只有一个invoke方法。Java.lang.reflect.Proxy类有一个native方法动态向JMV创建一个类对象- 动态代理类实现方法> - 使用java.lang.reflect.Proxy动态创建类对象> - 创建代理类实例> - 动态代理添加方法- 动态代理类实例- 接口:```javapackage com.proxy;import java.io.File;import java.io.Serializable;public interface FileSystem extends Serializable {String[] list(File file); //继承于Serializable的未实现的接口}
- 实现接口的方法
```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) {
} }System.out.println("正在执行[" + this.getClass().getName() + "]类的list方法,参数:[" + file + "]");return file.list();
- 动态代理处理类```javapackage com.proxy;import java.io.Serializable;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/*** Creator: yz* Date: 2020/1/14*/public class JDKInvocationHandler implements InvocationHandler, Serializable {private final Object target;public JDKInvocationHandler(Object target) {this.target = target;}@Override //这里就实现动态代理的功能,对已经实现的接口方法进行重写添加等public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 为了不影响测试Demo的输出结果,这里忽略掉toString方法if ("toString".equals(method.getName())) {return method.invoke(target, args);}System.out.println("即将调用[" + target.getClass().getName() + "]类的[" + method.getName() + "]方法...");Object obj = method.invoke(target, args);System.out.println("已完成[" + target.getClass().getName() + "]类的[" + method.getName() + "]方法调用...");return obj;}}
- 动态代理类
```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) {
} }// 创建UnixFileSystem类实例FileSystem fileSystem = new UnixFileSystem();// 使用JDK动态代理生成FileSystem动态代理类实例FileSystem proxyInstance = (FileSystem) Proxy.newProxyInstance(FileSystem.class.getClassLoader(),// 指定动态代理类的类加载器new Class[]{FileSystem.class}, // 定义动态代理生成的类实现的接口new JDKInvocationHandler(fileSystem)// 动态代理处理类);System.out.println("动态代理生成的类名:" + proxyInstance.getClass());System.out.println("----------------------------------------------------------------------------------------");System.out.println("动态代理生成的类名toString:" + proxyInstance.toString());System.out.println("----------------------------------------------------------------------------------------");// 使用动态代理的方式UnixFileSystem方法String[] files = proxyInstance.list(new File("."));System.out.println("----------------------------------------------------------------------------------------");System.out.println("UnixFileSystem.list方法执行结果:" + Arrays.toString(files));System.out.println("----------------------------------------------------------------------------------------");boolean isFileSystem = proxyInstance instanceof FileSystem;boolean isUnixFileSystem = proxyInstance instanceof UnixFileSystem;System.out.println("动态代理类[" + proxyInstance.getClass() + "]是否是FileSystem类的实例:" + isFileSystem);System.out.println("----------------------------------------------------------------------------------------");System.out.println("动态代理类[" + proxyInstance.getClass() + "]是否是UnixFileSystem类的实例:" + isUnixFileSystem);System.out.println("----------------------------------------------------------------------------------------");
```

