I'm aware that this could be a possible duplicate, but the other threads haven't solved my problem completely.
Let's say I have the following classes A and B which extend BasicClass.
public abstract class BasicClass {
// ...
}
public class A extends BasicClass {
// ...
}
public class B extends BasicClass {
// ...
}
And now I want to cast class A to B dynamically.
a.getClass().cast(bClass.newInstance);
but every time I get an Exception.
java.lang.ClassCastException
at java.lang.Class.cast(Unknown Source)
Can you tell me why?
Because, in your inheritance hierarchy, a B is not an A. You cannot cast one to the other.
Answer:
Because A is not extending B. (technicaly: A IS not B)
Explanation:
JVM performs "IS-A" test before it casts.
If "IS-A" test fails, you will get "ClassCastException".(Just like you are getting now).
IS-A :
IS-A test is to check whether a class(to be casted, in your case A) is in inheritance tree of the class(casted to, in your case B).
IS-A is the functional term, syntax to check IS-A test is instanceof".
e.g a instanceof b :
explanation of instance of:
LHS and RHS of the instance of must be the object.
thus a and b are obeject.
Their respective classes are checked for inheritance.
In your example following result will come.
a instanceof b : False
a instanceof basicObject : True
b instanceof a : False
b instanceof basicObject : True
basicObject instanceof a : False
basicObject instanceof b : False
You can only cast where result of instanceof is true.
Your hierarchy looks like this:
BasicClass
/ \
/ \
A B
A is not an ancestor of B, so it's impossible to cast an instance of B to A.
Related
I have the following
Class A extends B
B class is an abstract class
What will be returned if I do:
A a = new A();
a instance of B?
If it returns false, which solution I could use for having true as result?
//Define these classes.
class A {} //It can be an abstract class as well.
class B extends A {}
//Main code.
A b = new B();
System.out.println(b instanceof A); //prints true.
If you try B instanceof A // you will get a compilation error because B is not an object, but it is a class name.
"x instanceof y" returns true if "object" x is instance of class "y". The word instance is used for an object. Since A and B are both classes the code should return a compilation error
I think the title is self explanatory.
So suppose I have this code:
interface A { }
abstract class B { }
class C { }
C c = new C();
System.out.println(c instanceof A); //fine
System.out.println(c instanceof B); // compile error
In a comment from the question I read this:
The compiler can never know whether a given type doesn't implement an interface because a potential subclass could implement it.
So if for interface this works, why it should not work for an abstract class ? It also should be extended by some other class, as it can't exist by it's own. Can someone clarify this?
Update
Compile message:
Error:(22, 28) java: incompatible types: C cannot be converted to B
It is simple: C extends Object. No subclass of C could possible extend B. You can't add another base class, because Java doesn't support multiple inheritance.
Whereas a subclass of C can very well implement that additional interface.
But there is simply no way how a C object could also be a B instance.
So:
D extends C implements B // obviously all fine
whereas
D extends B extends C
is impossible. Because B is already defined to not extend anything but Object. Of course, the "trick" here is that both classes B, C are both known, and as said: C isn't extending B.
Take for example
class D extends C implements A{}
C c = new D();
The compiler can immediately tell that c can never refer to an instance of B because if a class extends C it cannot extend B also. As the above example shows, the same cannot be said of interfaces.
That is because it's strictly impossible to create instances of an abstract class in java.
The operator instanceof is called from class Object and cannot be called if there is no instance of a class that revoked it (object).
class A {}
class B {}
public class Demo {
public static void main(String[] args) {
A a = new A();
System.out.println(a instanceof B);
}
}
This code is giving compile time error.
How can I use instanceof to give false instead of compile time error when object is not an instance of class specified.
Java knows an A cannot be a B so it won't compile. If you change the line to
Object a = new A();
it will compile (and return false) as it can no longer tell if an Object can be cast into type B.
If class A and B are not related through inheritance, then compiler will throw an error when you try to perform a instanceof B
In your case, A is NOT a subclass of B, so you can't do an instanceof check like a instanceof B
But, if you change your classes like below:
class A {}
class B extends A {}
public static void main(String[] args) {
B b=new B();
System.out.println(b instanceof A);
}
Now b instanceof A will return true because B IS-A (type of) A
You can read the Java doc here on the same subject:
The instanceof operator compares an object to a specified type. You
can use it to test if an object is an instance of a class, an instance
of a subclass, or an instance of a class that implements a particular
interface.
You can use this :
System.out.println(a.getClass().equals(B.class));
Instead of :
System.out.println(a instanceof B);
Quoting JLS Sec 15.20.2:
If a cast (§15.16) of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.
(Where they are describing RelationalExpression instanceof ReferenceType)
You can't write B b = (B) a; either, because A and B are both classes (*), and are unrelated, in the sense that A does not directly or indirectly extend B, nor vice versa.
As such, a reference to an A can never contain an instance of a B, so it is nonsensical to test this. As such, the compiler stops you from testing this, as it likely indicates a logical error.
(*) You could write a instanceof B if B were an interface, because a might refer to a subclass of A which additionally implements B, e.g.
class ChildOfA extends A implements B {}
A a = new ChildOfA();
System.out.println(a instanceof B); // fine.
How to I test if a is a subclass of b?
Class<?> a = A.class;
Class<?> b = B.class;
Are you looking for:
Super.class.isAssignableFrom(Sub.class)
If you want to know whether or not a Class extends another, use Class#isAssignableFrom(Class). For your example, it would be:
if(B.class.isAssignableFrom(A.class)) { ... }
If you're interested in whether or not an instance is of a particular type, use instanceof:
A obj = new A();
if(obj instanceof B) { ... }
Note that these will return true if the class/instance is a member of the type hierarchy and are not restrictive to direct superclass/subclass relationships. For example:
// if A.class extends B.class, and B.class extends C.class
C.class.isAssignableFrom(A.class); // evaluates to true
// ...and...
new A() instanceof C; // evaluates to true
If you want to check for direct superclass/subclass relationships, Tim has provided an answer as well.
You want to know if b is assignable from a:
b.isAssignableFrom(a);
Additionally, if you want to know that a is a direct subclass of b:
a.getSuperclass().equals(b);
How to I test if a is a subclass of b?
Class<?> a = A.class;
Class<?> b = B.class;
Are you looking for:
Super.class.isAssignableFrom(Sub.class)
If you want to know whether or not a Class extends another, use Class#isAssignableFrom(Class). For your example, it would be:
if(B.class.isAssignableFrom(A.class)) { ... }
If you're interested in whether or not an instance is of a particular type, use instanceof:
A obj = new A();
if(obj instanceof B) { ... }
Note that these will return true if the class/instance is a member of the type hierarchy and are not restrictive to direct superclass/subclass relationships. For example:
// if A.class extends B.class, and B.class extends C.class
C.class.isAssignableFrom(A.class); // evaluates to true
// ...and...
new A() instanceof C; // evaluates to true
If you want to check for direct superclass/subclass relationships, Tim has provided an answer as well.
You want to know if b is assignable from a:
b.isAssignableFrom(a);
Additionally, if you want to know that a is a direct subclass of b:
a.getSuperclass().equals(b);