Wednesday, June 25, 2008

Do Interfaces really inherit the Object class in Java?


Do Interfaces really inherit the class Object in Java (the cosmic sperclass)?


Well... the answer is NO. An interface can't inherit from a class in Java, not at least directly. So, we can safely say that interfaces don't inherit from the Object class. Okay... so how can they do that indirectly? We know that interfaces can have classes declared as members as well just like they can have constants. Such a class is called a member class and like constants all the member classes of an interface would be static and public. And that static member class (like any other class in java) inherits Object class.


But, how are we able to compile code having Object method calls on the references of an interface type in Java? We all know that the object of the implementing class (and hence its type) will be assigned to only at run time and we can compile a code only if the compiler finds a method of that signature in the declared type (either declared directly or inherited from superclasses). This is absolutely correct for classes in Java, but only partially correct for interfaces in Java. Surprised? Let's try to understand what internally happens in case of interfaces.


The Java Language Specification clearly says that the members of an interface are those which are declared in the interface and those which are inherited from direct super interfaces. If an interface has no direct superinterface then the interface implicitly declares a public abstract member method corresponding to each public instance method declared in the Object class, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by that interface. This is what makes the signatures of the Object methods available to the compiler and the code compiles without any error. Remember if the interface tries to declare a public instance method declared 'final' in the Object class then it'll result into a compile-time error. For example, 'public final Class getClass()' is a public instance method declared 'final' in the Object class and therefore if an interface tries to declare a method with this signature then the compilation will fail.


Is this Inheritance of Object methods by the Interfaces?


No. This can not be termed as 'Object methods being inherited by the Interfaces'. This is just a special treatment given to the interfaces in Java.


In this case all the qualified (public instance) Object class methods are declared as public abstract, which is not inheritance. Right? In inheritance we get the definition of the method as well and the non-abstract methods are not inherited as 'abstract'. But an interface in Java can't have any of these two - definition or non-abstract method. Hence, the designers of Java had to think of an alternative.


Moreover, only public instance methods are implicitly declared in the interfaces and what about other methods - for example, protected Object clone() and protected void finalize()? In case of inheritance they are also inherited by the subclasses.


Thus, we see that it's not exactly inheritance of the Object class by the interfaces. An interface can't inherit a class for the simple reason that interfaces can only have abstract methods (i.e., they can't have body). Please don't say that we can have an abstract class having only abstract methods which can be inherited safely by interfaces :-) We will better have an interface in that case.


Example: a simple Java program showing Object method access on interface ref type


package test;

public class TestInterfaceDemo{


public static void main(String[] args) {


TestInterface testInterface = new TestInterfaceImpl();

//... calling Object class method - toString - OK

System.out.println(testInterface.toString());

//... calling the interface method - testMethod - OK

testInterface.testMethod();

//... calling the implementing class method - implClassMethod - ERROR

//testInterface.implClassMethod();

//... calling the same method after casting the reference - OK

((TestInterfaceImpl)testInterface).implClassMethod();


}


}


package test;

public class TestInterfaceImpl implements TestInterface{

public void testMethod(){

System.out.println("Test Method if the Interface");

}

public void implClassMethod(){

System.out.println("Test Interface Impl Class Method");

}

}


Output:-

test.TestInterfaceImpl@45a877 (variable)

Test Method if the Interface

Test Interface Impl Class Method


If we uncomment the line '//testInterface.implClassMethod();' for accessing a method of the implementing class which is not a member of the interface type then expectedly we get a compiler error:-


Error(14,23): method implClassMethod() not found in interface test.TestInterface


As at the compiler doesn't know the type of the assigned object and hence can't resolve the signature of the method call on the declared reference type during compilation and therefore report an error.


One of our visitors, Martin raised this point in response to the article - Differences between Interfaces & Abstract Classes >> Thanks Martin for raising such an important point. Keep contributing!


Liked the article? You may like to Subscribe to this blog for regular updates. You may also like to follow the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. You can find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


8 comments:

Unknown said...

Why wasn't this made more explict by having an interface named Interface which defines the methods currently defined for Object.

Object implements Interface, and every interface implicitly extends Interface in much the same way as every class implicitly extends Object?

Problem solved, no?

S. Gregory said...

I'm confused. Why would an interface need to extend Object? I think there must be confusion about what is an object vs what is a type.

Let's take the Runnable interface.

public interface Runnable{

public void run();

}

We know we can't create an instance of it right? We can't go Runnable r = new Runnable();?

Of course we can go.

Runnable r = new Runnable(){

public void run(){
System.out.println("hi");
}

};

This is merely shorthand for:

Runnable r = new Object() implements Runnable{

public void run(){
System.out.println("hi");
}
}

So while the Runnable type doesn't inherit from Object, any instances of Runnable will.

Geek said...

Don: Good point! The designers of Java might have thought of not having this approach probably because it'll add an extra indirection for accessing those Object class methods in all the classes in Java - irrespective of whether they implement any interface or not because in that case every class will automatically implement that super interface via Object class ... right? These days JVMs are quite faster and you may not notice the performance difference in a direct method call OR a method call via interface indirection... but in the initial days the difference would have been significant. And why to follow an approach which incurs any extra load when you have another approach. Making the task of compilers easier and straightforward would probably have been among the least important priorities for them, I guess (particularly in comparison to Performance).

