Java中的非泛型与泛型集合的区别
首先来了解什么是泛型集合和非泛型集合,最重要的是处理实现部分,因为在实现过程中才能真正理解概念和它们之间的差异。
泛型基本上是编译时出现的错误,而不是运行时出现的错误。 泛型相对于非泛型有以下优势:
- 代码重用: 在泛型的帮助下,只需编写一次方法/类/接口并将其用于任何类型,而在非泛型中,代码需要在需要时一次又一次地编写。
- 类型安全: 泛型使错误在编译时出现而不是在运行时出现(在编译时知道代码中的问题总是比让代码在运行时失败更好)。
示例:要创建一个存储学生姓名的
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>(); |
类型安全 | 可以保存任何类型的数据,因此不是类型安全的。 | 只能保存定义类型的数据,因此类型安全。 |
类型转换 | 每次检索都需要进行单独的类型转换。 | 不需要类型转换。 |
编译时检查 | 在运行时检查类型安全。 | 在编译时检查类型安全。 |