java构建继承树_java - 使用继承构建通用树 - 堆栈内存溢出

我正在构建一个通用的Tree类,它支持子树的继承。 但我遇到了一些问题。 请你帮帮我吗?

描述

让我们定义Tree类和BlueTree类,其中BlueTree extends Tree 。

让我们定义Leaf类和RedLeaf类,其中RedLeaf extends Leaf 。 它们被用作树包含的“数据”。

Tree表示Tree类型的Tree ,其“data”是Leaf类型。

对于继承 (这不是适当的Java继承):

Tree可以有类型的子项

Tree , Tree , BlueTree和BlueTree 。

Tree可以有类型的子项

Tree和BlueTree ,

但不是 Tree或BlueTree 。

BlueTree可以有类型的子项

BlueTree和BlueTree ,

但不是 Tree或Tree 。

BlueTree可以有类型的子项

BlueTree ,

但不是 Tree , Tree或BlueTree 。

*这里,“孩子”是指树的分支/叶子。

(有点复杂,这就是我将线分开的原因。)

代码

(如果你有一个解决方案,你可能不需要阅读下面我的尝试的详细说明。如果你想一起找到解决方案,我的代码可能会给你一些想法 - 或者,它可能会混淆它们。)

初审 :(简单的)

// This is the focus of this question, the class signature

public class Tree {

// some fields, but they are not important in this question

private Tree super T> mParent;

private T mData;

private ArrayList> mChildren;

// This is the focus of this question, the addChild() method signature

public void addChild(final Tree extends T> subTree) {

// add the subTree to mChildren

}

}

该类结构满足描述中的大多数要求。 除此之外,它允许

class BlueTree extends Tree { }

class Leaf { }

class RedLeaf extends Leaf { }

Tree tree_leaf = new Tree();

BlueTree blueTree_leaf = new BlueTree();

blueTree_leaf.addChild(tree_leaf); // should be forbidden

违反了

BlueTree 不能具有Tree类型的子项。

问题是因为,在BlueTree ,它的addChild()方法签名仍然存在

public void addChild(final Tree extends Leaf> subTree) {

// add the subTree to mChildren

}

理想情况是, BlueTree.addChild()方法签名被更改(在继承时自动)

public void addChild(final BlueTree extends Leaf> subTree) {

// add the subTree to mChildren

}

(注意,此方法不能通过继承覆盖上述方法,因为参数类型不同。)

有一个解决方法。 我们可以添加一个类继承检查,并为这种情况抛出RuntimeException :

public void addChild(final Tree extends Leaf> subTree) {

if (this.getClass().isAssignableFrom(subTree.getClass()))

throw new RuntimeException("The parameter is of invalid class.");

// add the subTree to mChildren

}

但是使它成为编译时错误远比运行时错误好。 我想在编译时强制执行此行为。

二审

第一个试验结构中的问题是,方法addChild()的参数类型Tree不是泛型类型参数。 因此,它不会在继承时更新。 这一次,让我们尝试使它成为泛型类型参数。

首先,定义一般的Tree类。

public class Tree {

private Tree super T> mParent;

private T mData;

private ArrayList> mChildren;

/*package*/ void addChild(final Tree extends T> subTree) {

// add the subTree to mChildren

}

}

然后是管理Tree对象的TreeManager 。

