【问题标题】:Java Generics Silly Thing (Why cant I infer the type?)Java Generics Silly Thing(为什么我不能推断类型?)
【发布时间】:2012-04-24 00:33:21
【问题描述】:

我会尽量简短,因为这个问题没有得到很好的回答。如需详细说明,请阅读本简报。

我会展示我想要做什么。像这样的东西(从构造函数推断传入的类型,以便在另一个方法 getLeaderHerd 中使用它作为返回类型)...:

public class ZooCage{

    private CageFamily<T> inhabitants;  

    public <T>ZooCage(CageFamily<T> herd) {
        this.inhabitants=herd;      
    }

    public T getHerdLeader() {
        return inhabitants.getLeader();
    }   
}

或者这个

public class ZooCage{

    private (Type) T;   

    public ZooCage(CageFamily<T> herd) {
        this.T=T;       
    }

    public T getHerdLeader() {
        return inhabitants.getLeader();
    }   
}

所以我可以从 Main 调用类似:

ZooCage cage = new ZooCage(new CageFamily<Lion>()); //Imagine new CageFamily its not empty
Lion leader = cage.getHerdLeader();

即使不可能,我为什么要认为这是不合理的功能?如果编译器是智能的并且没有必要的类 ZooCage 那样冗余,那么它的类型是安全的

我正在评估针对特定行为使用泛型。我设法让它工作,但我不明白为什么我不能从 arg 推断类型。所以我创建了这个例子,它运行良好,没有警告,目的是简化实际架构。

(直接看最后两行 sn-p 快速简报)

假设我有这两个课程。目标一:

package Zoo;
import Zoo.Main.CageFamily;
import Zoo.Main.Vertebrate;

public class ZooCage<T extends Vertebrate>{

    private CageFamily<T> inhabitants;  

    public ZooCage(CageFamily<T> herd) {
        this.inhabitants=herd;      
    }

    public T getHerdLeader() {
        return inhabitants.getLeader();
    }   
}

想象一下,笼子里只能有脊椎动物(昆虫/蛛形纲动物不像大猩猩/章鱼需要水生介质)

另一个类,Main.java

package Zoo;
import java.util.ArrayList;

public class Main {

    public static void main(String[] args){
        new Main().test();
    }

    public void test(){
        CageFamily<Lion> lionsHerd = new CageFamily<Lion>();
        lionsHerd.add(new Lion("Simba"));
        lionsHerd.add(new Lion("Nala"));

        CageFamily<Bear> bearsHerd = new CageFamily<Bear>();
        bearsHerd.add(new Bear("Yogi"));
        bearsHerd.add(new Bear("Boo-boo"));

        ZooCage<Lion> cageLions = new ZooCage<Lion>(lionsHerd);     
        ZooCage<Bear> cageBears = new ZooCage<Bear>(bearsHerd);

        for (ZooCage<?> cage : new ZooCage[]{cageLions,cageBears} ) 
           System.out.println("The leader is "+ cage.getHerdLeader());

    }

    public interface Vertebrate{
        public String toString();
        public int numBones();
    }
    public class Lion implements Vertebrate{
        private String name;
        public Lion (String name){this.name=name;}
        public String toString(){return name + " (who has "+numBones()+" bones)";}
        public int numBones(){return 345;}
    }
    public class Bear implements Vertebrate{
        private String name;
        public Bear (String name){this.name=name;}      
        public String toString(){return name + " (who has "+numBones()+" bones)";}
        public int numBones(){return 658;}
    }
    public class CageFamily<E extends Vertebrate> extends ArrayList<E>{
        final static long serialVersionUID = 1L;
        public E getLeader(){
             return get(0); //Let,s assume the first added is the leader
        }
    }
}

这编译OK并打印

The leader is Simba (who has bones)
The leader is Yogi (who has bones)

我想知道的是:有什么方法(仅使用类型/泛型,不使用 supressingWarnings 或铸件)来避免整个 ZooCage 类的典型化?我尝试了上千种方法来从 ZooCage 的构造函数 arg 中推断出类型到 getHerdLeader 的返回值。当他的构造函数带有预期的类型时,应该没有必要指定 ZooCage。似乎是多余的,让你必须事先知道类型!

