在Java 8中,有“方法参考”功能。 其中一种是“引用特定类型的任意对象的实例方法”
http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html#type
有人可以解释“特定类型的任意对象”在该上下文中的含义吗?
答案 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)
作为比较方法的正文。然后你会问好a
和b
是什么。比较方法的第一个参数变为a
,第二个参数变为b
。这些是String类型(特定类型)的任意对象。
不明白?
从源头阅读更多内容: 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的内置类,但不适用于用户定义的类。在用户定义的类的情况下,实例方法只能由其对象引用。