Java的泛型是什么?为什么要用它?

简介: Java的泛型是什么?为什么要用它?

零、最直观的理解——泛型是什么

 

泛型 ,顾名思义就是 广泛的数据类型,也就是说什么数据类型都可以

一般来说,我们见到的泛型就是这个样子,用 T 表示。

如下所示,在类名后方申明泛型 T,接着就可以在成员变量、方法中使用泛型了。

1. public class User<T> {
2. 
3.  private T name;
4. }

对于这个name变量,我们可以放入不同数据类型的值,比如字符串String,比如整数int......

下面测试类创建了三个User对象,第一个对象的name属性放入了String字符串,第二个放入了int整数,第三个放入了Double浮点数。

1. //泛型测试方法
2. public static void main(String[] args) {
3.  User user1 = new User();
4.  user1.setName("zwz");
5.  System.out.println(user1.getName() instanceof String);
6. 
7.  User user2 = new User();
8.  user2.setName(123456);
9.  System.out.println(user2.getName() instanceof Integer);
10. 
11.   User user3 = new User();
12.   user3.setName(123.456);
13.   System.out.println(user3.getName() instanceof Double);
14. }

我们发现,不管放入什么数据类型,我们都可以正常运行,运行结果如下图所示

像上面这样,我们就可以理解为泛型的一种应用

如果数据类型不确定,可以使用泛型方法的方式,达到简化代码、提高代码重用性的目的

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,使代码可以应用于多种数据类型。


以上就是我对泛型比较直观的理解,如果你想了解更多,请继续阅读下面内容。

内容比较枯燥,但还是很有用的。


一、举个栗子——从ArrayList说起

 

List<String> list = new ArrayList<String>();

这行代码,相信很多小伙伴都经常使用。在Java中,虽然后原生的数组String[],但是String[]功能并不能满足我们的需要,更多的任会选择使用Java的集合类——List。

List有两大实现,那就是是 ArrayList 和 LinkedList,分别代表顺序表和链表这两个数据结构。

虽然顺序表和链表各有各的好处,但是对于新手来说,总喜欢使用ArrayList ,相信这也是大家有目共睹的。

细心地小伙伴应该发现过,在Eclipse中,我们按下Ctrl键 + 鼠标左键,就可以进入某个类或者方法的具体实现。

就像这样,我们可以打开List的底层代码。

1. public interface List<E> extends Collection<E> {
2. /**
3.      * Appends the specified element to the end of this list (optional
4.      * operation).
5.      *
6.      * <p>Lists that support this operation may place limitations on what
7.      * elements may be added to this list.  In particular, some
8.      * lists will refuse to add null elements, and others will impose
9.      * restrictions on the type of elements that may be added.  List
10.      * classes should clearly specify in their documentation any restrictions
11.      * on what elements may be added.
12.      *
13.      * @param e element to be appended to this list
14.      * @return {@code true} (as specified by {@link Collection#add})
15.      * @throws UnsupportedOperationException if the {@code add} operation
16.      *         is not supported by this list
17.      * @throws ClassCastException if the class of the specified element
18.      *         prevents it from being added to this list
19.      * @throws NullPointerException if the specified element is null and this
20.      *         list does not permit null elements
21.      * @throws IllegalArgumentException if some property of this element
22.      *         prevents it from being added to this list
23.      */
24. boolean add(E e);
25. 
26. // 其余方法省略
27. }

在第一行类的定义代码中,就使用到了泛型。

public interface List<E> extends Collection<E>

也就是说,在我们平时使用List的时候,可以初始化为String类型的List

List<String> list = new ArrayList<String>();

也可以初始化为 Integer(int)的List

List<Integer> list = new ArrayList<Integer>();

当你的List 为String类型,在调用add()方法时,IDE会提示你是String类型的参数

同理,当List为Integer类型,调用add()方法,

在JDK1.5之前,List的add()方法的参数是Object类型,不管把什么对象放入List中,都会被强制转换为Object类型。

在通过get()方法取出集合元素时,必须进行强制类型转换,这样不仅繁琐,也容易出现强制转换异常。

从JDK1.5开始,引入了泛型这样一个新概念,改写了集合框架中的所有接口和类,增加了泛型的支持

使用泛型集合在创建集合对象的时候,制定了集合中的元素类型,从集合中取出元素时,无需强制类型转换,并且在集合中放入非指定类型的对象,IDE将出现编译错误。

比如下图在String类型的集合中插入Double类型的浮点数:

使用泛型集合在创建集合对象时置顶集合中的元素类型,从集合中取出元素时无需进行强制类型转换。


二、更多应用——泛型用法远不止这些

 

在集合中使用泛型只是多种应用中的一种,在接口、类、方法等方面也有着泛型的广泛应用。


2.1 泛型类

对于一些常常处理不同类型数据转换的类,我们可以使用泛型来定义。比如一个人的身高,可以认为是整数,也可以是浮点数。

1. public class User<T> {
2. 
3.  private T height;
4. 
5.  public User(T height) {
6.    this.height = height;
7.  }
8. 
9.  public void say() {
10.     System.out.println("I am " + this.height + "cm(s) tall.");
11.   }
12. 
13.   public T getHeight() {
14.     return height;
15.   }
16. 
17.   public void setHeight(T height) {
18.     this.height = height;
19.   }
20. }

我们在测试方法中传入不同数据类型,都可以say()方法

1. public class Main {
2.  public static void main(String[] args) {
3.    User user1 = new User(180);
4.    user1.say();
5. 
6.    User user2 = new User(188.5);
7.    user2.say();
8.  }
9. }


2.2 泛型接口

1. interface SayHeight<T>{
2.  public T getHeight();
3. };

泛型接口同理,就是拥有一个或者多个类型参数的接口,泛型接口接口的定义方式和定义泛型类比较类似。

1. public class User<T> implements SayHeight{
2. 
3.  private T height;
4. 
5.  public T getHeight() {
6.    return height;
7.  }
8. 
9.  public void setHeight(T height) {
10.     this.height = height;
11.   }
12. }

即getHeight()返回的类型由外部决定。

1. public class Main {
2.  public static void main(String[] args) {
3.    User<String> user = new User();
4.    user.setHeight("188.8");
5.    System.out.println(user.getHeight());
6.  }
7. }


2.3泛型方法

有一些方法常常需要对某个类型数据进行处理,但是处理的数据类型不唯一,就可以通过定义泛型方法,简化代码,以提高代码利用率。

1. public class Main {
2. 
3.  public <String> void showType(String s) {
4.    System.out.println(s.getClass().getName());
5.  }
6. 
7.  public static void main(String[] args) {
8.    Main main = new Main();
9.    main.showType(123);
10.     main.showType(123.456);
11.     main.showType(123.456f);
12.     main.showType(123l);
13.     main.showType("hello zwz");
14.   }
15. }

虽然在方法中写了String,但是可以传入多种数据类型的参数,进行不同的操作。

 


相关文章
|
3月前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
75 2
|
16天前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
14 0
[Java]泛型
|
25天前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
10 1
|
1月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
26 5
|
30天前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
17 1
|
2月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
35 9
Java——包装类和泛型
|
1月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
18 2
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
30天前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
13 0
|
2月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。