这是我看了几个网友的文章之后总结出来的,没用总结那么细,但是对我们学习泛型应该基本够用了,有什么遗漏的地方希望大家提出来!
为什么使用泛型
使用泛型的典型例子,是在集合中的泛型使用。
在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型。
如果我们只写一个排序方法,就能够对整形数组、字符串数组甚至支持排序的任何类型的数组进行排序,这该多好啊。
使用Java泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。
规则限制
class
Gen<T> {
private
T ob;
// 定义泛型成员变量
public
Gen(T ob) {
this
.ob = ob;
}
public
T getOb() {
return
ob;
}
public
void
setOb(T ob) {
this
.ob = ob;
}
public
void
showType() {
System.out.println(
"T的实际类型是: "
+ ob.getClass().getName());
}
}
public
class
GenDemo {
public
static
void
main(String[] args) {
// 定义泛型类Gen的一个Integer版本
Gen<Integer> intOb =
new
Gen<Integer>(
88
);
intOb.showType();
int
i = intOb.getOb();
System.out.println(
"value= "
+ i);
System.out.println(
"----------------------------------"
);
// 定义泛型类Gen的一个String版本
Gen<String> strOb =
new
Gen<String>(
"Hello Gen!"
);
strOb.showType();
String s = strOb.getOb();
System.out.println(
"value= "
+ s);
}
}
class
Gen2 {
private
Object ob;
// 定义一个通用类型成员
public
Gen2(Object ob) {
this
.ob = ob;
}
public
Object getOb() {
return
ob;
}
public
void
setOb(Object ob) {
this
.ob = ob;
}
public
void
showTyep() {
System.out.println(
"T的实际类型是: "
+ ob.getClass().getName());
}
}
public
class
GenDemo2 {
public
static
void
main(String[] args) {
// 定义类Gen2的一个Integer版本
Gen2 intOb =
new
Gen2(
new
Integer(
88
));
intOb.showTyep();
int
i = (Integer) intOb.getOb();
System.out.println(
"value= "
+ i);
System.out.println(
"---------------------------------"
);
// 定义类Gen2的一个String版本
Gen2 strOb =
new
Gen2(
"Hello Gen!"
);
strOb.showTyep();
String s = (String) strOb.getOb();
System.out.println(
"value= "
+ s);
}
}
-----------------------------------------------------------------------------------------------------------------------------------------
深入泛型
有两个类如下,要构造两个类的对象,并打印出各自的成员x
public
class
StringFoo {
private
String x;
public
StringFoo(String x) {
this
.x = x;
}
public
String getX() {
return
x;
}
public
void
setX(String x) {
this
.x = x;
}
}
public
class
DoubleFoo {
private
Double x;
public
DoubleFoo(Double x) {
this
.x = x;
}
public
Double getX() {
return
x;
}
public
void
setX(Double x) {
this
.x = x;
}
}
重构
因为上面的类中,成员和方法的逻辑都一样,就是类型不一样,因此考虑重构。Object是所有类的父类,因此可以考虑用Object做为成员类型,这样就可以实现通用了,实际上就是“Object泛型”,暂时这么称呼。
public
class
ObjectFoo {
private
Object x;
public
ObjectFoo(Object x) {
this
.x = x;
}
public
Object getX() {
return
x;
}
public
void
setX(Object x) {
this
.x = x;
}
}
public
class
ObjectFooDemo {
public
static
void
main(String args[]) {
ObjectFoo strFoo =
new
ObjectFoo(
new
StringFoo(
"Hello Generics!"
));
ObjectFoo douFoo =
new
ObjectFoo(
new
DoubleFoo(
new
Double(
"33"
)));
ObjectFoo objFoo =
new
ObjectFoo(
new
Object());
System.out.println(
"strFoo.getX="
+ (StringFoo) strFoo.getX());
System.out.println(
"douFoo.getX="
+ (DoubleFoo) douFoo.getX());
System.out.println(
"objFoo.getX="
+ objFoo.getX());
}
}
实现
public
class
GenericsFoo<T> {
private
T x;
public
GenericsFoo(T x) {
this
.x = x;
}
public
T getX() {
return
x;
}
public
void
setX(T x) {
this
.x = x;
}
}
public
class
GenericsFooDemo {
public
static
void
main(String args[]) {
GenericsFoo<String> strFoo =
new
GenericsFoo<String>(
"Hello Generics!"
);
GenericsFoo<Double> douFoo =
new
GenericsFoo<Double>(
new
Double(
"33"
));
GenericsFoo<Object> objFoo =
new
GenericsFoo<Object>(
new
Object());
System.out.println(
"strFoo.getX="
+ strFoo.getX());
System.out.println(
"douFoo.getX="
+ douFoo.getX());
System.out.println(
"objFoo.getX="
+ objFoo.getX());
}
}
高级应用
有界的类型参数:
可能有时候,你会想限制参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。
这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界(<T extends Comparable<T>>)。
实例
下面的例子演示了"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 %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "Maxm of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "Max of %s, %s and %s is %s\n","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
CollectionGenFoo<T
extends
Collection> {
private
T x;
public
CollectionGenFoo(T x) {
this
.x = x;
}
public
T getX() {
return
x;
}
public
void
setX(T x) {
this
.x = x;
}
}
public
class
CollectionGenFooDemo {
public
static
void
main(String args[]) {
CollectionGenFoo<ArrayList> listFoo =
null
;
listFoo =
new
CollectionGenFoo<ArrayList>(
new
ArrayList());
// 出错了,不让这么干。
// 原来作者写的这个地方有误,需要将listFoo改为listFoo1
// 需要将CollectionGenFoo<Collection>改为CollectionGenFoo<ArrayList>
// CollectionGenFoo<Collection> listFoo1 = null;
// listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
System.out.println(
"实例化成功!"
);
}
}
多接口限制
public
class
Demo<T
extends
Comparable & Serializable> {
// T类型就可以用Comparable声明的方法和Seriablizable所拥有的特性了
}
通配符泛型
public
class
CollectionGenFooDemo {
public
static
void
main(String args[]) {
CollectionGenFoo<ArrayList> listFoo =
null
;
listFoo =
new
CollectionGenFoo<ArrayList>(
new
ArrayList());
// 出错了,不让这么干。
// 原来作者写的这个地方有误,需要将listFoo改为listFoo1
// CollectionGenFoo<Collection> listFoo1 = null;
// listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
System.out.println(
"实例化成功!"
);
}
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
泛型方法
我们可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
下面是定义泛型方法的规则:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
实例
下面的例子演示了如何使用泛型方法打印不同字符串的元素:
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
泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
实例
如下实例演示了我们如何定义一个泛型类:
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 :%d\n\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); } }
编译以上代码,运行结果如下所示:
Integer Value :10 String Value :Hello World
有界的类型参数:
可能有时候,你会想限制参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。
这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界(<T extends Comparable<T>>)。
实例
下面的例子演示了"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 %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "Maxm of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "Max of %s, %s and %s is %s\n","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