Java 为什么LinkedHashSet<;E>;扩展HashSet<;e>;并实施Set<;E>;
今天打开LinkedHashSet源代码,发现了一些有趣的东西:Java 为什么LinkedHashSet<;E>;扩展HashSet<;e>;并实施Set<;E>;,java,collections,hashtable,Java,Collections,Hashtable,今天打开LinkedHashSet源代码,发现了一些有趣的东西: public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable { 公共类LinkedHashSet 扩展哈希集 实现Set、Cloneable、java.io.Serializable{ 问题是:为什么他们同时需要“扩展哈希集”和“实现集”
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
公共类LinkedHashSet
扩展哈希集
实现Set、Cloneable、java.io.Serializable{
问题是:为什么他们同时需要“扩展哈希集”和“实现集”当HashSet已经是集合时?他们不需要显式地编写
实现集合
。他们这样做是为了可读性。这是多余的。你可以不用实现集合
也许这与生成javadoc的方式有关。你知道Java API是如何告诉你所有具体的类的NT是一个接口还是继承其他类?我同意在运行时它的冗余,我可以看到这可能会自动地产生JavaDoc。这只是一个疯狂的猜测当然。 < P>还有另一个原因;考虑下面的java程序:-< /P>
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()));
}
}
请注意,Class1没有定义显式接口,因此类#getInterfaces()不包含这些接口,而Class2包含这些接口。只有在本程序中才能清楚地使用这些接口:-
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);
}
}
虽然Class1隐式实现了MyInterface,但创建的代理没有
因此,如果我们想要为具有隐式接口继承的对象创建一个实现所有接口的动态代理,那么一般来说,唯一的方法就是将超类遍历回java.lang.object,以及遍历所有实现的接口及其超类(记住Java支持多接口继承),这听起来不是很有效,但是显式命名接口要容易得多(也更快),因为我认为它们是在编译时设置的
那么什么使用反射和代理呢?RMI就是其中之一
因此,是的,这是一种方便,但不是多余的:请记住,这些类是由Josh Bloch精心设计和实现的,因此我怀疑它们是以这种方式显式编程的,以便代理网络存根和骨架可以像它们那样工作。很好,它们不需要将
java.io.Serializable
也可以。我问过Josh Bloch,他告诉我这是个错误。很久以前,他曾认为它有一些价值,但后来他“看到了曙光”。显然JDK维护人员认为这不值得以后退出。事实上,我认为你是对的。我看到javadoc做了“错误”的事情除非添加了冗余的“实现”,否则即使是接口的列出顺序也很重要。旁注:虽然当所有接口都处于同一级别时,动态代理确实更容易创建,但您始终可以反射地遍历类继承权(因为Java是单继承的,所以很容易)找出父类的所有接口。“可读性”这就是你如何犯错误,保住工作,以及如何在绩效考核中摸索
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);
}
}
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)