非常感谢所有可以提供帮助的人!

【问题讨论】:

  • 您到底想避免哪一部分? “避免典型化”是什么意思?
  • 避免在类的 ZooCage 定义中指定 ,所以我必须将其用作 ZooCage = new ZooCage。我想从构造函数中的传入类型推断 getHerdLeader 的返回类型。我的意思是返回 T,它是与 CageFamily arg 一起传入的 T,并且忘记了泛型的类定义。

标签: java generics types inference


【解决方案1】:

Java 7 允许您执行ZooCage&lt;Type&gt; = new ZooCage&lt;&gt;(argument)。不过,该功能是 Java 7 中的新功能,并且在 Java 的早期版本中不可用。

另外,解决 Java 6 缺乏类型推断的传统方法是编写工厂方法

public static <T> ZooCage<T> newZooCage() {
  return new ZooCage<T>();
}

然后newZooCage() 会自动推断其类型,因为即使是 Java 5 也可以为 methods 进行类型推断——只是不适用于构造函数。

【讨论】:

  • 但是我不想在任何地方的 ZooCage 调用中指定类型。我很确定一定有办法将 T 带到 public ZooCage(CageFamily herd) { this.inhabitants=herd; } 到公共 T 上的 T getHerdLeader() { returnresident.getLeader(); }
  • 仅供参考,在 Java 5 中执行静态工厂方法存在某种错误(现在可能已修复)。即这将不起作用“ZooCage b = ZooCage.newZooCage();” ...你必须做 ZooCage b = ZooCage.newZooCage();但是前者将与 Eclipse JDT 一起使用。
  • 谢谢,但我认为我不善于暴露情况。我想拼写没有泛型的 ZooCage。我必须这样做来编译示例,但我正在寻找一种解决方案来编写 ZooCage a = new ZooCage( 并仅从构造函数中作为参数传递的 CageFamily 的类型获取 getHerdLeader 上的返回类型。书面代码已经在运行,因此任何需要使用 参数化 ZooCage 的解决方案对我来说都无效,对不起
  • Java 中没有解决方案可以满足您的描述。构造时的类型信息不会被保留——它可以用来确定getHerdLeader 的返回类型的唯一类型信息是ZooCage 的类型——不是构造ZooCage 时的任何信息。
  • @AdamGent:……真的吗? ZooCage&lt;Blah&gt;.newZooCage()从未工作过;类型参数总是在. 的另一边。当然,Java 6 几乎总是可以让您在没有类型参数的情况下使用ZooCage.newZooCage(),不过——如果 Java 5 不允许您这样做,我会感到惊讶。
【解决方案2】:

Java 不支持类型推断。

如果你对此感兴趣,你应该看看 Scala。

在 Java 7 中,您可以省略右侧 之间的类型。 In Java 6 you can do it with static methods with Guava。 Java 8 可能/将会有文字(或至少上次检查),所以这也可能有所帮助。

我不同意这些都是真正的类型推断 (见下面的 cmets)

【讨论】:

  • Java 确实支持类型推断:docs.oracle.com/javase/tutorial/java/generics/… 正如您所指出的,直到 7 才支持构造函数。
  • @PaulBellora 他们(甲骨文)对类型推断的含义采取了一些严肃的态度。真正的类型推断允许您不在方法参数和左侧声明中声明类型。恕我直言,Java (7) 甚至比不上 C#、Scala、F#、Ocaml 或 Haskell 的类型推断。
  • 是的,我实际上可以推断出 Java 6 中的传入类型。问题是我无法将它传播到构造函数的范围之外。如果我尝试将它分配给一个类的私有 var T,那么它显然会抱怨,因为 T 没有在整个类的范围内定义(ZooCage
  • 我什至不知道“推断”是什么意思了。每个人的使用方式都与我不同。
  • 嗯,我不太清楚,我认为字面意思是从另一件事中猜测某事,所以在这种情况下,我会说根据未知的参数化传入类型处理和使用一种类型。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多