public final class TreeManager, DataType> {

private NodeType mTree;

public TreeManager(Class ClassNodeType) {

try {

mTree = ClassNodeType.newInstance();

} catch (Exception e) {

e.printStackTrace();

}

}

public void managerAddChild(final NodeType subTree) {

mTree.addChild(subTree);

// compile error: The method addChild(Tree extends capture#1-of ? super DataType>)

// in the type Tree

// is not applicable for the arguments (NodeType)

}

// for testing

public static void main(String[] args) {

@SuppressWarnings("unchecked")

TreeManager , Leaf> tm_TreeLeaf_Leaf = new TreeManager, Leaf> ((Class>) new Tree ().getClass());

TreeManager, RedLeaf> tm_TreeRedLeaf_RedLeaf = new TreeManager, RedLeaf>((Class>) new Tree ().getClass());

TreeManager , Leaf> tm_BlueTreeLeaf_Leaf = new TreeManager, Leaf> ((Class>) new BlueTree ().getClass());

TreeManager, RedLeaf> tm_BlueTreeRedLeaf_RedLeaf = new TreeManager, RedLeaf>((Class>) new BlueTree().getClass());

System.out.println(tm_TreeLeaf_Leaf .mTree.getClass()); // class Tree

System.out.println(tm_TreeRedLeaf_RedLeaf .mTree.getClass()); // class Tree

System.out.println(tm_BlueTreeLeaf_Leaf .mTree.getClass()); // class BlueTree

System.out.println(tm_BlueTreeRedLeaf_RedLeaf.mTree.getClass()); // class BlueTree

@SuppressWarnings("unchecked")

TreeManager , RedLeaf> tm_TreeLeaf_RedLeaf = new TreeManager, RedLeaf>((Class>) new Tree ().getClass());

TreeManager , RedLeaf> tm_BlueTreeLeaf_RedLeaf = new TreeManager, RedLeaf>((Class>) new BlueTree ().getClass());

System.out.println(tm_TreeLeaf_RedLeaf .mTree.getClass()); // class Tree

System.out.println(tm_BlueTreeLeaf_RedLeaf .mTree.getClass()); // class BlueTree

// the following two have compile errors, which is good and expected.

TreeManager, Leaf> tm_TreeRedLeaf_Leaf = new TreeManager, Leaf> ((Class>) new Tree ().getClass());

TreeManager, Leaf> tm_BlueTreeRedLeaf_Leaf = new TreeManager, Leaf> ((Class>) new BlueTree().getClass());

}

}

TreeManager初始化没有问题; 虽然线条有点长。 它也符合说明中的规则。

但是,在TreeManager调用Tree.addChild()时会出现编译错误,如上所示。

第三次审判

为了修复第二次试用中的编译错误,我尝试更改类签名(甚至更长)。 现在是mTree.addChild(subTree); 编译没有问题。

// T is not used in the class. T is act as a reference in the signature only

public class TreeManager3, DataType extends T> {

private NodeType mTree;

public TreeManager3(Class ClassNodeType) {

try {

mTree = ClassNodeType.newInstance();

} catch (Exception e) {

e.printStackTrace();

}

}

public void managerAddChild(final NodeType subTree) {

mTree.addChild(subTree); // compile-error is gone

}

}

我使用与第二次试验非常相似的代码对其进行了测试。 正如第二次试验所做的那样,它没有任何问题。 (甚至更长。)

(您可以跳过下面的代码块,因为它只是在逻辑上重复。)

public static void main(String[] args) {

@SuppressWarnings("unchecked")

TreeManager3 , Leaf> tm_TreeLeaf_Leaf = new TreeManager3, Leaf> ((Class>) new Tree ().getClass());

TreeManager3, RedLeaf> tm_TreeRedLeaf_RedLeaf = new TreeManager3, RedLeaf>((Class>) new Tree ().getClass());

TreeManager3 , Leaf> tm_BlueTreeLeaf_Leaf = new TreeManager3, Leaf> ((Class>) new BlueTree ().getClass());

TreeManager3, RedLeaf> tm_BlueTreeRedLeaf_RedLeaf = new TreeManager3, RedLeaf>((Class>) new BlueTree().getClass());

System.out.println(tm_TreeLeaf_Leaf .mTree.getClass()); // class Tree

System.out.println(tm_TreeRedLeaf_RedLeaf .mTree.getClass()); // class Tree

System.out.println(tm_BlueTreeLeaf_Leaf .mTree.getClass()); // class BlueTree

System.out.println(tm_BlueTreeRedLeaf_RedLeaf.mTree.getClass()); // class BlueTree

@SuppressWarnings("unchecked")

TreeManager3 , RedLeaf> tm_TreeLeaf_RedLeaf = new TreeManager3, RedLeaf>((Class>) new Tree ().getClass());

TreeManager3 , RedLeaf> tm_BlueTreeLeaf_RedLeaf = new TreeManager3, RedLeaf>((Class>) new BlueTree ().getClass());

System.out.println(tm_TreeLeaf_RedLeaf .mTree.getClass()); // class Tree

System.out.println(tm_BlueTreeLeaf_RedLeaf .mTree.getClass()); // class BlueTree

// the following two have compile errors, which is good and expected.

TreeManager3, Leaf> tm_TreeRedLeaf_Leaf = new TreeManager3, Leaf> ((Class>) new Tree ().getClass());

TreeManager3, Leaf> tm_BlueTreeRedLeaf_Leaf = new TreeManager3, Leaf> ((Class>) new BlueTree().getClass());

}

