【问题标题】:Automatic cast to subclass in getter/setter在 getter/setter 中自动转换为子类
【发布时间】:2015-08-24 15:54:31
【问题描述】:

我有一个很奇怪的问题。考虑以下两个类:

public class Node<T> {
    private Node<T> parent;
    private Node<T> left;
    private Node<T> right;
    private T data;

    public Node(Node<T> parent, T data) {
        this.parent = parent;
        this.data = data;
    }

    public Node<T> getParent() {
        return parent;
    }

    public void setParent(Node<T> parent) {
        this.parent = parent;
    }

    public Node<T> getLeft() {
        return left;
    }

    public void setLeft(Node<T> left) {
        this.left = left;
    }

    public Node<T> getRight() {
        return right;
    }

    public void setRight(Node<T> right) {
        this.right = right;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}

public class RedBlackNode<T> extends Node<T> {

    private Color color;

    public RedBlackNode(Node<T> parent, T data) {
        super(parent, data);
        this.color = Color.Black;
    }

    public RedBlackNode(Node<T> parent, T data, Color color) {
        super(parent, data);
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

}

我的问题是..有什么方法可以写:

RedBlackNode<Whatever> x = y.getLeft();

其中 y 是 RedBlackNode,而无需使用:

RedBlackNode<Whatever> x = (RedBlackNode<Whatever>) y.getLeft();

而且,不必重写 RedBlackNode 类中的 getter/setter?

我的意思是,我只是想以某种方式让 RedBlackNode “意识到”它是一个 RedBlackNode,并且知道它的所有子/父实际上也是 RedBlackNode。我不确定,但也许以某种方式在 Node 类之上添加了一个新的抽象层?

泰!

后期编辑:

感谢您的所有及时回答,这就是我目前所拥有的:

public abstract class AbstractNode<T, U extends AbstractNode<T, U>> {
    private AbstractNode<T, U> parent;
    private AbstractNode<T, U> left;
    private AbstractNode<T, U> right;
    private T data;

    public AbstractNode(AbstractNode<T, U> parent, T data) {
        this.parent = parent;
        this.data = data;
    }

    public AbstractNode<T, U> getParent() {
        return parent;
    }

    public void setParent(AbstractNode<T, U> parent) {
        this.parent = parent;
    }

    public AbstractNode<T, U> getLeft() {
        return left;
    }

    public void setLeft(AbstractNode<T, U> left) {
        this.left = left;
    }

    public AbstractNode<T, U> getRight() {
        return right;
    }

    public void setRight(AbstractNode<T, U> right) {
        this.right = right;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}

public class RedBlackNode<T extends Element> extends AbstractNode<Element, RedBlackNode<Element>> {

    private Color color;

    public RedBlackNode(RedBlackNode<Element> parent, T data) {
        super(parent, data);
        this.color = Color.Black;
    }

    public RedBlackNode(RedBlackNode<Element> parent, T data, Color color) {
        super(parent, data);
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

}


public class Node<T> extends AbstractNode<T, Node<T>> {

    public Node(AbstractNode<T, Node<T>> parent, T data) {
        super(parent, data);
    }

}

但是,我需要创建 2 种类型的树。一个简单的二叉搜索树,它只有 Node 类的实例作为节点,并且正如预期的那样,红黑树只有 RedBlackNode 的实例作为节点。

我为这些树创建了一个抽象类(有更多方法,这是修剪后的版本),但我担心我遗漏了一些东西,因为我似乎将这个 Node&lt;Element&gt; 作为类定义中的泛型类型。

public abstract class Tree<T extends AbstractNode<Element, Node<Element>>> {

    protected T root;

    public T getRoot() {
        return this.root;
    }

    public abstract T search(T n, int key);

    public abstract T insert(Element e, T cRoot);
}

我在这里缺少什么?如何最好地建模?


后期编辑2:

我目前有:

public abstract class AbstractNode<E extends Element, U extends AbstractNode<E, U>> {
    private U parent;
    private U left;
    private U right;
    private E data;

    public AbstractNode(U parent, E data) {
        this.parent = parent;
        this.data = data;
    }

    public U getParent() {
        return parent;
    }

    public void setParent(U parent) {
        this.parent = parent;
    }

    public U getLeft() {
        return left;
    }

    public void setLeft(U left) {
        this.left = left;
    }

    public U getRight() {
        return right;
    }

    public void setRight(U right) {
        this.right = right;
    }

    public E getData() {
        return data;
    }

    public void setData(E data) {
        this.data = data;
    }

}

public class Node<E extends Element> extends AbstractNode<E, Node<E>> {

    public Node(Node<E> parent, E data) {
        super(parent, data);
    }

}

public class RedBlackNode<E extends Element> extends AbstractNode<E, RedBlackNode<E>> {

