java泛型
1 泛型
1.1 泛型的作用
泛型有两种作用,一种是让接口或方式更通用,一种是限制作用。
第一种是一种是让接口或方式更通用,泛型和C++的模板很相似,有时在定义函数或者接口时,不确定需要传入的参数是什么类型,这时可能要创建多个重载函数来枚举所有的数据类型。而有了泛型之后,直接用一个标识符代替具体的数据类型,在调用的时候传入具体的数据类型给标识符。从而实现接收任意数据类型的方法。例如:
public interface Generator<T> {
public T next();
}
第二则是限制作用。例如创建List时是以Object作为基类,所以可以放入任何类型的对象List arrayList = new ArrayList();arrayList.add("aaaa");arrayList.add(100);但是在输出的时候,不知道输出是什么类型。使用不当会导致奔溃。所以需要通过泛型来限制输入数据的类型。List<String> arrayList = new ArrayList<String>();只能输入String类型的数据,其他类型数据则会报错。
1.2 泛型的使用
1.2.1 泛型类
泛型类的定义
public class Generic<T>{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
泛型对象的创建
//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
//传入的实参类型需与泛型的类型参数类型相同,即为Integer.
Generic<Integer> genericInteger = new Generic<Integer>(123456);
Log.d("泛型测试","key is " + genericInteger.getKey());
也可以省略泛型形参,会根据输入的数据类型自动识别。
Generic generic2 = new Generic(55.55);
Generic generic3 = new Generic(false);
1.2.2 泛型接口
定义泛型接口:
public interface Generator<T> {
public T next();
}
实现泛型接口
(1)不指定泛型类型,实现类中也要加入泛型标识
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
(2)指定泛型类型,实现类中无需泛型标识
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)];
}
}
1.2.3 泛型方法
首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,
public <T> T showKeyName(Generic<T> container){
System.out.println("container key :" + container.getKey());
//当然这个例子举的不太合适,只是为了说明泛型方法的特性。
T test = container.getKey();
return test;
}
在泛型类中者形参中带有泛型标识符public void showKeyValue1(T key) ;showKeyValue1(Generic<Number> obj);带有通配符的函数 public void showKeyValue2(Generic<?> obj);或返回值是泛型标识符public T getKey();这些都不算是真正的泛型方法。其中的泛型标识符是类的泛型标识符,创建对象时传入实际的数据类型,调用泛型方法时,必须传入创建对象时的泛型数据类型。泛型类中泛型方法声明泛型标识符T可以与泛型类的泛型标识符T一样,也可以换成E,或者其他标识符。泛型方法中的标识符在泛型方法调用时,传入实际的数据类型,与泛型类中的标识符T没有必然联系,例如泛型类传入的类型是String,并不代表泛型方法中的T也是String类型。而是在泛型方法调用时传入具体的数据类型。总之泛型标识符只是用来标识,由传入数据类型决定。
1.2.4 泛型可变参数
泛型也可以用于可变参数:
public <T> void printMsg( T... args){
for(T t : args){
Log.d("泛型测试","t is " + t);
}
}
printMsg("111",222,"aaaa","2323.4");//传入不同类型的变量。
1.2.5 静态方法与泛型
因为静态方法属于类,而不属于对象,所有无法使用创建对象传入泛型的数据类型。所以静态方法如果要用泛型的话,只能定义为泛型方法。在静态方法调用时,传入具体的数据类型。
public class StaticGenerator<T> {
//public static void show(T t){..};ERROR此时编译器会提示错误信息:
public static <T> void show(T t){ }};
1.2.6 泛型通配符?
Ingeter是Number的一个子类,Ingeter变量可以传给Number。但是Generic<Ingeter>变量却不可以传给Generic<Number>,不是子类和父类关系。这样就无法传递,因此类型通配符云而生。
public void showKeyValue1(Generic<?> obj);
使用?代替具体的类型实参,可以把?看成所有类型的父类。任何类型的Generic<Number>、Generic<String>、Generic<Integer>等都可以传入,Generic<?>各种泛型的父类,但是只能作为泛型形参,不能创建对象保存数据。可以解决不确定具体类型时,直接用?号代替;但同时也引入另外一个问题,因为不确定是什么类型,所在方法中只使用Object类中的基本功能方法。不可以用传入类型的特殊的方法。
1.2.7 泛型的边界
泛型的作用是能够传入任意数据类型,但是有时需要限制输入的类型范围,例如只允许number的子类传入。这时就需要设置边界;
public void showKeyValue1(Generic<? extends Number> obj);
这样只有Number的子类构成的变量Generic<Integer>、Generic<Float>等才可以传人,而Generic<String>则不能传入。这就是边界。
泛型类也可以设置边界:
public class Generic<T extends Number>{};
泛型方法也可以设置边界:
public <T extends Number> T showKeyName(Generic<T> container){};
1.2.8 泛型数组
Java是不支持泛型数组的,也就是说下面的这个例子是不可以的:
List<String>[] ls = new ArrayList<String>[10];
那么为什么不可以呢?来看一个例子:
List<String>[] lsa = new List<String>[10]; // 实际是不可行,先假设可以这样.
Object o = lsa;//创建一个object引用指向数组
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();//新建一个Integer的 List
li.add(new Integer(3));//加入一个数据
oa[1] = li; // 将list赋值给数组的第一个元素
String s = lsa[1].get(0); //这里会报异常
由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。所以无法创建指定类型的泛型数组,可以采用通配符的方式创建数组:
List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li; // Correct.
Integer i = (Integer) lsa[1].get(0); // OK
因为使用了通配符,所以获取数据后需要进行强制类型转换,就不会出错。
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:
https://www.cnblogs.com/bclshuai/p/11380657.html
百度云盘下载地址:
链接:https://pan.baidu.com/s/1swkQzCIKI3g3ObcebgpIDg
提取码:mc8l
微信公众号获取最新的软件和视频介绍
QStockView
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix