Java 什么时候需要一些<;E扩展了一些<;E>&燃气轮机;而不是一些<;E扩展了一些>;?

Java 什么时候需要一些<;E扩展了一些<;E>&燃气轮机;而不是一些<;E扩展了一些>;?,java,generics,recursion,enums,type-parameter,Java,Generics,Recursion,Enums,Type Parameter,注意:这个问题与枚举无关,因此它不是重复的。由于编译器生成了类型参数,而不是java递归类型参数,因此枚举只能与自身进行比较 我试图找到将类声明为的优势: public class Some<E extends Some<E>> 尽管存在通用递归,我仍然可以比较狗和猫: Dog dog = new Dog(); dog.compare(new Cat()); 转盐理论: 你们知道,任何扩展了动物的类都只能和它自己比较 这是错误的-我认为这类狗是用猫来扩展动物的,而不是

注意:这个问题与枚举无关,因此它不是重复的。由于编译器生成了类型参数,而不是java递归类型参数,因此枚举只能与自身进行比较

我试图找到将类声明为的优势:

public class Some<E extends Some<E>>
尽管存在通用递归,我仍然可以比较狗和猫:

Dog dog = new Dog();
dog.compare(new Cat());
转盐理论:

你们知道,任何扩展了动物的类都只能和它自己比较


这是错误的-我认为这类狗是用猫来扩展动物的,而不是它自己。

它看起来像目前
一些
一些

根据与Java拥护者和创建者共同编写的:

文章承认了一些可能性/假设:

  • 因为Enum是一个泛型类,所以我们只能将它与类型一起使用
  • Java可能变得更加严格,原始类型可能变得非法
我认为Enum就足够了。 然而,正如Philip Wadler向我指出的,因为Enum是一个泛型 类,我们只能将其与类型结合使用。在里面 将来,Java可能会变得更加严格,原始类型可能会变得更加复杂 非法的。因此,我们可以选择编写
Enum

或者
Enum区别在于
Some
意味着两件事:

  • E
    是原始类型。简言之,原始类型从类中剥离了所有泛型信息,这反过来会产生意外的行为
  • E
    可以是某些
    的任何类别
    
相反,使用
Some
意味着:

  • E
    已键入
  • E
    必须与声明它的类相同
原始部分是一个问题,但更大的含义是类型界限。这段代码演示了不同之处,“B”类使用(或试图使用)A类作为泛型类型

// The raw version
interface Some<E extends Some> {
    E get();
}

class SomeA implements Some<SomeA> {
    public  SomeA get() {
         return new SomeA();
    }
}

// Compiles OK
class SomeB implements Some<SomeA> {
   public SomeA get() {
         return new SomeA();
    }
}

// The typed version
interface SomeT<E extends SomeT<E>> {
    E get();
}

class SomeTA implements Some<SomeTA> {
    public  SomeTA get() {
         return new SomeTA();
    }
}

// Compile error 
class SomeTB implements SomeT<SomeA> {
   public SomeA get() { 
         return new SomeTA();
   }
}
//原始版本
接口一些{
E get();
}
类SomeA实现了一些{
公共服务{
返回新SomeA();
    }
}
//编译OK
类SomeB实现了一些{
公共服务{
返回新SomeA();
    }
}
//打字版
接口SomeT{
E get();
}
类SomeTA实现了一些{
公共部分{
返回新的SomeTA();
    }
}
//编译错误
类SomeTB实现了SomeT{
公共SomeA get(){
返回新的SomeTA();
   }
}
Class
SomeB
编译良好-E的类型仅绑定到
Some
,因此任何
Some
类都可以,但Class
SomeTB
会引发编译错误:

类型参数SomeTA不在类型变量E的范围内

E
的类型必须与包含的类完全相同

如果希望参数和返回类型与类本身相同,这一点很重要,这通常是类型化类所需要的



由原始类型绑定的类型不太重要,因为它仍然是一个
Some
,但在某些情况下可能会产生不同(我现在想不出任何区别)。

很少有情况需要像
类Some
这样的绑定。大多数情况下,人们写这篇文章时,代码中并没有实际使用边界,而
class-Some
也可以使用

