3

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 
Lei Zuo
  • 39
  • 5
  • 2
    `Classes can be derived from classes that are derived from classes that are derived from classes, and so on, and ultimately derived from the topmost class, Object. Such a class is said to be descended from all the classes in the inheritance chain stretching back to Object.` - Java Documentation – vinS Dec 09 '17 at 13:08
  • 1
    See [What is the 'instanceof' operator used for in Java?](https://stackoverflow.com/questions/7313559/what-is-the-instanceof-operator-used-for-in-java) – Richard Chambers Dec 09 '17 at 13:09
  • For completeness: [Oracle's tutorial on Equality, Relational, and Conditional Operators](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html). – Turing85 Dec 09 '17 at 13:14
  • 1
    Cats are a "subclass" of animal; tigers are a subclass of cat. But Tigers are still both Cats and Animals, yes? It's the same whether the Animals, Cats and Tigers are living beings or Java classes. – Kevin Anderson Dec 09 '17 at 13:24
  • This is a basic tenet of OOP. See [Liskov substitution principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle) – Bohemian Dec 09 '17 at 13:39

2 Answers2

4

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

Practical example

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

Details of 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 is true if the value of the RelationalExpression is not null and the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException. Otherwise the result is false.

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:

If S (source) is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
1

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();
        }
    }
}
Jinnah
  • 148
  • 10