Что означает произвольный объект определенного типа в Java 8?

В Java 8 есть функция "Справочник по методам". Одним из таких является «Ссылка на метод экземпляра произвольного объекта определенного типа».

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

Может кто-нибудь объяснить, что означает «произвольный объект определенного типа» в этом контексте?


person Roman Ivanov    schedule 08.05.2014    source источник
comment
Определенного типа = String, или Integer, или MyClass, или... Произвольный объект = некоторый экземпляр типа, например, для типа String, abf или другой строки.   -  person assylias    schedule 08.05.2014


Ответы (7)


Это ссылка на метод экземпляра из некоторого типа. В примере compareToIgnoreCase — это метод из String. Программа знает, что она может вызвать этот метод для экземпляра String, поэтому она может взять ссылку и любой объект этого типа и гарантировать, что метод существует.

Я бы сравнил это с классом Method в том смысле, что они ссылаются на метод и могут быть вызваны для произвольного экземпляра некоторого типа.

Например, он может использовать два объекта String и вызывать compareToIgnoreCase для одного, а другой использовать в качестве аргумента для соответствия сигнатуре метода. Это позволяет ему брать массив и сортировать его на основе любого метода типа массива вместо того, чтобы требовать, чтобы экземпляр компаратора делал это вместо этого.

А вот пример для тех, кто не нажал на ссылку в вопросе:

String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda", "George" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
person Andrew Vitkus    schedule 08.05.2014
comment
Хорошо объяснил дружище. - person Rakesh Yadav; 08.08.2018

Пример, приведенный из ссылки 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) в качестве тела метода сравнения. Затем вы хорошо спросите, что такое a и b. Первым аргументом метода сравнения становится a, а вторым — b. Это произвольные объекты типа String (конкретный тип).

Не понимаю?

  • Убедитесь, что вы знаете, что такое компаратор и как его реализовать.
  • Узнайте, что такое функциональный интерфейс и как он влияет на лямбда-выражения в Java.
  • Компаратор — это функциональный интерфейс, поэтому ссылка на метод становится телом метода сравнения внутри объекта компаратора.
  • Прочтите источник ниже для другого примера в нижней части страницы.

Подробнее читайте в источнике: http://moandjiezana.com/blog/2014/understanding-method-references/< /а>

person Jawad    schedule 03.09.2014
comment
спасибо за ответ и ссылку, мне помогло :) - person Tomasz Mularczyk; 14.07.2016
comment
Отличное объяснение! - person Varun Ajay Gupta; 19.05.2017

См. приведенный ниже пример кода, объясняющий категорию «Ссылка на метод экземпляра произвольного объекта определенного типа», описанную в 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» в классе «Person» с методом экземпляра «compareToIgnoreCase» в классе «String» (https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareToIgnoreCase-java.lang.String-), чтобы увидеть сходство. Оба принимают один параметр с одним и тем же типом.

Сравните сценарий 1 и сценарий 2, чтобы увидеть разницу.

person Viraj    schedule 11.08.2018
comment
Хорошая работа, как создание собственного примера класса и методов, так и иллюстрация существенных различий между тремя разными сценариями. - person JL_SO; 03.01.2019
comment
очень хорошо объяснил Вирадж !! - person Mayur; 17.01.2019
comment
Я долго ломал голову, почему можно передать String::concat в качестве компаратора, не ссылаясь на конкретный объект String. Таким образом, синтаксис ссылки на метод экземпляра произвольного объекта определенного типа — ContainingType::methodName. Итак, для ясности, тип параметров имени метода должен точно совпадать с типом ContainingType, верно? Итак, если вы определили класс Person2 с тем же методом экземпляра 1, что и класс Person, то Arrays.sort(personArray, Person2::personInstanceMethod1) не скомпилируется? - person Nicholas Cousar; 22.07.2021

Я думаю, что это тот случай, когда понимание концепции затруднено из-за использования неопределенной терминологии в документации.

Имейте в виду, что ссылка на метод, как тип лямбды, реализует функциональный интерфейс, и что ЛЮБОЙ метод, который соответствует сигнатуре интерфейса, может использоваться, если вы можете ссылаться на него в своей программе.

Из четырех видов ссылок на методы, которые представляют различные способы доступа (ссылки) к методу. Синтаксис трех довольно прост: если это статический метод, вы используете имя класса перед оператором ::, если это метод экземпляра в объекте, то вы обычно используете ссылочную переменную для объекта, или если это конструктор вы используете ClassName::new.

Четвертый тип — это когда вы хотите вызвать метод, который является методом экземпляра параметра, переданного в функцию. С лямбдой проблем нет, потому что вы можете ссылаться на переменную параметра, например:

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

Однако, поскольку в ссылке на метод нет явной переменной параметра, вместо этого используется следующий синтаксис:

String::toLowerCase;

Компилятор использует конкретный тип (String) для ссылки на функциональный метод (toLowerCase), содержащийся в произвольном объекте (объект, переданный в параметре). Термин «произвольный объект» используется потому, что фактический объект, передаваемый в параметре, может быть другим при каждом выполнении ссылки на метод.

person Steve McCollom    schedule 11.01.2021

Позвольте мне сказать это по-другому. Итак, если ваше лямбда-выражение выглядит следующим образом:

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

Его можно заменить ссылкой на метод, такой как

ContainingType::instanceMethod

Итак, для лямбда-выражения

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

Его можно заменить ссылкой на метод, такой как

String::compareToIgnoreCase

Здесь конкретным типом является ContainingType, то есть String. И его экземпляр (String) является произвольным, так как мы еще не объявили и не инициализировали его, и это просто аргументы здесь. И, следовательно, «произвольный объект определенного типа» в данном контексте — это «произвольный объект типа String».

person Laks    schedule 06.03.2020

Все используют один и тот же пример 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);
    }
}
person onkar ruikar    schedule 25.02.2021

В этом случае существует массив объектов определенного типа (String), и любой случайный объект в массиве может вызывать свой метод экземпляра. Этот подход позволяет классу ссылаться на свой метод экземпляра, как если бы это был статический метод.

Также этот подход работает только для встроенного класса java, такого как String, но не для пользовательского класса. В случае определяемого пользователем класса на метод экземпляра может ссылаться только его объект.

person Raj Gopal Bhallamudi    schedule 30.04.2018