2010-01-27 44 views
3

如何創建對常量對象的引用?如何在Java中創建一個常量對象?

final Myclass obj = new Myclass(); 

不起作用,它表示obj(引用)不應該被重新賦值,但我們仍然可以更改引用的對象。

我想確保對象本身一旦構建就不會改變。

+1

到底是如何改變你的對象引用?你是否重新設定obj的價值?或者你是否在改變obj中的值? Java不應該允許你改變obj指向的內容。這就是最終變量的含義。爲了處理使obj的內容不可變,你需要編寫一個不可變的類,如下所述。 – justkt 2010-01-27 13:34:25

回答

16

只是使它不可變(如String是)。或者將其包裝在另一個對象中,該對象限制訪問有問題的對象的增變器(如Collections.unmodifiableList()和consorts)。

+2

檢查有效Java中的「有利於不變性」:http://wiki.glassfish.java.net/attach/JavaProgramming/ej.html#immutablerecipe – dfa 2010-01-27 13:47:50

+0

@dfa:這太棒了。但是,他的第二本書有討論的鏈接嗎? – 2011-06-01 16:50:55

0

是的,你似乎忘記了設置類型。

final MyClass obj = new Myclass(); 

這意味着obj只能分配一次。 Java沒有像C++那樣的const關鍵字。如果MyClass沒有被聲明爲final(final class MyClass {...}),它仍然可以改變。

0

最終變量應在聲明時分配。

final MyClass obj = new MyClass(); 
1

我不認爲有任何內置的關鍵字做到這一點在Java中。即使參考是恆定/最終的,對象的內部仍然可以改變。

你最好的選擇是擁有你的類的ReadOnly實現版本。

你可以閱讀更多關於此這裏:http://en.wikipedia.org/wiki/Const-correctness#final_in_Java

+1

如果你的對象對於外部類是不可改變的(沒有setter和只有私有成員),並且你不改變對象類本身內部的狀態。 – justkt 2010-01-27 13:33:23

+0

是的,這就是我的只讀實現的意思。只允許訪問內部但不允許改變它們的公共函數。 – rui 2010-01-27 13:36:30

+0

沒錯,但在Java中仍然有可能:)。 – justkt 2010-01-27 13:37:37

9

你需要的是一個Immutable Object。 Java中沒有可以立即使對象不可變的關鍵字。你必須設計對象的邏輯,以便它的狀態不能改變。正如BalusC所說的那樣,你可以把它包裝在另一個對象中,這個對象限制對它的增變器的訪問。

0

在Java對象常量意味着你不能改變它的引用,但你可以改變它的狀態變量的值,直到它們不是最終的。如果所有的成員變量都是最終的,那麼它就是一個完美的常量,你不能改變任何東西。

10

你在混合兩件事:final和immutable。

變量可以是最終,所以不能改變它的值(或對象引用)被初始化之後(但當然也可以改變參考的對象屬性)

對象可以是不可變的(不是關鍵字,而是屬性),因此在創建後您無法將其更改爲。字符串是一個很好的例子 - 你不能在String對象內改變後備char []。

+0

嗨。我有一個問題問你。當你說'最後'時,'你在初始化後不能改變它的值(或對象引用)「,我明白這一點。所以'final int x = 10; x = 11;'會產生編譯器錯誤。但我不明白你的第二個陳述'但當然你可以改變引用的對象屬性'。你能提供一小段代碼給我看嗎?我將不勝感激。 tyvm – 2011-06-01 16:47:25

+1

@Harry Pham - 聽起來很複雜,但不是:考慮一個'final List l = new ArrayList()'。您不能將另一個列表指定給'l'(因爲它是最終的),但可以將對象添加到列表中。這是*改變列表屬性*:在這個例子中包裹的數組。 – 2011-06-01 20:30:49

+0

非常感謝。 – 2011-06-01 20:36:25

1

在Java中,不可變類通常意味着它沒有「setter」,任何可以用「getter」訪問的字段也應該是不可變的。爲了讓您的數據進級開始,你需要有一個構造函數的值作爲參數:

 
public class MyClass { 
    String something; 
    int somethingElse; 

    // The class can only be modified by the constructor 
    public MyClass(String something, int somethingElse) { 
    this.something = something; 
    this.somethingElse = somethingElse; 
    } 

    // Access "something". Note that it is a String, which is immutable. 
    public String getSomething() { 
    return something; 
    } 

    // Access "somethingElse". Note that it is an int, which is immutable. 
    public int getSomethingElse() { 
    return somethingElse; 
    } 
} 
0

這是包裝的任何對象,以便能夠「大致」不可改變的一種方式。

所有不是'getters'的方法調用都會拋出異常。此代碼定義的吸氣劑作爲滿足這些條件的方法:

  • 的方法的名稱與getis
  • 它不接受任何參數
  • 它返回一個值(未void返回類型)開始

是的,吸氣劑方法可以突變一個對象。但是,如果你的代碼(或您使用的代碼)是這樣做的,你有一些更大的問題,請去得到一些幫助:)

代碼:

class ImmutableWrapper 
    public static <T> T wrap(T thing) { 
     return (T) Proxy.newProxyInstance(thing.getClass().getClassLoader(), new Class[]{thing.getClass()}, OnlyGettersInvocationHandler.instance); 
    } 

    private static class OnlyGettersInvocationHandler implements InvocationHandler { 
     public static InvocationHandler instance; 
     @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
      final String name = method.getName(); 
      if ((args == null || args.length == 0) 
        && (name.startsWith("get") || name.startsWith("is") 
        && !method.getReturnType().equals(Void.class))) { 
       return method.invoke(proxy, args); 
      } else { 
       throw new UnsupportedOperationException("immutable object: " + proxy + ", cannot call " + name); 
      } 
     } 
    } 
} 

SomeClass myThing = ... create and populate some object ... 
SomeClass myImmutableThing = ImmutableWrapper.wrap(myThing); 
myImmutableThing.setValue('foo'); // throws Exception 
myImmutableThing.whatever();  // throws Exception 
myImmutableThing.getSomething(); // returns something 
myImmutableThing.isHappy();   // returns something 
相關問題