简体   繁体   English

如何绕过 Java 无法从多个类扩展

[英]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.要注意的另一件事是,不可能为诸如equalstoStringObject的方法编写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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM