为什么在这种情况下,单参数实例方法对 BiConsumer 的类型推断不同?
Why is the type inference to a BiConsumer for a one-argument instance method different in this case?
我正在尝试编译这段代码:
import java.util.Collection;
import java.util.function.BiConsumer;
import de.hybris.platform.servicelayer.exceptions.ModelSavingException;
import de.hybris.platform.servicelayer.model.ModelService;
public class Foo {
public static interface ModelService2 {
public abstract void saveAll(Object[] paramArrayOfObject) throws ModelSavingException;
public abstract void saveAll(Collection<? extends Object> paramCollection) throws ModelSavingException;
public abstract void saveAll() throws ModelSavingException;
}
public void bar() {
final BiConsumer<ModelService2, Collection<? extends Object>> consumer1 = ModelService2::saveAll;
final BiConsumer<ModelService, Collection<? extends Object>> consumer2 = ModelService::saveAll;
}
}
接口ModelService
由SAP hybris平台定义。 ModelService2
只是复制了在 hybris 平台的接口中定义的名称为 saveAll
的重载方法。
编译上面的代码时出现以下编译器错误:
1. ERROR in src\Foo.java (at line 17)
final BiConsumer<ModelService, Collection<? extends Object>> consumer2 = ModelService::saveAll;
^^^^^^^^^^^^^^^^^^^^^
Cannot make a static reference to the non-static method saveAll(Object[]) from the type ModelService
为什么编译器对 ModelService
进行不同的类型推断,而我能够发现的唯一区别是每个接口所在的位置?
在这种情况下,我使用 javac 1.8.0_77 进行编译。例如,Eclipse 不会报告上述代码的任何错误。
编辑:
相对类似的错误也发生在以下变量声明中:
final Consumer<ModelService2> consumer3 = ModelService2::saveAll;
final Consumer<ModelService> consumer4 = ModelService::saveAll;
本例编译错误为:
1. ERROR in src\Foo.java (at line 19)
final Consumer<ModelService> consumer4 = ModelService::saveAll;
^^^^^^^^^^^^^^^^^^^^^
Cannot make a static reference to the non-static method saveAll(Object[]) from the type ModelService
EDIT2:
编译参数是:
'-noExit'
'-classpath'
'<classpath>'
'-sourcepath'
'<source path>'
'-d'
'<path>\classes'
'-encoding'
'UTF8'
编辑 3:
这些是 Eclipse class 文件查看器显示的 3 种方法的定义:
// Method descriptor #43 (Ljava/util/Collection;)V
// Signature: (Ljava/util/Collection<+Ljava/lang/Object;>;)V
public abstract void saveAll(java.util.Collection arg0) throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
// Method descriptor #45 ([Ljava/lang/Object;)V
public abstract void saveAll(java.lang.Object... arg0) throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
// Method descriptor #10 ()V
public abstract void saveAll() throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
解析:
问题是由 java v4.4.1 的 eclipse 编译器引起的。它至少从 v4.5.1 开始是固定的。一开始命令行编译的时候没注意到是hybris平台编译代码用的eclipse编译器
方法重载、可变参数和类型推断之间的交互可能是 Java 类型检查中最复杂和最棘手的部分。这是一个错误经常出现的领域,不同编译器之间经常存在差异。
我的猜测如下:
ModelService
有一个可变参数 saveAll
。因为带有两个对象参数的 saveAll
是对此类对象的有效方法调用。如果该方法是静态的,则用一个 ModelService
和一个 Collection
调用它是有效的,因此方法引用表达式对 BiConsumer<ModelService2, Collection<? extends Object>>
类型有效。
由于编译器错误,编译器注意到该方法不是静态的,因此推断方法引用表达式在这里无效。这会产生编译错误。
另一方面,ModelService2.saveAll
不是可变参数,不能用一个 ModelService
和一个 Collection
调用。因此,编译器在尝试这种可能性时不会陷入此错误。
当我尝试使用 Eclipse 4.5.2 和 javac 1.8 编写此代码时。0_77 您为我编译的所有示例。我不知道为什么你会得到不同的结果。
我正在尝试编译这段代码:
import java.util.Collection;
import java.util.function.BiConsumer;
import de.hybris.platform.servicelayer.exceptions.ModelSavingException;
import de.hybris.platform.servicelayer.model.ModelService;
public class Foo {
public static interface ModelService2 {
public abstract void saveAll(Object[] paramArrayOfObject) throws ModelSavingException;
public abstract void saveAll(Collection<? extends Object> paramCollection) throws ModelSavingException;
public abstract void saveAll() throws ModelSavingException;
}
public void bar() {
final BiConsumer<ModelService2, Collection<? extends Object>> consumer1 = ModelService2::saveAll;
final BiConsumer<ModelService, Collection<? extends Object>> consumer2 = ModelService::saveAll;
}
}
接口ModelService
由SAP hybris平台定义。 ModelService2
只是复制了在 hybris 平台的接口中定义的名称为 saveAll
的重载方法。
编译上面的代码时出现以下编译器错误:
1. ERROR in src\Foo.java (at line 17)
final BiConsumer<ModelService, Collection<? extends Object>> consumer2 = ModelService::saveAll;
^^^^^^^^^^^^^^^^^^^^^
Cannot make a static reference to the non-static method saveAll(Object[]) from the type ModelService
为什么编译器对 ModelService
进行不同的类型推断,而我能够发现的唯一区别是每个接口所在的位置?
在这种情况下,我使用 javac 1.8.0_77 进行编译。例如,Eclipse 不会报告上述代码的任何错误。
编辑:
相对类似的错误也发生在以下变量声明中:
final Consumer<ModelService2> consumer3 = ModelService2::saveAll;
final Consumer<ModelService> consumer4 = ModelService::saveAll;
本例编译错误为:
1. ERROR in src\Foo.java (at line 19)
final Consumer<ModelService> consumer4 = ModelService::saveAll;
^^^^^^^^^^^^^^^^^^^^^
Cannot make a static reference to the non-static method saveAll(Object[]) from the type ModelService
EDIT2:
编译参数是:
'-noExit'
'-classpath'
'<classpath>'
'-sourcepath'
'<source path>'
'-d'
'<path>\classes'
'-encoding'
'UTF8'
编辑 3:
这些是 Eclipse class 文件查看器显示的 3 种方法的定义:
// Method descriptor #43 (Ljava/util/Collection;)V
// Signature: (Ljava/util/Collection<+Ljava/lang/Object;>;)V
public abstract void saveAll(java.util.Collection arg0) throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
// Method descriptor #45 ([Ljava/lang/Object;)V
public abstract void saveAll(java.lang.Object... arg0) throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
// Method descriptor #10 ()V
public abstract void saveAll() throws de.hybris.platform.servicelayer.exceptions.ModelSavingException;
解析:
问题是由 java v4.4.1 的 eclipse 编译器引起的。它至少从 v4.5.1 开始是固定的。一开始命令行编译的时候没注意到是hybris平台编译代码用的eclipse编译器
方法重载、可变参数和类型推断之间的交互可能是 Java 类型检查中最复杂和最棘手的部分。这是一个错误经常出现的领域,不同编译器之间经常存在差异。
我的猜测如下:
ModelService
有一个可变参数 saveAll
。因为带有两个对象参数的 saveAll
是对此类对象的有效方法调用。如果该方法是静态的,则用一个 ModelService
和一个 Collection
调用它是有效的,因此方法引用表达式对 BiConsumer<ModelService2, Collection<? extends Object>>
类型有效。
由于编译器错误,编译器注意到该方法不是静态的,因此推断方法引用表达式在这里无效。这会产生编译错误。
另一方面,ModelService2.saveAll
不是可变参数,不能用一个 ModelService
和一个 Collection
调用。因此,编译器在尝试这种可能性时不会陷入此错误。
当我尝试使用 Eclipse 4.5.2 和 javac 1.8 编写此代码时。0_77 您为我编译的所有示例。我不知道为什么你会得到不同的结果。