什么是#34;特定类型的任意对象"在java 8中意味着什么?

时间:2014-05-08 05:23:33

标签: java java-8 method-reference

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

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

有人可以解释“特定类型的任意对象”在该上下文中的含义吗?

7 个答案:

答案 0 :(得分:19)

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)作为比较方法的正文。然后你会问好ab是什么。比较方法的第一个参数变为a,第二个参数变为b。这些是String类型(特定类型)的任意对象。

不明白?

  • 确保您知道比较器是什么以及如何实施
  • 了解功能界面是什么以及它如何影响Java中的lambdas。
  • 比较器是一个功能接口,这就是方法引用成为比较器对象内部compare方法主体的原因。
  • 请阅读页面底部的来源以获取其他示例

从源头阅读更多内容: http://moandjiezana.com/blog/2014/understanding-method-references/

答案 1 :(得分:12)

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

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

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

以下是没有点击问题链接的人的例子:

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

答案 2 :(得分:2)

请参见下面的代码示例,其中解释了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

中描述的“对特定类型任意对象的实例方法的引用”

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

调用该实例方法。

将“ Person”类中的“ personInstanceMethod1”实例方法与“ String”类(https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareToIgnoreCase-java.lang.String-)中的“ compareToIgnoreCase”实例方法进行比较,以了解相似之处。两者都使用具有相同类型的单个参数。

比较方案1和方案2,以查看区别。

答案 3 :(得分:2)

我认为在这种情况下,在文档中使用未定义的术语会使理解概念变得更加困难。

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

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

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

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

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

String::toLowerCase;

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

答案 4 :(得分:0)

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

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

它可以替换为方法引用,例如

ContainingType::instanceMethod

所以,对于lambda表达式

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

它可以替换为方法引用,例如

String::compareToIgnoreCase

在这里,特殊类型是ContainingType,它是String 。而且,它的实例(字符串)是任意的,因为我们尚未声明或初始化它,而这些只是此处的参数。因此,“ 特定类型的任意对象”在此上下文中为“ String类型的任意对象

答案 5 :(得分: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);
    }
}

答案 6 :(得分:-1)

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

此方法也适用于类似于String的内置类,但不适用于用户定义的类。在用户定义的类的情况下,实例方法只能由其对象引用。