Java中的接口派生

时间:2015-10-01 05:56:59

标签: java haskell generics interface typeclass

我最近在使用Java,并且想知道Java中是否存在任何类型的接口实现派生。我首选的编程语言是Haskell,它在很多方面与Java相对立,但我想知道Java是否具有类似功能的一个特性是能够从其参数的接口实现派生复合类型的接口实现。例如,在Haskell中:

data Pair k v = Pair k v

instance (Ord k) => Ord (Pair k v) where
    compare (Pair x _) (Pair x' _) = compare x x'

如果可以订购第一个参数,则允许您订购Pair,而不明确要求这样做。但是,我在Java中最接近的是通过明确的要求:

class Pair<K extends Comparable<K>, V> extends Comparable<Pair<K,V>> {
    K k;
    V v;
    public int compareTo(Pair<K,V> p) {
        return k.compareTo(p.k);
    }
}

如果没有一种方法可以推断可比性,我就不可能在不确保所有对具有可比较的第一个元素的情况下实现对的BST,所以我不能实现任何类型的Map,其中第一个元素不是明确要求是可比较的。有没有办法解决这个问题,除了创建一个我的BST类的方法,试图通过首先将其作为可比较的方式来比较泛型类型,然后作为具有可比较密钥的对,比较可能的可比性?

3 个答案:

答案 0 :(得分:4)

这是不可能的。 Java缺少类型类机制; Java的接口只是模糊地类似于类型类,但缺乏自动实现接口的任何手段(其中,与类型类的更基本的差异)。一个类型实现或者没有实现一个接口 - 没有办法让一个类型在编译时神奇地继承它已经没有的东西,也没有一个类型停止继承它已经没有的东西。

也无法将约束向下移动到compareTo,因为这必须发生在compareToComparable的定义中。

我很高兴有人在此证明我错了。

最接近JVM上的Haskell样式类型的类是Scala和Frege - Scala的隐式解析机制在某种程度上比Haskell更强大/更具表现力,但也更冗长,并且有一些基本限制WRT使用存在和一起输入类约束; Frege只是Haskell到JVM的克隆。

解决方法:

除了特定于Java或特定于问题,可能基于模式和部分的解决方法之外,我所知道的最接近的是类型类的显式重新实现(这只是Haskell特定的术语/实现ad-hoc polymorphism)。

由bayou.io链接的问题会让你开始(尽管它很简单):Constrained interface implementation。类型类实例派生也需要明确地发生 - 你不会得到任何类型级别,你在Haskell或Scala中获得的编译时自动计算魔法,但你仍然可以获得灵活性和(大多数?)静态检查。

P.S。一些Haskeller认为即使在Haskell中它应该如何完成,所以这可能会给你一个或三个想法:http://www.haskellforall.com/2012/05/scrap-your-type-classes.html

答案 1 :(得分:2)

在Java中,为这类问题提供一种“伴侣”接口或类通常会更好。从某种意义上说,这些随机数比使用继承构造的类更接近Haskell类型类。为了比较,这个“伴侣”是Comparator。一个优点是你可以用不同的比较器(比如一个用于名称,一个用于年龄......)对一个类(比如Person)进行排序。在您的情况下,“伴侣”方法也解决了“泛型必须更具体的工作”问题:

public class Pair<K, V> {
    final public K k;
    final public V v;

    public Pair(K k, V v) {
        this.k = k;
        this.v = v;
    }
}

public class PairComparator<K extends Comparable<? super K>, V>
    implements Comparator<Pair<K,V>> {

    @Override
    public int compare(Pair<K, V> o1, Pair<K, V> o2) {
        return o1.k.compareTo(o2.k);
    }
}

//works for any Pairs with comparable keys:
PairComparator<String, Integer> comp = 
    new PairComparator<String, Integer>();
Pair<String, Integer> p1 = new Pair<>("z",1);
Pair<String, Integer> p2 = new Pair<>("a",3);
System.out.println(comp.compare(p1,p2));

答案 2 :(得分:0)

您可以创建两个不同的Pair类,如下所示:

public class Pair<K, V> {
    protected final K key;
    protected final V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
}

public class ComparablePair<K extends Comparable<K>, V> extends Pair<K, V> implements
        Comparable<ComparablePair<K, V>> {

    public ComparablePair(K key, V value) {
        super(key, value);
    }

    @Override
    public int compareTo(ComparablePair<K, V> o) {
        return key.compareTo(o.key);
    }
}

并将您的Comparable树限制为第二类。但是,使用不可比较的对看起来更干净(特别是在Java-8中),但是指定Comparator代替:

class MyTree<K, V> {
    final Comparator<K> comparator;

    public MyTree(Comparator<K> comparator) {
        this.comparator = comparator;
    }

    ... instead of k1.compareTo(k2) use comparator.compare(k1, k2) ...
}

通过这种方式,您可以获得更大的灵活性,因为您不仅可以按自然顺序比较键,还可以按照您喜欢的顺序比较键。如果您需要自然顺序,请使用new MyTree<String, Integer>(Comparator.naturalOrder());。这样,您将有一个编译时检查您的密钥类型是否具有可比性。