JAVA泛型
创始人
2024-01-31 15:19:26
0

泛型的由来

因为JAVA中假如构建了一个object集合,在集合里存储任何的数据类型对象,定义了一个字符串,又定义一个常数。呢么在遍历数组Arraylist的时候,在代码行里并不会报错,但是运行之后会出现ClassCastException异常。
JAVA泛型提供了编译时类型安全检测机制,在代码行里就可以看到报错啦,能够检测到非法的类型数据结构,而不是在运行才能看到。
泛型的本质就是参数化类型,也就是所操作的数据类型是指定为一个参数。

泛型类

得到代码的复用

class 类名称 <泛型标识,泛型标识,...> {private 泛型标识 变量名;......
}

常用的泛型标识:T,E,K,V,N
T - Type(Java 类)
E - Element (在集合中使用,因为集合中存放的是元素)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的 java 类型

使用语法
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
Java1.7之后,后面的<>中的具体的数据类型可以省略不写
类名<具体的数据类型> 对象名 = new 类名<>();

泛型类的定义
package demo1;/*** 泛型类的定义* @param  泛型标识-类型形参*  T 创建对象的时候里指定具体的数据类型*/
public class Generic {
// T是由外部使用类的时候来指定的private T key;public Generic(T key) {this.key = key;}public T getKey() {return key;}public void setKey(T key) {this.key = key;}public String toString() {return "Generic{" +"key=" + key +"}";}
}
泛型类
package demo1;public class MainClass {public static void main(String[] args) {//泛型类在创建对象的时候,来指定操作的具体数据类型。Generic strGeneric = new Generic<>("abc");String key1 = strGeneric.getKey();System.out.println("key1:" + key1);

输出结果:key1:abc

试一下定义integer型

        Generic integerGeneric = new Generic<>(100);int key2 = integerGeneric.getKey();System.out.println("key2:" + key2);

运行得到
key1:abc


key2:100
在这里插入图片描述

泛型类注意:
泛型类,如果没有指定具体的数据类型,此时,操作类型是object
泛型的类型参数只能是类类型,不能是基本数据类型(不能用int,用interger)
泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同的类型。

第三条难理解的话 上代码

        System.out.println(intGeneric.getClass());System.out.println(strGeneric.getClass());

输出结果:
class demo1.Generic
class demo1.Generic
是一样的
在这里插入图片描述
从泛型类派生子类
子类也是泛型类,子类和父类的泛型类型要一致。

class ChildGeneric extends Generic

子类不是泛型类,父类要明确泛型的数据类型。

class ChildGeneric extends Generic

第一种情况
泛型类派生子类,子类也是泛型类,呢么子类的泛型式表示要和父类一致
父类

package demo2;public class Parent {private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}
}

子类

package demo2;public class ChildFilrst extends Parent {public T getValue(){return super.getValue();}}

主类

package demo2;public class TEST {public static void main(String[] args) {ChildFilrst childFilrst = new ChildFilrst<>();childFilrst.setValue("abc");String value = childFilrst.getValue();System.out.println(value);}
}

运行得到 abc
在这里插入图片描述
第二种情况
泛型类派生子类,如果子类不是泛型类,呢么父类要明确数据类型

        ChildSecond childSecond = new ChildSecond();childSecond.setValue(100);Integer value1 =childSecond.getValue();System.out.println(value1);

在这里插入图片描述

泛型接口

定义语法

interface 接口名称 <泛型标识,泛型标识,...> {泛型标识 方法名();......
}

泛型接口的使用
实现类不是泛型类,接口要明确数据类型

实现类也是泛型类,实现类和接口的泛型类型要一致。

第一种
实现泛型接口的类,不是泛型类,需要明确实现泛型接口的数据类型
这里Test类不是泛型类,所以要明确泛型接口的数据类型 这里定义T是String类型

public class Test extends Generator {

实现类

package demo3;public class Test extends Generator {public String getKey() {return "hello generic";}
}

泛型接口类

package demo3;/*** 泛型接口*/public class Generator {T getKey() {return null;}
}

主类

package demo3;public class main {public static void main(String[] args) {Test test = new Test();String key = test.getKey();System.out.println(key);}
}

运行得到
hello generic
在这里插入图片描述
泛型接口的实现类,是一个泛型类,呢么要保证实现接口的泛型类的泛型标识包含泛型接口的泛型标识

实现类Test1

package demo3;public class Test1 extends Generator {private T key;public Test1(T key) {this.key = key;}public T getKey() {return key;}}

主类

        Test1 test1 = new Test1<>("generic");String key1 = test1.getKey();System.out.println(key1);}
}

