java泛型通俗讲解
项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步
1.为什么需要泛型
我们知道java是属于强类型编程语言。变量在使用之前,需要先进行定义,而定义个变量时必须要指定其数据类型,这样编译器在编译阶段就能将很多类型错误消灭在萌芽状态。
如果我们有这样一个需求:定义一个坐标类。但是该坐标类的数据类型可能是整数,也可以能是小数,还有可能是字符串。举个例子
x=10; y=15;
x="东经116",y="北纬39"
x=10.01; y=15
坐标有可能是整型,也有可能是字符串类型,还有可能是double类型。如果没有泛型,我们可能会这么做
package edu.bit.test;public class ObjectType {public static void main(String[] args) {Point p = new Point();p.setX(10);p.setY(15);//向下转型,此时没有问题,代码能正常运行int x = (Integer)p.getX();int y = (Integer)p.getY();System.out.println(p);p.setX("东经116");p.setY("北纬39");//此时向下转型会有问题double x1 = (Double)p.getX();double y1 = (Double)p.getY();System.out.println(p);}
}class Point {Object x = 0;Object y = 0;public Object getX() {return x;}public void setX(Object x) {this.x = x;}public Object getY() {return y;}public void setY(Object y) {this.y = y;}@Overridepublic String toString() {return "Point{" +"x=" + x +", y=" + y +'}';}
}
将代码run起来
Point{x=10, y=15}
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Doubleat edu.bit.test.ObjectType.main(ObjectType.java:22)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:497)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)Process finished with exit code 1
在上面的示例代码中,用的是Object类型。这样,在调用set方法的时候是没有问题的。但是在使用get方法时,因为需要将Object类向下转型成其他类,这样容易带来问题。并且,这种问题在jdk编译阶段还不容易被发现,往往只有在运行的时候才会抛出异常!像我们上面的代码,在IDE中是不会报错的,但是代码run起来以后,会抛出一个ClassCastException的异常!
2.泛型的使用方式
将上面的代码改用泛型的方式实现
package edu.bit.test;public class GenericType {public static void main(String[] args) {Point1<Integer,Integer> p1 = new Point1<Integer, Integer>();p1.setX(10);p1.setY(15);System.out.println(p1);Point1<String,String> p2 = new Point1<String,String>();p2.setX("东经116");p2.setY("北纬39");System.out.println(p2);}}class Point1<T1,T2> {T1 x;T2 y;public T1 getX() {return x;}public void setX(T1 x) {this.x = x;}public T2 getY() {return y;}public void setY(T2 y) {this.y = y;}@Overridepublic String toString() {return "Point1{" +"x=" + x +", y=" + y +'}';}
}
将代码run起来
Point1{x=10, y=15}
Point1{x=东经116, y=北纬39}
在上面的例子里,直接将Point1类定义为泛型类。泛型类的定义方法为类名后面用尖括号将<T1,T2>包起来,其中的T1,T2是我们自己定义的类标志符,用来表示数据的类型。并且注意的是,T1,T2只是类型标识的占位符,编译阶段并不会真正确定类型,只有在运行阶段才会替换为真正的数据类型。
使用泛型的好处是:当我们在是使用泛型的时候,即指定了数据类型,又可以根据需要灵活使用不同数据类型,在使用严谨性与灵活性之间做了一个很好的兼顾。尤其是在各种框架中,泛型的使用非常广泛。
3.限制泛型的使用类型
在我们上面的代码中,没有对参数类型做任何限制,可以使用任何类型的参数。然后在很多实际场景中,还是需要对参数类型做一定限制的,只能传递部分参数类型,传递其他类型则会引发错误。例如在前面的Point类中,我们希望用户只能传递数字类型,而不能传递字符串等其他类型:
package edu.bit.test;public class GenericSmallType {public static void main(String[] args) {Point2<Integer,Integer> p1 = new Point2<Integer,Integer>();p1.setX(10);p1.setY(15);System.out.println(p1);Point2<Double,Double> p2 = new Point2<Double,Double>();p2.setX(10.0);p2.setY(15.01);System.out.println(p2);}
}class Point2<T1 extends Number,T2 extends Number> {public T1 x;public T2 y;public T1 getX() {return x;}public void setX(T1 x) {this.x = x;}public T2 getY() {return y;}public void setY(T2 y) {this.y = y;}@Overridepublic String toString() {return "Point2{" +"x=" + x +", y=" + y +'}';}
}
将代码run起来:
Point2{x=10, y=15}
Point2{x=10.0, y=15.01}
4.类型擦除(type erasure)
java字节码中不包含有泛型的类型信息。编译器在编译阶段去掉泛型信息,在运行的时候加上类型信息,这个过程被称为类型擦除。
我们在使用泛型的过程中,如果没有指定数据类型,那么将会擦除泛型类型。
package edu.bit.test;public class TypeErasure {public static void main(String[] args) {Point3 p1 = new Point3();p1.setX("东经116");p1.setY("北纬39");//向下转型String longitude = (String)p1.getX();String latitude = (String)p1.getY();System.out.println(p1);}
}class Point3<T1,T2> {public T1 x;public T2 y;public T1 getX() {return x;}public void setX(T1 x) {this.x = x;}public T2 getY() {return y;}public void setY(T2 y) {this.y = y;}@Overridepublic String toString() {return "Point3{" +"x=" + x +", y=" + y +'}';}
}
本例中,创建Point3对象的时候没有指定数据类型。编译器在处理的时候,会将所有数据向上变为Object类型。然而这样处理完以后,使用get方法的时候,又需要向下转型。这样的话,跟第一部分没有使用泛型就一样了!
java泛型通俗讲解相关推荐
- Java线程通俗讲解
Java线程介绍 通常情况下,在一个服务器上面运行的程序是很多的,可能同一时间会有多个客户 端的程序访问服务器,服务器都要对这些客户端做出响应.如果我们处理器有限, 只有一个处理器的时候,如何能够让这 ...
- Java泛型详解-史上讲解最详细的,没有之一
目录 1. 概述 2. 一个栗子 3. 特性 4. 泛型的使用 4.1 泛型类 4.2 泛型接口 4.3 泛型通配符 4.4 泛型方法 4.4.1 泛型方法的基本用法 4.4.2 类中的泛型方法 4. ...
- Java基础之泛型简单讲解(通俗易懂)
Java基础之泛型简单讲解(通俗易懂) 1. 前言 2. 简单例子对比理解 2.1 未使用泛型例子--ArrayList 2.2 使用泛型的例子 2.2.1 ArrayList 举例 2.2.2 Ha ...
- Java多数据源最通俗讲解
Java多数据源最通俗讲解 before after 理论 实操 编码 小总结 before 项目中可能会用到很多的数据源,例如目前这个项目中用到了五个数据源,那么数据源的 配置和数据源的切换就成为了 ...
- java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一,大厂 HR 如何面试
写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 对j ...
- java泛型(360°无死角讲解)
什么是泛型 Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构.泛型的本质就是参数化类型,也就是所操作的数据 ...
- java泛型特点_java泛型简单总结
Java泛型简单总结 1)基本概念: 泛型(Generic Type或Generics)是 对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看做是使用参数化类型时 ...
- java 泛型 t_Kotlin(2) 泛型与集合
前言 以一个java老鸟的角度,如何去看 kotlin.Java源代码应该如何用Kotlin重构.如何正确学习kotlin并且应用到实际开发中.本文将会探究. 本文分两大块,重难点和潜规则. 重难点: ...
- 一文搞懂 Java 泛型,非常详细!
作者: ZiWenXie http://www.ziwenxie.site/2017/03/01/java-generic/ 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广 ...
- java泛型的作用和实现原理_java泛型的作用及实现原理
一.泛型的介绍 泛型是Java 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Ja ...
最新文章
- Android studio 编译器导入一个背景图片
- 东莞厚街工业机器人展会_工业机器人四大家族齐聚!东莞将在12月举办智博会...
- 【转】BT5汉化步骤
- springmvc二十七:springmvc-ResponseBody与ResponseEntity
- 我们编写的C代码是怎样跑起来的?
- Flex开发中遇到未整理资源
- RS-232 vs. TTL Serial Communication(转载)
- 解决文件上传_使用FastDfs上传头像上传不成功的问题---SpringCloud Alibaba_若依微服务框架改造---工作笔记002
- 企业数据安全防护不可忽视,数据丢失/损坏如何处理?
- java模式:深入单例模式
- 京瓷1020手动双面打印提示_自动双面打印时纸张是如何被翻转的?
- 阿里云服务器搭建私人云盘
- 飞秒激光制备量子计算机,制备出世界最大规模光量子计算芯片
- 自动驾驶常用传感器介绍
- Compose 这次要送 Pixel 5 了!
- (三)Latex的字体字号设置
- ECMAScript 6 简明教程(一文搞懂ES6)
- FCoin币改试验区(主版C)筹备公告(5号)
- CSS 关键字 initial、inherit 和 unset
- Ubuntu22.04 美化