Java元組Tuple介紹與使用
文章來源:
Java程式設計思想 第十五章 泛型 (簡單泛型)
一、元組介紹
僅僅一次方法呼叫就可以返回多個物件,你應該經常需要這樣的功能吧.可以return語句只允許返回單個對(可能有人說返回一個集合就可以了,請記住,一個集合也只是一個物件而已)因此,解決辦法就是建立一個物件,用它來持有想要返回的物件.當然,可以在每次需要的時候,專門建立一個類來完成這樣的工作.可是有了泛型,我們就能夠一次性的解決問題,以後再也不用再這種問題上浪費時間了.同時,我們再編譯器就可以確保型別安全.
上述概念稱為元組(tuple),它是將一組物件直接打包儲存與其中的一個單一物件.這個容器物件允許讀取其中的元素.但是不允許向其中存放新的物件.(這個概念也稱為資料傳送物件,或信使)
通常元素具有任意長度,同時,元組中的物件可以是任何不同的型別.不過,我們希望能夠為每一個物件指明其型別,並且從容器中讀取出來時,能夠得到正確的型別.要處理不同長度的問題,我們需要建立不同的元組.採用下面的編碼形式無疑是更安全的做法,這樣的話,如果程式設計師想要使用具有不同元素的元組,就強制要求他們建立一個新的元組物件.並且可以利用繼承機制實現長度更長的元組.
元組和列表list一樣,都可能用於資料儲存,包含多個數據;但是和列表不同的是:列表只能儲存相同的資料型別,而元組不一樣,它可以儲存不同的資料型別,比如同時儲存int、string、list等,並且可以根據需求無限擴充套件。比如說在web應用中,經常會遇到一個問題就是資料分頁問題,查詢分頁需要包含幾點資訊:當前頁數、頁大小;查詢結果返回資料為:當前頁的資料記錄,但是如果需要在前臺顯示當前頁、頁大小、總頁數等資訊的時候,就必須有另外一個資訊就是:資料記錄總數,然後根據上面的資訊進行計算得到總頁數等資訊。這個時候查詢某一頁資訊的時候需要返回兩個資料型別,一個是list(當前也的資料記錄),一個是int(記錄總數)。當然,完全可以在兩個方法、兩次資料庫連線中得到這兩個值。事實上在查詢list的時候,已經通過sql查詢得到總計錄數,如果再開一個方法,再做一次資料庫連線來查詢總計錄數,不免有點多此一舉、浪費時間、浪費程式碼、浪費生命。言重了~在這種情況下,我們就可以利用二元組,在一次資料庫連線中,得到總計錄數、當前頁記錄,並存儲到其中,簡單明瞭!(
http://www.cnblogs.com/davidwang456/p/4514659.html)
二、使用介紹
二元組常見程式碼形式可以如下所示:
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 + ")";
}
}
利用繼承機制實現長度更長的元組.將上述二元組擴充套件為三元組程式碼形式可以如下所示:
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 + ")";
}
}
利用繼承機制實現長度更長的元組.將上述三元組擴充套件為四元組程式碼形式可以如下所示:
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 + ")";
}
}
為了使用元組,你只需定義一個長度適合的元組,將其作為方法的返回值,然後在return語句中建立該元組,並返回即可.例如下面使用方式:
使用方式例項一:
/**
* 由於有了泛型,你可以很容易的建立元組,令其返回一組任意型別的物件,而你所要做的,只是編寫表示式而已.
*/
public class TupleTest {
static TwoTuple<String, Integer> f(){
//Autoboxing conveerts 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);
}
public static void main(String[] args) {
TwoTuple<String, Integer> ttsi = f();
System.out.println(ttsi);
System.out.println(g());
System.out.println(h());
}
}
class Amphibian {}
class Vehicle {}
使用方式例項二:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class DynamicProxyMixin {
public static void main(String[] args) {
Object mixin = MixinProxy.newInstance(new TwoTuple(new BasicImpl(), Basic.class), new TwoTuple(new TimeStampedImp(), TimeStamped.class), new TwoTuple(new SerialNumberedImpl(), SerialNumbered.class));
Basic b = (Basic) mixin;
TimeStamped t = (TimeStamped) mixin;
SerialNumbered s = (SerialNumbered) mixin;
b.set("hello");
System.out.println(b.get());
System.out.println(t.getStamp());
System.out.println(s.getSerialNumber());
}
}
class MixinProxy implements InvocationHandler{
Map<String, Object> delegatesByMethod;
public MixinProxy(TwoTuple<Object, Class<?>>... pairs){
delegatesByMethod = new HashMap<String, Object>();
for(TwoTuple<Object, Class<?>> pair : pairs){
for(Method method : pair.second.getMethods()){
String methodName = method.getName();
if(!delegatesByMethod.containsKey(methodName)){
delegatesByMethod.put(methodName, pair.first);
}
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Object delegate = delegatesByMethod.get(methodName);
return method.invoke(delegate, args);
}
public static Object newInstance(TwoTuple... pairs){
Class[] interfaces = new Class[pairs.length];
for(int i = 0; i < pairs.length; i++){
interfaces[i] = (Class) pairs[i].second;
}
ClassLoader cl = pairs[0].first.getClass().getClassLoader();
return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
}
}
interface TimeStamped{
long getStamp();
}
class TimeStampedImp implements TimeStamped{
private final long timeStamp;
public TimeStampedImp() {
timeStamp = new Date().getTime();
}
@Override
public long getStamp() {
return timeStamp;
}
}
interface SerialNumbered{
long getSerialNumber();
}
class SerialNumberedImpl implements SerialNumbered{
private static long counter = 1;
private final long serialNumber = counter++;
public long getSerialNumber(){
return serialNumber;
}
}
interface Basic{
public void set(String val);
public String get();
}
class BasicImpl implements Basic{
private String value;
public void set(String val){
value = val;
}
@Override
public String get() {
return value;
}
}