输出 generic
在这里插入图片描述

泛型方法

泛型类:是在实例化类的时候指明泛型的具体类型
泛型方法:是在调用方法的时候指明泛型的具体类型

语法

修饰符  	返回值类型 方法名(形参列表) {方法体...
}
public 与返回值中间	非常重要,可以理解为声明此方法为泛型方法。
只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法
表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型,

Test.java

package demo4;import java.util.ArrayList;public class Test {public static void main(String[] args) {ProductGetter productGetter = new ProductGetter<>();ArrayList strList = new ArrayList<>();strList.add("电脑");strList.add("手机");strList.add("机器人");//泛型方法的调用,类型是通过调用方法的时候来指定。String product1 = productGetter.getProduct(strList);System.out.println(product1 + "\t" + product1.getClass().getSimpleName());}
}
package demo4;import java.util.ArrayList;
import java.util.Random;public class ProductGetter {static Random random  = new Random();//奖品private T product;//奖品池ArrayList list = new ArrayList<>();/*** 添加奖品*/public void addProduct(T t) {list.add(t);}/*** 抽奖*/public T getProduct() {product = list.get(random.nextInt(list.size()));return product;}/*** 定义泛型方法* list 参数* 泛型标识,具体类型由调用方法的时候来指定*/public  E getProduct (ArrayList list) {return list.get(random.nextInt(list.size()));}}

运行得到:
电脑 String
在这里插入图片描述
java类里面的泛型和方法里面的泛型是完全无关的,
java类里的泛型假如是T ,而方法里的也是T

    public  T getProduct (ArrayList list) {return list.get(random.nextInt(list.size()));

在这里定义了T已经是integer类型

ProductGetter productGetter = new ProductGetter<>();

但是运行没有变化
在这里插入图片描述
即使定义泛型标识的名字和泛型类里面的标识是相同的,但是在使用上,我们泛型方法里面的泛型和泛型类里的泛型是没有任何关系的,是独立存在的。

泛型方法与可变参数
泛型可变参数的定义

public  void print(E... e) {for (E el : e) {System.out.println(e);}
}
    /*** 泛型可变参数的定义*/public static  void print(E... e) {for(int i = 0; i < e.length; i++ ) {System.out.println(e[i]);}}
        productGetter.print(1,2,3,4,5);productGetter.print("a","b","c");

![在这里插入图片描述](https://img-blog.csdnimg.cn/577eba3bda2844678daca7309c2c9b56.png
泛型方法总结
泛型方法能使方法独立于类而产生变化
如果static方法要使用泛型能力,就必须使其成为泛型方法。

类型通配符

类型通配符一般是使用"?"代替具体的类型实参。
所以,类型通配符是类型实参,而不是类型形参。
Test.java

package demo5;public class Test {public static void main(String[] args) {Box box1 = new Box<>();box1.setFirst(100);showBox(box1);Box box2 = new Box<>();box2.setFirst(200);showBox(box2);}public static void showBox(Box box) {Number first = box.getFirst();System.out.println(first);}
}

Box,java

package demo5;public class Box {private E first;public E getFirst() {return first;}public void setFirst (E first) {this.first = first;}
}

在这里插入图片描述
我们这里

    public static void showBox(Box box) {

定义的是number类型,在第二条

        Box box2 = new Box<>();

咱们用的是Integer类型
所以出现了报错 呢么怎么办呢?
引用了类型通配符

    public static void showBox(Box box) {

在这里插入图片描述

类型通配符的上限

语法
类/接口
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。

    public static void showBox(Box  box) {Number first = box.getFirst();System.out.println(first);

决定了最大上限只能是Number
在这里插入图片描述

类型通配符的下限

类/接口
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。

    public static void showBox(Box  box) {Object first = box.getFirst();System.out.println(first);

这里定义类型只能是Object,不能是Number。不然会报错(因为super定义了下限。)
在这里插入图片描述
Super叫做下限,因为要从指定的参数往上看
extends叫做上限,因为要从参数往下看
集合比较器用super,因为确定了所有类型不可能超过已经规定的类型,保证安全地比较。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...