文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

java中泛型Generic的作用是什么

2023-06-15 01:08

关注

java中泛型Generic的作用是什么?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

1. 背景

泛型技术诞生之前(JDK5以前),创建集合的类型都是Object 类型的元素,存储内容没有限制,编译时正常,运行时容易出现ClassCastException 异常。

public class Test {public static void main(String[] args) {ArrayList list = new ArrayList();list.add("java");list.add(100);list.add(true);for(int i = 0;i <list.size();i++) {Object o = list.get(i);String str = (String)o;System.out.println(str);}}}

输出:

java
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.chengyu.junit.Test.main(Test.java:18)

2. 泛型概念

JDK5 中引入泛型,从而可以在编译时检测是否存在非法的类型数据结构
其本质就是参数化类型,可以用于类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

public static void main(String[] args) {ArrayList<String> strList = new ArrayList<String>();strList.add("java");strList.add("C#");for(int i = 0;i < strList.size();i++) {String str = strList.get(i);System.out.println(str);}}

3. 泛型类

3.1 定义与调用

定义类时设置泛型,该泛型可用于类中的属性或方法中,调用该泛型类时,指定具体类型;

// 调用泛型类public class GenericTest {public static void main(String[] args) {Generic<String> strGen = new Generic<>("a");String key = strGen.getKey();System.out.println(key);}}// 定义泛型类// @param <T> 使用类时指定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;}@Overridepublic String toString() {return "GenericTest [key=" + key + "]";}}

3.2 注意

1)调用泛型类时未定义类型,则会按照Object 类型处理;
2)调用时分别指定不同类型,但本质都是Object 类型;
3)泛型不支持基本数据类型;
4)泛型类的成员方法不可以用static 修饰(泛型方法可以)。

3.3 使用

需求:抽奖活动,但抽奖内容没有确定,可能都是现金,也可能都是物品

public class ProductGetterTest {public static void main(String[] args) {// 抽物品ProductGetter<String> strProductGetter = new ProductGetter<>();String[] str = {"手机","电视","洗衣机"};for(int i = 0; i < str.length; i ++ ) {strProductGetter.addProduct(str[i]);}String strProduct = strProductGetter.getProduct();System.out.println("恭喜您抽中了" + strProduct);System.out.println("=============================================");// 抽现金ProductGetter<Integer> intProductGetter = new ProductGetter<>();Integer[] integer = {1000,2000,3000};for(int i = 0; i < integer.length; i ++ ) {intProductGetter.addProduct(integer[i]);}int intProduct = intProductGetter.getProduct();System.out.println("恭喜您抽中了" + intProduct);}}// 抽奖器class ProductGetter<T>{Random random = new Random();// 奖品池ArrayList<T> list = new ArrayList<>();// 添加奖品public void addProduct(T t) {list.add(t);}// 抽奖(获取奖品)public T getProduct() { return list.get(random.nextInt(list.size()));}}

3.4 泛型类的继承

3.4.1 子类也是泛型类

子类也是泛型类,则泛型要保持一致。

class ChildFirst<T> extends Parent{ ... }

1)指定子类泛型,不指定父类泛型,父类默认为Object 类型

class Parent<E>{private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}}class ChildFirst<T> extends Parent{@Overridepublic Object getValue() {return super.getValue();}}

2)若父类保留原有泛型,与子类泛型不一致,则会编译出错

class ChildFirst<T> extends Parent<E>{@Overridepublic E getValue() {return super.getValue(); }

3)父类泛型与子类保持一致
具体泛型指定是由子类传递到父类当中,所以继承时父类要与子类泛型保持一致(当然都写成E也可以)。

class Parent<E>{private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}}class ChildFirst<T> extends Parent<T>{@Overridepublic T getValue() {return super.getValue();}}

4)调用

public class GenericTest {public static void main(String[] args) {ChildFirst<String> childFirst = new ChildFirst<>();childFirst.setValue("chengyu");System.out.println(childFirst.getValue());}}

5)补充:
子类可以进行泛型扩展,但子类必须有一个泛型与父类一致

public class GenericTest {public static void main(String[] args) {ChildFirst<String,Integer> childFirst = new ChildFirst<>();childFirst.setValue("chengyu");System.out.println(childFirst.getValue());}}class Parent<E>{private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}}class ChildFirst<T,E> extends Parent<T>{@Overridepublic T getValue() {return super.getValue();}}
3.4.2 子类不是泛型类

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

class ChildSecond extends Parent<String>{ ... }

1)子类不是泛型类,不指定父类泛型,父类默认为Object 类型

class Parent<E>{private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}}class ChildSecond extends Parent{@Overridepublic Object getValue() {return super.getValue();}}

2)父类要明确泛型的数据类型

class ChildSecond extends Parent<String>{@Overridepublic String getValue() {return super.getValue();}}

3)调用

public class GenericTest {public static void main(String[] args) {ChildSecond childSecond = new ChildSecond();childSecond.setValue("chengyu2");System.out.println(childSecond.getValue());}}

4. 泛型接口

4.1 定义

public interface Generator<T>{ ... }

4.2 使用(与继承特点相同)

