当一个方法具有泛型参数而另一个方法具有泛型lambda时,Java方法是不明确的

当一个方法具有泛型参数而另一个方法具有泛型lambda时,Java方法是不明确的,java,generics,lambda,Java,Generics,Lambda,考虑以下几点: public void run() { run(o -> {}); } //replace CharSequence with whatever except Object public <E extends CharSequence> void run(E e) { } public <E extends CharSequence> void run(Consumer<E>

考虑以下几点:

    public void run() {
        run(o -> {});
    }

    //replace CharSequence with whatever except Object
    public <E extends CharSequence> void run(E e) {
    }
    public <E extends CharSequence> void run(Consumer<E> e){
    }
注: 用java.lang.Object以外的任何东西替换CharSequence将产生相同的问题

另请注意: 即使这两个泛型不同并且彼此不相关,也没有关系!只要它们不是java.lang.Object

因此,这将不会:

    public void run() {
        run(o -> {});
    }
    public <E extends ArrayList> void run(E e) {
    }
    public <E extends String> void run(Consumer<E> e){
    }

现在猜猜看,但是所有东西都有一个toString方法,通过让编译器隐式地调用它,隐式地将东西转换为字符串是很常见的。String当然是CharSequence的继承者。因此,编译器可能会抱怨它无法决定:

run((CharSequence)(o -> {}).toString());


现在猜猜看,但是所有东西都有一个toString方法,通过让编译器隐式地调用它,隐式地将东西转换为字符串是很常见的。String当然是CharSequence的继承者。因此,编译器可能会抱怨它无法决定:

run((CharSequence)(o -> {}).toString());

也不能将CharSequence声明为lambda

看一看

interface WeirdCharSequence extends CharSequence {
  default int length() { return 0; }
  default char charAt(int index) { return 0; }
  default CharSequence subSequence(int start, int end) { return null; }

  void accept(CharSequence i); 
}
证明它可以

WeirdCharSequence charSequence = o -> {};
run(charSequence);
o->{}可能意味着很多事情,并且没有足够的上下文来理解lambda到底代表什么。您可以通过显式声明所需的类型来帮助编译器

this.<CharSequence>run(o -> {});
也不能将CharSequence声明为lambda

看一看

interface WeirdCharSequence extends CharSequence {
  default int length() { return 0; }
  default char charAt(int index) { return 0; }
  default CharSequence subSequence(int start, int end) { return null; }

  void accept(CharSequence i); 
}
证明它可以

WeirdCharSequence charSequence = o -> {};
run(charSequence);
o->{}可能意味着很多事情,并且没有足够的上下文来理解lambda到底代表什么。您可以通过显式声明所需的类型来帮助编译器

this.<CharSequence>run(o -> {});

经过一些调查,我意识到这是java语言中的一个bug

试试你自己:

    public void run() {
        run(o -> {});
    }
    public <E extends Class> void run(E e) {
    }
    public void run(Consumer e) {
    }
或:

即使这两个函数的参数彼此不相关。不知何故,java编译器认为它们是


总之,使用泛型参数创建方法将使该方法作为接受lambda表达式的方法有效。

经过一些调查,我意识到这是java语言中的一个缺陷

试试你自己:

    public void run() {
        run(o -> {});
    }
    public <E extends Class> void run(E e) {
    }
    public void run(Consumer e) {
    }
或:

即使这两个函数的参数彼此不相关。不知何故,java编译器认为它们是


总之,使用泛型参数创建方法将使该方法作为接受lambda表达式的方法有效。

相同的行为语句包括:在参数赋值中不强制转换,仍然使用泛型类型,保留相同的名称和相同的classI获得不同的编译错误,此表达式的目标类型必须是函数接口。Java 11.0.6非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法,而不会出现编译时错误,那么一个方法比另一个方法更具体。根据这个定义,这两个方法都不具体,所以它们都是不明确的。是的,我也知道了。即使传递的参数显然是lambda,并且两个方法中只有一个是lambda-这是不正确的。他们都不是羔羊。你对兰博达斯有一个基本的误解。lambda创建接口的实例,因此它可以在任何需要普通功能接口的地方使用。Consumer是一个接口,E也可以是一个接口。相同的行为语句包括:参数赋值中没有强制转换,仍然使用泛型类型,保留相同的名称和相同的classI获取不同的编译错误,该表达式的目标类型必须是函数接口。Java 11.0.6非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法,而不会出现编译时错误,那么一个方法比另一个方法更具体。根据这个定义,这两个方法都不具体,所以它们都是不明确的。是的,我也知道了。即使传递的参数显然是lambda,并且两个方法中只有一个是lambda-这是不正确的。他们都不是羔羊。你对兰博达斯有一个基本的误解。lambda创建接口的实例,因此它可以在任何需要普通功能接口的地方使用。Consumer是一个接口,E也可以是一个接口。如果参数是一个异常/数字或基本上是其他什么呢?我写CharSequence作为一个例子,实际上,我面临着throwable的问题编译器隐式地为您调用它-编译器不会隐式地为您调用toString。如果您考虑的是System.out.printlnmyObject,那么toString调用是在println方法中显式实现的。这个答案完全错误。编译器仅在字符串串联中隐式调用toString。如果参数是异常/数字或基本上是其他任何东西,该怎么办?我写CharSequence作为一个例子,实际上,我面临着throwable的问题编译器隐式地为您调用它-编译器不会隐式地为您调用toString。如果您正在考虑System.out.PrintLNMObject,则toString
调用是在println方法中显式实现的。这个答案完全错误。编译器仅在字符串连接中隐式调用toString。您将我的语句理解为lol。我的意思是您无法创建对CharSequence的lambda转换。无论如何,CharSequence只是一个例子。进一步的问题,this.runo->{};帮助,为什么不使用这个.runconsumera->{};?lambda可以在任何需要普通接口的地方使用,只要它是函数式的。问题是,即使你用任何类(比如字符串)替换CharSequence,它也无法修复issue@Naman我认为两者都应该有所帮助,因为它们都清楚地说明了什么是Consumer=o->{};runconsumer;,我只是不喜欢卡斯特你把我的话字面上理解为lol。我的意思是你不能为CharSequence创建lambda cast。无论如何,CharSequence只是一个例子。进一步的问题,this.runo->{};帮助,为什么不使用这个.runconsumera->{};?lambda可以在任何需要普通接口的地方使用,只要它是函数式的。问题是,即使你用任何类(比如字符串)替换CharSequence,它也无法修复issue@Naman我认为两者都应该有所帮助,因为它们都清楚地说明了什么是Consumer=o->{};runconsumer;,我只是不喜欢石膏
    public void run() {
        run(o -> {});
    }
    public <E extends Class> void run(E e) {
    }
    public <E extends Integer> void run(Consumer<E> e) {
    }