Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiating interfaces having default methods [duplicate]

I came across this question:

What is the output of the following?

1  public class A {
2      public static void main(String[] args){
3          I i = new I() {};
4          System.out.println(I.x + i.getValue() + "" + i);
5      }
6  }
7
8  interface I {
9      int x = 10;
10
11     public default int getValue() {
12         return 5;
13     }
14
15     public default String toString() {
16         return "I";
17     }
18 }

My thinking:

My first instinct tells me - I i = new I() {}? We can't instantiate interfaces hence - issue 1.

Then I think public default String toString()? Overriding Object class method? Doesn't sound good - issue 2

Possible answers:

a) 10I

b) 15I

c) Compilation fail due to line 11

d) Compilation fail due to line 15

e) Compilation fail due to multiple errors

Having explained my thoughts I picked answer E) which is wrong. The correct answer is D) which I also got right.

My question - why is the following statement valid?

I i = new I() {};

Is this statement doing something I don't understand due to the "{}" added to it? To my understanding the new keyword means: instantiate.

like image 845
arfromdee Avatar asked Apr 07 '26 13:04

arfromdee


2 Answers

There is nothing wrong with the statement:

I i = new I() {};

It simply instantiates an anonymous class that implements the I interface. Since the I interface has only default methods, an empty body would be sufficient to implement it, if not for the problem with the toString() method.

JLS 9.4.1.2 states that an interface cannot have a default implementation of the toString() method :

It is a compile-time error if a default method is override-equivalent with a non-private method of the class Object, because any class implementing the interface will inherit its own implementation of the method.

The prohibition against declaring one of the Object methods as a default method may be surprising. There are, after all, cases like java.util.List in which the behavior of toString and equals are precisely defined. The motivation becomes clearer, however, when some broader design decisions are understood:

  • First, methods inherited from a superclass are allowed to override methods inherited from superinterfaces (§8.4.8.1). So, every implementing class would automatically override an interface's toString default. This is longstanding behavior in the Java programming language. It is not something we wish to change with the design of default methods, because that would conflict with the goal of allowing interfaces to unobtrusively evolve, only providing default behavior when a class doesn't already have it through the class hierarchy.
  • Second, interfaces do not inherit from Object, but rather implicitly declare many of the same methods as Object (§9.2). So, there is no common ancestor for the toString declared in Object and the toString declared in an interface. At best, if both were candidates for inheritance by a class, they would conflict. Working around this problem would require awkward commingling of the class and interface inheritance trees.
  • Third, use cases for declaring Object methods in interfaces typically assume a linear interface hierarchy; the feature does not generalize very well to multiple inheritance scenarios.
  • Fourth, the Object methods are so fundamental that it seems dangerous to allow an arbitrary superinterface to silently add a default method that changes their behavior.

toString() is a method of the Object class, and therefore cannot have a default implementation in any interface.

like image 136
Eran Avatar answered Apr 09 '26 01:04

Eran


I don't understand because of "{}" added to it?

You are instantiating anonymous class

I i = new I() {};
like image 35
Ravi Avatar answered Apr 09 '26 02:04

Ravi