【问题标题】:How to make subclass accept superclass as value?如何使子类接受超类作为值?
【发布时间】:2016-04-10 02:54:11
【问题描述】:

我有一个名为 Tree 的超类和一个名为 AVLTree 的子类,它扩展了 Tree 类。

一棵树的子节点也是 Tree 类型。 AVLTree 的子节点是 AVLTree。我想使用我在 Tree 类上编写的方法,在这种情况下 getLeft(返回左子)和 setLeft(设置左子)。

问题是编译器无法将 Tree 转换为 AVLTree,即使它们具有相同的变量、结构和构造函数。

关于我应该如何解决这个问题的任何想法?还是我应该只编写 AVLTree 在 Tree 类上的所有方法?

代码:

Tree.java:

public class Tree<T extends Tree<T>> {
  private T left = null;
  private T right = null;
  private Object data = null;

  public Tree () {
    //nothing
  }
  public Tree (Object data, T left, T right) {
    this.data = data;
    this.left = left;
    this.right = right;
  }
  public Tree (Object data) {
    this.data = data;
  }


  //Get Values
  public T getLeft() {
    return this.left;
  }
  public T getRight() {
    return this.right;
  }
  public Object getData() {
    return this.data;
  }
  //Set Values
  public void setLeft(T left) {
    this.left = left;
  }
  public void setRight(T right) {
    this.right = right;
  }
  public void setData(Object data) {
    this.data = data;
  }

  public T treeFromText(String in) {
    if (in=="()") return null;
    int i=0;
    T result = null;
    //Find expression
    int d = in.indexOf('c')+1;
    if (d==0) return null;


    int begl, endl, begr, endr;

    begl = d+1;
    endl = ClosingParentesis(in,begl);
    endr = in.length()-2;
    begr = OpeningParentesis(in,endr);

    T left = null, right = null;

    if (begl-endl==0) {
      left = null;
    } else left = treeFromText(in.substring(begl,endl+1));
    if (begr-endr==0) {
      right = null;
    } else right = treeFromText(in.substring(begr,endr+1));

    result.setData(in.charAt(d));
    result.setLeft(left);
    result.setRight(right);
    return result;
  }


  public static int ClosingParentesis(String in, int openPos) {
    int closePos = openPos;
    int counter = 1;
    while (counter > 0 && closePos < in.length()-1) {
      closePos++;
      if (in.charAt(closePos)=='(') counter++;
      if (in.charAt(closePos)==')') counter--;
    }
    return closePos;
  }

  public static int OpeningParentesis(String in, int closePos) {
    int openPos = closePos;
    int counter = 1;
    while (counter > 0 && openPos > 0) {
      openPos--;
      if (in.charAt(openPos)=='(') counter--;
      if (in.charAt(openPos)==')') counter++;
    }
    return openPos;
  }

AVLTree.java:

public class AVLTree extends Tree<AVLTree> {
  /*
  //Values and Variables
  private AVLTree left = null;
  private AVLTree right = null;
  private Object data;


  //Inicialization
  public AVLTree (Object data, AVLTree left, AVLTree right) {
    super(data,left,right);
  }
  public AVLTree (Object data) {
    super(data);
  }


  */
  public int getfactor() {
    return getHeight(this.getLeft())-getHeight(this.getRight());
  }
}

Test.java:

public static void main(String[] args) {
  AVLTree tree = new AVLTree();

  Scanner console = new Scanner(System.in);
  String in = console.nextLine().toLowerCase();

  tree = (AVLTree) tree.treeFromText(in); //The error is here.
  System.out.println(tree.getHeight());
  System.out.println(tree.TreePreOrder());


}

我希望它起作用的方式是,如果 Test.java 中的“in”字符串是“(c3()(c2()()))”,则返回值必须是值为 3 和右的树值为 2 的儿子。此返回必须是 Tree 类型或任何扩展 Tree 的类型。

【问题讨论】:

