我必須承認我不是一個Java程式員,日常開發主要是C++和Delphi,使用Java完全是為了開發Android應用。今天在看Java的泛型,有些方面感到很奇怪,先來看下面的代碼:
class Shape {
public void Draw()
{
System.out.println("Draw Shape");
}
}
class Rect extends Shape
{
@Override
public void Draw()
{
System.out.println("Draw Rect");
}
}
class Line extends Shape
{
@Override
public void Draw()
{
System.out.println("Draw Line");
}
}
class Drawer<T> {
public
void DrawShape(T shape) {
shape.Draw();
}
}
Drawer是一個泛型類,DrawShape方法繪製一個圖形,從使用C++模板的經驗來看,這絕對是正確的,但Java居然出現編譯錯誤了:shape.Draw這樣調用不被允許。
我再把代碼修改了一下:
class Drawer<T> {
public
void DrawShape(T shape) {
shape.toString();
}
}
這樣就編譯通過了,看來Java是把 T 解釋成 Object
了,有沒有辦法讓它解釋成Shape呢,又看了一下文檔,才知道要這樣寫:
class Drawer<T extends Shape>
{
public void DrawShape(T shape)
{
shape.Draw();
}
} 原來類型參加也可以指定繼承的,如果是這樣,那和不用泛型的代碼有什麼區別呢: class Drawer {
public void
DrawShape(Shape shape) {
shape.Draw();
}
}
看來Java的泛型和C++的模板有很大的區別,Java的泛型更多的是用於容器,並且在我看來,它的最大作用是省去類型轉換的操作,並且在編譯期檢查一下類型是否正確,傳統容器類可能要這樣寫:
List intList = new ArrayList();
intList.add(new Integer(10));
Integer i =
(Integer)intList.get(0);
有了泛型以後可以改成這樣寫:
List<Integer> intList = new
ArrayList<Integer>();
intList.add(new Integer(10));
Integer i = intList.get(0);
我還注意到泛型參數不能是基本類型,只能是對象,這跟C++的模板差距又進一步拉大了。感覺Java泛型的作用並不是很大,但又搞得很複雜,比如萬用字元這種東西,先看下面的代碼:
private static void
PrintList(List<Object> list) {
for (Object o: list)
{
System.out.println(o.toString());
}
}
public static void DoTest() {
List<Rect> intList = new ArrayList<Rect>();
intList.add(new Rect());
intList.add(new Rect());
intList.add(new Rect());
PrintList(intList);
}
PrintList這一句編譯不過,因為List<Rect>與List<Object>不相容,怎麼改呢,用萬用字元:
private static void PrintList(List<?>
list) {
for (Object o: list)
{
System.out.println(o.toString());
}
}
List<?>
的意思是列表的元素類型未知,但變成Object總是沒有問題的,所以可以編譯通過,現在如果我想它是Shape,該怎麼辦呢,用萬用字元再加Extends的辦法:
class Shape {
public String
getName() {
return "Shape";
}
}
class Rect extends Shape
{
@Override
public String getName()
{
return "Rect";
}
}
public class TestGenerics {
private static void PrintList(List<?
extends Shape> list) {
for (Shape s: list)
{
System.out.println(s.getName());
}
}
public static void DoTest()
{
List<Rect> intList = new
ArrayList<Rect>();
intList.add(new
Rect());
intList.add(new Rect());
intList.add(new Rect());
PrintList(intList);
}
}
看看List<? extends Shape>
list,我已經快被搞暈了,它的意思是List的項必須是Shape或繼承自Shape,搞了一圈又回到使用多態就可以解決問題了。
但這個用法又帶來了一些限制,就是List<? extends Shape> list中的list是不能增加刪除元素的,比如:
private static void PrintList(List<?
extends Shape> list) {
for (Shape s: list)
{
System.out.println(s.getName());
}
list.add(new
Line());
}
list.add(new Line())這句編不過,因為帶有萬用字元的集合類,根本不能確定它的元素是什麼類型。
個人覺得Java不要泛型的好,因為沒有一定要用它的理由啊,它只可以幫你自動轉換和檢查一下類型,但它所帶來的文法複雜性,其實是得不償失的。