How can I make an interface instance method accept

2020-02-06 07:49发布

This SO discussion proposes the following idiom:

public interface IComparable<T extends IComparable<T>> {
    int compare(T t);
}

which then allows:

public class Foo implements IComparable<Foo> {
    public int compare(Foo foo) {
        return 0;
    }
}

However, this idiom allows more than just the above as the following code compiles as well:

class A implements IComparable<A> {
    public int compare(A a) {return 0;}
}

public class Foo implements IComparable<A> {

    public int compare(A a) {
        return 0;
    }
}

Therefore (unless I've misunderstood something) the original idiom doesn't really buy anything more compared to the far less dramatic:

public interface IComparesWith<T> {
    int compare(T t);
}

public class A implements IComparesWith<A> {
    public int compare(A a) {...}
}

So, is there a way to actually declare an interface such that whatever class declares to implement it has a method to compare with objects of its own class, without any loopholes such the one above?

I obviously could't post the above as a comment hence I created a new post.

5条回答
相关推荐>>
2楼-- · 2020-02-06 08:32

Don't use generics:

public interface Foo {
    public void doSomething(Foo foo);
}
查看更多
够拽才男人
3楼-- · 2020-02-06 08:42

No, that sort of restriction is not possible with the generics as written. Your assessment seems correct to me.

查看更多
Lonely孤独者°
4楼-- · 2020-02-06 08:46

Indeed. I'd advocate that we use This as the conventional name for such type parameters

public interface IComparesWith<This> 
{
    int compare(This t);
}

my previous answer: Convenient way to write generic interface that points out to its implementor

查看更多
男人必须洒脱
5楼-- · 2020-02-06 08:51

You are correct: this idiom does not prevent classes from being compared to different classes. All it does is ensure that the compared object also implements the same interface. If there is a requirement to only compare the same types, that can be enforced by the implementing class.

What you call a "loophole" is what I would call "intentionally doing something you don't want to do".

Foo objects can be compared to A objects IF such behavior is desired.

This is a feature, not a loophole.

If you want Foo to be comparable to other Foos, you should define Foo to implement IComparable<Foo>.

If you don't want Foo to be comparable to A, then you shouldn't define Foo to implement IComaparable<A>. Why would anybody do that unless they were trying to write broken code on purpose?

The actual answer to your question has already been provided by @caskey:

"No, you can't do what you want using interfaces in Java. [You have to do it with classes]."

There is one thing that you missed:

Therefore (unless I've misunderstood something) the original idiom doesn't really buy anything more compared to the far less dramatic:

public interface IComparable<T>

The original idiom does buy you something. It enforces that the compared object must implement IComparable. The less dramatic example would allow you to compare implementing classes to any object without restriction. So... The compiler would allow you to specify Long, or InputStream, or LinkedHashSet<Byte[]>, or anything at all as a type parameter.

When you look at it that way, it's easy to see why this idiom is so common.

查看更多
冷血范
6楼-- · 2020-02-06 08:51

Therefore (unless I've misunderstood something) the original idiom doesn't really buy anything more compared to the far less dramatic:

It does buy something, but it's a different thing than what you're thinking of. And when someone writes that, 99.9% of the time it is not what they are trying to buy.

So, is there a way to actually declare an interface such that whatever class declares to implement it has a method to compare with objects of its own class, without any loopholes such the one above?

No. Because it's not useful in terms of type safety. There's nothing wrong with the public class Foo implements IComparable<A> -- it's perfectly type safe. If someone wants to make a Foo that can safely compare to A in some way, then that's great. I agree with jahroy'a answer -- it's not a "loophole"; it's a feature. Why not make it more general, as long as it's safe? It doesn't get in the way of anything you're doing. If you want to make all your classes compare to themselves, that's fine too. Everything is fine, as long as it's type safe.

The only place where you should care about the relationship about a type and the type parameter with which it implements IComparable is where you use it, because that place may legitimately have a need for such a relationship. So in that place (a generic class or generic method which is parameterized by a comparable type), we can easily bound the type variable that represents the comparable type like this: T extends IComparable<? super T>, allowing us to guarantee that T can compare to itself.

查看更多
登录 后发表回答