2017-10-20 165 views
1

我在寻找一个类似的推断拍摄的泛型类型,类似于下面的方法片段的概念,但不是为捕获泛型类:推断的Java泛型类型

public <X, Y, Z> static void someMethod(ObjectInterface<X, Y, Z> object) { 
    // code that uses inferred generic type parameters X, Y and Z... 
} 

的代码在这个片段将捕获类型并将其分配给通用参数类型X,YZ。这允许在代码体内使用泛型类型变量,并使该方法在使用中更加灵活。在这段代码中,如果调用方法时没有指定类型(即没有参数化),那么Java将推断这些类型,即someMethod(instaceOfImplementedObject)将起作用并且将推断这些类型。

我的问题是,我有以下的(简化)结构的对象接口和实现接口的对象:

public interface ObjectInterface<X, Y, Z> { 
    //... 
} 

class ImplementedObject implements ObjectInterface<SomeType1, SomeType2, SomeType3> { 
    //... 
} 

然后,我有一个能够捕获不少泛型类型变量的其他类,其中之一是实现ObjectInterface<X, Y, Z>的对象。在这样的类中,我还需要处理在捕获的对象中定义的类型(X,Y,Z)。

以下(不理想,而且很简单的)代码的工作:

public class ClassWorks<X, Y, Z, N extends ObjectInterface<X, Y, Z>> { 
    // code body uses X, Y, Z and N... 
} 

然而,这是试图用/启动这个类,即使在这样的简化版本,例如人很麻烦:

public class ImplementedObject implements ObjectInterface<Integer, Double, String> { 
    //... 
} 

public class RandomExample { 
    public static void main(String[] args) { 
     ObjectInterface<Integer, Double, String> implementedObj = new ImplementedObject(); 
     ClassWorks<Integer, Double, String, ImplementedObject>> example = new ClassWorks<Integer, Double, String, ImplementedObject>(/* possible params */); 
    } 
} 

有没有一种方法来“解压”或捕捉这些类型使他们推断,而不是明确的,因为它是在工作示例ClassWorks? 可能类似于以下的东西(注意,这不工作):

pulic class WishfullClass<N extends ObjectInterface<X, Y, Z>> { 
    // type N is captured; X, Y and Z is not explicitly captured. 
    // code uses type N, as well as X, Y and Z 
    // where, X, Y and Z is inferred somehow from N. 
} 

编辑: 所以WishfullClass的实施例子是:

public class ImplementedObject implements ObjectInterface<Integer, Double, String> { 
    //... 
} 

public class WishfullExample { 
    public static void main(String[] args) { 
     ObjectInterface<Integer, Double, String> implementedObj = new ImplementedObject(); 
     WishFullClass<ImplementedObject> example = new WishfullClass<ImplementedObject>(/* possible params */); 
    } 
} 

即。编译器应该知道,ImplementedObject从它实现ObjectInterface<Integer, Double, String>为X,Y和Z

请注意类的声明,上述这些都是非常简单的,并在实际的代码是不是需要捕捉的唯一参数,所以这三个额外的参数有很大的不同。也是实现目标还捕获泛型类型,

所以最好我想只集中捕捉延长ObjectInterface<X, Y, Z>,并有XYZ推断的对象。有没有办法做到这一点?

即使someMethod的片段展示了如何推断方法范围的X,Y和Z.我的问题指的是,是否有办法通过仅捕获延伸ObjectInterface的类型来推断整个课程范围内的X,Y和Z.

我遇到了一些麻烦措辞/解释这个问题,所以如果有任何不确定性,请要求澄清:)

+0

您可以使用类型变量(如任何其他变量)的唯一方法是将该类型变量作为范围。所以要么你必须声明它,要么在包含范围内必须有一个已经可见。 –

+0

@AndyTurner是:)这是问题来自哪里。所以我知道如何推断变量X,Y,Z(不必明确指定变量 - 给出扩展ObjectInterface的对象就足够了),一个方法,显示在第一个小代码片段中,并在问题开始时解释。我的问题涉及到,是否可以通过扩展ObjectInterface 的类型参数N来推断X,Y和Z,但是可以用于类的整个范围。 – Smiley

