2012-04-24 164 views
3

我会尽量缩短这个问题的答案。对于长时间的解释,请遵循这个简报。Java泛型愚蠢的事情(为什么不能推断这种类型?)

我会显示我在做什么。事情是这样的(为了在另一种方法getLeaderHerd作为返回类型使用它从构造infering输入型)...:

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(); 
    } 
} 

,所以我可以从打电话主要是这样的:

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

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

我,m评估使用泛型为特定行为。我设法得到它的工作,但我不明白为什么不能从arg中推断出这种类型。所以我创建了这个示例,它可以在没有警告的情况下正常运行,以简化实际的体系结构。

(直接看最后2行片断的快速简报)

想我得到了这两个类。目标之一:

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(); 
    } 
} 

试想一下,在笼子里只能有脊椎动物(昆虫/ aracnids并不大昂巨头quids /章鱼需要水介质)

另外一类,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) 

什么我想知道的是:是有没有办法(只使用类型/泛型,没有抑制威望或铸件)来避免类ZooCage作为一个整体的类型化?我尝试了几千种方法来从ZooCage的构造函数arg中得到对getHerdLeader的返回值的推断。当他的构造函数带有预期类型时,应该没有必要对ZooCage进行典型化。看起来多余,让你不得不事先知道类型!

非常感谢所有能够帮助的人!

+1

你试图避免什么部分? “避免典型化”是什么意思? – 2012-04-24 00:46:01

+0

避免在类的ZooCage定义中指定,所以我必须使用它作为ZooCage = new ZooCage 。编号喜欢从构造函数中的传入类型推断getHerdLeader的返回类型。我的意思是返回T,它是CageFamily arg传入的T,并伪造泛型的类定义。 – Whimusical 2012-04-24 00:48:45

回答

10

Java 7可以让你做ZooCage<Type> = new ZooCage<>(argument)。但是,该功能在Java 7中是新功能,并且在早期版本的Java中不可用。

或者,围绕Java 6的缺乏类型推断得到的一种传统方式是写一个工厂方法

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

然后newZooCage()得到它的类型自动推断,因为即使Java 5的有类型推断方法 - 不适用于构造函数。

+0

但Id喜欢不指定在任何地方的ZooCage调用类型。我很肯定,必须有一些公共的ZooCage(CageFamily 牧群)带来的T thisoffice = herd; } to the public T getHerdLeader(){ return inhabitants.getLeader(); } – Whimusical 2012-04-24 00:58:09

+0

仅供参考使用Java 5中的静态工厂方法存在某种错误(现在可能已修复)。即,这不起作用“ZooCage b = ZooCage.newZooCage();” ...你必须做ZooCage b = ZooCage .newZooCage();但是前者将与Eclipse JDT一起工作。 – 2012-04-24 00:59:37

+0

谢谢,但我认为我不好暴露的情况。我想在没有泛型的情况下拼写ZooCage。我不得不编写这个例子来编译这个例子,但是我正在寻找一个解决方案来编写ZooCage a = new ZooCage(并且从构造函数中传递的CageFamily 的类型中获取getHerdLeader的返回类型。已经工作了,所以任何需要使用<>来参数化ZooCage的解决方案对我来说无效对不起 – Whimusical 2012-04-24 01:06:41

1

Java不支持类型推断。

如果你有兴趣,你应该看看斯卡拉。

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

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

+1

Java确实支持类型推断:http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html直到7时,它才被构造函数支持,就像你记下的那样。 – 2012-04-24 03:28:00

+1

@PaulBellora他们(Oracle)对于类型推断的内容有一些认真的自由。 True类型推断允许您不在方法参数和左侧声明中声明类型。恕我直言Java(7)甚至没有接近C#的,斯卡拉,F#,Ocaml或Haskell的类型推理。 – 2012-04-24 14:31:12

+0

是的,我可以实际推断Java 6中的传入类型。问题是我无法将它传播到构造函数的范围之外。如果我尝试将它分配给一个类的私有变量T,那么显然它会抱怨,因为T没有在整个类的范围内定义(ZooCage ) – Whimusical 2012-04-24 16:44:01