java 泛型详解
1、定义:泛型的本质是参数化类型,就是将类型由原来的具体的类型参数化,这种参数类型可以用在类、接口、方法中,分别称为泛型类、泛型接口、泛型方法;
2、泛型类:泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分,最典型的就是各种容器类,List、Set、Map;
不积跬步,无以至千里;不积小流,无以成江海
1、定义:泛型的本质是参数化类型,就是将类型由原来的具体的类型参数化,这种参数类型可以用在类、接口、方法中,分别称为泛型类、泛型接口、泛型方法;
2、泛型类:泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分,最典型的就是各种容器类,List、Set、Map;
public class Test<T>{ private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } }
a、泛型的类型参数只能是引用型类型<Integer>、<Double>(包括自定义类)等,不能是原始类型<int>、<double>等;
b、实例化泛型类时,必须指定 T 的具体类型;
c、参数化类型 T 可以写成任意字符,常用的 T 、E、K、V等表示泛型;
3、泛型接口:泛型接口与泛型类的定义及使用基本相同;
a、实现泛型接口的类未传入泛型实参时,在声明此类的时候,需将泛型的声明也加到类中;
class B<T> implements Test<T>{ @Override public T next() { return null; }
b、实现泛型接口的类传入泛型实参时,需将所有使用泛型的地方都要换成实参类型;
public class B implements Test<String> { private String[] strs= new String[]{"a", "b", "c"}; @Override public String next() { return null; } }
4、泛型方法:调用方法的时候,指明泛型的具体类型;
// 泛型类 class Box<T> { /** * 在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型,可以类型与T相同,也可以不同。 * 由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。 */ public <E> void B_1(E t) { System.out.println(t.toString()); } /** * 在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。 * */ public <T> void B_2(T t) { System.out.println(t.toString()); } // 不是泛型方法 public void B_3(T t){ System.out.println(t.toString()); } }
a、所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在上面例子中的<E>、<T>);
b、只有声明了<T>、<E>的方法才是泛型方法(B_1、B_2),泛型类中使用泛型的成员方法不是泛型方法(B_3);
c、<T>、<E>表明该方法将使用泛型类型T、E,此时才可以在方法中使用泛型类型T、E;
d、泛型方法体的声明和其他方法一样,只能是引用型类型,不能是原始类型(int、double,char等);
5、泛型上下边界:在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,类型实参只准传入某种类型的父类或某种类型的子类;为泛型添加上边界,即传入的类型实参必须是指定类型的子类型;比如:
List<? extends Animal>, 通配符的上限,不能往里存,只能往外取,因为编译器只知道容器里的是父类或者父类的子类,但不知道它具体是什么类型,所以存的时候,无法判断是否要存入的数据的类型与容器种的类型一致,所以会拒绝set操作
<? super E>通配符的下限,往外取只能赋值给Object变量,不影响往里存,因为编译器只知道它是子类或者它的父类,这样实际上是放松了类型限制,父类一直到Object类型的对象都可以往里存,但是取的时候,就只能当成Object对象使用了
// 泛型类 class Box<T extends Number> { private T t; public Box(T t){ this.t = t; } public T getT(){ return t; } }
// Integer类型是Number类型的子类————正确
Box<Integer> b = new Box<Integer>(1000);
// String类型不是Number类型的子类————错误
Box<String> s = new Box<String>("1000");
6、类型通配符:一般是使用 ?代替具体的类型参数,?是类型实参,和Integer、Number一样都是一种实际的类型,?可以看成所有的类型的父类(List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类);
public static void main(String[] args) { Box b = new Box(); List<String> sLst = new ArrayList<String>(); sLst.add("100"); List<Integer> iLst = new ArrayList<Integer>(); iLst.add(100); List<Number> nLst = new ArrayList<Number>(); nLst.add(1000); b.BPrint(sLst); b.BPrint(iLst); b.BPrint(nLst); } /** * <? extends T>表示该通配符所代表的类型是T类型的子类 * <? super T>表示该通配符所代表的类型是T类型的父类 */ class Box { public void BPrint(List<?> lst) { System.out.println(lst); } }
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
23 | 24 | 25 | 26 | 27 | 28 | 1 | |||
2 | 3 | 4 | 5 | 6 | 7 | 8 | |||
9 | 10 | 11 | 12 | 13 | 14 | 15 | |||
16 | 17 | 18 | 19 | 20 | 21 | 22 | |||
23 | 24 | 25 | 26 | 27 | 28 | 29 | |||
30 | 31 | 1 | 2 | 3 | 4 | 5 |
可能是我太菜了,看得云里雾里
为何选是否具有让程序长时间执行的特
Powered by:
博客园
Copyright © 2025 胡子就不刮
Powered by .NET 9.0 on Kubernetes
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)