2

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.

Community
  • 1
  • 1
arfromdee
  • 71
  • 1
  • 7

4 Answers4

12

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.

Community
  • 1
  • 1
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Is `I.x` valid though? `x` is not a static variable in `I`. – marstran Mar 23 '17 at 14:17
  • 5
    @marstran: `x` *is* `static` and `final`. Since all interface fields are `public static final`, you don’t need to specify that explicitly. – Holger Mar 23 '17 at 14:19
  • Thanks a million Eran for your reply, all makes sense to me now. – arfromdee Mar 23 '17 at 14:20
  • Just to emphasis the answer, taken from Brian Goetz's answer https://stackoverflow.com/questions/24016962/java8-why-is-it-forbidden-to-define-a-default-method-for-a-method-from-java-lan "Defaults are supposed to be defaults. Adding a default to an interface where there was none (anywhere in the hierarchy) should not affect the semantics of concrete implementing classes. But if defaults could "override" Object methods, that wouldn't be true." – nantitv Feb 27 '19 at 08:39
2

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

You are instantiating anonymous class

I i = new I() {};
Ravi
  • 30,829
  • 42
  • 119
  • 173
2

I i = new I() {}; creates an anonymous class that implements interface I. Since interface I doesn't have any abstract methods to implement, the body of the anonymous class inside the brackets {} can be empty.

Joe
  • 320
  • 1
  • 7
2

A default method can't override a method from java.lang.Object such as toString() .

Mustafa Çil
  • 766
  • 8
  • 15