Sorry that I had a mistake while posting. The class that implements I should be B rather than A in this case. And here it is where I find confusing. Also, if it is class C that implements I rather than A or B, the results are still the same.
interface I{}
public class A{
A() {
System.out.print("A: " + (this instanceof I) + " ");
}
public static void main(String[] args) {
new C();
}
}
class B extends A implements I {
B() {
System.out.print("B: " + (this instanceof I) + " ");
}
}
class C extends B {
C() {
System.out.print("C: " + (this instanceof I) + " ");
}
}
Why both subclass and superclass are true
while using instanceof
?
The result of this code is:
A: true
B: true
C: true
The instanceof
operator checks whether the given object is a sublcass (not necessarily a true subclass) of the given class. This does in general mean that you can cast the object to that class (reduce the view to it).
So for example if we have an ArrayList
we could cast it to List
, also instanceof
would return true
if we check that ArrayList
against List
. So in your example of course you could do
new C() instanceof B // true
new B() instanceof A // true
However the classes also inherit such properties from their parents. Thus the class C
is of course also subclass of A
, since it is subclass of B
and B
is subclass of A
, so we get
new C() instanceof A // true
And the same holds for interfaces too, we get
new A() instanceof I // true
and by inheritance
new B() instanceof I // true
new C() instanceof I // true
Take a look at the following example
public interface CanBark { }
public class Dog implements CanBark { }
public class Pug extends Dog { }
of course the Pug
is a Dog
and since Dog
is a CanBark
the Pug
is also a CanBark
, we get
new Pug() instanceof Dog // true
new Dog() instanceof CanBark // true
new Pug() instanceof CanBark // true
instanceof
The Java Language Specification (§15.20.2) defines the behavior of the instanceof
operator as
At run time, the result of the
instanceof
operator istrue
if the value of the RelationalExpression is notnull
and the reference could becast
(§15.16) to the ReferenceType without raising aClassCastException
. Otherwise the result isfalse
.
Whereas the cast
(§15.16) behaves like
[...] or checks, at run time, that a reference value refers to an object whose class is compatible with a specified reference type.
Therefore the casting refers to the casting rules specified in (§5.5). Your specific case is defined in (§5.5.1) as
If
T
(target) is an interface type:
IfS
(source) is not a final class (§8.1.1), then, if there exists a supertypeX
ofT
, and a supertypeY
ofS
, such that bothX
andY
are provably distinct parameterized types, and that the erasures ofX
andY
are the same, a compile-time error occurs.
Otherwise, the cast is always legal at compile time (because even ifS
does not implementT
, a subclass ofS
might).
This is a fundamental of object oriented programming. Let me give you an example which might help you to feel why subclasses get the behavior of interfaces implemented by parent class. Let me know if this helps.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
interface Flyable {
/* Guys, Don't worry about what kind of flyable object you are talking to.
* just call me if you want to request someone to fly. */
public void fly();
}
/*
* Bird is abstract since there is nothing called 'Bird' existing in the world.
* It should be either a Crow, Pegion, Sparrow and so on.
*/
abstract class Bird implements Flyable {
public void fly() {
/* All birds follow same sequence of actions to fly.
This method contains set of instructions to fly. */
}
// call this method to know where the bird was born
public abstract String getCountry();
}
class Sparrow extends Bird {
private String country;
// I am responsible to give birth to a new sparrow.
Sparrow(String beakColor, int weight, String bodyColor, String countryToLive) {
this.country = countryToLive;
// code to give birth to a new sparrow.
}
// Call me to know where i'm born
public String getCountry() {
return this.country;
}
}
class Helicopter implements Flyable {
private Date manufacturDate;
private int engineCapacity;
Helicopter() {
/* sequence of instruction on how to assemble a new helicopter with default specifications */
}
@Override
public void fly() {
/* sequence of instruction on how helicopter should fly
* Of course it will be different from how birds fly
* */
}
public Date getManufacturDate() {
return this.manufacturDate;
}
public int getEngineCapacity() {
return this.engineCapacity;
}
}
class RandomSkyObjectsHandler {
public static List<Flyable> getFewFlyableObjectsOfAnyType() {
List<Flyable> randomList = new ArrayList<Flyable>();
Sparrow sp1 = new Sparrow("black", 50, "brown", "India");
Helicopter h1 = new Helicopter();
Helicopter h2 = new Helicopter();
Sparrow sp2 = new Sparrow("Brown", 60, "white", "Kenya");
Helicopter h3 = new Helicopter();
Sparrow sp3 = new Sparrow("white", 70, "black", "USA");
Flyable[] f = {sp1, sp2, h1, sp3, h2, h3};
randomList = Arrays.asList(f);
return randomList;
}
}
public class TestProgramExecutor {
public static void main(String... commandLineArguments) {
List<Flyable> mixOfFlyingStuff = RandomSkyObjectsHandler.getFewFlyableObjectsOfAnyType();
/* here is the beauty of OOPS. I don't need the knowledge of whether i'm telling a helicopter to fly or a sparrow to fly.
* I'm just pretty sure that I'm talking to a flyable object and it understand if i say fly();
* */
for(Flyable f: mixOfFlyingStuff) {
f.fly();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With