2013-01-31 42 views
0

我有一個涉及RMI,序列化和運行時多態性的問題。將子類對象投射到RMI中的超類參考

我有一個RMI服務器下面:

public interface Shape extends Remote, Serializable { 
    public double getArea() throws RemoteException; 
} 

public class Circle implements Shape { 
    double radius; 
    public Circle(double r) { radius = r; } 
    public double getArea() { return Math.PI * radius * radius; } 
} 

Circle類的cObj在RMI註冊處註冊的對象:現在

Circle cObj = new Circle (10); 
registry.bind("cObj", cObj); 

,在客戶端,我有形狀CLASSPATH上的.class文件,但CLASSPATH上沒有Circle.class文件。 RMI客戶端可以在下面執行嗎?

Shape obj = (Shape) registry.lookup("cObj"); 
obj.getArea(); 

注意Circle.class是不是在RMI客戶端的CLASSPATH和客戶端上的代碼不直接引用Circle類反正。它只是引用Shape接口類型。

我該如何看待這個問題,可能是客戶端執行查找並找到具有cObj名稱和Circle類型的對象。服務器知道Circle是Shape的子類型,並將該對象序列化並將其發送給客戶端。現在,我不確定客戶端是否可以將其轉換爲超類(Shape)類型,而無需訪問Circle類定義。

幫助讚賞。

+2

你試過了嗎?回答這些問題的最好方法是設置一個簡單的測試,然後實際嘗試。它看起來像你有一些有效的代碼。測試它! – rmlan

+0

謝謝。似乎適用於Shape類型,但不適用於Circle類型。由於限制新的人員,無法發佈答案。我明天會發布完整的代碼和觀察結果。 – Pat

+0

如果你提到的是真實的,那麼它將無法與Circle一起工作:「無法訪問Circle類定義」。如果客戶端只知道形狀,它將永遠不能將其轉換爲圓形對象。我真的很驚訝它的作品,甚至只是將其投影到Shape界面。 – rmlan

回答

1

如果您不希望部署Circle類的客戶端,你有兩個選擇:

  1. 使用RMI代碼庫的功能。您需要查看它,因爲它在這裏討論的話題太大了,但基本上它使得可以從RMI服務器指定的附加位置加載類。

  2. 使其成爲導出的遠程對象,以便對它的調用也是RMI調用。通過將Shape擴展爲Remote,您已經達到了一半,但您還需要導出Circle,或者通過擴展UnicastRemoteObject或在構建時使用它來調用UnicastRemoteObject.exportObject()。

在我看來,通過擴展Remote,你真的打算做(2)一直。如果你這樣做,你不需要做Shape擴展Serializable。如果你不要做(2)有形狀延伸遠程沒有意義。你應該刪除一個或另一個:它們是相互排斥的。

+0

謝謝。我嘗試了執行測試,是的,我使用了方法(2),因爲我想檢查遠程客戶端是否可以調用Circle對象的方法(重寫了courese)而沒有實際定義Circle類。看來,它可以。雖然,一個奇怪的觀察與行: 形狀存根=(形狀)UnicastRemoteObject.exportObject(cObj,0);我不能這樣做: Circle stub =(Circle) 它給服務器上的編譯錯誤。看看我發佈的完整代碼。順便說一句,感謝關於Remote&Serializable的提示。 – Pat

+0

@Pratik當然,你不能。 exportObject的結果不是原始對象,它是一個實現相同遠程接口的RMI存根,在這種情況下爲Shape。看到Javadoc。所以你可以將它轉換成Shape,但不能轉換成Circle。如果Circle具有想要公開給客戶的擴展API,則需要使Circle成爲一個擴展Shape的接口,並將當前Circle類的名稱更改爲CircleImpl,CircleServer等。 – EJP