1. 程式人生 > >Java元組Tuple介紹與使用

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;
    }
}