• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

doubt question #4 Test 2 Enthuware

 
John Lerry
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a doubt about the operation cast a question test Enthuware.

Given this code:


and the following statements:


identify options that will compile and run without error.

The possible answers are:
- a = (B) (I) b;
- b = (B) (I) a;
- a = (I) b;
- I i = (C) a;


I have indicated the second option, however, is wrong, but even reading the explanation can not understand what happens in the other options.
Can you help me to understand the working of those four statements?
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:Can you help me to understand the working of those four statements?

I'll explain the 1st one and then the others are up to you.

The 1st option a = (B) (I) b; can be rewritten asSo first of all, you have to verify if this code will compile? The answer is yes. Why?
1/ The type of the reference variable b is B and B implements the interface I indirectly (through class A) => the cast (I) b is allowed by the compiler
2/ The type of the reference variable temp is I, I can be implemented by any non-final class and B is a non-final class (and it's implementing I as well) => the cast (B) temp is allowed by the compiler
3/ The type of the reference variable a is A and B IS-A A => it's valid (as in "no compiler errors) an object of type B to a reference variable of type A

Secondly you have to verify if all casts are valid and none of them will result in a runtime ClassCastException.
1/ The type of the actual object reference variable b is referring to, is B and B implements the interface I indirectly (through class A) => the cast (I) b will run successfully (no runtime exception)
2/ The type of the actual object reference variable temp is referring to, is B => the cast (B) temp will run successfully (no runtime exception) as well

So the 1st option a = (B) (I) b; is correct! Now it's up to you

Hope it helps!
Kind regards,
Roel
 
Paul Anilprem
Enthuware Software Support
Ranch Hand
Posts: 3820
10
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just FYI, if you click the "Discuss" button on the question view, you will see an existing discussion on this question that explains this point. Here is the link - http://enthuware.com/forum/viewtopic.php?f=2&t=1050

HTH,
Paul.
 
John Lerry
Ranch Hand
Posts: 145
1
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried to give my solution for the various pieces of code.
I start by saying that when I will refer to "downcast" or "upcast" with interfaces I am not referring to a real operation of cast but more schematic representation where conceptually an interface that implements a class finds himself at a higher level , as if there was a superclass instead of an interface.


- b = (B) (I) a;


- COMPILE TIME: OK
the reference a is type A and A implements I as allowed the cast (I)a (say a kind of upcast).
the reference temp is type I and B implements indirectly I as allowed the cast (B)temp (say a kind of downcast).

- RUNTIME: OK
the object associated with the reference a is type A and because A implements I the cast (I)a works.
the object associated with the reference temp is type A and because B extends A the cast (B)temp works.

I think there is something wrong because this statement should not be corrected.


- a = (I) b;


- COMPILE TIME: ERROR
the reference b is type B and because B implements indirectly I the cast (say a kind of downcast) works.
the problem occurs when trying to associate a (type A) to b (now type I).
To avoid this problem the statements should be changed so:

or like this:



- I i = (C) a;


- COMPILE TIME: ERROR
the reference is type A and because C extends indirectly A the cast (say a kind of downcast) works.
the problem occurs when trying to associate a (now type C) to i and this is because the superclass B does not implement I.
To avoid this problem the statements should be changed so:

or like this:

or like this:
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:

- b = (B) (I) a;


- COMPILE TIME: OK
the reference a is type A and A implements I as allowed the cast (I)a (say a kind of upcast).
the reference temp is type I and B implements indirectly I as allowed the cast (B)temp (say a kind of downcast).

- RUNTIME: OK
the object associated with the reference a is type A and because A implements I the cast (I)a works.
the object associated with the reference temp is type A and because B extends A the cast (B)temp works.

I think there is something wrong because this statement should not be corrected.

The explanation about COMPILE TIME is spot-on, but you made a mistake in your RUNTIME explanation. So let's review that one:
1/ the object associated with the reference a is type A and because A implements I the cast (I)a works (this one was easy for me, I could simply copy your explanation because it's correct )
2/ the type of the actual object reference variable temp is referring to, is A and B IS-A A (meaning: A is the superclass of B) => the cast (B)temp will throw a ClassCastException. Why? The cast (B)temp will execute successfully if and only if tempIS-A B. But that's not the case at all, because the type of temp is A and we know A is the superclass of B, so A IS-NOT-A B. You can check using the instanceof operator as illustrated in the following code:

Hope it helps!
Kind regards,
Roel
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:

- a = (I) b;


- COMPILE TIME: ERROR
the reference b is type B and because B implements indirectly I the cast (say a kind of downcast) works.
the problem occurs when trying to associate a (type A) to b (now type I).
To avoid this problem the statements should be changed so:

or like this:

Spot-on!

Bonus question: both statements you suggested will indeed avoid the problem and compile successfully. Will both statements also execute successfully (as in no runtime exceptions)? Or will you get a runtime exception?

Hope it helps!
Kind regards,
Roel
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:

- I i = (C) a;


- COMPILE TIME: ERROR
the reference is type A and because C extends indirectly A the cast (say a kind of downcast) works.
the problem occurs when trying to associate a (now type C) to i and this is because the superclass B does not implement I.

Incorrect!

A implements I => every subclass of A implements I indirectly => B (which is a subclass of A) does implement I (so B IS-A I as well). And again that's confirmed using this code snippet:

Have another try at this one.

Hope it helps!
Kind regards,
Roel
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Anilprem wrote:Just FYI, if you click the "Discuss" button on the question view, you will see an existing discussion on this question that explains this point.

A star (*) after "Discuss" (as in this printscreen of a question) indicates that this question has already been discussed in the Enthuware forums. (But of course we - the CodeRanch community - prefer you discuss your doubts in this forum ).
 
John Lerry
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:
John Lerry wrote:

- a = (I) b;


- COMPILE TIME: ERROR
the reference b is type B and because B implements indirectly I the cast (say a kind of downcast) works.
the problem occurs when trying to associate a (type A) to b (now type I).
To avoid this problem the statements should be changed so:

or like this:

Spot-on!

Bonus question: both statements you suggested will indeed avoid the problem and compile successfully. Will both statements also execute successfully (as in no runtime exceptions)? Or will you get a runtime exception?

Hope it helps!
Kind regards,
Roel


both statements compile and run without problems.
tell me if the reasoning is correct:




- COMPILE TIME: OK
the reference b is type B and because B implements indirectly I the cast (I) b is valid.
the reference temp is type I and because A implements I the cast (A) temp is valid.

- RUNTIME: OK
the type of the associated object to b is type B and B IS-A so the cast is invalid.
the type of the associated object to temp is B and B IS-A so the cast is invalid.






- COMPILE TIME: OK
the reference b is type B and because B implements indirectly I the cast (I) b is valid.
the reference temp is type I and because B implements I the cast (B) temp is valid.

- RUNTIME: OK
the type of the associated object to b is B and B IS-A so the cast is invalid.
the type of the object associated to temp is B and B IS-A B so the cast is invalid.
 
John Lerry
Ranch Hand
Posts: 145
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:

- I i = (C) a;



I try again:

- COMPILE TIME: OK
the type of the reference a is A and because C implements indirectly A the cast (C)a is valid.

- RUNTIME: ERROR
the type of the object associated to the reference a is type A but A IS-NOT-A C and then cast (C)a generate a ClassCastException.
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Lerry wrote:both statements compile and run without problems.

Spot-on!

John Lerry wrote:tell me if the reasoning is correct:

Your reasoning is correct as well. Although you made a few minor typos in your explanation:
  • forgot the types in the B IS-A part
  • using the cast is invalid instead of the cast is invalid
  •  
    Roel De Nijs
    Sheriff
    Posts: 10666
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    John Lerry wrote:
    John Lerry wrote:

    - I i = (C) a;



    I try again:

    - COMPILE TIME: OK
    the type of the reference a is A and because C implements indirectly A the cast (C)a is valid.

    - RUNTIME: ERROR
    the type of the object associated to the reference a is type A but A IS-NOT-A C and then cast (C)a generate a ClassCastException.

    Again spot-on! But I can't give you full marks. Why? C is a class, so it extends A indirectly (and not implements because that's used for interfaces only).

    Hope it helps!
    Kind regards,
    Roel
     
    Mark Justison
    Ranch Hand
    Posts: 31
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I thought I had this all figured out until the Ii = (C)a;

    If I look back at question 1:
    a = (B)(I)b;

    My understanding was that since b indirectly implements I through A that:
    I temp = (I)b;
    compiles and runs successfully.

    now we have something similar with Ii = (C)a;
    But the ref. variable a is not-a C so how is this passable to the compiler?
    I feel like I'm on the cusp of understanding all this but I'm concerned I may be imprinting a completely false concept of this in my head.
     
    Joe Bishara
    Ranch Hand
    Posts: 175
    17
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    now we have something similar with Ii = (C)a;
    But the ref. variable a is not-a C so how is this passable to the compiler?

    a is not-a C but type A and type C are related.

    The compiler allows (C)a because type A is cast to type C (narrowing conversion).
    The JVM disallows (C)a because type A is cast to type C (narrowing conversion).

    When casting, the compiler allows widening AND narrowing conversion (based on compile-time types as long as the types are related).
    When casting, the JVM allows ONLY widening conversion (based on runtime types).
     
    Roel De Nijs
    Sheriff
    Posts: 10666
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Mark Justison wrote:But the ref. variable a is not-a C so how is this passable to the compiler?
    I feel like I'm on the cusp of understanding all this but I'm concerned I may be imprinting a completely false concept of this in my head.

    Let's start with a very important rule: the compiler does not execute any code! Meaning: the compiler only knows the type of the reference variable a (= A), but doesn't know (and also doesn't care) about the type of the actual object the reference variable is referring to (in this case A as well). That's really very important to know and always remember. It will be helpful in many different situations, e.g. when you need to determine if a cast is a compiler error or runtime exception, when code is unreachable or not, and many more.

    Now back to the statement you are struggling with. We have this class hierarchyAnd this statementAnd finally the question: will the following statement compile and run without error
    In short, the compiler is fine with this statement, because classes A and C belong to the same class hierarchy (C IS-A A). For a more detailed explanation, just have a look at this post. It explains very well when the compiler is happy with a cast and when it isn't (and thus gives one of its very famous compiler errors ). When you are casting to an interface, it's a little bit trickier. But don't worry, this thread has a very good explanation as well.

    If you still have some doubts and/or questions after reading both threads, just hit the reply button and let us know

    Hope it helps!
    Kind regards,
    Roel
     
    Mark Justison
    Ranch Hand
    Posts: 31
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    You know, I think I finally get this. Excellent explanation. Thank you for the links as well.

    -Mark
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic