[英]How to bypass Java not being able to extend from multiple classes
I think I have a design problem in my Java app, but I cannot figure out how to solve or bypass it.我认为我的 Java 应用程序存在设计问题,但我不知道如何解决或绕过它。
Say I have an interface and an abstract class implementing it as follows:假设我有一个接口和一个实现它的抽象类,如下所示:
public interface IntegerCollection extends Collection<Integer> {
public int sum();
}
public abstract class AbstractIntegerCollection
extends AbstractCollection<Integer> implements IntegerCollection {
public int sum() {
// fancy code to calculate the sum of all collection members (just an example)
}
}
Now I would want to make this class instantiable by using the existing implementations of Collection (eg, LinkedList);现在我想通过使用 Collection 的现有实现(例如,LinkedList)使这个类可实例化; something like this:像这样:
public class IntegerLinkedList extends AbstractIntegerCollection, LinkedList<Integer> {
}
IntegerCollection ic = new IntegerLinkedList();
However, this does not work because Java does not support extending several classes.但是,这不起作用,因为 Java 不支持扩展多个类。 Also it looks quite ugly to me, as there is a mixture of hierarchies.对我来说它看起来也很丑陋,因为层次结构混合。
Of course, I could let IntegerLinkedList implement IntegerCollection instead of letting it extend AbstractIntegerCollection.当然,我可以让 IntegerLinkedList 实现 IntegerCollection 而不是让它扩展 AbstractIntegerCollection。 But then, I would have to repeat the code for sum() in all other implementations (eg, IntegerArrayList).但是,我将不得不在所有其他实现(例如,IntegerArrayList)中重复 sum() 的代码。
Is there a better way to do this?有一个更好的方法吗?
I'm not sure what exactly, you are trying to achieve, but rather you could implements List
instead of extending LinkedList
我不确定究竟是什么,您正在尝试实现,但您可以实现List
而不是扩展LinkedList
public class IntegerLinkedList
extends AbstractIntegerCollection
implements List<Integer>
{
}
But, you need to implements all abstract method of List
.但是,您需要实现List
所有抽象方法。
Since java 8 it has been possible to include implementations in an interface by using the default
keyword.从 java 8 开始,可以使用default
关键字在接口中包含实现。 Therefore you don't need AbstractIntegerCollection
- all the common code can be put in the interface.因此您不需要AbstractIntegerCollection
- 所有通用代码都可以放在接口中。 Here is an example:下面是一个例子:
import java.util.Collection;
import java.util.LinkedList;
public class Main {
interface IntegerCollection extends Collection<Integer> {
default int sum() {
int sum = 0;
for (int a : this)
sum += a;
return sum;
}
}
static class IntegerLinkedList extends LinkedList<Integer> implements IntegerCollection {
}
public static void main(String[] args) {
IntegerCollection list = new IntegerLinkedList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.sum()); // Prints 6
}
}
This works, but I'm not sure it's a good idea.这行得通,但我不确定这是个好主意。 I'd think very carefully before extending a class like LinkedList
.在扩展像LinkedList
这样的类之前,我会非常仔细地考虑。 Some people also consider it an anti-pattern to extend generic classes with non-generic ones.有些人还认为用非泛型类扩展泛型类是一种反模式。
Another thing to be aware of is that it is not possible to write default
methods for the methods of Object
like equals
and toString
etc.要注意的另一件事是,不可能为诸如equals
和toString
等Object
的方法编写default
方法。
Since you are using Java 7, the above solution is not available.由于您使用的是 Java 7,因此上述解决方案不可用。 However, with a load of tedious forwarding methods, you can do it using composition rather than inheritance.但是,对于繁琐的转发方法的负载,您可以使用组合而不是继承来完成。 Josh Bloch's book Effective Java gives a very good explanation of why composition is preferable anyway. Josh Bloch 的 Effective Java 一书很好地解释了为什么组合更可取。 Here is an (incomplete) example - you'll need to add a few more forwarding methods to avoid UnsupportedOperationException
s when you try doing other things with the list.这是一个(不完整的)示例 - 当您尝试对列表执行其他操作时,您需要添加更多转发方法以避免UnsupportedOperationException
。
import java.util.*;
public class Main {
abstract static class AbstractIntegerCollection extends AbstractCollection<Integer> {
public int sum() {
int sum = 0;
for (int a : this)
sum += a;
return sum;
}
}
static class IntegerLinkedList extends AbstractIntegerCollection implements List<Integer> {
private final List<Integer> list = new LinkedList<>();
@Override
public Iterator<Integer> iterator() {
return list.iterator();
}
@Override
public int size() {
return list.size();
}
@Override
public boolean addAll(int index, Collection<? extends Integer> c) {
return list.addAll(index, c);
}
@Override
public Integer get(int index) {
return list.get(index);
}
@Override
public Integer set(int index, Integer element) {
return list.set(index, element);
}
@Override
public boolean add(Integer element) {
return list.add(element);
}
@Override
public void add(int index, Integer element) {
list.add(index, element);
}
@Override
public Integer remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<Integer> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<Integer> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<Integer> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
// More of these
}
public static void main(String[] args) {
IntegerLinkedList list = new IntegerLinkedList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.sum()); // Prints 6
}
}
This solution is far from perfect.这个解决方案远非完美。 For one thing, it would be better if IntegerLinkedList
extended AbstractList<Integer>
rather than just AbstractCollection<Integer>
, but then you couldn't extend AbstractIntegerCollection
too.一方面,如果IntegerLinkedList
扩展AbstractList<Integer>
而不仅仅是AbstractCollection<Integer>
会更好,但是你也不能扩展AbstractIntegerCollection
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.