一、泛型常见符号
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types源码中都比较常见
二、泛型类
主要是根据自己所需,在使用的时候再赋值类型
public class Generic<T> {
private T t;
}
public class GenericTest {
public static void main(String[] args) {
Generic<String> generic = new Generic<>();
generic.setT("string");
generic.setT("");
}
}三、泛型方法
public class GenericMethod<T> {
/**
* 泛型普通方法
*
* @param t
*/
public void say(T t) {
System.out.println(t + "说话了");
}
/**
* 静态泛型方法中的类型占位符和类中的占位符 毫无关系
* 必须在static后面定义 占位符
* 返回值为void
*/
public static <T> void staticVoidSay(T t) {
System.out.println(t + "这是一个静态泛型方法");
}
/**
* 静态泛型方法必须自己声明泛型<p>
* 返回值为 你传递进来的类型
*
* @param t 参数
* @param <W> 类型
* @return T
*/
public static <W> W staticTSay(W t) {
return t;
}
/**
* @param r 传递的值
* @param <R> 你想传递的类型
*/
public <R> void differentSay(R r) {
System.out.println(r + "说:这是一个与类泛型不同的普通泛型方法");
}
}四、泛型接口
//接口
public interface GenericInterface<T> {
/**
* 普通泛型接口 与泛型接口的类型一致
*
* @param t
*/
void say(T t);
}
//普通实现
@Service
class PersonInterfaceStringImpl implements GenericInterface<String> {
@Override
public void say(String o) {
System.out.println(o + "说话了");
}
}
//泛型实现
@Service
class PersonInterfaceTImpl<T> implements GenericInterface<T> {
@Override
public void say(T t) {
System.out.println(t + ", 在实现中定义了类型");
}
public static void main(String[] args) {
//泛型接口的实现类可以指定具体的泛型接口的具体泛型类型
GenericInterface<String> string = new PersonInterfaceStringImpl();
string.say("xiao");
//泛型接口的实现类 如果没有指定具体的泛型类型,必须要在这个实现类中声明一个类型占位符给接口使用
GenericInterface t = new PersonInterfaceTImpl();
t.say(2);
t.say("小黄");
}
}
五、泛型通配符上线边界
@Data
public class GenericWildcard<T> {
private T name;
public void say(GenericWildcard<T> GenericWildcard) {
this.setName(GenericWildcard.getName());
System.out.println("这是无法识别Java继承关系的的say:" + name);
}
//测试
@Test
void genericWildcardTest() {
GenericWildcard<Number> numberGenericWildcard = new GenericWildcard<>();
GenericWildcard<Integer> integerGenericWildcard = new GenericWildcard<>();
//即便 Integer和Number 是父子关系,但是泛型当中它是无法识别的
//numberGenericWildcard.say(integerGenericWildcard);
}
/**
* ? 通配符 表示 任何类型 Object
*
* @param GenericWildcard 参数
*/
public void sayWildcardObj(GenericWildcard<?> GenericWildcard) {
//强制转换
this.setName((T) GenericWildcard.getName());
System.out.println("这是任意通配符?的say:" + name);
}
//测试
@Test
void GenericWildcardTest() {
GenericWildcard<Number> numberGenericWildcard = new GenericWildcard<>();
GenericWildcard<Integer> integerGenericWildcard = new GenericWildcard<>();
//即便 Integer和Number 是父子关系,但是泛型当中它是无法识别的
//numberGenericWildcard.say(integerGenericWildcard);
integerGenericWildcard.setName(1111);
//将它换为通配符?即可实现继承关系
numberGenericWildcard.sayWildcardObj(integerGenericWildcard);
//但是 不是继承关系也可以 因为 通配符?表示Object类型
GenericWildcard<String> stringGenericWildcard = new GenericWildcard<>();
stringGenericWildcard.setName("小明");
numberGenericWildcard.sayWildcardObj(stringGenericWildcard);
}
/**
* 上边界
* <p>
* 传递进来的值 必须为 特定类型的子类 或者 特定类型本身
* <p>
* ? extends T 传递进来的类型 必须 继承 T
*
* @param GenericWildcard 本身类型 or 子类类型
*/
public void sayWildcardExtends(GenericWildcard<? extends T> GenericWildcard) {
this.setName(GenericWildcard.getName());
System.out.println("这是上边界 指定泛型类型 指定泛型可以传入 T 和 T的子类:" + name);
}
//测试
@Test
void test1(){
GenericWildcard<Number> numberGenericWildcard = new GenericWildcard<>();
GenericWildcard<Integer> integerGenericWildcard = new GenericWildcard<>();
GenericWildcard<String> stringGenericWildcard = new GenericWildcard<>();
//上边界 限制 Number 类型的子类 或者是Number类型本身
numberGenericWildcard.sayWildcardExtends(integerGenericWildcard);
//String不是Number类型的子类,所以不可传递
//numberGenericWildcard.sayWildcardExtends(stringGenericWildcard);
}
/**
* 下边界
* 传递进来的值 必须为 特定类型的父类 或者 特定类型本身
* ? super T 传递进来的类型 必须是T的父类
*
* @param GenericWildcard 必须是T或者T的父类
*/
public void sayWildcardSuper(GenericWildcard<? super T> GenericWildcard) {
this.setName((T) GenericWildcard.getName());
System.out.println("这是下边界 泛型类型必须是T 或者T的父类:" + name);
}
//测试
@Test
void test(){
GenericWildcard<Number> numberGenericWildcard = new GenericWildcard<>();
GenericWildcard<Integer> integerGenericWildcard = new GenericWildcard<>();
//下边界 限制Number类型 或者Number的父类
numberGenericWildcard.sayWildcardSuper(numberGenericWildcard);
//Integer不是Number的父类,所以不能船体
//numberGenericWildcard.sayWildcardSuper(integerGenericWildcard);
}
}
上界<? extends T>不能往里存,只能往外取
原因是编译器只知道容器内是Number或者它的派生类,但具体是什么类型不知道
下界<? super T>不影响往里存,但往外取只能放在Object对象里
因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是Number的基类,那往里存粒度比Number小的都可以。但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失。
PECS原则
最后看一下什么是PECS(Producer Extends Consumer Super)原则,已经很好理解了:
- 频繁往外读取内容的,适合用上界Extends。
- 经常往里插入的,适合用下界Super。
版权声明:本文为Jesse_tan原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。