但是,当我尝试调用TreeManager3.managerAddChild()时出现问题。

tm_TreeLeaf_Leaf.managerAddChild(new Tree());

tm_TreeLeaf_Leaf.managerAddChild(new Tree()); // compile error: managerAddChild(Tree) cannot cast to managerAddChild(Tree)

tm_TreeLeaf_Leaf.managerAddChild(new BlueTree());

tm_TreeLeaf_Leaf.managerAddChild(new BlueTree()); // compile error: managerAddChild(BlueTree) cannot cast to managerAddChild(BlueTree)

这是可以理解的。 TreeManager3.managerAddChild(NodeType)表示TreeManager3.managerAddChild(Tree)并且没有通配符Tree extends T> 在第一次试验中,在参数类型中Tree extends T> ,如Tree.addChild(final Tree extends T> subTree) 。

乞求你的帮助......

我已经没有想法了。 我是否朝错误的方向解决这个问题? 我花了很多时间来打理这个问题,并尽最大努力使其更具可读性,更易于理解和遵循。 我不得不说抱歉它仍然很长很冗长。 但是,如果你知道方式,请你帮忙,或者请给我任何想法? 您的每一个输入都非常感谢。 非常感谢!

编辑#1(以下评论 )

总部设在一审判决后 ,只允许mChildren被修改addChild()等方法与isAssignableFrom()检查),因此即使允许用户继承Tree和压倒一切addChild()不会打破树的完整性。

/developer/util/Tree.java

package developer.util;

import java.util.ArrayList;

public class Tree {

private Tree super T> mParent;

private final ArrayList> mChildren = new ArrayList>();

public int getChildCount() { return mChildren.size(); }

public Tree extends T> getLastChild() { return mChildren.get(getChildCount()-1); }

public void addChild(final Tree extends T> subTree) {

if (this.getClass().isAssignableFrom(subTree.getClass()) == false)

throw new RuntimeException("The child (subTree) must be a sub-class of this Tree.");

subTree.mParent = this;

mChildren.add(subTree);

}

}

/user/pkg/BinaryTree.java

package user.pkg;

import developer.util.Tree;

public class BinaryTree extends Tree {

@Override

public void addChild(final Tree extends T> subTree) {

if (getChildCount() < 2) {

super.addChild(subTree);

}

}

}

/Main.java

import user.pkg.BinaryTree;

import developer.util.Tree;

public class Main {

public static void main(String[] args) {

Tree treeOfInt = new Tree();

BinaryTree btreeOfInt = new BinaryTree();

treeOfInt.addChild(btreeOfInt);

System.out.println(treeOfInt.getLastChild().getClass());

// class user.pkg.BinaryTree

try {

btreeOfInt.addChild(treeOfInt);

} catch (Exception e) {

System.out.println(e);

// java.lang.RuntimeException: The child (subTree) must be a sub-class of this Tree.

}

System.out.println("done.");

}

}

你怎么看?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值