iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >深入理解java泛型Generic
  • 323
分享到

深入理解java泛型Generic

2024-04-02 19:04:59 323人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录一、背景二、泛型概念三、泛型类3.1 定义与调用3.2 注意3.3 使用3.4 泛型类的继承3.4.1 子类也是泛型类3.4.2 子类不是泛型类四、泛型接口4.1 定义4.2 使

一、背景

泛型技术诞生之前(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)

二、泛型概念

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.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;
	}
	@Override
	public 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{
	@Override
	public Object getValue() {
		return super.getValue();
	}
}

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


class ChildFirst<T> extends Parent<E>{
	@Override
	public 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>{
	@Override
	public 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>{
	@Override
	public 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{
	@Override
	public Object getValue() {
		return super.getValue();
	}
}

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


class ChildSecond extends Parent<String>{
	@Override
	public 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.1 定义


public interface Generator<T>{ ... }

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

4.2.1 实现类不是泛型类

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


class Apple implements Generator<String>{
	@Override
	public String getKey() {
		return "Generator interface";
	}
}

4.2.2 实现类也是泛型类

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


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

五、泛型方法

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.1 类型通配符介绍

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

6.2 为什么要用类型通配符

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


public class BoxTest {
	public static void main(String[] args) {
		// 3.调用showBox
		Box<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.调用showBox
		Box<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 类型进行遍历;

七、类型擦除

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

到此这篇关于深入理解java泛型Generic的文章就介绍到这了,更多相关java泛型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 深入理解java泛型Generic

本文链接: https://www.lsjlt.com/news/125643.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入理解java泛型Generic
    目录一、背景二、泛型概念三、泛型类3.1 定义与调用3.2 注意3.3 使用3.4 泛型类的继承3.4.1 子类也是泛型类3.4.2 子类不是泛型类四、泛型接口4.1 定义4.2 使...
    99+
    2022-11-12
  • 深入了解golang中的的泛型(Generic)
    本篇文章给大家带来的内容是介绍深入理解golang中的泛型?泛型怎么使用?有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所助。什么是泛型泛型(Generic)是一种编程技术。在强类型语言中, 允许编写代码时使用以后才指定的类型, ...
    99+
    2023-05-14
    Go 后端
  • Java泛型Generic机制实例详解
    目录泛型是什么?泛型类泛型方法类型变量的限制类型擦除通配符上界通配符下界通配符无界通配符反射和泛型类型字面量限制和局限性不能使用基本类型实例化类型参数运行时类型查询只适用于原始类型不...
    99+
    2022-11-13
    Java 泛型 Generic Java Generic
  • 深入浅出理解Java泛型的使用
    目录一、泛型的意义二、泛型的使用三、自定义泛型类1.关于自定义泛型类、泛型接口:2.泛型在继承方面的体现3.通配符的使用一、泛型的意义 二、泛型的使用 1.jdk 5.0新增特性 ...
    99+
    2022-11-12
  • 深入学习java之泛型
    概念:泛型,即“参数化类型”。就是将原来具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。本质:为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不...
    99+
    2017-12-30
    java入门 java 泛型
  • java中泛型Generic的作用是什么
    java中泛型Generic的作用是什么?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. 背景泛型技术诞生之前(JDK5以前),创建集合的类型都是Object 类型的元素...
    99+
    2023-06-15
  • 深入了解Java核心类库--泛型类
    目录1.1 泛型的使用1.1.1 泛型类1.1.2 泛型接口1.1.3 泛型方法1.1.4 tips 1.2 泛型限制类型1.3 通配符?1.3.1 上界限定1.3.2 下...
    99+
    2022-11-12
  • Java深入浅出讲解泛型与包装类
    目录1、什么是泛型2、泛型的语法3、泛型的上界4、通配符(1)通配符的上界(2)通配符的下界5、包装类1、什么是泛型 泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指...
    99+
    2022-11-13
  • 一文带你深入理解Golang中的泛型
    目录1. 概述1.1 什么是泛型1.2 Go 泛型的背景1.3 Go 泛型的特点2. 语法2.1 泛型函数2.2 泛型类型2.3 泛型约束2.4 泛型特化2.5 泛型接口2.5.1 ...
    99+
    2023-05-18
    Golang泛型用法 Golang泛型 Go 泛型
  • C++泛型模板约束深入讲解
    CPP参考:(新标准) 传送门 模板对于类型的约束: 约束 template_get_size 泛型T只允许接受类型:list<T>,其实为 C/C++ 泛型模板例化特性...
    99+
    2022-11-13
  • 深入了解Rust中泛型的使用
    目录楔子函数中的泛型结构体中的泛型枚举中的泛型方法中的泛型楔子 所有的编程语言都致力于将重复的任务简单化,并为此提供各种各样的工具。在 Rust 中,泛型(generics)就是这样...
    99+
    2022-11-13
    Rust泛型使用 Rust泛型
  • 深入浅析java中集合泛型的本质
    深入浅析java中集合泛型的本质?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、初始化两个集合,一个使用泛型,一个不使用ArrayList list1 = new Array...
    99+
    2023-05-31
    java 集合泛型 ava
  • 重新理解Java泛型
    这篇文章的目的在于介绍Java泛型,使大家对Java泛型的各个方面有一个最终的,清晰的,准确的理解,同时也为下一篇《重新理解Java反射》打下基础。简介泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从...
    99+
    2023-05-30
    java 泛型的理解 ava
  • Java 泛型超详细入门讲解
    目录1、什么是泛型2、泛型是怎么编译的泛型的编译机制:擦除机制1、什么是泛型 泛型其实就是将类型作为参数传递,泛型允许程序员在编写代码时使用一些以后才指定的类型 ,在实例化该类时将想...
    99+
    2022-11-13
  • 怎么深入理解Java内存模型JMM
    这期内容当中小编将会给大家带来有关怎么深入理解Java内存模型JMM,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java 内存模型Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组...
    99+
    2023-06-05
  • 怎么理解Java/Scala泛型
    本篇内容介绍了“怎么理解Java/Scala泛型”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!泛型(Generics)是强类型编程语言中经常...
    99+
    2023-06-16
  • Java中的泛型怎么理解
    本篇内容介绍了“Java中的泛型怎么理解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!泛型:是JDK5中引入的特性,可以在编译阶段约束操作的...
    99+
    2023-06-30
  • Java IO流深入理解
    目录阻塞(Block)和非阻塞(Non-Block)同步(Synchronization)和异步(Asynchronous)BIO与NIO对比面向流与面向缓冲阻塞与非阻塞选择器的问世...
    99+
    2022-11-12
  • java String的深入理解
    java String的深入理解一、Java内存模型 按照官方的说法:Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。     JVM主要管理两种类型内存...
    99+
    2023-05-31
    java string ava
  • Java内存模型的深入讲解
    目录内存模型硬件架构Java内存模型与硬件关联对象的可见性竞争条件总结Java内存模型展示了Java虚拟机是如何与计算机内存交互的,解决多线程读写共享内存时资源访问的问题。 内存模型...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作