Java 为什么我传递给Arrays.sort的方法引用需要是静态的?

Java 为什么我传递给Arrays.sort的方法引用需要是静态的?,java,methods,java-8,Java,Methods,Java 8,我是Java 8的新手。我试图创建一个示例,用于引用特定类型的任意对象的实例方法 我有一个只有一个字段名的person类,并试图对person类的firstName字段上的person对象数组进行排序 public class Person{ String firstName; public Person(String firstName) { super(); this.firstName = firstName; } pu

我是Java 8的新手。我试图创建一个示例,用于引用特定类型的任意对象的实例方法

我有一个只有一个字段名的person类,并试图对person类的firstName字段上的person对象数组进行排序

public class Person{

    String firstName;

    public Person(String firstName) {
        super();
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public int compareByFirstName(Person p1, Person p2) {
        return p1.getFirstName().compareTo(p2.getFirstName());
    }

}

public class TestInstanceMethorRefArbObjSample {

    public static void main(String[] args) {
        TestInstanceMethorRefArbObjSample obj=new TestInstanceMethorRefArbObjSample();
        obj.personSorting();
    }

    private void personSorting() {
        Person[] personArr= {new Person("Jinesh"),new Person("Sejal"),new Person("Ashish")};
        Arrays.sort(personArr,Person::compareByFirstName);
    }
}
但我在下面一行面临着编译问题

Arrays.sort(personArr,Person::compareByFirstName);
1.类型Person未定义适用的compareByFirstNameT,T 这里是testInstanceMethodoreBobjSample.java/InstaceMethoderBitaryObjectProject/src/com/methodreference/InstanceMethoderBitary/client行 11 Java问题 2.类型Person未定义适用的compareByFirstNameT,T 这里是testInstanceMethodoreBobjSample.java/InstaceMethoderBitaryObjectProject/src/com/methodreference/InstanceMethoderBitary/client行 11 Java问题

我只是想通过int compareto1,t2的实现;使用Person类的compareByFirstname

只要我将Person类的compareByFirstname方法更改为static,一切都正常工作


为什么我需要将compareByFirstname更改为静态方法以使其工作?

您使用的是一个方法引用,并且由于您将其编写为Person::compareByFirstname,因此它引用的是一个静态方法。如果要引用实例方法,则需要首先创建对象的实例,然后使用实例引用方法,如下所示:

Person p = new Person("");
p::compareByFirstName
但是,在您的案例中,这不是您想要做的,因为compare方法不是特定于实例的

通过将对象实例与另一个对象进行比较,可以更改比较方法,使其特定于实例

public int compareByFirstName(Person p2) {
    return this.getFirstName().compareTo(p2.getFirstName());
}

在这种情况下,当比较变得任意时,您可以使用方法引用Person::compareByFirstName。

您使用的是方法引用,并且由于您将其作为Person::compareByFirstName编写,因此它引用的是静态方法。如果要引用实例方法,则需要首先创建对象的实例,然后使用实例引用方法,如下所示:

Person p = new Person("");
p::compareByFirstName
但是,在您的案例中,这不是您想要做的,因为compare方法不是特定于实例的

通过将对象实例与另一个对象进行比较,可以更改比较方法,使其特定于实例

public int compareByFirstName(Person p2) {
    return this.getFirstName().compareTo(p2.getFirstName());
}
在这种情况下,当比较变得任意时,您可以使用方法reference Person::compareByFirstName。

一些背景知识

Arrays.sort需要一个比较器,在传递方法引用时,该比较器必须是一个接受两个适当类型实例的方法

创建这种方法有两种方法:

在任何接受两个适当类型参数的类中创建静态方法。这基本上就是你所做的。这样的方法不需要在特定的类中声明,您还可以使用其他一些类来提供这样的帮助器方法。 编译器将确保生成的Comparator实例调用引用的方法,并使用它想要比较的2个实例

在该类型的特定类中创建一个实例方法,该方法接受一个适当类型的参数。 编译器将确保生成的比较器实例调用第一个实例上的引用方法,并将第二个实例作为参数

你的具体情况

因为您的方法需要两个参数,所以它必须是静态的,否则它需要第三个实例来运行。要么将其声明为静态,要么删除一个参数并实现此参数与参数之间的比较。

一些背景信息

Arrays.sort需要一个比较器,在传递方法引用时,该比较器必须是一个接受两个适当类型实例的方法

创建这种方法有两种方法:

在任何接受两个适当类型参数的类中创建静态方法。这基本上就是你所做的。这样的方法不需要在特定的类中声明,您还可以使用其他一些类来提供这样的帮助器方法。 编译器将确保生成的Comparator实例调用引用的方法,并使用它想要比较的2个实例

在该类型的特定类中创建一个实例方法,该方法接受一个适当类型的参数。 编译器将确保生成的比较器实例调用第一个实例上的引用方法,并将第二个实例作为参数

你的具体情况


因为您的方法需要两个参数,所以它必须是静态的,否则它需要第三个实例来运行。要么将其声明为静态,要么删除一个参数并实现此参数与参数之间的比较。

因为没有静态,您的方法是一个实例方法,您将
s需要3个Person对象来调用它:接收方,即this、p1和p2。一个比较器是一个需要2个人的函数,而不是3个人。删除p1参数,并将其与p2进行比较,它将按预期工作。compareByFirstName不是静态的。方法定义需要一个比较器实例作为其第二个参数。@JBNiZet谢谢您的解释。我这边的一个问题是,为什么下面的代码作为String[]stringArray={Barbara,James,Mary,John,Patricia,Robert,Michael,Linda}工作;Arrays.sortstringArray,String::CompareTIgnoreCase;我看不出compareToIgoreCase被定义为静态方法。好吧,请再次阅读我的评论。compareToIgnoreCase不像方法那样接受2个参数。需要一个。因此,它将这个字符串与另一个字符串进行比较。因此,它可以作为比较器使用,因为它是一个包含两个字符串的函数:接收方字符串和作为参数传递的字符串。因为没有static,您的方法是一个实例方法,因此您需要3个Person对象来调用它:接收方,即this、p1和p2。一个比较器是一个需要2个人的函数,而不是3个人。删除p1参数,并将其与p2进行比较,它将按预期工作。compareByFirstName不是静态的。方法定义需要一个比较器实例作为其第二个参数。@JBNiZet谢谢您的解释。我这边的一个问题是,为什么下面的代码作为String[]stringArray={Barbara,James,Mary,John,Patricia,Robert,Michael,Linda}工作;Arrays.sortstringArray,String::CompareTIgnoreCase;我看不出compareToIgoreCase被定义为静态方法。好吧,请再次阅读我的评论。compareToIgnoreCase不像方法那样接受2个参数。需要一个。因此,它将这个字符串与另一个字符串进行比较。因此,它作为比较器是可以接受的,因为它是一个包含两个字符串的函数:接收方字符串和作为参数传递的字符串。而且,由于您将其编写为Person::compareByFirstName,它引用的是一个静态方法否,construct ClassName::method并不仅仅保留给静态方法。如果我们有一些FunctionInterface,它包含像handleSomeClass sc、Foo f、Bar b这样的方法,那么我们可以提供ClassName::nonStaticMethod作为它的实现。这类似于使用lambda SomeClass sc,Foo f,Bar b->sc.nonStaticMethodf,b;实现它;。因此,第一个参数将被视为调用非静态方法的实例。由于您已将其编写为Person::compareByFirstName,它引用的是一个静态方法否,因此construct ClassName::method不仅保留给静态方法。如果我们有一些FunctionInterface,它包含像handleSomeClass sc、Foo f、Bar b这样的方法,那么我们可以提供ClassName::nonStaticMethod作为它的实现。这类似于使用lambda SomeClass sc,Foo f,Bar b->sc.nonStaticMethodf,b;实现它;。因此,第一个参数将被视为调用非静态方法的实例。@感谢JBNizet和MaxVollmer的详细解释。为了完整起见:它也可以是一个包含两个参数的非静态方法,引用来自一个实例,与personInstance::CompareByFirstName类似,但首选的方法是使用Comparator.comparingPerson::getFirstName,它完全不需要额外的比较方法。@感谢JBNizet和MaxVollmer的详细解释。为了完整性:它也可以是一个包含两个参数的非静态方法,使用从实例获取的引用,如personInstance::CompareByFirstName,但首选方法是使用Comparator.comparingPerson::getFirstName,这样就完全不需要额外的比较方法。