29

在 Java 8 中有“方法参考”功能。其中一种是“对特定类型的任意对象的实例方法的引用”

http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html#type

有人可以解释在这种情况下“特定类型的任意对象”是什么意思吗?

4

7 回答 7

28

链接的 Oracle Doc 给出的示例是:

String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

的 lambda 等效于

 String::compareToIgnoreCase

将会

(String a, String b) -> a.compareToIgnoreCase(b)

Arrays.sort()方法正在寻找一个比较器作为其第二个参数(在此示例中)。传递String::compareToIgnoreCase创建一个比较器a.compareToIgnoreCase(b)作为比较方法的主体。然后你很好地问什么是aand b。compare 方法的第一个参数变为a第二个b。这些是字符串类型(特定类型)的任意对象。

不明白?

  • 确保您知道什么是比较器以及如何实现它
  • 了解什么是函数式接口以及它如何影响 Java 中的 lambda。
  • 比较器是一个功能接口,这就是方法引用成为比较器对象内部比较方法主体的原因。
  • 阅读下面的源代码以获取页面底部的另一个示例。

在来源阅读更多信息:http: //moandjiezana.com/blog/2014/understanding-method-references/

于 2014-09-03T00:28:22.750 回答
19

它是对某种类型的实例方法的引用。在示例的情况下,compareToIgnoreCase是来自 的方法String。程序知道它可以在 的实例上调用此方法String,因此它可以获取该类型的引用和任何对象,并保证该方法存在。

我会将其与Method类进行比较,因为它们引用了一个方法,并且可以在某种类型的任意实例上调用。

例如,它可以使用两个String对象并调用compareToIgnoreCase一个对象并将另一个对象用作参数来匹配方法签名。这允许它获取数组并根据数组类型的任何方法对其进行排序,而不是需要比较器实例来执行此操作。

这是未单击问题中链接的任何人的示例:

String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda", "George" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
于 2014-05-08T06:08:17.677 回答
5

请参阅下面的代码示例,它解释了https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html中描述的“引用特定类型的任意对象的实例方法”类别

import java.util.Arrays;

class Person{
    String name;

    //constructor
    public Person(String name){
        this.name = name;
    }

    //instance method 1
    public int personInstanceMethod1(Person person){
        return this.name.compareTo(person.name);
    }

    //instance method 2
    public int personInstanceMethod2(Person person1, Person person2){
        return person1.name.compareTo(person2.name);
    }
}

class Test {
    public static void main (String[] args) throws Exception{
        Person[] personArray = {new Person("A"), new Person("B")};
    
        // Scenario 1 : Getting compiled successfully
        Arrays.sort(personArray, Person::personInstanceMethod1);
    
        // Scenario 2 : Compile failure
        Arrays.sort(personArray, Person::personInstanceMethod2);
    
        // Scenario 3 : Getting compiled successfully. 
        Person personInstance = new Person("C");
        Arrays.sort(personArray, personInstance::personInstanceMethod2);

        // Scenario 4 : Getting compiled successfully. As the same way as "Scenario 1"
        String[] stringArray = { "Barbara", "James", "Mary", "John",
                                "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, String::compareToIgnoreCase);
    }

}

场景 1 和场景 4 描述了https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html中描述的“对特定类型的任意对象的实例方法的引用”类别

如果方法参数采用与元素的实例类型相同的实例类型中的变量,则可以使用 Type.( Person::personInstanceMethod1)调用该实例方法

将“ ”类中的“ ”实例方法与personInstanceMethod1“ ”类中的“”实例方法进行比较(https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareToIgnoreCase-java.lang .String- ) 来查看相似度。两者都采用具有相同类型的单个参数。PersoncompareToIgnoreCaseString

比较方案 1 和方案 2 以查看差异。

于 2018-08-11T09:13:02.250 回答
4

我认为这是通过在文档中使用未定义的术语而使理解概念变得更加困难的情况。

请记住,作为 lambda 类型的方法引用实现了一个函数式接口,只要您可以在程序中引用它,任何与接口签名匹配的方法都可以使用。

四种方法引用中,代表访问(引用)方法所需的不同方式。三者的语法非常简单:如果是静态方法,则在 :: 运算符之前使用类名,如果是对象中的实例方法,则通常使用对象的引用变量,或者如果它是您使用 ClassName::new 的构造函数。

第四种是您要调用的方法,该方法是传递给函数的参数的实例方法。使用 lambda 没有问题,因为您可以引用参数变量,如下所示:

(String someString) -> someString.toLowerCase();

但是,由于方法引用中没有显式参数变量,因此使用的语法是:

String::toLowerCase;

编译器采用“特定类型”(String)来引用“任意对象”(参数中传递的对象)中包含的功能方法(toLowerCase)。使用术语“任意对象”是因为每次执行方法引用时传入参数的实际对象可能不同。

于 2021-01-11T00:34:01.150 回答
0

让我换一种说法。因此,如果您的 lambda 表达式如下所示:

(<ContainingType arg>, <otherArgs>) -> arg.instanceMethod(<otherArgs>)

它可以替换为方法参考,例如

ContainingType::instanceMethod

所以,对于 lambda 表达式

(String a, String b) -> a.compareToIgnoreCase(b)

它可以替换为方法参考,例如

String::compareToIgnoreCase

在这里,特定类型是 String 的 ContainingType。它的一个实例(String)是任意的,因为我们还没有声明或初始化它,这些只是这里的参数。因此,在这种情况下,“特定类型的任意对象”是“字符串类型的任意对象

于 2020-03-06T14:13:17.537 回答
0

每个人都在使用相同的 String::compareToIgnoreCase 示例。为了更好地理解这一点,请考虑以下所有引用类型的示例:

public class Test {
    public static void main(String[] args) {

        Consumer<String> con = str-> StringPrinter.staticPrint(str);
        //using static method ref
        con = StringPrinter::staticPrint; 

        StringPrinter prtr = new StringPrinter();
        con = str-> prtr.instancePrint(str);
        //using instance method ref
        con = prtr::instancePrint;
        

        BiConsumer<StringPrinter, String> biCon = (pp,str)->pp.instancePrint(str);
        //using instance method ref of an arbitrary object of particular type
        biCon = Printer::instancePrint; //notice stringPrinter object of Printer type
        
        //constructor ref
        Supplier<StringPrinter> sup = StringPrinter::new; 
    }
}


interface Printer {
    public void instancePrint(String msg);
}

class StringPrinter implements Printer{
    public static void staticPrint(String msg) {
        System.out.println("Static: " + msg);
    }

    public void instancePrint(String msg) {
        System.out.println("Instance: " + msg);
    }
}
于 2021-02-25T14:02:57.080 回答
-1

在这种情况下,有一个特定类型(String)的对象数组,并且数组中的任何随机对象都可以调用其实例方法。这种方法允许类引用它的实例方法,就好像它是一个静态方法一样。

此外,这种方法仅适用于像 String 这样的 java 内置类,但不适用于用户定义的类。在用户定义类的情况下,实例方法只能由其对象引用。

于 2018-04-30T13:05:11.880 回答