  • 请向我们展示代码 sn-ps,以便我们确定我们理解您的要求。
  • @StephenC 刚刚添加了问题上的代码。
  • 将 Tree 视为一个接口,并在基类(可能是 BaseTree)和 AVLTree 上实现它。然后只接受 Tree(接口)作为类型

标签: java tree subclass


【解决方案1】:

您需要使用Tree.treeFromText 中的逻辑从String 实例化AVLTree 的方法。

  1. Tree 声明为abstract

  2. Tree中创建一个新方法:

    abstract protected T createEmptyTree();

  3. 覆盖AVLTree 中的该方法以返回AVLTree 的空实例。

    @Override protected AVLTree createEmptyTree() { return new AVLTree(); }

  4. treeFromText() 中,无论您需要创建T 的空实例,调用createEmptyTree()

你已经掌握了其余的逻辑。

尽量避免在任何地方返回null。最好返回一个空的 AVLTree 而不是 null

【讨论】:

    【解决方案2】:

    您可以通过泛型的力量来实现这一点:定义一个新的循环泛型 T:

    public class Tree<T extends Tree<T>>
    {
        T left;
        T right;
    
        public T doSomething()
        {
            return left;
        }
    
        public static class AVLTree extends Tree<AVLTree>
        {
            public AVLTree foo()
            {
                return doSomething();
            }
        }
    } 
    

    更新:这里是创建不同树实例的方法:

    导入 java.util.Objects;

    public class TreesFactory
    {
        public static AVLTree createAVLTreeFrom(String in)
        {
            return treeFromText(in, AVLTree::new);
        }
    
        @FunctionalInterface
        interface SimpleFactory<T extends Tree<T>>
        {
            T createNew();
        }
    
        public static <T extends Tree<T>> T treeFromText(String in, SimpleFactory<T> treeFactory)
        {
            if (Objects.equals(in, "()"))
                return null;
    
            T result = treeFactory.createNew();
            //Find expression
            int d = in.indexOf('c') + 1;
            if (d == 0)
                return null;
    
            int begl, endl, begr, endr;
    
            begl = d + 1;
            endl = ClosingParentesis(in, begl);
            endr = in.length() - 2;
            begr = OpeningParentesis(in, endr);
    
            T left, right;
    
            if (begl - endl == 0)
            {
                left = null;
            }
            else
                left = treeFromText(in.substring(begl, endl + 1), treeFactory);
            if (begr - endr == 0)
            {
                right = null;
            }
            else
                right = treeFromText(in.substring(begr, endr + 1), treeFactory);
    
            result.setData(in.charAt(d));
            result.setLeft(left);
            result.setRight(right);
            return result;
        }
    
    
        public static int ClosingParentesis(String in, int openPos)
        {
            int closePos = openPos;
            int counter = 1;
            while (counter > 0 && closePos < in.length() - 1)
            {
                closePos++;
                if (in.charAt(closePos) == '(')
                    counter++;
                if (in.charAt(closePos) == ')')
                    counter--;
            }
            return closePos;
        }
    
        public static int OpeningParentesis(String in, int closePos)
        {
            int openPos = closePos;
            int counter = 1;
            while (counter > 0 && openPos > 0)
            {
                openPos--;
                if (in.charAt(openPos) == '(')
                    counter--;
                if (in.charAt(openPos) == ')')
                    counter++;
            }
            return openPos;
        }
    }
    

    还有主要的:

    public static void main(String[] args)
    {
        Scanner console = new Scanner(System.in);
        String in = console.nextLine().toLowerCase();
    
        AVLTree tree = TreesFactory.createAVLTreeFrom(in);
        //...
    }
    

    【讨论】:

    • 好的,我就是这样做的,并使用了一种方法来获取字符串并将其解析为树。该方法应该返回什么类型的变量?如果我返回 Tree 它不起作用。
    • 贴出代码让我更了解你
    • 您可以按照 Erick 提到的方式进行操作,也可以将 treeFromText 提取到不同的工厂类,并向其添加另一个参数 - Factory 是具有一种方法的接口 - 创建返回新 T . 比你为 Tree、AVLTree 等创建一个工厂......注意你在 treeFromText 中将树初始化为 null 并且永远不要更改它,所以总是返回 null。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多