    private Color color;

    public RedBlackNode(RedBlackNode<E> parent, E data) {
        super(parent, data);
        this.color = Color.Black;
    }

    public RedBlackNode(RedBlackNode<E> parent, E data, Color color) {
        super(parent, data);
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

}

树类:

public abstract class Tree<E extends Element, T extends AbstractNode<E, T>> {

    protected T root;

    public T getRoot() {
        return this.root;
    }

    public abstract T search(T n, int key);
}

BinarySearchTreeClass

public class BinarySearchTree<Element> extends Tree<Element, Node<Element>> {

    @Override
    public Node<Element> search(Node<Element> n, int key) {
        if (n == null || n.getData().getIntegerData() == key) {
            return n;
        }
        return key < n.getData().getIntegerData() ? search(  n.getLeft(), key) : search( n.getRight(), key);
    }

}

我到底为什么会收到Bound mismatch: The type Element is not a valid substitute for the bounded parameter &lt;E extends Element&gt; of the type Node&lt;E&gt;。这是E extends Element。这是否意味着它也可以是Element 类型? 尽管如此,我尝试使用扩展 Element 的单独类之类的东西,但无济于事..

另外,我收到了The type parameter Element is hiding the type Element,但我不知道为什么..

我为此创建了一个GIST

【问题讨论】:

  • 最简单的解决方案(仍然是样板)是覆盖超类方法并将返回类型更改为RedBlackNode
  • 是的,我知道,但是有什么方法可以避免覆盖这些方法吗?
  • 也许您提取样板代码并将其添加为具有泛型的接口?因此,您为 Node 和 NodeGetters 或父类实现 NodeGetters
  • 是的,但它们很烂:( stackoverflow.com/questions/10968557/…
  • 您的抽象类没有正确的泛型。请参阅 SamYonnou 的示例:AbstractNode&lt;T, U extends AbstractNode&lt;T, U&gt;&gt;T 是每个节点中数据的类型。 U——我个人称它为N——是U extends AbstractNode&lt;T,U&gt;类型的关联节点(父、左、右)的类型(也就是说“AbstractNode的某些子类型,其中T 是其中的数据,其相关节点(父、左、右)也是U") 类型。如果这一切听起来有点递归,那是因为它是。

标签: java oop


【解决方案1】:

如果您不介意将 Node 拉到抽象类中,您可以将类型指定为通用签名的一部分,如下所示:

public abstract class AbstractNode<T, U extends AbstractNode<T, U>> {
    ...
    public U getLeft() {
        ...
    }
    ...
}

// inherited getLeft() will return Node<T>
public class Node<T> extends AbstractNode<T, Node<T>> { ... }

// inherited getLeft() will return RedBlackNode<T>
public class RedBlackNode<T> extends AbstractNode<T, RedBlackNode<T>> { ... }

编辑:对于您的树,您可以为每个节点类型创建一个单独的树,或者如果您想重用基本功能,您可以执行以下操作:

// base functionality goes here, T is the element type, U is the node type
public abstract class Tree<T, U extends AbstractNode<T, U>> { ... }

public class BinarySearchTree<T> extends Tree<T, Node<T>> { ... }

public class RedBlackTree<T> extends Tree<T, RedBlackNode<T>> { ... }

或者,如果您只想共享方法签名,则将Tree 设为接口而不是抽象类。或者更好的是,拥有一个Tree 接口和一个实现共享功能的AbstractTree 抽象类。

【讨论】:

  • 应该可以。我们在流畅的表单组件库中使用这种方法,允许每个组件了解并返回其自己的方法链接类型。
  • +1,但是,我建议我们使用This 作为此类类型参数的常规名称;并失去界限。见stackoverflow.com/questions/30382847/…
  • 真的很传统吗?我以前从未见过这种用途。我个人不会因为This 看起来像一个类名。在大多数情况下, 习惯于对泛型类型参数使用单个大写字母。我会使用N(用于节点)。
  • @Paul - 还不是传统的,但这就是我的提议:)
  • @Alexandr 如果Element 是具体类型而不是泛型,那么您就不用写BinarySearchTree&lt;Element&gt; extends Tree&lt;Element, Node&lt;Element&gt;&gt;,而是写BinarySearchTree extends Tree&lt;Element, Node&lt;Element&gt;&gt;,或者如果您打算使用泛型类型,那么BinarySearchTree&lt;E extends Element&gt; extends Tree&lt;E, Node&lt;E&gt;&gt;跨度>
猜你喜欢
  • 2014-09-05
  • 2011-01-17
  • 1970-01-01
  • 1970-01-01
  • 2013-05-15
  • 1970-01-01
  • 2021-09-21
  • 2018-06-30
  • 2011-06-13
相关资源
最近更新 更多