首先来了解什么是泛型集合和非泛型集合,最重要的是处理实现部分,因为在实现过程中才能真正理解概念和它们之间的差异。
泛型基本上是编译时出现的错误,而不是运行时出现的错误。 泛型相对于非泛型有以下优势:

  • 代码重用:在泛型的帮助下,只需编写一次方法/类/接口并将其用于任何类型,而在非泛型中,代码需要在需要时一次又一次地编写。
  • 类型安全:泛型使错误在编译时出现而不是在运行时出现(在编译时知道代码中的问题总是比让代码在运行时失败更好)。

    示例:要创建一个存储学生姓名的 ArrayList,如果程序员错误地添加了一个整数对象而不是字符串,编译器允许这样做。 但是,当从 ArrayList 检索此数据时,它会在运行时导致非泛型 ArrayList 出现问题。

示例1

// Java program to Demonstrate that Not Using Generics
// Can cause Run Time Exceptions

// Importing all utility classes
import java.util.*;

// Main class
class YBA {

    // Main driver method
    public static void main(String[] args)
    {
        // Creating an ArrayList
        // Declaring object without any type specified
        ArrayList al = new ArrayList();

        // Adding elements to the above object
        // Custom input elements
        al.add("Sachin");
        al.add("Rahul");

        // Compiler will allows this operation
        al.add(10);

        String s1 = (String)al.get(0);
        String s2 = (String)al.get(1);

        // Try block to check for exceptions
        try {

            // Causes Runtime Exception
            String s3 = (String)al.get(2);
        }

        // Catch block to handle the exceptions
        catch (Exception e) {

            // Display the exception
            System.out.println("Exception: " + e);
        }
    }
}

运行结果如下:

prog.java:19: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
        al.add("Sachin");
              ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
prog.java:20: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
        al.add("Rahul");
              ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
prog.java:23: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList
        al.add(10);
              ^
  where E is a type-variable:
    E extends Object declared in class ArrayList
3 warnings

泛型如何解决这个问题?

如果这个列表是通用的,那么它只需要 String 对象并在任何其他情况下抛出编译时错误。
示例2:

// Java Program to Illustrate Conversion of
// Runitime Exceptions into compile time errors
// Using generics

// Importing all utility classes
import java.util.*;

// Main class
class GFG {

    // Main driver method
    public static void main(String[] args)
    {
        // Creating an ArrayList
        // Declaring object of string type
        ArrayList<String> al = new ArrayList<String>();

        // Adding elements to the ArrayList
        // Custom input elements
        al.add("Sachin");
        al.add("Rahul");

        // Now compiler does not allow this operation
        al.add(10);

        String s1 = al.get(0);
        String s2 = al.get(1);
        String s3 = al.get(2);
    }
}

运行结果:

prog.java:24: error: incompatible types: int cannot be converted to String
        al.add(10);
               ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

下面继续,不需要单独的类型转换。

如果不需要泛型,那么在上面的示例中,每次要从 ArrayList 中检索数据时,都需要对其进行类型转换。 每次检索操作的类型转换都是一件令人头疼的事情。 如果以某种方式已知列表仅包含字符串数据,则可以避免这种情况。

示例3

/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Project/Maven2/JavaApp/src/main/java/${packagePath}/${mainClassName}.java to edit this template
 */
package com.yzinfo.demo;

import java.util.ArrayList;

/**
 *
 * @author Administrator
 */
public class YBA {

    public static void main(String[] args) {
        // Creating an ArrayList
        // Declaring object without any type specified
        ArrayList al = new ArrayList();

        // Adding elements to the above object
        // using add() method
        al.add(10);
        al.add("Sachin");
        al.add("Rahul");

        // For every retrieval,
        // it needs to be casted to String for use
        String s1 = (String) al.get(0);
        String s2 = (String) al.get(1);
        System.out.print(s1);
    }
}

运行结果:

--- exec-maven-plugin:3.0.0:exec (default-cli) @ project1 ---
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at com.yzinfo.project1.Project1.main(Project1.java:28)
Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at org.apache.commons.exec.DefaultExecutor.executeInternal (DefaultExecutor.java:404)
    at org.apache.commons.exec.DefaultExecutor.execute (DefaultExecutor.java:166)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine (ExecMojo.java:982)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine (ExecMojo.java:929)

现在来看看泛型是如何解决这个问题?

如果这个列表是通用的,那么它只需要 String 对象,并且在检索时只返回 String 对象。 因此不需要单独的类型转换。 上述说法是有道理的。

示例4

// A Simple Java program to demonstrate that
// type casting is not needed in Generic

import java.util.*;

class Test {
    public static void main(String[] args)
    {
        // Creating an ArrayList
        // Declaring object of type String
        ArrayList<String> al = new ArrayList<String>();

        // Custom input elements
        al.add("Sachin");
        al.add("Rahul");

        // Retrieval can be easily
        // without the trouble of casting
        String s1 = al.get(0);
        String s2 = al.get(1);

        // Print and display out the elements in objects
        System.out.print(al);
    }
}

运行结果:

[Sachin, Rahul]

注意:在泛型的帮助下,虽然可以实现算法实现泛型算法,但可以在不同类型的对象上工作,同时它们也是类型安全的。

请记住,有些要点将描述泛型和非泛型之间的区别,下表列出了它们之间的清晰理解。

基础 非通用集合 通用集合
语法 ArrayList list = new ArrayList(); ArrayList<ReferenceType> list = new ArrayList<ReferenceType>();
类型安全 可以保存任何类型的数据,因此不是类型安全的。 只能保存定义类型的数据,因此类型安全。
类型转换 每次检索都需要进行单独的类型转换。 不需要类型转换。
编译时检查 在运行时检查类型安全。 在编译时检查类型安全。