内部静态类继承内部静态类,子级的外部类也继承父级的外部类,为什么我不能进行强制转换

时间:2018-12-01 15:56:15

标签: java

我有以下课程:

public class BinarySearchTree<E extends Comparable<E>> implements Tree<E> {
    BinarySearchTreeNode<E> root = null;
    protected int size = 0;
    private LinkedList<E> inOrderData = new LinkedList<>();
    private LinkedList<E> postOrderData = new LinkedList<>();
    private LinkedList<E> preOrderData = new LinkedList<>();

    public BinarySearchTree() {

    }

    public BinarySearchTree(E[] objects) {
        for (E e : objects) {
            insert(e);
        }
    }

    public static class BinarySearchTreeNode<E extends Comparable<E>> {
        protected E data;
        protected BinarySearchTreeNode<E> left;
        protected BinarySearchTreeNode<E> right;

        public BinarySearchTreeNode(E e) {
            data = e;
        }

        @Override
        public String toString() {
            return this.data.toString();
        }
    }

public LinkedList<BinarySearchTreeNode<E>> path(E e) {
    LinkedList<BinarySearchTreeNode<E>> list = new LinkedList<>();
    BinarySearchTreeNode<E> current = root;
    while (current != null) {
        list.add(current);
        int compareElement = e.compareTo(current.data);
        if (compareElement < 0) {
            current = current.left;
        } else if (compareElement > 0) {
            current = current.right;
        } else {
            break;
        }
    }
    return list;
}

public class AVLTree<E extends Comparable<E>> extends BinarySearchTree<E> {
    public AVLTree() {

    }

    public AVLTree(E[] objects) {
        super(objects);
    }

    protected static class AVLTreeNode<E extends Comparable<E>> extends BinarySearchTree.BinarySearchTreeNode<E> {
        protected int hight = 0;

        public AVLTreeNode(E data) {
            super(data);
        }
    }
    private void balance(E e) {
        LinkedList<BinarySearchTreeNode<E>> path = path(e);
        for (int i = path.size() - 1; i >= 0; i--) {
            AVLTreeNode<E> A = (AVLTreeNode<E>) path.get(i);
            updateHeight(A);
            AVLTreeNode<E> parentOfA = (A == root) ? null : (AVLTreeNode<E>) (path.get(i - 1));

            switch (balanceFactor(A)) {
                case -2:
                    if (balanceFactor((AVLTreeNode<E>) A.left) <= 0) {
                        LLRotate(A, parentOfA);
                    } else {
                        LRRotate(A, parentOfA);
                    }
                case +2:
                    if (balanceFactor((AVLTreeNode<E>) A.right) >= 0) {
                        RRRotate(A, parentOfA);
                    } else {
                        RLRotate(A, parentOfA);
                    }
            }
        }
    }
}

但是在运行时,我在以下行中得到以下异常:

AVLTreeNode<E> A = (AVLTreeNode<E>) path.get(i);

"C:\Program Files\Java\jdk-11.0.1\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\lib\idea_rt.jar=61223:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\plugins\junit\lib\junit-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\plugins\junit\lib\junit5-rt.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\platform\junit-platform-launcher\1.3.1\junit-platform-launcher-1.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\apiguardian\apiguardian-api\1.0.0\apiguardian-api-1.0.0.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\platform\junit-platform-engine\1.3.1\junit-platform-engine-1.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\platform\junit-platform-commons\1.3.1\junit-platform-commons-1.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\opentest4j\opentest4j\1.1.1\opentest4j-1.1.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.3.1\junit-jupiter-engine-5.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.3.1\junit-jupiter-api-5.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\junit\vintage\junit-vintage-engine\5.3.1\junit-vintage-engine-5.3.1.jar;C:\Users\Albaraa Kefaya\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\Albaraa Kefaya\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\Albaraa Kefaya\PhotonE\DataStructuresProjects\bin;C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.6\lib\junit.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit5 datastructures.tests.TestAVLTree

java.lang.ClassCastException: class datastructures.trees.BinaryTrees.BinarySearchTree$BinarySearchTreeNode cannot be cast to class datastructures.trees.BinaryTrees.AVLTree$AVLTreeNode (datastructures.trees.BinaryTrees.BinarySearchTree$BinarySearchTreeNode and datastructures.trees.BinaryTrees.AVLTree$AVLTreeNode are in unnamed module of loader 'app')

at datastructures.trees.BinaryTrees.AVLTree.balance(AVLTree.java:32)
at datastructures.trees.BinaryTrees.AVLTree.insert(AVLTree.java:26)
at datastructures.trees.BinaryTrees.BinarySearchTree.<init>(BinarySearchTree.java:20)
at datastructures.trees.BinaryTrees.AVLTree.<init>(AVLTree.java:12)
at datastructures.tests.TestAVLTree.<init>(TestAVLTree.java:10)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:431)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:60)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeTestClassConstructor(ClassTestDescriptor.java:342)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:289)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:281)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateAndPostProcessTestInstance(ClassTestDescriptor.java:269)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$2(ClassTestDescriptor.java:259)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$3(ClassTestDescriptor.java:263)
at java.base/java.util.Optional.orElseGet(Optional.java:369)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$testInstanceProvider$4(ClassTestDescriptor.java:262)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:82)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$0(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:66)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:110)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:110)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