4.2.1 实现类不是泛型类

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

class Apple implements Generator<String>{@Overridepublic String getKey() {return "Generator interface";}}
4.2.2 实现类也是泛型类

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

class Apple<T> implements Generator<T>{private T key;@Overridepublic T getKey() {return key;}}

5. 泛型方法

5.1 定义

5.1.1 泛型方法
修饰符 <T,E,..> 返回值类型 方法名(形参列表){}// 泛型方法public <E,T> E getProduct(ArrayList<E> list) {return list.get(random.nextInt(list.size()));}
5.1.2 静态泛型方法
修饰符 <T,E,..> 返回值类型 方法名(形参列表){}// 泛型方法public <E,T> E getProduct(ArrayList<E> list) {return list.get(random.nextInt(list.size()));}
5.1.3 可变参数的泛型方法
public <E> void print(E... e) {for(int i = 0; i < e.length;i++){System.out.println(e[i]);}}// 调用print(1,2,3,4);

5.2 注意

1)包含泛型列表的方法才是泛型方法,泛型类中使用了泛型的方法并不是泛型方法;
2)泛型列表中声明了泛型类型,才可以在方法中使用泛型类型;
3)泛型方法中的泛型类型独立于泛型类的泛型,与类泛型类型无关;
4)泛型方法可以用static 修饰(泛型类的成员方法不可以)。

5.3 使用

5.3.1 定义泛型方法
// 抽奖器// @param <t>class ProductGetter<T>{Random random = new Random();// 奖品池ArrayList<T> list = new ArrayList<>();// 添加奖品public void addProduct(T t) {list.add(t);}// 抽奖(获取奖品)public T getProduct() { return list.get(random.nextInt(list.size()));}// 泛型方法public <E> E getProduct(ArrayList<E> list) {return list.get(random.nextInt(list.size()));}}
5.3.2 调用泛型方法
public class ProductGetterTest {public static void main(String[] args) {ProductGetter<Integer> intProductGetter = new ProductGetter<>();ArrayList<String> strList = new ArrayList<>();strList.add("手机");strList.add("电视");strList.add("洗衣机");String product = intProductGetter.getProduct(strList);System.out.println("恭喜您抽中了" + product);}}

6. 类型通配符

6.1 类型通配符介绍

类型通配符一般用【?】代替具体的类型 实参

6.2 为什么要用类型通配符

泛型类被调用时,需要指定泛型类型,当泛型类的方法被调用时,不能灵活对应多种泛型类型的需求,如下面代码【4.】部分所示:

public class BoxTest {public static void main(String[] args) {// 3.调用showBoxBox<Number> box1 = new Box<>();box1.setFirst(100);showBox(box1);// 4.再次调用showBox// 出现问题:类型发生变化后会报错Box<Integer> box2 = new Box<>();box2.setFirst(200);showBox(box2);}// 2. 调用泛型类,此时需要指定泛型类型public static void showBox(Box<Number> box) {Number first = box.getFirst();System.out.println(first);}}// 1.定义泛型类class Box<E>{private E first;public E getFirst() {return first;}public void setFirst(E first) {this.first = first;}}

解决上述问题,类型通配符【?】登场

public class BoxTest {public static void main(String[] args) {// 3.调用showBoxBox<Number> box1 = new Box<>();box1.setFirst(100);showBox(box1);// 4.再次调用showBox// 问题得以解决Box<Integer> box2 = new Box<>();box2.setFirst(200);showBox(box2);}// 2. 调用泛型类,此时需要指定泛型类型// 【?】类型通配符等成public static void showBox(Box<?> box) {Object first = box.getFirst();System.out.println(first);}}// 1.定义泛型类class Box<E>{private E first;public E getFirst() {return first;}public void setFirst(E first) {this.first = first;}}

6.3 泛型通配符上限 extends

【6.2】代码例中,虽然使用了通配符,但 box.getFirst()返回类型仍然需要定义成Object 类型,并不理想。

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

通配符上限登场:
调用showBox 方法时,传递的泛型类型可以是Number 及其子类(Integer)

public static void showBox(Box<? extends Number> box) {Number first = box.getFirst();System.out.println(first);}

注意:

public static void showBox(Box<? extends Number> box) {Number first = box.getFirst();// 此处编译报错:类型不一致// 虽然定义上限,showBox 被调用时没问题,但在方法内同时定义多种类型,编译器无法识别Integer second = box.getFirst();System.out.println(first);}

6.4 泛型通配符下限 super

public static void showBox(Box<? super Integer> box) {Number first = box.getFirst();System.out.println(first);}

注意:
遍历时要用Object 类型进行遍历;

7. 类型擦除

泛型信息只存在于代码编译阶段,进入JVM之前,与泛型相关的信息会被擦除,这个行为称为类型擦除。

Java有哪些集合类

Java中的集合主要分为四类:1、List列表:有序的,可重复的;2、Queue队列:有序,可重复的;3、Set集合:不可重复;4、Map映射:无序,键唯一,值不唯一。

关于java中泛型Generic的作用是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网行业资讯频道了解更多相关知识。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