泛型
泛型即参数化类型,使用的时候传入具体的参数类型,也就是说在泛型的使用过程中,操作的数据类型被定义为一个参数,视情况而定即可,此种参数类型可用于类,接口和方法中。
- 泛型的生命周期:
泛型的生命周期只在编译阶段有效,泛型是提供给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{
@Override
public void sale() {
System.out.println("出租房子");
}
}
代理类
public class AgentRental implements Rental{
private Rental target; // 被代理对象
public AgentRental(Rental target) {
this.target = target;
}
@Override
public 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));
}
}
![](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)
![](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)
<a name="ev0o9"></a>
### Java动态代理
> 创建动态代理用到:①java.lang.reflect.Proxy类②java.lang.reflect.InvocationHandler接口。
- java.lang.reflect.Proxy主要用于生成动态代理类class、创建代理类实例,该类实现了java.io.Seriaizable接口
> 类比于供货商发货给超市,我们去超市购买东西,超市就是一个代理类。
> 在Java的代理模式中,我们需要定义一个接口,这个接口不可以被直接实例化,需要通过类去实现这个接口,才能实现对这个接口中的方法的调用。
> 而动态代理实现了不需要中间商(类)直接“创建”某个接口的实例,对其方法进行调用,当我们调用某个动态代理对象的方法时,都会触发代理类的invoke方法,并传递对应的内容。
Demo:
```java
import 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动态创建类对象
> - 创建代理类实例
> - 动态代理添加方法
- 动态代理类实例
- 接口:
```java
package 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();
- 动态代理处理类
```java
package 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("----------------------------------------------------------------------------------------");
```