簡體   English   中英

在Java中返回對可變對象的不變引用

[英]Returning an immutable reference to a mutable object in Java

基本上,我在Java中有一個可變對象,並且某個類的幾種方法都可以訪問和修改其狀態。 存儲在對象中的數據也由另一個類使用,但是不同之處在於,不應僅允許使用第二類來修改數據。

在C ++中,我通常只將const引用傳遞給手頭的對象,但是我意識到Java中沒有直接的等效項。

為了澄清起見,以下代碼片段顯示了我的想法:

public interface Figure
{
    void onSizeChanged(SizeInfo info);
    void draw();
}
public class FigureView extends View
{
    private Figure figure;
    private SizeInfo sizeInfo;

    ...

    public void onResize()
    {
        //Modify the state of sizeInfo, then pass it to the figure.
        figure.onSizeChanged(sizeInfo);
    }
}

假設SizeInfo是一個大對象,所以我不想進行成員復制,而只是通過引用傳遞它。 上面的代碼成功地允許任何Figure存取SizeInfo對象的數據,但也允許Figure修改該對象。 由此類行為引起的錯誤可能很難跟蹤,因此我想向SizeInfo傳遞“不可變的引用”。

到目前為止,我發現的最佳解決方案是創建SizeInfo的非靜態內部類, SizeInfo僅包含getter:

public class SizeInfo
{
    //These represent the large set of data inside the class.
    private long foo;
    private double bar;
    private Export mExport = new Export();

    //Setters (only available if you have a direct reference to SizeInfo):
    public void incrementFoo()
    {
        foo++;
    }
    public void setBar(double bar)
    {
        this.bar = bar;
    }

    //SizeInfo getters:
    public long getFoo()
    {
        return foo;
    }
    public double getBar()
    {
        return bar;
    }
    public double getBaz()
    {
        return bar * foo;
    }

    //A non-static inner class:
    public class Export
    {
        public long getFoo() { return foo; }
        public double getBar() { return bar; }
        public double getBaz() { return bar * foo; }
    }
    public Export export() { return mExport; }
}

使用此代碼,您只需要將Figure的方法簽名從onSizeChanged(SizeInfo)更改為onSizeChanged(SizeInfo.Export) ,並將sizeInfo.export()傳遞給該方法而不是sizeInfo即可使其按預期工作。 從客戶端使用這非常容易,但是由於必須重復每個getter兩次而導致的代碼冗余絕對不是很好。 僅將吸氣劑放置在SizeInfo.Export並將每個sizeInfo.getBaz()替換為sizeInfo.export().getBaz()方法更加糟糕。 這就是為什么我正在尋找一種更優雅的方法。

我意識到,就SizeInfo而言,它太大而不能創建一個逐級克隆,因此可能無法相信這個特定示例。 但是,還有無數其他示例。 例如,如果我有一個可變的對象表示圖像的ARGB數據(可能是由於使用某些數學公式逐個像素生成了圖像),然后想要將其傳遞給一種方法,該方法應該對其進行修改,問題仍然會出現。

創建一個包含吸氣劑的ReadOnlySizeInfo接口,使SizeInfo實現該接口,然后將該接口而不是SizeInfo傳遞給onSizeChanged()

您仍然會傳遞一個可變的對象,但是Figure對此並不了解:它所接收到的所有信息僅是ReadOnlySizeInfo 它仍然可以對對象進行強制轉換和變異,但這不再是一個錯誤:這將是一種邪惡的行為。

您可以創建一個接口,例如SizeInfoView ,其中僅包含吸氣劑。 然后, SizeInfo將實現該接口,但還要添加setter。 Figure將僅收到對SizeInfoView接口的引用。 調用者當然仍然可以向下轉換為SizeInfo ,但是在C ++中,使用const_cast會遇到相同的問題。 通常足以防止發生意外。

但是請記住,您得到的是不可修改的對象,而不是不可變的對象。 不同之處在於其他人可以對其進行修改,並且這些更改將反映在不可修改的視圖中。 但是同樣,對於C ++ const引用也是如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM