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.");
}
}
你怎么看?
java构建继承树_java - 使用继承构建通用树 - 堆栈内存溢出相关推荐
- java poi 段落行间距_java - Apache poi XWPF Paragraph行间距 - 堆栈内存溢出
我正在尝试使用Java / Coldfusion中的Apache Poi构建一个word文档. 到目前为止,它让我做了很多我想要的格式,除了段落的行间距. 有谁知道如何将段落设置为单行间隔? 它不断构 ...
- java程序包r不存在_java - 从命令行使用Gradle构建时,“程序包R不存在”错误 - 堆栈内存溢出...
我正在尝试从命令行使用Gradle构建一个Android项目,但是当我想要更改目录结构时发现了一个问题. 目前是这样的: . └── main ├── AndroidManifest.xml ├── ...
- axis2 java客户端内存溢出怎么办_java - Axis2-总是出现404错误 - 堆栈内存溢出
我试图将一些Web服务存根从Metro移到Axis2,但是在使用wsdl2java生成存根后,每次尝试进行服务调用时,我都会不断收到404错误. 16/12/2010 11:14:57 AM org. ...
- java从端口接收数据_java - Java中通过串行端口接收数据的效率更高 - 堆栈内存溢出...
这是代码片段 我在这里启动一个动作监听器 try { port_seleted.addEventListener(this); } catch (TooManyListenersException e ...
- java获取excel文件第一行_java - 在Java中读取Excel文件,但第一行除外 - 堆栈内存溢出...
我正在尝试从使用xlsx文件的JasperReport模板自动创建报告,我用来从excel文件读取的方法是这样的: String[] columnNames = new String[]{" ...
- java 获取permgen_java - Java:如何检查当前的Perm / PermGen大小? - 堆栈内存溢出
您可以在这里使用jmap ,它是JVM堆转储工具. 例如: jmap -heap 5900 它将打印: Heap Configuration: MinHeapFreeRatio = 40 MaxHea ...
- java远程计算机终止,java - javax.net.ssl.SSLHandshakeException:远程主机终止了握手 - 堆栈内存溢出...
我已经使用以下命令在Java信任库(cacerts)中安装了证书: keytool-导入-文件" C:\\ Users \\ kdursoji \\ Downloads \\ Zscaler ...
- android 415错误,java - Android Retrofit2无法添加标头(415错误代码) - 堆栈内存溢出...
我正在尝试通过skyscanner api访问票证数据并将其传递到我的视图,但是我无法实现这一点,因为我收到415错误代码,我正在使用Retrofit2并以编程方式添加标头. 我的界面如下所示: pu ...
- java 抽象类继承抽象类_Java之继承、抽象类、接口篇
一.继承(extends) 什么是继承? 继承是对现实生活中的"分类"概念的一种模拟. 狮子拥有动物的一切基本特性,但同时又拥有自己的独特的特性,这就是"继承" ...
- java 封装 继承 堕胎_Java的继承、封装和多态
一.继承 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. 继承的特性 子类拥有父类非 private 的属性.方法. ...
最新文章
- 训练Rainbow算法需要1425个GPU Day?谷歌说强化学习可以降低计算成本
- Android(Linux)实时监控串口数据
- 环境变量太大解决方法
- cad自动标注界址点_CAD制图中的5个小技巧
- Python回调函数
- 【Linux网络编程】TCP三次握手和四次挥手
- 福昕熊雨前:PDFium开源项目的背后
- 通用单向链表设计(一)——接口的设计
- ubuntu 下安装和启动SSH 服务
- python优雅编程_Python——traceback的优雅处理
- 多变量频率统计——r
- 【数字信号调制】基于matlab GUI数字信号调制仿真系统【含Matlab源码 336期】
- Redis的安装和使用之二------phpredis与phpRedisAdmin
- 穷建站(一):申请免费的tk顶级域名
- 多肽细胞穿膜肽TAT修饰牛血清白蛋白BSA/人血清白蛋白HSA/卵清白蛋白OVA纳米粒(实验要求)
- 解决zing生成二维码时二维码太小、白框太大的问题
- 广东计算机二级考试大纲,全国计算机等级考试大纲(二级)
- 微星主板开启安全启动以更新win11教程
- MVC 音乐商店 第1部分: 概述和文件- 新建项目
- Unity光照效果_自发光动态改变并影响环境