0

We were forced to go from Java 1.6 up to Java 1.8 in my work environment. We did fix most of the code breakage which were introduced in this upgrade, but we now stumbled across following:

In Java 1.6 following were executing correctly:

class TestViz extends TestFrame
{
// this class is abstract
}

class TestChart extends TestViz
{
}

class MyClassTest extends JUnit
{
    public MyTest()
    {
        TestChart chartClone = (TestChart) chart.duplicate();
    }
}

Now the chart.duplicate() returns TestFrame, hence the cast.

Unfortunately using Java 1.8 this code fails, with the java.lang.ClassCastException.

Does anybody know what changed in regards to abstract class casting and probably how to fix this code?

Thank you.

EDIT

The error message says:

"TestFrame cannot be cast to TestChart"
Vladimir Vagaytsev
  • 2,871
  • 9
  • 33
  • 36
Igor
  • 5,620
  • 11
  • 51
  • 103
  • 2
    What's the message & stack trace? – SLaks Jul 26 '16 at 20:02
  • 2
    What is the code for duplicate()? – stdunbar Jul 26 '16 at 20:05
  • Also, where is `duplicate()` defined? – Daniel M. Jul 26 '16 at 20:06
  • `chart.duplicate()` does *not* return an object deriving from TestChart (the cast itself is unaffected by a Java update: this leaves the object provided in question). Find out why by inspecting the actual object returned from `duplicate()` and how it is created. – user2864740 Jul 26 '16 at 20:06
  • @SLaks, sorry, added error message. And there is no stack trace. – Igor Jul 26 '16 at 20:07
  • There is always a stack trace. Your testing framework may not be dumping it out to where you are looking, but you could catch the exception, call exception.printStackTrace() and then rethrow it. – Stephen M -on strike- Jul 26 '16 at 20:10
  • @rmlan, well it does work with Java 1.6, but not in 1.8. Also, the duplicate() method returns TestFrame, so I "CAN" cast. – Igor Jul 26 '16 at 20:10
  • 3
    @Igor You can only cast if the duplicate method returns TestChart (or any subclass of TestChart) – Daniel M. Jul 26 '16 at 20:11
  • @DanielM, OK, but the "TestChart" "is-a" "TestFrame". Just look at the inheritance diagram. The casting is perfectly legal. – Igor Jul 26 '16 at 20:14
  • 2
    @Igor But that doesn't work the other way around. Your code is taking a TestFrame (which isn't necessarily a TestChart) and trying to stuff it into a TestFrame. The question is then why did it work in Java 6. – Daniel M. Jul 26 '16 at 20:15
  • 1
    Igor, you're reading the inheritance backwards. TestChart is a TestFrame, but a TestFrame is not necessarily a TestChart. If you want more help, we'll need to see duplicate() as it seems to behaving differently between Java 1.6 and 1.8. – Stephen M -on strike- Jul 26 '16 at 20:15
  • @Igor a TestFrame cannot be cast to a TestChart because TestChart is not a subclass of TestFame (in fact, the opposite is true). You can only make that cast if the object returned by duplicate is a TestChart or a subtype of TestChart. – puhlen Jul 26 '16 at 20:16
  • @puhlen et al, is it possible that Java 1.6 allowed the upcasting but 1.8 no longer supports it? – Igor Jul 27 '16 at 03:40
  • @Igor you need too look at the duplicate() method and the runtime type of the object it returns. Without that information it is impossible to diagnose the problem. If anything changed it will be something to do with duplicate(). – puhlen Jul 27 '16 at 13:08

1 Answers1

2

The error happens because you trying to perform an invalid casting operation.

Your TestChart class is a subclass of TestFrame. This means that the following cast is valid:

TestChart chart = new TestChart();
TestFrame frame = (TestFrame) chart;

This is because Java will handle your chart object as if it was a TestFrame (which it is!), so any specific variables or method of TestChart will not be visible here (as they are not part of TestFrame).

However, when you try to go in the opposite direction, making a cast like

TestFrame frame = new TestFrame();
TestChart chart = (TestChart) frame;

You will get a ClassCastException, because you can not handle the TestFrame class in such a specific way. There are methods and variables declared in TestChart (and even in TestViz) that will not be present in your frame object (because, guess what... it is a TestFrame, and not a TestChart!)

This is how inheritance work in Java. You can always broadly refer to an object by one of its superclasses, but you can never refer to an object by one of its subclasses because you would be trying to narrow things more than the language can support you on.


If you can do your test considering that the object returned by duplicate() is of type TestFrame, your code would be like

TestFrame chartClone = chart.duplicate();

and that should work fine. Another solution would be changing the duplicate() method's signature and return an object of type TestChart, so no cast would be needed.

Bruno Toffolo
  • 1,504
  • 19
  • 24
  • is it possible that Java 1.6 did allow such upcasting while Java 1.8 is more strict and prohibits it? I know in C++ you can do both up- and down-casting, so maybe 1.6 mimic that, but 1.8 stopped doing it? – Igor Jul 27 '16 at 03:39
  • I'm not sure such downcasting would be allowed. Are you sure this exact code piece was running before the upgrade? It looks like **some** downcasts were allowed (http://stackoverflow.com/a/380828/3227787), but not all of them. – Bruno Toffolo Jul 27 '16 at 12:24
  • yes, I'm sure. I'm running both 1.6 and 1.8 in parallel. 1.6 passes, 1.8 fails. – Igor Jul 28 '16 at 16:03
  • As mentioned in this thread that exposes the same problem as you do with a working JDK 6 code piece (https://coderanch.com/t/590925/java/java/downcasting-ClassCastException-java-versions), "it could be because the JVM code changed in the more recent versions. In fact that's almost certainly why." – Bruno Toffolo Jul 29 '16 at 13:06