ChatGPT解决这个技术问题 Extra ChatGPT

Why is "extends T" allowed but not "implements T"?

Is there a special reason in Java for using always "extends" rather than "implements" for defining bounds of type parameters?

For example:

public interface C {}
public class A<B implements C>{} 

is prohibited, but

public class A<B extends C>{} 

is correct. What is the reason for that?

I don't know why people think the reply by Tetsujin no Oni really answers the question. It basically rephrases OP's observations using academic wording, but does not give any reasoning. "Why is there no implements?" - "Because there is only extends".
ThomasR: that's because it's not a question of "allowed", but of meaning: there's no difference in how you would write a generic consuming a type with a constraint whether the constraint is from an interface or an ancestor type.
Added an answer (stackoverflow.com/a/56304595/4922375) with my reasoning why implements wouldn't bring anything new and would complicate things further. I hope it will be helpful for you.
This post can help! veejnas.medium.com/…

T
Tetsujin no Oni

There is no semantic difference in the generic constraint language between whether a class 'implements' or 'extends'. The constraint possibilities are 'extends' and 'super' - that is, is this class to operate with assignable to that other one (extends), or is this class assignable from that one (super).


@KomodoDave(I think the number next to the the answer marks it as right, I am not sure if there is any other way to mark it, sometimes other answers may contain additional info - e.g. I had a particular problem I could not solve and google sends you here when searching for it.) @Tetsujin no Oni( Would it be possible to use some code to clarify? thanx :))
@ntg, this is a very good example on a question looking for examples - I'll link it in comment, rather than embedding in the answer at this point. stackoverflow.com/a/6828257/93922
I think the reason is at least I would like to have a generic that can have a constructor and methods that can accept any class that both axtends a base class and exhibits an interface not just interfaces that extend an interface. Then have the instantiation of the Genric test for the presense of interfaces AND have the actual class specified as a type parameter. Ideally I would want class Generic<RenderableT extends Renderable implements Draggable, Droppable, ...> { Generic(RenderableT toDrag) { x = (Draggable)toDrag; } } One wants compile time checks.
@peterk And you get that with RenderableT extends Renderable, Draggable, Droppable.... unless I'm not understanding what you want the erasure generics to do for you that this doesn't provide.
@TetsujinnoOni you don't in what I want is for a compile time enforcement of only accepting classes that implement a certain set of interfaces, and then be able to reference the OBJECT class ( that exhibits those interfaces) in the generic and then know that at least at compile time ( and desirably at run time ) anything assigned to the generic can safely be cast to any of the specified interfaces. This is not the case the way java is implemented now. But it would be nice :)
M
MikaelF

The answer is in here :

To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound […]. Note that, in this context, extends is used in a general sense to mean either extends (as in classes) or implements (as in interfaces).

So there you have it, it's a bit confusing, and Oracle knows it.


To add to the confusion getFoo(List<? super Foo> fooList) ONLY works with the class that literally are extended by Foo like class Foo extends WildcardClass. In this case a List<WildcardClass> would be acceptable input. However any class that Foo implements would not work class Foo implements NonWorkingWildcardClass does not mean List<NonWorkingWildcardClass> will be valid in the getFoo(List<? super Foo> fooList). Crystal clear!
b
beetstra

Probably because for both sides (B and C) only the type is relevant, not the implementation. In your example

public class A<B extends C>{}

B can be an interface as well. "extends" is used to define sub-interfaces as well as sub-classes.

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

I usually think of 'Sub extends Super' as 'Sub is like Super, but with additional capabilities', and 'Clz implements Intf' as 'Clz is a realization of Intf'. In your example, this would match: B is like C, but with additional capabilities. The capabilities are relevant here, not the realization.


Consider . E must not be a class.
@TomHawtin-tackline Except it seems that you can't use a type parameter ("E"), you must put an interface literal after that ampersand character so Java can trust you it is an interface. I would love to get corrected on this one.
@JaroslavZáruba That is true. Actual error is "unexpected type required: class found: type parameter E" (my emphasis on 'class'). However, the original poster (unfortunately) used single letters for type names as well as type parameters = E is supposed to mean write an actual type name (I think - I wrote that comment over a decade ago).
@TomHawtin-tackline damn, i was hoping there could be a workaround :)
n
ntg

Here is a more involved example of where extends is allowed and possibly what you want:

public class A<T1 extends Comparable<T1>>


T
Tom Hawtin - tackline

It may be that the base type is a generic parameter, so the actual type may be an interface of a class. Consider:

class MyGen<T, U extends T> {

Also from client code perspective interfaces are almost indistinguishable from classes, whereas for subtype it is important.


L
Lii

It's sort of arbitrary which of the terms to use. It could have been either way. Perhaps the language designers thought of "extends" as the most fundamental term, and "implements" as the special case for interfaces.

But I think implements would make slightly more sense. I think that communicates more that the parameter types don't have to be in an inheritance relationship, they can be in any kind of subtype relationship.

The Java Glossary expresses a similar view.


A
Andrew Tobilko

We are used to

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

and any slight deviation from these rules greatly confuses us.

The syntax of a type bound is defined as

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

(JLS 12 > 4.4. Type Variables > TypeBound)

If we were to change it, we would surely add the implements case

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

and end up with two identically processed clauses

ClassOrInterfaceType:
    ClassType 
    InterfaceType

(JLS 12 > 4.3. Reference Types and Values > ClassOrInterfaceType)

except we would also need to take care of implements, which would complicate things further.

I believe it's the main reason why extends ClassOrInterfaceType is used instead of extends ClassType and implements InterfaceType - to keep things simple within the complicated concept. The problem is we don't have the right word to cover both extends and implements and we definitely don't want to introduce one.

<T is ClassTypeA>
<T is InterfaceTypeA>

Although extends brings some mess when it goes along with an interface, it's a broader term and it can be used to describe both cases. Try to tune your mind to the concept of extending a type (not extending a class , not implementing an interface ). You restrict a type parameter by another type and it doesn't matter what that type actually is. It only matters that it's its upper bound and it's its supertype.


z
zhangde

In fact, when using generic on interface, the keyword is also extends. Here is the code example:

There are 2 classes that implements the Greeting interface:

interface Greeting {
    void sayHello();
}

class Dog implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Dog: Hello ");
    }
}

class Cat implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Greeting from Cat: Hello ");
    }
}

And the test code:

@Test
public void testGeneric() {
    Collection<? extends Greeting> animals;

    List<Dog> dogs = Arrays.asList(new Dog(), new Dog(), new Dog());
    List<Cat> cats = Arrays.asList(new Cat(), new Cat(), new Cat());

    animals = dogs;
    for(Greeting g: animals) g.sayHello();

    animals = cats;
    for(Greeting g: animals) g.sayHello();
}

D
David Hedin-Abreu

Using “extends” in is a promise that the data type will either itself directly implement Comparable, or else will extend a class implementing Comparable. You might have written a subclass B of another class A that implements Comparable, and if you declare your data type , then you may use either A or B as your data type when instantiating the class.