Java泛型使用全解

本文概述

  • Java泛型的优势
  • Java泛型的完整示例
  • 使用Map的Java泛型示例
  • 通用类
  • 类型参数
  • 通用方法
  • Java泛型中的通配符
  • 下界通配符
J2SE 5中引入了Java泛型编程, 以处理类型安全的对象。通过在编译时检测错误, 使代码稳定。
在使用泛型之前, 我们可以在集合中存储任何类型的对象, 即非泛型。现在, 泛型强制Java程序员存储特定类型的对象。
Java泛型的优势泛型主要有3个优点。它们如下:
1)类型安全:泛型中只能容纳一种类型的对象。它不允许存储其他对象。
没有泛型, 我们可以存储任何类型的对象。
List list = new ArrayList(); list.add(10); list.add("10"); With Generics, it is required to specify the type of object we need to store. List< Integer> list = new ArrayList< Integer> (); list.add(10); list.add("10"); // compile-time error

2)不需要强制类型转换:无需强制转换对象。
在泛型之前, 我们需要键入强制类型转换。
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); //typecasting After Generics, we don't need to typecast the object. List< String> list = new ArrayList< String> (); list.add("hello"); String s = list.get(0);

3)编译时检查:在编译时进行检查, 因此在运行时不会出现问题。好的编程策略表明, 在编译时处理问题比运行时要好得多。
List< String> list = new ArrayList< String> (); list.add("hello"); list.add(32); //Compile Time Error

使用通用集合的语法
ClassOrInterface< Type>

在Java中使用泛型的示例
ArrayList< String>

