【问题标题】:What does "an Arbitrary Object of a Particular Type" mean in java 8?java 8中的“特定类型的任意对象”是什么意思?
【发布时间】:2014-05-08 05:23:32
【问题描述】:

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

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

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

【问题讨论】:

  • 特定类型 = 字符串、整数、MyClass 或... 任意对象 = 该类型的某个实例,例如,对于字符串类型,“abf”或“另一个字符串"。

标签: java java-8 method-reference


【解决方案1】:

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

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

λ 等价于

 String::compareToIgnoreCase

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

Arrays.sort() 方法正在寻找一个比较器作为它的第二个参数(在这个例子中)。传递String::compareToIgnoreCase 创建一个比较器,其中a.compareToIgnoreCase(b) 作为比较方法的主体。然后你问清楚ab 是什么。 compare 方法的第一个参数变为a,第二个参数变为b。这些是 String 类型(特定类型)的任意对象。

不明白?

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

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

【讨论】:

  • 感谢您的回答和链接,它帮助了我:)
  • 很好的解释!
【解决方案2】:

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

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

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

以下是未点击问题中链接的任何人的示例:

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

【讨论】:

  • 说得好,伙计。
【解决方案3】:

请看下面的代码示例,它解释了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 中描述的“对特定类型的任意对象的实例方法的引用”类别

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

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

比较方案 1 和方案 2 以了解差异。

【讨论】:

  • 干得好,既创建了自己的示例类和方法,又说明了三种不同场景之间的关键区别。
  • Viraj 解释得非常好!!
  • 我一直在摸不着头脑,为什么可以在不引用特定 String 对象的情况下将 String::concat 作为比较器传递。因此,引用特定类型的任意对象的实例方法的语法是“ContainingType::methodName”。所以,为了清楚起见,methodname 的参数类型必须与 ContainingType 的类型完全匹配,对吗?所以如果你定义了一个类 Person2 与类 Person 具有完全相同的“实例方法 1”,那么 Arrays.sort(personArray, Person2::personInstanceMethod1) 将无法编译?
【解决方案4】:

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

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

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

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

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

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

String::toLowerCase;

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

【讨论】:

    【解决方案5】:

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

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

    可以换成方法引用如

    ContainingType::instanceMethod
    

    所以,对于 lambda 表达式

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

    可以换成方法引用如

    String::compareToIgnoreCase
    

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

    【讨论】:

      【解决方案6】:

      每个人都在使用相同的 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);
          }
      }
      

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-09
          • 2013-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-07
          相关资源
          最近更新 更多