主編:」我收到了來自‘埃裏克森’一個非常中肯的答案,但是這是沒有明確涵蓋在我原來的例子,並且不與解決的側問題(上鑄造?)他我已經擴展了這個例子來覆蓋這個問題,並且我已經將它包含在這篇文章的最後。感謝您的幫助。遞歸通用用法
我目前正面臨與相關的Java泛型有關的問題的東西,被稱爲"Curiously Recurring Generic Pattern"。我想我已經找到了解決方案,從喬恩斯基特閱讀這個問題的答案後"java enum definition"。不過,我發現自己不同的問題時,我試圖將其應用於我的代碼中。
我拿出哪裏出了問題我現在面臨一個出現「小」的例子。我希望它能清楚地說明我的問題。
示例說明:我想構建一個圖表,其中節點類型可以變化。我定義了一個抽象類節點,其中定義了一些基本方法,以及實現這些方法,即ConcreteNode的具體類。我也創建了一個名爲City的ConcreteNode的專業化。
在給定的圖中,一個重要的要求是,所有的元件應被由相同類型或它的亞型,即ConcreteNode的曲線圖中只能有ConcreteNodes 或城市。
這些都是我的類的定義:
abstract class Node<T extends Node<T>>
class ConcreteNode<T extends ConcreteNode<T>> extends Node<T>
class City extends ConcreteNode<City>
這些定義利用「定期通用模式」在枚舉類的定義還發現:
Class Enum<E extends Enum<E>>
問題:我遇到了使用這些類的問題。我沒有問題,如果我要留在層次結構中的城市級別,即市連接到市,但在嘗試訪問其他類當我在巨大問題。
在下面的代碼,我的問題,可以看出在GraphUtil的方法簽名:
- addNewNeighbors1a使用原始類型的節點,但至少它的工作原理。
- addNewNeighbors1b使用類型節點,但它並不在所有編譯(誤差被包括在代碼)。
- addNewNeighbors1c使用Node的更復雜的參數,我希望能夠工作,但它不能編譯(錯誤包含在代碼中)。
- addNewNeighbors3用來節點複雜的參數,但它並沒有重新編譯,即使參數是節點newNode相同。
在綜合中,我的問題是如何上傳這些參數化爲自己的泛型?。
我很樂意爲GraphUtil的方法獲得最佳簽名方面的幫助,假設這些方法將位於一個對City或甚至ConcreteNode不瞭解的庫中。
謝謝大家。
這裏的例子
package test.city;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class TestCity {
abstract class Node<T extends Node<T>> {
public abstract void addNeighbor(T n);
public abstract void addNeighbors(Collection<? extends T> nodes);
public abstract Collection<T> neighbors();
}
class ConcreteNode<T extends ConcreteNode<T>> extends Node<T> {
protected Collection<T> _neighbors = new ArrayList<T>();
@Override
public void addNeighbor(T n) {
_neighbors.add(n);
}
@Override
public void addNeighbors(Collection<? extends T> nodes) {
_neighbors.addAll(nodes);
}
@Override
public Collection<T> neighbors() {
return _neighbors;
}
}
class City extends ConcreteNode<City> {
protected String _name;
public City(String name) {
_name = name;
}
@Override
public String toString() {
return _name;
}
}
public TestCity() {
City nyc = new City("NYC");
nyc.addNeighbor(new City("Boston"));
nyc.addNeighbor(new City("Wash"));
GraphUtil.print("Printing cities", nyc.neighbors());
GraphUtil.printNeighbors1(nyc);
GraphUtil.printNeighbors2(nyc);
GraphUtil.printNeighbors3(nyc);
GraphUtil.printNeighbors4(nyc);
GraphUtil.addNewNeighbors1a(nyc, new City("Miami"));
GraphUtil.addNewNeighbors2(nyc, new City("NewOr"));
GraphUtil.addNewNeighbors3(nyc, new City("Dallas"));
}
static class GraphUtil {
static void printNeighbors1(Node<?> node) {
print("Nodes", node.neighbors());
}
static void printNeighbors2(ConcreteNode<?> node) {
print("Concrete nodes", node.neighbors());
}
static void printNeighbors3(Node<? extends Node<?>> node) {
print("Nodes2", node.neighbors());
}
static void printNeighbors4(ConcreteNode<? extends ConcreteNode<?>> node) {
print("Concrete nodes2", node.neighbors());
}
static void addNewNeighbors1a(Node node, City newNode) {
node.addNeighbor(newNode);
print("Add city to node", node.neighbors());
}
static void addNewNeighbors1b(Node<?> node, City newNode) {
// node.addNeighbor(newNode); <---- DOES NOT COMPILE!!!
// The method addNeighbor(capture#8-of ?) in the type
// TestCity.Node<capture#8-of ?>
// is not applicable for the arguments (TestCity.City)
}
static void addNewNeighbors1c(Node<? extends Node<?>> node, City newNode) {
// node.addNeighbor(newNode); <---- DOES NOT COMPILE!!!
// The method addNeighbor(capture#9-of ? extends TestCity.Node<?>)
// in the type
// TestCity.Node<capture#9-of ? extends TestCity.Node<?>> is not
// applicable for the arguments (TestCity.City)
}
static void addNewNeighbors2(Node node, ConcreteNode newNode) {
node.addNeighbor(newNode);
print("Add concrete node to node", node.neighbors());
}
static void addNewNeighbors3(Node<? extends Node<?>> node,
Node<? extends Node<?>> newNode) {
// node.addNeighbor(newNode); <---- DOES NOT COMPILE!!!
// The method addNeighbor(capture#8-of ? extends TestCity.Node<?>)
// in the type
// TestCity.Node<capture#8-of ? extends TestCity.Node<?>> is not
// applicable for the arguments
// (TestCity.Node<capture#10-of ? extends TestCity.Node<?>>)
}
static void print(String msg, Collection<?> col) {
System.out.println(msg + ": " + Arrays.toString(col.toArray()));
}
}
public static void main(String[] args) {
new TestCity();
}
}
的完整的代碼運行這段代碼的輸出如下(沒有驚喜可言):
Printing cities: [Boston, Wash]
Nodes: [Boston, Wash]
Concrete nodes: [Boston, Wash]
Nodes2: [Boston, Wash]
Concrete nodes2: [Boston, Wash]
Add city to node: [Boston, Wash, Miami]
Add concrete node to node: [Boston, Wash, Miami, NewOr]
問題的第二部分
有一個相關的問題,我沒有包括在原來的實例因爲我認爲解決方案也適用。
我現在已經添加了以下方法GraphUtil:
static <T extends Node<T>> T getSomeNeighbor(T node) {
return node.neighbors().iterator().next();
}
而且從我的主類我想以下幾點:
City someCity = GraphUtil.getSomeNeighbor(nyc);
someCity.addNeighbor(new City("London")); // OK
ConcreteNode someCN1 = GraphUtil.getSomeNeighbor(nyc);
someCN1.addNeighbor(new City("Paris")); // OK, but raw
ConcreteNode<?> someCN2 = GraphUtil.getSomeNeighbor(nyc);
someCN2.addNeighbor(new City("Berlin")); // Does not compile
ConcreteNode<?> nc = new City("");
nc.addNeighbor(new City("Bern")); // Does not compile
第一種情況的工作,因爲我知道返回的具體類型,並且與參數中提供的類型一致。
在第二和第三種情況下,我假設我不知道城市類型。第二種情況有效,但我使用的是原始類型ConcreteNode。
在第三種情況下,第二行中出現編譯錯誤:「TestCity.ConcreteNode類型中的方法addNeighbor(capture#3 of?)不適用於參數(TestCity.City)。 「
在這個例子中,我使用'new City(「 - 」)'作爲參數,因爲我不知道如何上傳它們。在第四種情況下,我試圖將City上傳到ConcreteNode,但失敗了。目前的編譯器錯誤如下:「的方法addNeighbor(捕獲#4的?)在類型TestCity.ConcreteNode不適用於參數(TestCity.City)」
問題:
- 如何在不知道城市類型的情況下修復情況2和3?
- 如何將City上傳到ConcreteNode(或Node)?
感謝您的幫助。
對不起,您更新後的問題中的示例過於設計,無法幫助我設想出現問題的地方。在你所有的例子中,你都知道'addNeighbor'的參數類型(它總是'City'')。你能不能展示你真的想寫的方法 - 也就是說,參數的類型沒有被靜態聲明?您可能需要展示如何調用此方法。 – erickson 2009-10-14 15:47:03