回答

0

所以经过一些进一步的研究,我在教科书Effective Java, by Joshua Block; Item 27: Favor generic methods找到了答案。我一直在寻找的是在调用泛型构造函数时简化/减少类型参数的重复 - 即减少繁琐和不重复已经提供的参数。

确实无法推断构造函数的类型,但是有一种方法可以利用泛型方法来减少构造函数的重复和类型参数 - 通过为每个构造函数制作泛型工厂方法并以这种方式推断类型参数代替。

这是解释这整个情况的信息,引述了课本的以下内容:

的通用方法,一个显着特点是,你不需要明确的指定类型参数的值你必须调用泛型构造函数。编译器通过检查方法参数的类型来计算出类型参数的值。在上述程序的情况下,编译器会发现union的两个参数都是Set类型的,所以它知道类型参数E必须是String。这个过程称为类型推断。

如第1项所述,您可以利用通用方法调用提供的类型推断来简化创建参数化类型实例的过程。为了刷新你的记忆,当调用泛型构造函数时需要显式传递类型参数的值可能会很烦人。该类型参数冗余出现在变量声明的左手和右手边:

// Parameterized type instance creation with constructor` 
Map<String, List<String>> anagrams = new HashMap<String, List<String>>(); 

为了消除这种冗余,写出对应于您要使用的每个构造一个通用的静态工厂方法。例如,下面是对应于无参数的HashMap构造一个通用的静态工厂方法:

// Generic static factory method 
public static <K,V> HashMap<K,V> newHashMap() { 
    return new HashMap<K,V>(); 
} 

有了这个通用的静态工厂方法,你可以用这个简洁的一个替换上面的重复声明:

// Parameterized type instance creation with static factory 
Map<String, List<String>> anagrams = newHashMap(); 

这将是很好,如果语言没有同类型推断的时候 调用C ^泛型类型上的泛型类型,就像调用泛型方法时一样。有一天它可能,但是到1.6版本,它不会。

0

我没有得到这种早期的要求,虽然这一次也许可以,如果你实现用作通配符(?)或在WishfullClass实现之前使用抽象类。我会做如下。

这不是要求。

更新: 否则,您可以按如下方式显式实现与您的类的接口。

class WishfullClass<X, Y, Z, N> implements ObjectInterface<X, Y, Z> { 
// Use N type variable here. 
} 
+0

我认为存在一些误解(很难解释我在找什么,对不起)。N是实现ObjectInterface的类型...因此,当WishfullClass捕获它时,它会将其捕获为有界类型,即例如,如果使用通配符,则>。然而,我所问的是:是否有一种方法可以只捕获***并以某种方式从*** N中推断出X,Y,Z ***,而不必为X,Y和Z明确捕获WishfulClass。 – Smiley

+0

没问题。所以基本上你需要将'ObjectInterface'的子类类型传递给type参数。但可能你没有办法。如果你没有放置类型,编译器会假定类型为Object。在这种情况下,您传递的是子类型参数,超类型的对象是不可接受的。一旦删除这些类型参数,泛型的目的也会丢失。你没有其他解决方案。 –

+0

不是,我可以将类型参数作为实现ObjectInterface的类型传递。我不想做的是重申实现ObjectInterface类型参数的类型,即X,Y和Z.所以我可以传递'ImplementedObject',它实现'ObjectInterface '..但是,我只想捕获(只传递)ImplementedObject ..并且不重复和重新捕获“someType#”类型。 – Smiley

1
Map<String, List<String>> anagrams = new HashMap<>(); 

会做同样在Java中7起。 <>是钻石经营者。

+0

昨天意识到了这一点。感谢您添加此。有一点需要注意的是,重申X,Y和Z必须在左边的声明中重复,即Class >。至少钻石操作员允许推断右侧,并且这样做不那么麻烦。 – Smiley