views:

442

answers:

6

Opened a LinkedHashSet source code today and found some interesting thing:

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {

The question is: why do they need both "extends HashSet" and "implements Set" when HashSet already is the Set?

+4  A: 

They didn't need to explicitly write implements Set<E>. They did it for readability.

sepp2k
A: 

It's redundant. You could do without the implements Set<E>.

tangens
+1  A: 

Perhaps it has something to do with the way javadoc gets generated. You know how Java API tells you all concrete classes that impement an interface or inherit from other classes? While I agree that at runtime its redundant, I can see how this might ease the automatic generation of javadoc. This is just a wild guess of course.

vicatcu
Actually, I think you're right. I have seen javadoc do the "wrong" thing unless a redundant "implements" is added, and even the order in which the interfaces are listed can matter.
Kevin Bourrillion
+2  A: 

There is another reason; consider the following java program:-

package example;

import java.io.Serializable;
import java.util.Arrays;

public class Test {

 public static interface MyInterface {
  void foo();
 }

 public static class BaseClass implements MyInterface, Cloneable, Serializable {

  @Override
  public void foo() {
   System.out.println("BaseClass.foo");
  }
 }

 public static class Class1 extends BaseClass {

  @Override
  public void foo() {
   super.foo();
   System.out.println("Class1.foo");
  }
 }

 static class Class2 extends BaseClass implements MyInterface, Cloneable,
   Serializable {

  @Override
  public void foo() {
   super.foo();
   System.out.println("Class2.foo");
  }
 }

 public static void main(String[] args) {

  showInterfacesFor(BaseClass.class);
  showInterfacesFor(Class1.class);
  showInterfacesFor(Class2.class);
 }

 private static void showInterfacesFor(Class<?> clazz) {
  System.out.printf("%s --> %s\n", clazz, Arrays.toString(clazz
    .getInterfaces()));
 }
}

Which outputs the following text (java 6u16):

class example.Test$BaseClass --> [interface example.Test$MyInterface, interface java.lang.Cloneable, interface java.io.Serializable]
class example.Test$Class1 --> []
class example.Test$Class2 --> [interface example.Test$MyInterface, interface java.lang.Cloneable, interface java.io.Serializable]

Notice how Class1 does not have explicit interfaces defined, so the Class#getInterfaces() does not include those interfaces, whereas Class2 does. The use of this only becomes clear in this program:-

package example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import example.Test.BaseClass;
import example.Test.Class1;
import example.Test.Class2;

public class Test2 extends Test {

 public static void main(String[] args) {

  MyInterface c1 = new Class1();
  MyInterface c2 = new Class2();

  // Note the order...
  MyInterface proxy2 = createProxy(c2);
  proxy2.foo();

  // This fails with an unchecked exception
  MyInterface proxy1 = createProxy(c1);
  proxy1.foo();
 }

 private static <T> T createProxy(final T obj) {

  final InvocationHandler handler = new InvocationHandler() {

   @Override
   public Object invoke(Object proxy, Method method, Object[] args)
     throws Throwable {
    System.out.printf("About to call %s() on %s\n", method
      .getName(), obj);
    return method.invoke(obj, args);
   }
  };

  return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
    .getClass().getInterfaces(), handler);
 }
}

Which outputs:-

About to call foo() on example.Test$Class2@578ceb
BaseClass.foo
Class2.foo
Exception in thread "main" java.lang.ClassCastException: $Proxy1 cannot be cast to example.Test$MyInterface
 at example.Test2.main(Test2.java:23)

While Class1 does implicitly implement MyInterface, but the created proxy does not.

Hence if we wanted to create a dynamic proxy which implements all interfaces for an object which has implicit interface inheritance then the only way to do it generically would be to walk the superclasses all the way back to java.lang.Object, as well as walking all the implemented interfaces and their superclasses (remember Java supports multiple interface inheritance), which doesn't sound very efficient, while it is much easier (and faster) to explicitly name interfaces as I suppose they are set in at compile time.

So what uses reflection & proxies? RMI for one...

Therefore, yes it is a convenience, but no it is certainly not redundant: remember that these classes were carefully designed and implemented by Josh Bloch, so I suspect that they were explicitly programmed this way so that proxied network stubs and skeletons work as they do.

rhu
Side note: While it does make dyanmic proxies easier to create when all of the interfaces are at the same level, you can always reflectively traverse the class heirarchy (easy since Java is single inheritance) and figure out all of the interfaces of the parents classes.
basszero
A: 

Good catch, they did not need to put java.io.Serializable either.

fastcodejava
+4  A: 

I've asked Josh, and he informs me that it was a mistake. He used to think, long ago, that there was some value in it, but he since "saw the light". Clearly JDK maintainers haven't considered this to be worth backing out later.

Since this is a "why did they do it" question, and the answer comes from the very person who did it, I think that makes this answer correct by definition; not that you're under any obligation to accept it or anything. :)

Kevin Bourrillion
And who is Josh?
zeroed
Josh Bloch... he wrote the Collections framework.
ColinD