然而,在某些特定情况下,实际使用的是
类some
中的边界。例如:

abstract class Some<E extends Some<E>> {
    abstract E foo();
    Some<E> bar() {
        return foo();
    }
}
抽象类{
抽象E-foo();
一些酒吧(){
返回foo();
}
}
至于你的问题——
有些课怎么样?首先,最明显的问题是您使用的是原始类型。新代码中不应使用原始类型。但你不相信

具有上述类(
classsome
)的原始类型编译时会出现警告(您可以忽略该警告,否则后果自负)。但是,raw类型意味着可能会使用它执行不安全的操作

需要一些努力才能拿出一个例子来证明它是不安全的。这里有一个:

abstract class Some<E extends Some> {
    abstract E foo();
    Some<E> bar() {
        return foo();
    }
}

class SomeFoo extends Some<SomeFoo> {
    SomeFoo foo() { return this; }
}

class SomeBar extends Some<SomeFoo> {
    SomeFoo foo() { return new SomeFoo(); }
}

class SomeBaz extends Some<SomeBar> {
    SomeBar foo() { return new SomeBar(); }
}

// then in some method:
Some<SomeBar> a = new SomeBaz();
Some<SomeBar> b = a.bar();
SomeBar c = b.foo();
抽象类{
抽象E-foo();
一些酒吧(){
返回foo();
}
}
类SomeFoo扩展了一些{
SomeFoo foo(){返回此;}
}
类SomeBar扩展了一些{
SomeFoo(){返回新的SomeFoo();}
}
类SomeBaz扩展了一些{
SomeBar foo(){返回新的SomeBar();}
}
//然后用某种方法:
Some a=新SomeBaz();
一些b=a.bar();
SomeBar c=b.foo();

代码编译时带有警告但没有错误,并在运行时抛出一个
ClassCastException

关于该语句

每次我尝试删除其他错误时,都不会出现新的错误/警告

事实不应如此。它应该打印一条警告,因为您使用的是原始类型
Some
,其结果是缺少类型安全性,如中所示


/
的例子有点做作,有些缺陷。您建议声明一个类

public class Dog extends Animal<Cat> { } // Note "Cat" !!!

但从我个人的经验来看,我可以说,当你认为你需要创造这样一种类型时,你应该彻底考虑它的优点和缺点。后者主要指可读性降低。当您可以选择以下方法时:

Node<? extends Node<? extends N, ? extends T>, T> doSomething(
    Node<? super Node<? extends N>, ? extends T> p, 
    Node<? extends Node<? super N>, ? super T> c) { ... }
Node doSomething(Node parent, Node child) { ... }

这不是类型安全的(因为原始类型,或者仅仅因为类型没有被泛化),那么我更喜欢后者。代码由人类读取

这是一样的,因为泛型是如何工作的(有些==编译后的一些)。搜索原始类型和有关泛型的信息。相关:@Pshemo:这实际上是该问题的重复;唉,这个问题没有好的答案:(从OO progra的角度来看)
public class RecurringTest {
    public static void main(String[] args) {
        SpecialNode sa = new SpecialNode(null);
        SpecialNode sb = new SpecialNode(sa);
        SpecialNode s = sa.getChildren().get(0);
    }
}

abstract class Node<N extends Node<N>> {
    private final List<N> children = new ArrayList<N>();
    private final N parent;

    protected Node(N parent) {
        this.parent = parent;
        if (parent != null) {
            this.parent.getChildren().add(getThis());
        }
    }

    abstract N getThis();

    public N getParent() {
        return parent;
    }

    public List<N> getChildren() {
        return children;
    }
}

class SpecialNode extends Node<SpecialNode> {
    public SpecialNode(SpecialNode parent) {
        super(parent);
    }

    SpecialNode getThis() {
        return this;
    }

}
Node<? extends Node<? extends N, ? extends T>, T> doSomething(
    Node<? super Node<? extends N>, ? extends T> p, 
    Node<? extends Node<? super N>, ? super T> c) { ... }
Node doSomething(Node parent, Node child) { ... }