S. Gregory: If you have an interface type declaration in your code and if you try to invoke any Object class method (public instance) on that interface type then also the code compiles and runs successfully. Did you get the point?

If you take your own example and add a line of code 'System.out.println(r.toString());' then also it'll compile and run. And as you know we can call only the methods declared in the interface (or inherited from superinterfaces) on an interface type reference variable...right? How is this code running then? Runnable interface (no superinterface for this interface) doesn't have any method called 'toString()'. The same holds true for all other public instance methods of the Object class.

The compiler needs to know the signature of those methods before you can successfully call them on an interface type reference variable. How will the Java compiler know?

That's what I've tried to explain in the above article. You may like to visit the article 'Difference between Interfaces and Abstract Classes' to read Martin's comments to understand how the discussion started.

Hope the reply helps. PLease let me know in case I need to further clarify anything OR if you differ anywhere. Keep visiting/posting!

S. Gregory said...

What's more interesting to think about is this situation:

Runnable r = ...;

Object o = r;

Even if runnable implicitly has a definition of all of the methods of Object, that alone doesn't make r assignable to Object. Java doesn't support duck typing.

The key thing to think about though is that r is actually an object (or null but that's not interesting in this case). All objects explicitly or implicitly extend from Object at some point. So even without the implicit definitions of Object methods in an interface we can prove that r has all of the properties of Object.

Geek said...

S. Gregory: Thanks for your active participation. I believe the discussion will help all of us to refine our concepts. Please find below my take on the various pieces of your last comment (pieces italicized) and let me know in case you differ anywhere.

Runnable r = ...;

'r' is not an object... it's only a reference of type Runnable which can be assigned to a reference of an object of a class which implements Runnable interface. You yourself talked about object and type in your first comment.

Object o = r;

Even if runnable implicitly has a definition of all of the methods of Object, that alone doesn't make r assignable to Object. Java doesn't support duck typing.


(1) Runnable being an interface gets implicitily added only public instance methods of the Object class and NOT all methods. finalize() and clone() being protected in Object class don't get implicitly added like other Object methods which are public (and instance as well).

(2) Runnable doesn't contain the definition of public instance methods of Object class. It contains only declaration - all the public instance methods of Object class are added to the topmost interface in the hierarchy as 'public abstract' methods. So no definition or implemenatation comes to an interface (otherwise it'll contradict with the basic concept of interfaces in Java)

(3) Did you actually see if the assignment 'Object o = r';' worked for you or not? Please run the below code and you can see that the assignment is valid.

package test;

public class RunnableDemo {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run(){
System.out.println("Hi...I'm in run method!");
}
};
Object object = runnable;
System.out.println("object = runnable possible! object = " + object);
}
}

Output:-

object = runnable possible! object = test.RunnableDemo$1@360be0

It's valid because an Object type reference can always be assigned to any other object reference given the fact that irrespective of what object that reference points to, it'll always be an instance of a class and every class implicitly inherits the Object class.

But, we can't call a method on a reference type which is not declared either in that type or any of its super types. Since every class inherits the Object class hence calling an Object method on a class type is not at all a problem. But, interfaces don't inherit Object class and hence if we try to call a public instance method of the Object class they should result in a compile time exception, which they don't. The reason is that all the 'public instance' methods (which are not explicitly declared in that interface) are added as 'public abstract' methods in that interface and this enables the compiler to allow such a method call.

The key thing to think about though is that r is actually an object (or null but that's not interesting in this case). All objects explicitly or implicitly extend from Object at some point. So even without the implicit definitions of Object methods in an interface we can prove that r has all of the properties of Object.

'r' is not an object ... it's just a reference to an object of a class which implements Runnable interface. And the class of that object do contain the definition of the Object class methods, but not the type of the reference variable 'r', which in this case is Runnable interface.

In case we call 'r.toString()' - the compiler will search the signature of the 'toString()' method in the declared type (which is Runnable interface) and not the run time type (which is the anonymous class which implemented Runnable). Hence interfaces required an alternative way of enabling them to be used for Object class method (public instance) calls.

I hope it clears your doubts (if you had any). I would like to discuss it again if we differ anywhere.

rits said...

:) Very nice article and discussion.
But below quoted text is still not clear to me :

Remember if the interface tries to declare a public instance method declared 'final' in the Object class then it'll result into a compile-time error. For example, 'public final Class getClass()' is a public instance method declared 'final' in the Object class and therefore if an interface tries to declare a method with this signature then the compilation will fail.

Then, why the following code compiles fine :


interface MyInter{
public void method() ;
}

class MyClass implements MyInter{

public final void method() {

}
}

Geek said...

what you are trying to compile is different from what's stated in the quoted lines... the quoted lines mean that a method which is declared 'final' in the Object class will cause a compile time error if an interface will try to have a method with the same signature... hope this helps!

mskumar said...

Thanks for a very nice article.
What if we consider a similar scenario for classes. All classes in Java extend the Object class by default. Also we know that Java does not support multiple (implementation) inheritance.
So if ClassB extends ClassA, does ClassB also extend the Object class directly? Or does it extend the Object class only through ClassA?

If the later was correct, why would I still get a compile error when i try to declare the method public final Class getClass(){} in ClassB.

I think either there is some special provision in Java for this or I must be missing some basics.