为什么这是在Java7编译而不是在Java8? [英] Why does this compile in Java7 and does not in Java8?

查看:654
本文介绍了为什么这是在Java7编译而不是在Java8?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

泛型很棘手。
看起来他们在不同版本的Java中的处理方式不同。



这段代码在Java 7中成功编译,无法使用Java 8编译。

  import java.util.EnumSet; 

public class Main {
public static void main(String [] args){
Enum foo = null;
tryCompile(EnumSet.of(foo));
}

static< C extends Enum< C> &另一个> void tryCompile(Iterable< C> i){}

静态接口另一个{}
}

这是Java 8的错误消息。我使用这个来编译它: http://www.compilejava。 net /

  /tmp/java_A7GNRg/Main.java:6:error:方法tryCompile在类Main中不能应用于给定类型; 
tryCompile(EnumSet.of(foo));
^
必需:可迭代< C>
found:EnumSet
reason:推断类型不符合上限
推断:枚举
上限:枚举< Enum>,另一个
其中C是类型变量:
C extends Enum C,在方法< C>中声明的另一个tryCompile(Iterable< C>)
/tmp/java_A7GNRg/Main.java:6:警告:[未选中]未检查的方法调用:类中的方法EnumSet应用于给定类型
tryCompile(EnumSet.of(foo));
^
必需:E
found:Enum
其中E是类型变量:
E extends Enum< E> (E)的方法< E>中声明的
1错误
1警告

问题是关于Java编译器版本之间的区别。

解决方案

Java 7和Java 8之间的主要区别是目标类型推断。虽然Java 7只考虑方法调用的参数来确定类型参数,但Java 8将使用表达式的目标类型,即在嵌套方法调用的情况下的参数类型,初始化或分配的变量的类型在 return 语句的情况下,方法的返回类型。



当写入时, List< Number> list = Arrays.asList(1,2,3,4); ,Java 7将推断出右侧的类型 List< Integer> 通过查看方法的参数并生成错误,而Java 8将使用目标类型 List< Number> 来推断方法参数必须是 Number 就是这种情况。因此,在Java 8中是合法的。



如果你对正式的细节感兴趣,你可以学习Java语言规范,第18章类型推断,特别是§18.5.2。调用类型推理,但是,这不容易阅读...



那么当你说 Enum foo = null会发生什么?在Java 7中,表达式的类型 EnumSet.of(enumSet.of(foo));



< (foo)
将通过查看参数类型 foo 来推断,这是原始类型 Enum ,因此将执行未经检查的操作,结果类型为原始类型 EnumSet 。这种类型实现了原始类型 Iterable ,因此可以传递到 tryCompile 形成另一个未检查的操作。



在Java 8中, EnumSet.of(foo)的目标类型是 tryCompile 这是 Iterable< C extends Enum< C> &另一个> ,因此没有太多的细节,在Java 7 EnumSet.of 将被视为原始类型调用,因为它有一个原始类型参数,在Java 8中,它将被视为通用调用,因为它具有通用目标类型。通过将其视为通用调用,编译器将得出结论( Enum )与所需类型不兼容 C extends Enum< C> &另一个。虽然你可以放弃将原始类型 Enum 分配给 C,但是扩展Enum< C> 将被认为与另一个(不带类型转换)不兼容。



  Enum foo = null; 
tryCompile(EnumSet.of((Enum& Another)foo));

这是编译,当然不是没有未经检查的警告由于枚举 C extends Enum< C>



类型关系,以便执行与Java 7中相同的步骤:

  Enum foo = null; 
EnumSet set = EnumSet.of(foo);
tryCompile(set);

这里,原始类型用于三行,所以这样编译与未检查的警告和相同的无知实现另一个约束,如在Java 7中。


Generics are tricky. And looks like they are treated differently in different versions of Java.

This code successfully compiles in Java 7 and fails to compile with Java 8.

import java.util.EnumSet;

public class Main {
  public static void main(String[] args) {
    Enum foo = null;
    tryCompile(EnumSet.of(foo));
  }

  static <C extends Enum<C> & Another> void tryCompile(Iterable<C> i) {}

  static interface Another {}
}

Here is an error message from Java 8. I used this one to compile it: http://www.compilejava.net/

/tmp/java_A7GNRg/Main.java:6: error: method tryCompile in class Main cannot be applied to given types;
    tryCompile(EnumSet.of(foo));
    ^
  required: Iterable<C>
  found: EnumSet
  reason: inferred type does not conform to upper bound(s)
    inferred: Enum
    upper bound(s): Enum<Enum>,Another
  where C is a type-variable:
    C extends Enum<C>,Another declared in method <C>tryCompile(Iterable<C>)
/tmp/java_A7GNRg/Main.java:6: warning: [unchecked] unchecked method invocation: method of in class EnumSet is applied to given types
    tryCompile(EnumSet.of(foo));
                         ^
  required: E
  found: Enum
  where E is a type-variable:
    E extends Enum<E> declared in method <E>of(E)
1 error
1 warning

The question is about the difference between versions of Java compiler.

解决方案

The main difference between Java 7 and Java 8 is the target type inference. While Java 7 only considers the parameters of a method invocation to determine the type arguments, Java 8 will use the target type of an expression, i.e. the parameter type in case of a nested method invocation, the type of the variable that is initialized or assigned to, or the method’s return type in case of a return statement.

E.g. when writing, List<Number> list=Arrays.asList(1, 2, 3, 4);, Java 7 will infer the type List<Integer> for the right hand side by looking at the method’s arguments and generate an error while Java 8 will use the target type List<Number> to infer the constraint that the method arguments must be instances of Number which is the case. Therefore, it is legal in Java 8.

If you are interested in the formal details, you may study the "Java Language Specification, Chapter 18. Type Inference", especially §18.5.2. Invocation Type Inference, however, that’s not easy reading…

So what happens when you say Enum foo = null; tryCompile(EnumSet.of(foo));?

In Java 7 the type of the expression EnumSet.of(foo) will be inferred by looking at the type of the argument, foo which is the raw type Enum, hence an unchecked operation will be performed and the result type is the raw type EnumSet. This type implements the raw type Iterable and hence can be passed to tryCompile forming another unchecked operation.

In Java 8 the target type of EnumSet.of(foo) is the type of the first parameter of tryCompile which is Iterable<C extends Enum<C> & Another>, so without going too much into details, in Java 7 EnumSet.of will be treated as raw type invocation because it has a raw type argument, in Java 8 it will be treated as generic invocation because it has a generic target type. By treating it as as a generic invocation, the compiler will conclude that the type found (Enum) is not compatible to the required type C extends Enum<C> & Another. While you could get away with assigning the raw type Enum to C extends Enum<C> with an unchecked warning, it will considered to be incompatible with Another (without a type-cast).

You can indeed insert such a cast:

Enum foo = null;
tryCompile(EnumSet.of((Enum&Another)foo));

This compiles, of course not without an unchecked warning due to the assignment of Enum to C extends Enum<C>.

You can also dissolve the target type relationship so that the same steps as in Java 7 are performed:

Enum foo = null;
EnumSet set = EnumSet.of(foo);
tryCompile(set);

Here, raw types are used throughout the three lines so this compiles with unchecked warnings and the same ignorance about the implements Another constraint as in Java 7.

这篇关于为什么这是在Java7编译而不是在Java8?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