2012-02-21 110 views
2

我正在查看一些代碼,並且我想確保我瞭解是否對對象所做的某些更改實際上是針對這些對象或這些對象的副本進行的。我是否在更改該對象的對象或副本?

這裏有一個例子:

for(int i = 0; i < myList.size(); i++) 
{ 
    DataObject myItem = (DataObject)myList.get(i); 
    myItem.setString("someKey", "someValue"); 
} 

myList中的數據對象的名單,所以我不知道目的是調用列表的get()方法後鑄造項目的數據對象的內容。但是我想知道它在編譯時是如何處理的 - 這個強制轉換是否會創建一個新對象,然後setString()方法將在該新對象上被調用並且不會影響列表中的對象?或者是myItem引用列表中的實際項目?

謝謝。

回答

2

它在鑄造後仍然是對列表中項目的引用。沒有創建副本。

List返回Object類的一個類型,以便它可以用於任何類型的Object(因爲所有類都擴展爲Object)。不過爲了調用setString,你需要將引用類型轉換爲更具體的東西,以便編譯器知道你要調用它的是什麼類型的對象。

使用泛型例如List與您的列表一起指定類型將意味着您不必投射,但如果您無法控制列表創建,或者不知道或想要限制其中可能包含的對象類型,則可能不適合。

0

如果使用泛型,則不需要強制轉換,否則需要強制轉換,因爲無法知道對象列表的類型。

但我不知道如何當它被編譯,這是處理 - 將投創建新的對象

編譯器不會創建任何對象。它只是檢查語法和語義。編譯該特定行時,編譯器知道引用是DataObject類型,但list.get()返回導致不兼容類型的對象類型。所以,你需要明確施放。

1

演員不會創建一個新的對象,它只會告訴編譯器'嘿,我知道我在做什麼,這是一個DataObject'。

不知道實際的List實現的類型,我們不能說你得到的是不是同一個對象。如果您正在使用Java集合集合(ArrayList,LinkedList等)之一,那麼它將是同一個對象實例。但我可以想象一個實現(當然是我自己製作的),它可以返回副本而不是底層實例。

public class MyList<T> implements List<T> { 
    private List<T> backingList = new ArrayList<T>(); 

    //methods to fulfil List interface contract... 

    @Override 
    public T get(int index) { 
     T t = backingList.get(index); 
     return makeCopy(t); 
    } 

    private T makeCopy(T t) { 
     //make a copy of t! 
    } 
} 

而正是因爲如此,我們不能告訴(沒有你告訴我們的基本類型),如果get(int)方法將返回一個副本或沒有。

+0

+1關於不知道列表將在內部做什麼的非常好的觀點。這是使用不可變列表元素的另一個原因。 – biziclop 2012-02-21 22:03:54

+0

噢,我們都假設這是一個行爲良好的List實現。但get()方法*可能會返回副本。但這不太可能。但是演員本身不會創建新的對象。好決定。 – 2012-02-21 22:05:00

+0

好點!我應該提到,'myList'是在代碼中通過調用'DataObject'類型的對象的getList()'方法來聲明的。 – Poosh 2012-02-21 22:23:39

0

該轉換不會創建新的數據對象。當將原語轉換爲包裝類型時,演員通常不會創建新對象,,或者將轉換爲包裝類型,或者將明確或隱含的轉換轉換爲字符串,從而調用方法toString()

1

它引用在列表中的實際項目,所有演確實是告訴編譯器忽略聲明類型,你知道什麼對象的實際類型將是。 (但是如果你錯了,你會得到一個ClassCastException的運行時間,這就是爲什麼要儘可能避免施法的原因。沒有詳細說明,泛型可以幫助解決這個問題。)

現在,這種事情(修改集合的元素)適用於沒有問題的列表,但是Set s和Map的鍵您必須使用不可變對象(基本上,在調用構造函數後其字段不能更改的對象),否則可以右對齊一塌糊塗。如果你的集合在多個線程之間共享,你也應該避免這種情況。

+0

+1回到你身邊。 – 2012-02-21 22:05:58

0

myList.get()可能被定義爲返回一個更通用的類型,例如Object。你不能使一個引用變量引用一個比它自己更通用的類型。因此,您必須進行演員製作 -

DataObject myItem = (DataObject) myList.get(i); 

演員陣容不會創建新對象。轉換隻會使變量myItem引用列表中已有的對象。因此,setString()方法會更改您的實際對象。因此,列表中的對象也會發生更改,因爲它是同一個對象。

0

如果myList被聲明爲一個類型列表,像這樣:

List<DataObject> myList = new ArrayList<DataObject>(); 

然後鑄造是沒有必要的。但是,如果它是無類型List,則其get方法將返回類型爲Object的對象。這可能是爲什麼演員是必要的(沒有看到聲明,我不知道)。

話雖如此,演員並沒有創建一個新的對象,所以你得到的是一個新的對列表中已經存在的對象的引用。這意味着任何修改都發生在myList之內。

+0

通過調用代碼中較早的'DataObject'上的'getList()'方法來聲明變量'myList'。我可能應該提到這一點。但是,這是有道理的,他們必須這樣寫,因爲get()方法正在返回Object類型的對象。謝謝! – Poosh 2012-02-21 22:20:10

0

它可能是相同的對象。

唯一創建new對象的方法是什麼? new關鍵字。有些人認爲clone()創建了一個新對象(如果正確實施),但是該怎麼辦?在克隆功能中有一個new關鍵字!

現在,我不知道你在處理什麼樣的myList,但假設它是標準Java庫(ArrayList, LinkedList, etc)的一部分,那麼你會得到同樣的對象。

P.S.記住陣列也是對象!

相關問題