if:
interface I{}
class A implements I{}
class B extends A{}
class C extends B{}
A a = new A();
B b = new B();
Why a = (B)(I)b; is correct
but b = (B)(I)a; is false?
I find casting to be very confusing, what is the best way to understand if I can down cast or up cast an object?
Your class hierarchy looks like this:
Object x can be casted to class Y, if runtime type of x is subclass of Y. Or, in other words, if there is a path from runtime type of x to Y. By "runtime type" i mean the type of object (the one used when constructing object) as opposed to type of variable (the one from variable declaration).
This is valid:
b = new B();
(B)(I)b;
Object stored in b has type B. It's casted to I and then back to B. B is a subclass of both of them. Cast to I doesn't actually do anything and is meant only to confuse you.
However, neither of those is valid:
a = new A();
(B)(I)a;
(B)a;
They will both fail with exception: java.lang.ClassCastException: A cannot be cast to B. a has type A which is not a subclass of B. There is a relation between A and B, but it's in the opposite direction - B is a subclass of A.
For more detailed explanation see here: http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
The only thing of relevance to answering the question in your coding sample is the following:
class B extends A{}
This means that B is a subclass of A. Subclasses can be cast to super class types, but super class cannot be cast to subclass types.
Therefore, A cannot be cast to type B.
Why? Think about the logic this way:
is a type of Programming_language, but Programming_language is not a type of
Related
The Problem
Consider the code below. B inherits from A, and none of them inherit from String.
I'd like to know the answers to the following questions:
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
Why is there a difference? Why doesn't the compiler see the problem in the first case?
The Code
public class Main {
public static void main(String[] args) {
A a1 = new A();
B b1 = (B) a1;
String b1 = (String) a1;
}
}
with class A:
public class A {}
and class B:
public class B extends A {}
A variable of type A could have been assigned an instance of B, because a B is an A. Eg a Dog is an Animal, so a box labelled “Animal” could contain a dog.
But a variable of type A cannot have been assigned a String. Eg A box labelled “Animal” will not contain a Brick.
You may be asking yourself why the compiler doesn’t complain when we can see that the code will clearly fail - there’s no way the variable is a B; it’s an A!
The compiler looks only at the type of the variable when making its checks. It doesn’t examine what code came before. Although your example is simple, checking what a variable actually contains would be an impossible task in the general case.
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
Variables of type A can store instances of B. However, not all instances of A are instances of B.
An A is not a B, but a B is an A. (Like, not all animals are dogs, but dogs are animals).
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
A is not a supertype of String, and String is not a supertype of B.
Why is there a difference? Why doesn't the compiler see the problem in the first case?
Because variables of type A can store instances of B; but variables of type A can never store instances of String.
A variable of type A could in fact be of type B as B extends A. But a variable of type A can never be of type String. That's why the compiler can catch the cast to String, but not the cast to B.
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
Because a1 is an instance of A, but is not compatible with B. Specifically, new A() creates an object that is not compatible with subclasses of A. If the runtime class (i.e., the class with which new was called) of the object is not the same as or a subclass of the target class, casting to that target class will fail at runtime. This is simply because the child class has nothing to do with that object.
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
Even if the actual casting happens at runtime, the compiler performs type checks and prevents pointless operations like this. For this scenario, casting an A object to String is nonsense and the compiler can detect it: there is no relationship between String and A, and the compiler knows what class is a child of what other class. The compiler knows that there is no way in Java for a1 to be an instance of String or of a subclass of String, and that's because String is not a parent of A, the declared type of a1. There are exceptions to this, such as when the cast is begin made to an interface.
Why is there a difference? Why doesn't the compiler see the problem in the first case?
The compiler only validates type casts based on static types (the type of the variable or of the expression). It doesn't look at the runtime class, which of course isn't available until runtime when the object is actually created. When it can determine with certainty that the cast can't possibly be valid (such as in the second case), it will fail. In the first case, casting from A to B passes compilation because the declared types are compatible (i.e., an A object can possibly be an instance of B, and the compiler leaves it for the runtime to check the actual object). In the second case, the compiler knows that an A object can never be an instance of String (because String is nowhere in A's type hierarchy, and this won't change at runtime)
The class hierarchy diagram for the class A would be:
Object -> A -> B (Note that every class extends Object)
B b1 = (B) a1;
The above line compiles because B extends A and hence the compiler sees it as a valid downcast. The java compiler only checks whether it is possible for an object of type A to be of type B, by checking the class hierarchy of B (whether B extends A directly or indirectly). It doesn't check the actual type of the object A at this point. It wasn't implemented this way since it would add a lot of complexity in the compiler. Also if an object is being downcast (to call some specific sub class method perhaps), then the responsibility is on the programmer to be aware of the specific type of the object. In this example since a1 can't be cast to type B, it will be detected by the JVM at runtime.
String b1 = (String) a1;
In this case, the class String is nowhere in the class hierarchy diagram of A. Therefore it can be detected at compile time that this is an invalid cast.
I'm looking at casting in Java, and specifically casting with interfaces. Suppose I have an interface I, that defines a method jump, i.e.:
interface I{
public void jump();
}
Additionally suppose I have 3 other classes, A, B and C. A implements I. B does not. However, C extends B and implements I.
class A implements I {
public void jump(){
System.out.print("A is jumping");
}
}
class B { }
class C extends B implements I {
public void jump(){
System.out.print("C is jumping");
}
}
Now if I try to assign an object of type A to an I, there is no problem and I do not even need a cast. I.e.:
I i = new A();
is OK no need to cast.
Presumably this is because the compiler knows that A implements I. Furthermore, if I try to this:
A mya = new A();
I i = mya;
No problems, even though mya could be referencing a subclass of A. But AFAIK that's OK since the compiler knows that every sub class of A must implicitly implement the jump method and therefore the interface A.
However, if I try to assign an object of type B to an I, then I do need a cast. e.g.
B myb = new B();
I i = (I)myb;
Presumably this is because the compiler knows that B does not implement I. However, since B could refer to a subclass which does implement I, then you are allowed to cast to I. So far so good.
Now here's my question: If I want to assign an object of type B that refers to an object of type C (which implements I) to an I then we require a cast. Why is that? E.g.
B b = new C();
I myI = b; //Won't compile this needs a cast
I myI = (C)b; // This will compile
myI = (I)b; // This will also compile
Why doesn't the compiler understand that B is referring to a C that implements I?
Presumably it's to do with the fact that B could refer to a B which doesn't actually implement I but why is it that the compiler doesn't know that? Presumably the compiler is limited to the information that is only available on each line? It can't run through your program and see that b is in fact pointing to a C? If that is correct can someone point me in the direction of some literature on how Java compilers work and what exactly are their limitations?
Presumably this is because the compiler knows that B does not implement I, however since B could refer to a subclass which does implement I then you are allowed to cast to I.
Not exactly. The compiler will let you cast B however you want. That doesn't mean you won't get a ClassCastException at runtime. (Your code will work this time, but the compiler won't prevent you from making bad casts.)
Why doesn't the compiler understand that B is referring to a C that implements I? Presumably it's to do with the fact that B could refer to a B which doesn't actually implement I but why is it that the compiler doesn't know that.
Because you told it to treat the object as a B when you declared B b = new C();
Presumably the compiler is limited to the information that is only available on each line? It can't run through your program and see that b is in fact pointing to a c?
It has access to the rest of the code. It's just doing what you told it to do: treat b as an object of class B.
In this particular case, compiler has the ability to determine that b actually refers to an object of C. However language creators chose not to make the the compiler so smart.
In practical scenario, actual object which b refers to, would not be so localized and so compile time determinable. So it was chosen not to make the compiler be over-smart which does not solve practical scenarios.
Let there be two classes defined as follows:
Class A{
int a;
}
Class B{
int b;
}
A and B are two unrelated classes. Is there anyway I can cast an object of A to B? If yes, please explain the various options I have.
You can do
Object b = new B();
A a = (A) b;
But this will throw a ClassCastException at runtime.
Instead you can use a copy Constructor
class B {
public B(A a) { ... }
public static B toB(A a) { return new B(a); }
}
And then you can do
B b = new B(a);
or
B b = toB(a);
You can do an upcast to a common super type, followed by a downcast
(Dog)(Pet)aCat
Of course, Object is the supertype of any type, so we can use it to cast between any 2 types
(Apple)(Object)aCat
Usually, this makes no sense, and it will cause runtime exception. But it may be helpful in some generic cases. For example, Supplier<Integer> and Supplier<number> are "unrelated"; as a matter of fact, they are mutually exclusive, i.e. the intersection is empty, or, no object can belong to the two types at the same time. Nevertheless, we may want to cast Supplier<Integer> to Supplier<Number>, due to lack of variance in Java, combined with the existence of erasure. See this case study.
You can't. That would break a fundamental principle of object-oriented programming.
Though JAVA allows you to type cast object across unrelated classes i.e. which are not in class hierarchy. This is allowed because of the below case
String s = (String)list.get(1);
Well list can certainly contain different type of object and while calling such a method it could return String as well.
Coming to your question you will succeed in typecasting but at runtime you will get ClassCastException .
You can type cast object B to type A iff B IS-A A that means B is a subtype of A. If both are not in a hierarchy then type casting them does not make sense. just like you can not type cast an Animal type to Furniture type.
Assume class B extends class A and I want to declare a variable for B. What is more efficient and why?
B b
OR
A<B> b.
You are confusing two different concepts.
class B extends A {
}
means that B is an A.
If you have something like A<B> it means that you class A is defined as
class A<T> {
}
meaning that you class A is a generic class.
For example (over simplified) you have
class List<T> {
}
So if T takes the value String you would have List<String> meaning a list of Strings
So A<B> does not mean that B extends A.
You should use B b.
Use B b. A<B> is a template class that uses B as a type, for example:
List<String> is a list of strings, so List<B> would be a list of B objects.
WeakReference<String> is a a weak reference to a string, so WeakReference<B> would be a weak reference to a B object.
If B extends A then I would use type A as much as possible.
A widget = new B();
This lowers the assumptions other parts of the code may make on your implementation.
I think it's not a matter of efficiency but of usage. If a pure A object isn't meant to use B, why would you want it to be A<B> b?
Your declarations don't do remotely the same thing. The first declares an object of type B, while the second declares an object of type A<T>, where T is a type parameter whose slot is filled by the type B.
Neither declaration is more efficient than the other.
But A<B> b doesn't declare a reference of type B, it declares a reference of type A that is templated on type B.
Unless A is a generic class, the second form is illegal.
In Java, suppose I have 3 classes, C extends from B which extends from A.
class X {
interface A {}
interface B extends A {}
interface C extends B {}
void f(A a) {}
void test() {
C c = new C()
B b = (B) c;
f(b);
}
}
If I do something like this as shown in test() above:
C c = new C()
B b = (B) c;
f(b);
f() accepts b as type C since C and B both extend from A. I wanted f() to receive b as type B and not type C.
Is there anyway to force this upcasting?
f() will always receive something typed as A (despite under the covers it's actually a B or C, and can be downcast appropriately).
You can define an additional f() thus
f(B b);
and if necessary
f(C c);
and the correct one will be called depending on the class of the argument. i.e. the compiler determines which function is called depending on the type of the argument. This is different from a dynamic dispatch (or polymorphism) which would occur at runtime.
Note that your cast in the question is redundant. You can write:
C c = new C()
B b = c;
f(b);
since C extends from B, C is a B.
You seem to be confused about the difference between compile time type and runtime type.
You are creating an object (pointed at by the references c and b) of type C, and it will stay a C, because it is impossible to change an object's runtime type and therefore behaviour; by casting you can merely change its compile time type, which affects how the compiler treats it.
Can you give some more information about the concrete problem you're trying to solve? Most likely there is a way to achieve your goal by changing the design.
I wanted f to receive b as type B and not type C.
A C is a B is an A.
Inside of f, f only sees the A part of its parameter a If f calls a public A function that is overridden in C, the C override is called.
That's how virtual functions work. The idea being, the object referred to is really a C, so it should exhibit C behavior. If you want B behavior, pass a B instance, not a C instance.
If 'C' and "B' should have the same behavior, don't ovveride that behavior in C.
Why do you want to do this?
Your question does not make sense. What do you mean by "f accepts b as type C"?
f accepts b as type A, since the method signature says "A". If you invoke methods on b, they will be invoked on C if C overrides them. But this is standard behaviour in Java (all methods are like virtual methods in C++), and there's no way to change it.
Maybe you can describe your actual problem, then we might be able to help.
Your issue can be resolved by understanding the difference between REFERENCE type and INSTANCE type. When you cast you C object as a B, you only change the reference type - the actual instance of the object is still a C object - this should be quite obvious if you look at your object in debug mode. Changing the reference type only impacts how the compiler handles/perceives the code - runtime behaviour should not be affected. Any method call on an C object will always invoke C's method (regardless of whether or not the object has been casted to something else). If you overode a method from B and want to invoke B's version of the method, then you will need to create a B instance.
The fact that you can pass any subclass of A as a parameter of f(A a) is inherent to OO in Java, there's no way you can go around this. If C extends A, you can always use it where an A is expected.
you can use reflection to check if the parameter is of class A:
public void f(A a) {
if (a.getClass() == A.class) {
// ok, go on
}
else {
System.err.println("The parameter is not of class A!");
}
}
don't know if that's what you want, but it may be helpful.
The fact your code has a reference to an A doesn't mean the object being pointed too is an A. If it's a a C it remains a C. The reference in your source only limits the available methods in your source. Casting is only necessary because sometimes one needs a method on a different type and we need to trick the compiler so it let's us start using methods on the castes to type. Naturally the cast can fail at runtime if the attempt us invalid.
In upcasting and downcasting the object first upcast then downcastenter
class A
{
}
class B extends A
{
}
Class M
{
psvm(String ar[])
{
A a1= new B();
B b2=(B)a1;
}