进程结束,退出代码为-1

我不知道为什么我不能将BinarySearchTreeNode<E>下放到AVLTreeNode<E>

1 个答案:

答案 0 :(得分:0)

The stacktrace Shows that the AVLTree child constructor in calling the BinarySearchTree super constructor which again calls an insert, overriden in the child.

at datastructures.trees.BinaryTrees.AVLTree.balance(AVLTree.java:32)
at datastructures.trees.BinaryTrees.AVLTree.insert(AVLTree.java:26)
at datastructures.trees.BinaryTrees.BinarySearchTree.<init>(BinarySearchTree.java:20)
at datastructures.trees.BinaryTrees.AVLTree.<init>(AVLTree.java:12)
at datastructures.tests.TestAVLTree.<init>(TestAVLTree.java:10)

Many an IDE will warn about the call to the overridable insert in the constructor.

What happens is quite dirty:

class A {
    A() {
        f();
    }
    protected void f() {
    }
}

class B {
    String s;
    String t = null;
    String u = "U";
    B() {
        // 0. B is not created, all fields are defaulted: 0, null, false, 0.0.
        //    s == null, t == null, u == null (!)
        // 1. super() is called
        //    s == "S",  t == "T",  u == null (!)
        // 2. all field initialisations are done: for t and u.
        //    s == "S",  t == null, u == "U" 
        // 3. the rest of the constructor code is done.
        System.out.printf("B.B: s %s; t %s; u %s%n", s, t, u);
    }

    @Override
    protected void f() {
        System.out.printf("B.f: s %s; t %s; u %s%n", s, t, u);
        // When called from A(): s, t and u (!) are null.
        s = "S";
        t = "T";
    }
}
  • f does not receive initialized values; deadly in case of new ArrayList<>() and such.
  • f's assignments will be overwritten by field initialisations.

Hence do not use overridable Methods in constructors.

In your case the AVLTree.insert may not use initialized fields of AVLTree.

One way to solve this would be a factory method:

class AVLTree {
    AVLTree() { … not calling insert … }

    /** Factory method. */
    public static AVLTree create(E.. data) {
        AVLTree tree = new AVLTree();
        tree.insert(…);
    }

The error that the private inner parent node class is created by the super class method's and the private inner child node class only in the child class, can be resolved in the same manner:

public class BinarySearchTree<…> … {

     protected static class Node { … }

     protected BinarySearchTree.Node createNode() { return new Node(); }
}

public class AVLTree<…> … {
     protected static class Node extends BinarySearchTree.Node { … }

     @Override
     protected AVLTree.Node createNode() { return new AVLTree.Node(); }
}

Do not use an explicit new Node in the base class.