2010-03-09 71 views
3

有沒有辦法在Java中進行自動隱式類型轉換?例如,假設我有兩種類型,'FooSet'和'BarSet',它們都是Set的表示。這是很容易的類型之間轉換,這樣我寫了兩個實用的方法:Java中的自動類型轉換?

/** Given a BarSet, returns a FooSet */ 
public FooSet barTOfoo(BarSet input) { /* ... */ } 

/** Given a FooSet, returns a BarSet */ 
public BarSet fooTObar(FooSet input) { /* ... */ } 

現在說有這樣的方法,我想打電話:

public void doSomething(FooSet data) { 
    /* .. */ 
} 

但我只有一個BarSet myBarSet ...這意味着額外的輸入,如:

doSomething(barTOfoo(myBarSet)); 

有沒有辦法告訴某些類型可以自動轉換爲其他類型的編譯器?我知道這是可能的C++與重載,但我找不到在Java中的一種方式。我想就可以輸入:

doSomething(myBarSet); 

並且編譯器知道自動調用barTOfoo()

+0

更多詳細信息...我有我不能改變兩個獨立的庫,並且它們都使用相似但不兼容數據結構。我經常需要從一個庫中獲取數據,操作它,然後將它傳遞給另一個庫。我的代碼最終遍佈着各處的fooTObar和barTOfoo調用。 – davr 2010-03-09 01:58:46

+3

這種類似但不太直接兼容的API之間的粘合絕對不是Java的強項之一。有很多樣板可以完成。 – Yishai 2010-03-09 02:26:47

+1

如果有人很好奇,這兩個庫是基於JSON的對象(用於與web服務交談)和基於AMF的對象(用於通過持久RMTP連接與Flash客戶端交談)。 AMF和JSON都有數組,列表,關聯數組,對象等概念。所以在Java中,我不斷地在AMFDataArray和JSONArray,AMFDataObj和JSONObject等之間進行轉換。 – davr 2010-03-10 00:56:39

回答

5

答案是矮:這是可能的,在C++超載但沒有辦法做到這一點在Java中。

+0

也可以在C#和其他許多相關語言中使用,因爲它是一個非常有用的功能。 – 2015-01-26 21:29:30

2

你可以重載的方法是這樣的:

public void doSomething(FooSet data) { 
    /* .. */ 
} 

public void doSomething(BarSet data) { 
    doSomething(barTOfoo(data)); 
} 
+1

doSomething是我無法修改的方法,它位於外部庫中。但我想編寫我自己的重載方法,調用外部方法是一個選項。 – davr 2010-03-09 02:03:54

+0

@davr是的,我寫了我的答案後,我看到了編輯。我想你的代碼和庫之間的另一層可能有點麻煩,但這取決於多少討厭的barTOfoo和fooTObar是......它還將允許你改變庫代碼的實現方式if它的功能發生了變化。 – masher 2010-03-09 02:25:29

0

超載作品以相反的方式,聲明接收對象的兩個方法:

public void doSomething(FooSet data) 
{ 
    /* .. */ 
} 

public void doSomething(BarSet data) 
{ 
    doSomething(barToFoo(data)); 
} 

然後感謝 動態綁定wikipedia)在運行時選擇正確的方法。

當然在Java中重載在對象級的作用域(因爲呼叫限制爲實例或類聲明),但它在相同的方式工作。

在你的情況,你可以通過還擴展類,如果它在外部庫嘗試,因爲它是Java中,你應該能夠做到這一點,並添加方法或使用反射java tutorial)來添加方法動態。

+0

doSomething是我無法修改的方法,它位於外部庫中。但我想編寫我自己的重載方法,調用外部方法是一個選項。 – davr 2010-03-09 02:04:18

+1

這不是一個動態綁定的例子。它只是重載,它發生在編譯時基於聲明的變量類型。 – vava 2010-03-09 02:10:16

+0

我的錯,動態綁定只適用於選擇派生對象的方法.. – Jack 2010-03-09 02:46:21

-1

Java創建時考慮到了可見性。每個程序員都應該只能讀一行,瞭解那裏發生的事情。這就是爲什麼它沒有運算符重載,這就是爲什麼它沒有任何類型的自動自定義類型轉換。所以,除非你自己的包裝器圍繞一個圖書館編寫,這個圖書館接受來自其他圖書館的類型並明確地轉換它們,那麼你就不會那麼幸運了。

+1

我想這就解釋了爲什麼你必須使用String.equals而不是==所有的時間...這麼愚蠢。 – davr 2010-03-24 02:16:30

+0

@davr,確切地說,他們希望你能夠發現它是引用還是實際內容正在進行比較。 – vava 2010-03-24 07:38:15

1

你可以兩者都做在一起:

(1)寫包裝方法,其做背場景轉換。

(2)如果你的對象有適當hashCode覆蓋方法,包裝方法可以管理一個非常簡單和快速的緩存,您可以用簡單的Map實施和可能同步建立自己(如果你使用的對象同時在所有)。

這會讓你擺脫兩種類型之間的轉換,並且可能會影響性能。即使你反對緩存,我仍然會推薦(如其他海報所說)使用包裝方法。至少可以節省大量不必要的打字。

祝你好運。

0

自動不支持類型轉換(您希望Scala的implicit type conversions)。

但是你可以嘗試使用Variant類型的接線盒的類型之間切換:

/** Given a BarSet, returns a FooSet */ 
public Function<BarSet, FooSet> barTofoo = new Function<BarSet, FooSet>() { 
    @Override public FooSet apply(BarSet input) { /* ... */ } 
} 

/** Given a FooSet, returns a BarSet */ 
public Function<FooSet, BarSet> fooToBar = new Function<FooSet, BarSet>() { 
    @Override public BarSet apply(FooSet input) { /* ... */ } 
} 

/** Create a type conversion context in which both of these conversions are registered */ 
TypeConversionContext fooBarConversionContext = MatchingTypeConversionContext.builder() 
    .register(FooSet.class, BarSet.class, fooToBar) 
    .register(BarSet.class, FooSet.class, barToFoo) 
    .build(); 

/** Put a FooSet into a Variant, bound to our type conversion context */ 
FooSet fooSet = new FooSet(); 
Variant data = Variant.of(fooSet).in(fooBarConversionContext); 

/** Pull a BarSet out of the Variant */ 
public void doSomething(Variant data) { 
    Preconditions.checkArgument(data.isConvertibleTo(BarSet.class); 
    BarSet barSet = data.as(BarSet.class); 
    // ... 
} 
+0

這很有趣,但它對我來說是典型的Java過度冗長。我最終會讓事情變得複雜,而不是像我想的那樣簡化它們。 – davr 2012-08-10 20:41:57