Java泛型的完整示例在这里, 我们使用ArrayList类, 但是你可以使用任何集合类, 例如ArrayList, LinkedList, HashSet, TreeSet, HashMap, Comparator等。
import java.util.*; class TestGenerics1{ public static void main(String args[]){ ArrayList< String> list=new ArrayList< String> (); list.add("rahul"); list.add("jai"); //list.add(32); //compile time errorString s=list.get(1); //type casting is not required System.out.println("element is: "+s); Iterator< String> itr=list.iterator(); while(itr.hasNext()){ System.out.println(itr.next()); } } }

import java.util.*; class TestGenerics1{ public static void main(String args[]){ ArrayList< String> list=new ArrayList< String> (); list.add("rahul"); list.add("jai"); //list.add(32); //compile time errorString s=list.get(1); //type casting is not required System.out.println("element is: "+s); Iterator< String> itr=list.iterator(); while(itr.hasNext()){ System.out.println(itr.next()); } } }

立即测试
输出:
element is: jai rahul jai

使用Map的Java泛型示例现在, 我们将使用泛型使用map元素。在这里, 我们需要传递键和值。让我们通过一个简单的例子来理解它:
import java.util.*; class TestGenerics2{ public static void main(String args[]){ Map< Integer, String> map=new HashMap< Integer, String> (); map.put(1, "vijay"); map.put(4, "umesh"); map.put(2, "ankit"); //Now use Map.Entry for Set and Iterator Set< Map.Entry< Integer, String> > set=map.entrySet(); Iterator< Map.Entry< Integer, String> > itr=set.iterator(); while(itr.hasNext()){ Map.Entry e=itr.next(); //no need to typecast System.out.println(e.getKey()+" "+e.getValue()); }}}

立即测试
输出量
1 vijay 2 ankit 4 umesh

通用类可以引用任何类型的类称为泛型类。在这里, 我们使用T类型参数创建特定类型的泛型类。
【Java泛型使用全解】让我们看一个简单的示例来创建和使用泛型类。
创建一个通用类:
class MyGen< T> { T obj; void add(T obj){this.obj=obj; } T get(){return obj; } }

T类型表示它可以引用任何类型(例如String, Integer和Employee)。你为该类指定的类型将用于存储和检索数据。
使用通用类:
让我们看一下使用通用类的代码。
class TestGenerics3{ public static void main(String args[]){ MyGen< Integer> m=new MyGen< Integer> (); m.add(2); //m.add("vivek"); //Compile time error System.out.println(m.get()); }}

立即测试
输出量
2

类型参数类型参数命名约定对于彻底学习泛型很重要。常见的类型参数如下:
  1. T型
  2. 电子元素
  3. K键
  4. N-号码
  5. V-值
通用方法像通用类一样, 我们可以创建一个通用方法, 该方法可以接受任何类型的参数。在这里, 参数的范围限于声明它的方法。它允许静态和非静态方法。
我们来看一个简单的java通用方法来打印数组元素的示例。我们在这里用E表示元素。
public class TestGenerics4{public static < E > void printArray(E[] elements) { for ( E element : elements){ System.out.println(element ); } System.out.println(); } public static void main( String args[] ) { Integer[] intArray = { 10, 20, 30, 40, 50 }; Character[] charArray = { 'J', 'A', 'V', 'A', 'T', 'P', 'O', 'I', 'N', 'T' }; System.out.println( "Printing Integer Array" ); printArray( intArray); System.out.println( "Printing Character Array" ); printArray( charArray ); } }

立即测试
输出量
Printing Integer Array 10 20 30 40 50 Printing Character Array J A V A T P O I N T

Java泛型中的通配符? (问号)符号表示通配符元素。它表示任何类型。如果我们写< ?扩展Number> , 表示Number的任何子类, 例如Integer, Float和double。现在我们可以通过任何子类对象调用Number类的方法。
我们可以使用通配符作为参数, 字段, 返回类型或局部变量的类型。但是, 不允许将通配符用作泛型方法调用, 泛型类实例创建或超类型的类型参数。
让我们通过以下示例了解它:
import java.util.*; abstract class Shape{ abstract void draw(); } class Rectangle extends Shape{ void draw(){System.out.println("drawing rectangle"); } } class Circle extends Shape{ void draw(){System.out.println("drawing circle"); } } class GenericTest{ //creating a method that accepts only child class of Shape public static void drawShapes(List< ? extends Shape> lists){ for(Shape s:lists){ s.draw(); //calling method of Shape class by child class instance } } public static void main(String args[]){ List< Rectangle> list1=new ArrayList< Rectangle> (); list1.add(new Rectangle()); List< Circle> list2=new ArrayList< Circle> (); list2.add(new Circle()); list2.add(new Circle()); drawShapes(list1); drawShapes(list2); }}

输出量
drawing rectangle drawing circle drawing circle

上界通配符
上限通配符的目的是减少对变量的限制。它将未知类型限制为特定类型或该类型的子类型。它通过声明通配符(“?”), 扩展名(在类的情况下)或实现(在接口的情况下)关键字以及其上限来使用。
句法
List< ? extends Number>

这里,
?是通配符。
扩展, 是一个关键字。
数字, 是java.lang包中存在的类
假设我们要为Number及其子类型(如Integer, Double)的列表编写方法。使用列表< ? extend Number> 适用于Number类型或其任何子类的列表, 而List < Number> 仅适用于Number类型的列表。那么, 列表< ?扩展Number> 的限制比List < Number> 的限制少。
上界通配符示例
在此示例中, 我们使用上限通配符为List < Integer> 和List < Double> 编写方法。
import java.util.ArrayList; public class UpperBoundWildcard { private static Double add(ArrayList< ? extends Number> num) { double sum=0.0; for(Number n:num) { sum = sum+n.doubleValue(); }return sum; } public static void main(String[] args) {ArrayList< Integer> l1=new ArrayList< Integer> (); l1.add(10); l1.add(20); System.out.println("displaying the sum= "+add(l1)); ArrayList< Double> l2=new ArrayList< Double> (); l2.add(30.0); l2.add(40.0); System.out.println("displaying the sum= "+add(l2)); } }

立即测试
输出量
displaying the sum= 30.0 displaying the sum= 70.0

无限通配符
无限制的通配符类型表示未知类型的列表, 例如List < ?> 。这种方法在以下情况下很有用:-
  • 通过使用Object类中提供的功能实现给定方法时。
  • 当泛型类包含不依赖于type参数的方法时。
无界通配符示例
import java.util.Arrays; import java.util.List; public class UnboundedWildcard { public static void display(List< ?> list) {for(Object o:list) { System.out.println(o); } } public static void main(String[] args) { List< Integer> l1=Arrays.asList(1, 2, 3); System.out.println("displaying the Integer values"); display(l1); List< String> l2=Arrays.asList("One", "Two", "Three"); System.out.println("displaying the String values"); display(l2); }}

立即测试
输出量
displaying the Integer values 1 2 3 displaying the String values One Two Three

下界通配符下限通配符的目的是将未知类型限制为特定类型或该类型的超类型。通过先声明通配符(“?”), 再声明super关键字, 再声明其下限来使用它。
句法
List< ? super Integer>

这里,
?是通配符。
超级, 是关键字。
整数, 是包装器类。
假设我们要为Integer列表及其超类型(如Number, Object)编写方法。使用列表< ? super Integer> 适用于Integer类型的列表或其任何超类, 而List < Integer> 仅适用于Integer类型的列表。那么, 列表< ? super Integer> 的限制比List < Integer> 的限制少。
下界通配符示例
在此示例中, 我们使用下限通配符为List < Integer> 和List < Number> 编写方法。
import java.util.Arrays; import java.util.List; public class LowerBoundWildcard { public static void addNumbers(List< ? super Integer> list) {for(Object n:list) { System.out.println(n); } } public static void main(String[] args) { List< Integer> l1=Arrays.asList(1, 2, 3); System.out.println("displaying the Integer values"); addNumbers(l1); List< Number> l2=Arrays.asList(1.0, 2.0, 3.0); System.out.println("displaying the Number values"); addNumbers(l2); }}

立即测试
输出量
displaying the Integer values 1 2 3 displaying the Number values 1.0 2.0 3.0

    推荐阅读