前言:雖然對於這種需求不常用,且比較冷門,但是還是有其存在的價值,再次做一下整理。我們常用的return語句只允許返回單個對象,相對的解決辦法就是創建一個對象,用它來持有想要返回的多個對象。
實現這種功能,還要歸功於Java1.5的新特性-泛型,我們利用泛型,可以一次性地解決該問題,以后再也不用在這個問題上浪費時間了,並且,我們可以再編譯期就能夠確保類型安全。
你也許已經想到使用集合可以實現我們的需求,但是雖然一次可以返回多個值,但是其類型都是相同的,並不完全符合我們的需求。
我們需要引入一個概念:元組(tuple),元組也稱為數據傳送對象或信使。元組是將一組對象直接打包存儲於其中的一個單一對象,這個容器對象允許讀取其中元素,但是不允許向其中存放新的對象。
通常,元組可以具有任意長度,同時元組中的對象可以是任意不同的類型。我們能夠為每一個對象指明其類型,並且可以正確讀取到數據,這就是元組可以提供的功能。我們要處理不同長度的問題,需要創建多個不同的元組。
首先我們創建一個2維元組:
-
//: net/mindview/util/TwoTuple.java(Java編程思想_代碼_目錄)
-
package net.mindview.util;
-
-
public class TwoTuple<A, B> {
-
public final A first;
-
public final B second;
-
public TwoTuple(A a, B b) {
-
first = a;
-
second = b;
-
}
-
public String toString() {
-
return "(" + first + ", " + second + ")";
-
}
-
}
構造器捕獲了要存儲的對象,而toString()方法是一個便利函數,用來顯示列表中的值。
注意:元組隱含地保持了其中元素的次序。
閱讀上面的代碼,以及根據元組的定義,你一定會感到詫異,設計思路不是應該將first和second聲明為private,然后生成這兩個變量的get方法嗎?
以上是我們大多數人的思維,但是我們仔細分析上面的代碼,可以發現完全符合我們的要求。首先我們可以讀取first和second,並且因為使用了final聲明,我們就無法在修改其值。我們對比這兩種寫法,很顯然,上面給出的代碼更加合理,更加簡潔明了。
還有另一種設計考慮,即你確實希望允許客戶端程序員改變first或second所引用的對象。然而,采用上面的形式無疑是更安全的做法,這樣的話,如果程序員想要使用具有不同元素的元組,就強制要求他們另外創建一個新的TwoTuple對象。
我們可以利用繼承機制實現長度更長的元組:
-
//: net/mindview/util/ThreeTuple.java
-
package net.mindview.util;
-
-
public class ThreeTuple<A,B,C> extends TwoTuple<A,B> {
-
public final C third;
-
public ThreeTuple(A a, B b, C c) {
-
super(a, b);
-
third = c;
-
}
-
public String toString() {
-
return "(" + first + ", " + second + ", " + third +")";
-
}
-
}
-
//: net/mindview/util/FourTuple.java
-
package net.mindview.util;
-
-
public class FourTuple<A,B,C,D> extends ThreeTuple<A,B,C> {
-
public final D fourth;
-
public FourTuple(A a, B b, C c, D d) {
-
super(a, b, c);
-
fourth = d;
-
}
-
public String toString() {
-
return "(" + first + ", " + second + ", " +
-
third + ", " + fourth + ")";
-
}
-
}
-
//: net/mindview/util/FiveTuple.java
-
package net.mindview.util;
-
-
public class FiveTuple<A,B,C,D,E>
-
extends FourTuple<A,B,C,D> {
-
public final E fifth;
-
public FiveTuple(A a, B b, C c, D d, E e) {
-
super(a, b, c, d);
-
fifth = e;
-
}
-
public String toString() {
-
return "(" + first + ", " + second + ", " +
-
third + ", " + fourth + ", " + fifth + ")";
-
}
-
}
為了使用元組,你只需定義一個長度適合的元組,將其作為方法的返回值,然后在return語句中創建該元組,並返回即可。
實例:
-
//: generics/TupleTest.java
-
import net.mindview.util.*;
-
-
class Amphibian {
-
}
-
class Vehicle {
-
}
-
-
public class TupleTest {
-
static TwoTuple<String, Integer> f() {
-
// Autoboxing converts the int to Integer:
-
return new TwoTuple<String, Integer>("hi", 47);
-
}
-
static ThreeTuple<Amphibian, String, Integer> g() {
-
return new ThreeTuple<Amphibian, String, Integer>(new Amphibian(), "hi",
-
47);
-
}
-
static FourTuple<Vehicle, Amphibian, String, Integer> h() {
-
return new FourTuple<Vehicle, Amphibian, String, Integer>(new Vehicle(),
-
new Amphibian(), "hi", 47);
-
}
-
static FiveTuple<Vehicle, Amphibian, String, Integer, Double> k() {
-
return new FiveTuple<Vehicle, Amphibian, String, Integer, Double>(
-
new Vehicle(), new Amphibian(), "hi", 47, 11.1);
-
}
-
public static void main(String[] args) {
-
TwoTuple<String, Integer> ttsi = f();
-
System.out.println(ttsi);
-
// ttsi.first = "there"; // Compile error: final
-
System.out.println(g());
-
System.out.println(h());
-
System.out.println(k());
-
}
-
}
輸出結果:
-
(hi, 47)
-
(Amphibian@15db9742, hi, 47)
-
(Vehicle@6d06d69c, Amphibian@7852e922, hi, 47)
-
(Vehicle@4e25154f, Amphibian@70dea4e, hi, 47, 11.1)
由於有了泛型,你可以很容易地創建元組,令其返回一組任意類型的對象。而你所要做的,只是編寫表達式而已。
通過ttsi.first = "there";語句的錯誤,我們可以看出,final聲明確實能夠保護public元素,在對象被構造出來之后,聲明為final的元素便不能被再賦予其他值了。
參考資料:
- 《Java編程思想》
