java泛型详解
主要参考网址:
https://zhuanlan.zhihu.com/p/331620060
泛型和Object的区别
2.编译时更安全
如果使用Object类的话,可能转换异常 — ClassCastException
案例
Foo newFoo = (Foo) my.doSomething(foo); // 可能转换异常 Foo newFoo = my.doSomething(foo); // 编译时更安全
泛型分类
泛型类、泛型接口、泛型方法
泛型常用标记含义
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
泛型类
//在实例化泛型类时,必须指定具体类型
public class Generic<T>{
//key这个成员变量的类型为T, T的类型由外部指定
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey(){
return key;
}
}
//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
Generic<Integer> genericInteger = new Generic<Integer>(10000);
Generic<String> genericString = new Generic<String>("minnersun");
泛型接口
定义泛型接口
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
实现类1,未传实参
未传入泛型实参时,与泛型类的定义相同
在声明类的时候,需将泛型的声明也一起加到类中
// 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
实现类2,传实参
在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
// 即:Generator<T>,public T next();中的的T都要替换成传入的String类型
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
泛型方法
基本用法
public class GenericTest {
public class Generic<T>{
private T key;
public Generic(T key) {
this.key = key;
}
// 注意!!! 虽然在方法中使用了泛型,但是这并不是一个泛型方法。
// 这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。
public T getKey(){
return key;
}
}
/**
* 这才是一个真正的泛型方法
* 首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
* 这个T可以出现在这个泛型方法的任意位置
* 泛型的数量也可以为任意多个
* 如:public <T,K> K showKeyName(Generic<T> container){
* ...
* }
*/
public <T> T showKeyName(Generic<T> container){
System.out.println("container key :" + container.getKey());
//当然这个例子举的不太合适,只是为了说明泛型方法的特性。
T test = container.getKey();
return test;
}
//这也不是一个泛型方法,这就是一个普通的方法,只是使用了Generic<Number>这个泛型类做形参而已。
public void showKeyValue1(Generic<Number> obj){
Log.d("泛型测试","key value is " + obj.getKey());
}
//这也不是一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符?
//同时这也印证了泛型通配符所描述的,?是一种类型实参,可以看做为Number等所有类的父类
public void showKeyValue2(Generic<?> obj){
Log.d("泛型测试","key value is " + obj.getKey());
}
/**
* 注意!!!
* 只声明了泛型类型T,并未声明泛型类型E,因此编译器并不知道该如何处理E这个类型。
* 译器会为我们提示错误信息:"UnKnown class 'E' "
*/
public <T> T showKeyName(Generic<E> container){
...
}
}
可变参数
public static <T> void printMsg(String str,T... args){
for (T t: args){
System.out.println(t);
}
}
printMsg("minnersun",20000,"summer",44.45); // 20000 summer 44.45
静态方法与泛型
因为静态方法加载顺序与类同级,所以 静态方法无法访问类上定义的泛型
必须要将泛型定义在方法上
public class StaticGenerator<T> {
public static <T> void show(T t){
}
}
泛型上下边界
为泛型添加上边界
传入的类型实参必须是指定类型的子类型
public void showKeyValue1(Generic<? extends Number> obj){
System.out.println("泛型测试","key value is " + obj.getKey());
}
Generic<String> generic1 = new Generic<String>("10000");
Generic<Integer> generic2 = new Generic<Integer>(10000);
Generic<Float> generic3 = new Generic<Float>(5.5f);
Generic<Double> generic4 = new Generic<Double>(3.15);
//这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
//showKeyValue1(generic1);
showKeyValue1(generic2);
showKeyValue1(generic3);
showKeyValue1(generic4);
public class Generic<T extends Number>{
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey(){
return key;
}
}
//这一行代码也会报错,因为String不是Number的子类
Generic<String> generic1 = new Generic<String>("10000");
下边界
必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加
//public <T> T showKeyName(Generic<T extends Number> container),编译器会报错:"Unexpected bound"
public <T extends Number> T showKeyName(Generic<T> container){
System.out.println("container key :" + container.getKey());
T test = container.getKey();
return test;
}
保存redis相关笔记

浙公网安备 33010602011771号