Java泛型类是指在定义类时使用泛型,以便把类的定义与使用分开,使得类可以接受不同的数据类型。泛型类的定义格式如下:
public class 类名<T> { // 类中的成员变量、方法 }
其中T表示一个占位符,当创建对象时,可以把具体的数据类型传递进去。例如:
public class Point<T> { private T x; private T y; public Point(T x, T y) { this.x = x; this.y = y; } public void setX(T x) { this.x = x; } public void setY(T y) { this.y = y; } public T getX() { return x; } public T getY() { return y; } }
上面代码定义了一个Point泛型类,该类有两个成员变量x、y,并有相应的getter/setter方法。在创建Point对象时,需要传入x、y的数据类型。例如:
Point<Integer> point1 = new Point<Integer>(10, 20); // 创建一个Point对象,x、y都是Integer类型 Point<Double> point2 = new Point<Double>(10.5, 20.5); // 创建一个Point对象,x、y都是Double类型
Java泛型最大的好处就是在定义时就能够将数据类型进行限制,避免出错。此外还能够减少代码量、提高代码可读性。因此在开发中应该尽量使用泛型来定义对象。
泛型在 java 中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。
什么是泛型?为什么要使用泛型?
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型只在编译阶段有效。看下面的代码:
List<String> stringArrayList = new ArrayList<String>(); List<Integer> integerArrayList = new ArrayList<Integer>(); Class classStringArrayList = stringArrayList.getClass(); Class classIntegerArrayList = integerArrayList.getClass(); if(classStringArrayList.equals(classIntegerArrayList)){ Log.d("泛型测试","类型相同"); }
输出结果:D/ 泛型测试: 类型相同。
通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息输出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法的规则:
下面的例子演示了如何使用泛型方法打印不同字符串的元素:
public class GenericMethodTest
{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { "H", "E", "L", "L", "O" };
System.out.println( "Array integerArray contains:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "nArray doubleArray contains:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "nArray characterArray contains:" );
printArray( charArray ); // 传递一个字符型型数组
}
}
编译以上代码,运行结果如下所示:
Array integerArray contains:
1 2 3 4 5 6
Array doubleArray contains:
1.1 2.2 3.3 4.4
Array characterArray contains:
H E L L O
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受 Number 或者 Number 子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟 extends 关键字,最后紧跟它的上界。
下面的例子演示了 "extends" 如何使用在一般意义上的意思 "extends"(类)或者"implements"(接口)。该例子中的泛型方法返回三个可比较对象的最大值。
public class MaximumTest
{
// 比较三个值并返回最大值
public static <T extends Comparable<T>> T maximum(T x, T y, T z)
{
T max = x; // 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
max = y; //y 更大
}
if ( z.compareTo( max ) > 0 ){
max = z; // 现在 z 更大
}
return max; // 返回最大对象
}
public static void main( String args[] )
{
System.out.printf( "Max of %d, %d and %d is %dnn",
3, 4, 5, maximum( 3, 4, 5 ) );
System.out.printf( "Maxm of %.1f,%.1f and %.1f is %.1fnn",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
System.out.printf( "Max of %s, %s and %s is %sn","pear",
"apple", "orange", maximum( "pear", "apple", "orange" ) );
}
}
编译以上代码,运行结果如下所示:
Maximum of 3, 4 and 5 is 5
Maximum of 6.6, 8.8 and 7.7 is 8.8
Maximum of pear, apple and orange is pear
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
如下实例演示了我们如何定义一个泛型类:
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%dnn", integerBox.get());
System.out.printf("String Value :%sn", stringBox.get());
}
}
编译以上代码,运行结果如下所示:
Integer Value :10
String Value :Hello World
Java 给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个...
Java 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。接下来我们会详细介绍 Java 9 ...
Java 8 StreamJava 8 新特性Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类...
Java流 -Java创建流已将新方法添加到Java库以返回流。我们可以通过以下方式创建流。从值创建流从空流创建流从函数创建流从数组创...
java.util包提供了Date类来封装当前的日期和时间。 Date类提供两个构造函数来实例化Date对象。第一个构造函数使用当前日期和时间...