Java. Види посилань на методи. Посилання на статичні методи. Посилання на методи екземпляру




Види посилань на методи. Посилання на статичні методи. Посилання на методи екземпляру


Зміст


Пошук на інших ресурсах:

1. Посилання на методи. Зв’язок лямбда-виразів з посиланнями на методи. Види посилань на методи

Якщо лямбда-вирази зв’язуються з функціональним інтерфейсом, то методи так само можуть бути зв’язані з функціональним інтерфейсом. Зв’язок методу з функціональним інтерфейсом здійснюється з допомогою посилання на метод.

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

У Java розрізняють 4 види посилань на методи:

  • посилання на статичні методи;
  • посилання на методи екземпляру;
  • посилання на конструктори;
  • посилання на узагальнені (шаблонні) методи.

 

2. Посилання на статичні методи
2.1. Загальна форма посилань на статичні методи. Розділювач ::

У мові Java можна оголошувати посилання на статичні методи. Посилання на статичний метод може бути передане в деякий метод і там використане для виклику статичного методу.

Загальна форма оголошення посилання на статичний метод наступна:

ім’я_класу::ім’я_методу

Розділювач :: впроваджений у версії JDK 8 для визначення посилання на метод.

Наприклад. Якщо в класі A оголошено статичний метод з іменем Method()

class A {
  // ...
  static return_type Method(parameters) {
    // ...
  }
}

то посилання на цей метод буде наступним

A::Method

 

2.2. Приклади посилань на статичні методи
2.2.1. Посилання на статичний метод обчислення об’єму кулі

Умова задачі. Розробити статичний метод, який отримує радіус сфери та обчислює об’єм сфери. Реалізувати передачу методу обчислення об’єму сфери в інший метод в якості параметру. Провести тестувальні обчислення.

Розв’язок. При рішенні даної задачі потрібно побудувати такі елементи в програмі:

  • функціональний інтерфейс ICalcFigure. В інтерфейсі оголошується єдиний метод Volume(), який отримує число типу double та повертає значення типу double;
  • клас CalcVolume(), в якому оголошується статичний метод SphereVolume(). Метод отримує радіус сфери (double) та повертає об’єм сфери (double);
  • клас FigureOperation, в якому оголошується метод Volume(). Цей метод отримує два параметри. Перший параметр є посиланням на інтерфейс ICalcFigure. Другий параметр – радіус кола. За посиланням на ICalcFigure буде передано статичний метод обчислення об’єму сфери.

Текст програми, що розв’язує дану задачу наступний.

// Посилання на статичний метод, що обчислює об'єм кулі
// 1. Функціональний інтерфейс, який визначає метод, що отримує параметром
//   число типу double і повертає результат типу double
interface ICalcFigure {
  double Volume(double radius);
}

// 2. Клас, в якому визначений статичний метод що визначає об'єм кулі
class CalcVolume {
  static double SphereVolume(double radius) {
    // повернути об'єм кулі
    return 4.0/3.0*Math.PI*radius*radius*radius;
  }
}

// 3. Клас, в якому визначений метод, що отримує посилання на функціональний інтерфейс
class FigureOperation {
  double Volume(ICalcFigure ref, double radius) {
    return ref.Volume(radius);
  }
}

// 4. Клас, що демонструє використання посилання на статичний метод
public class RefMethod {

  public static void main(String[] args) {
    // Обчислити об'єм кулі
    // 1. Оголосити екземпляр класу FigureOperation
    FigureOperation fo = new FigureOperation();

    // 2. Викликати метод Volume і передати йому посилання на статичний метод
    //    Обчислити об'єм кулі радіусом 5.0
    double volume = fo.Volume(CalcVolume::SphereVolume, 5.0);

    // 3. Вивести результат
    System.out.println("volume = " + volume);
  }
}

Результат виконання програми

volume = 523.5987755982989

 

2.2.2. Посилання на узагальнений статичний метод обертання масиву чисел

Умова задачі. Розробити узагальнений статичний метод ReverseNumbers, який реалізує обертання масиву чисел. Реалізувати передачу методу за посиланням в інший метод.

Розв’язок. Послідовність кроків, які потрібно виконати щоб розв’язати задачу:

  • оголосити узагальнений (шаблонний) функціональний інтерфейс IArrayFunction. В інтерфейсі повинен бути визначений метод Function(), що отримує параметром масив чисел та повертає масив чисел (оператором return);
  • оголосити клас ProcessArray з узагальненим статичним методом ProcessArrayReverse();
  • оголосити клас DemoRefMethods в якому реалізувати шаблонний метод DemoReverse(). У методі DemoReverse() використати посилання функціональний інтерфейс IArrayFunction для виклику методу Function();
  • в функції main() продемонструвати передачу статичного методу ProcessArrayReverse() в метод DemoReverse().

Текст програми, що розв’язує задачу, наступний

// Посилання на статичний метод
// 1. Узагальнений функціональний інтерфейс
interface IArrayFunction<T extends Number> {
  // Метод, що отримує масив типу T та повертає масив типу T
  T[] Function(T[] array);
}

// 2. Клас, що містить узагальнений статичний метод, який обертає масив чисел
class ProcessArray {
  public static <T extends Number> T[] ProcessArrayReverse(T[] array) {
    T tmp;
    for (int i=0; i<array.length/2; i++) {
      tmp = array[i];
      array[i] = array[array.length - 1 - i];
      array[array.length - 1 - i] = tmp;
    }
    return array;
  }
}

// 3. Клас, в якому визначений метод, що отримує посилання на функціональний інтерфейс
class DemoRefMethods {
  // Метод, що отримує посилання на функціональний інтерфейс IArrayFunction<T>
  <T extends Number> T[] DemoReverse(IArrayFunction<T> ref, T[] array) {
    return ref.Function(array);
  }
}

// 4. Клас, що демонструє використання посилання на статичний метод
public class RefMethod {

  public static void main(String[] args) {
    // Реалізувати обертання масиву цілих чисел
    // 1. Оголосити екземпляр класу DemoRefMethods
    DemoRefMethods obj = new DemoRefMethods();

    // 2. Тестувальний масив
    Integer AI[] = { 1, 3, 5, 8, 4, 2 };
    System.out.println("Array AI: ");
    for (int i=0; i<AI.length; i++)
      System.out.print(" " + AI[i]);
    System.out.println();

    // 3. Передати статичний метод  ProcessArray.ProcessArrayReverse() в
    //   метод obj.DemoReverse()
    Integer AI2[] = obj.DemoReverse(ProcessArray::ProcessArrayReverse, AI);

    // 4. Вивести результат - масив AI2
    System.out.println("Array AI2: ");
    for (int i=0; i<AI2.length; i++)
      System.out.print(" " + AI2[i]);
    System.out.println();
  }
}

Результат роботи програми

Array AI:
1 3 5 8 4 2
Array AI2:
2 4 8 5 3 1

 

3. Посилання на методи екземпляру
3.1. Загальна форма посилань на методи екземпляру

Щоб оголосити посилання на метод екземпляру використовується одна з двох загальних форм:

ім’я_екземпляру::ім’я_методу
ім’я_класу::ім’я_методу

У другому випадку метод екземпляру вказується разом з будь-яким об’єктом даного класу, а не тільки з вказаним об’єктом.

 

3.2. Приклади використання посилань на методи екземпляру
3.2.1. Посилання на методи, що виконують дії над комплексними числами

Умова задачі. Продемонструвати передачу в деякий метод класу методів додавання та віднімання комплексних чисел.

Розв’язок. Для розв’язку задачі у програмі потрібно розробити наступні елементи.

1. Клас Complex, який визначає комплексне число

class Complex {
  // Дійсна та уявна частини комплексного числа
  public double re;
  public double im;
  ...
}

2. Функціональний інтерфейс для оперування типом Complex

interface IFunction {
  // Метод, що оперує комплексними числами типу Complex
  Complex Function(Complex c1, Complex c2);
}

У функціональному інтерфейсі оголошується метод Function(). Сигнатура методу визначає отримання двох комплексних чисел та повернення комплексного числа. Така сигнатура може підійти для операцій додавання, віднімання, множення, ділення комплексних чисел та інших операцій.

3. Клас, що містить власне методи обробки комплексних чисел (додавання, віднімання).

class ProcessComplex {
  // Додавання комплексних чисел
  Complex Add(Complex c1, Complex c2) {
    ...
  }

  // Віднімання комплексних чисел
  Complex Sub(Complex c1, Complex c2) {
    ...
  }
}

4. Клас, що містить метод, який отримує посилання на метод екземпляру. У нашому випадку потрібно передавати методи Add() та Sub() екземпляру класу ProcessComplex.

class DemoRefMethods {
  // У цей метод буде передаватись посилання на методи Add() та Sub()
  // екземпляру класу ProcessComplex
  Complex RefMethod(IFunction ref, Complex c1, Complex c2) {
    ...
  }
}

5. Клас, що демонструє використання посилання на метод екземпляру.

// 5. Клас, що демонструє використання посилання на метод екземпляру
public class RefMethod {
  public static void main(String[] args) {
    ...
  }
}

Нижче наведено текст розв’язку задачі.

// Посилання на метод екземпляру
// 1. Клас, що визначає комплексне число
class Complex {
  // Дійсна та уявна частини комплексного числа
  public double re;
  public double im;

  // Конструктор
  public Complex(double _re, double _im) {
    re = _re;
    im = _im;
  }

  // Метод, що виводить комплексне число
  void Print(String text) {
    System.out.print(text);
    System.out.print(re);
    if (im>0)
      System.out.print("+");
    System.out.println(im);
  }
}

// 2. Функціональний інтерфейс, що оперує типом Complex
interface IFunction {
  // Метод, що оперує комплексними числами типу Complex
  Complex Function(Complex c1, Complex c2);
}

// 3. Клас, що містить методи обробки комплексних чисел
class ProcessComplex {
  // Додавання комплексних чисел
  Complex Add(Complex c1, Complex c2) {
    Complex c3 = new Complex(c1.re+c2.re, c1.im+c2.im);
    return c3;
  }

  // Віднімання комплексних чисел
  Complex Sub(Complex c1, Complex c2) {
    Complex c3 = new Complex(c1.re-c2.re, c1.im-c2.im);
    return c3;
  }
}

// 4. Клас, в якому визначений метод, що отримує посилання
//   на функціональний інтерфейс IFunction
class DemoRefMethods {
  // Метод, що отримує комплексні числа та посилання
  // на функціональний інтерфейс IFunction.
  // У цей метод буде передаватись посилання на метод екземпляру
  // класу ProcessComplex
  Complex RefMethod(IFunction ref, Complex c1, Complex c2) {
    Complex c3;
    c3 = ref.Function(c1, c2);
    return c3;
  }
}

// 5. Клас, що демонструє використання посилання на метод екземпляру
public class RefMethod {
  public static void main(String[] args) {
    // Реалізувати додавання та віднімання комплексних чисел
    // 1. Оголосити екземпляр класу ProcessComplex
    ProcessComplex obj1 = new ProcessComplex();

    // 2. Оголосити екземпляр класу DemoRefMethods
    DemoRefMethods objDemo = new DemoRefMethods();

    // 3. Створити комплексні числа для тестування
    Complex c1 = new Complex(5, -8);
    Complex c2 = new Complex(3, 4);
    c1.Print("c1 = ");
    c2.Print("c2 = ");

    // 4. Передати в метод objDemo.RefMethod() посилання на
    //    метод obj1.Add() та вивести результат
    Complex c3 = objDemo.RefMethod(obj1::Add, c1, c2);
    c3.Print("c3 = c1 + c2 = ");

    // 5. Продемонструвати віднімання комплексних чисел
    Complex c4;
    c4 = objDemo.RefMethod(obj1::Sub, c1, c2); // передати obj1::Sub
    c4.Print("c4 = c1 - c2 = ");
  }
}

Результат роботи програми

c1 = 5.0-8.0
c2 = 3.0+4.0
c3 = c1 + c2 = 8.0-4.0
c4 = c1 - c2 = 2.0-12.0

 

3.2.2. Посилання на узагальнений метод екземпляру

Умова задачі. Реалізувати клас, що містить наступні узагальнені (шаблонні) методи роботи з масивами:

  • обчислення суми елементів масиву;
  • обчислення середнього арифметичного елементів масиву.

Продемонструвати виклик методів обробки масивів використовуючи спосіб передачі посилання на метод екземпляру в якості параметра.

Розв’язок.

// Посилання на узагальнений метод екземпляру
// 1. Узагальнений (шаблонний) функціональний інтерфейс
interface IFuncArray<T extends Number> {
  // Метод, що отримує масив типу T і повертає тип double
  double FuncArray(T[] array);
}

// 2. Клас, що містить методи обробки масивів
class ProcessArray<T extends Number> {
  // Сума елементів масиву
  double Sum(T[] array) {
    double sum = 0;
    for (T value : array)
      sum += value.doubleValue();
    return sum;
  }

  // Середнє арифметичне елементів масиву
  double Avg(T[] array) {
    double avg = 0;
    for (T value : array)
      avg += value.doubleValue();
    return avg/array.length;
  }
}

// 3. Клас, що містить шаблонний метод,
// який отримує посилання на метод екземпляру
class ClassOperation {

  <T extends Number> double Operation(IFuncArray<T> ref, T[] array) {
    // викликати метод інтерфейсу IFuncArray
    double result = ref.FuncArray(array);
    return result;
  }
}

// 4. Клас, що демонструє використання посилання на метод екземпляру
public class RefMethod {

  public static void main(String[] args) {
    // 1. Оголосити екземпляр класу ClassOperation
    ClassOperation Op = new ClassOperation();

    // 2. Оголосити екземпляр класу ProcessArray<T>
    ProcessArray<Integer> Array = new ProcessArray<Integer>();

    // 3. Підготувати масив цілих чисел для обробки та вивести його
    Integer[] AI = { 2, 4, 8, -1, 3, -5 };
    System.out.print("AI = ");
    for (int t : AI)
      System.out.print(t + " ");
    System.out.println();

    // 4. Обчислити середнє арифметичне масиву AI,
    //     передаючи метод Array.Avg() в метод Op.Operation()
    double average = Op.Operation(Array::Avg, AI);
    System.out.println("average = " + average);

    // 5. Обчислити суму елементів масиву AI.
    //    Для цього потрібно передати метод Array.Sum() в Op.Operation()
    double sum = Op.Operation(Array::Sum, AI);
    System.out.println("sum = " + sum);
  }
}

Як видно з коду функції main(), передача методів Avg() та Sum() екземпляру Array здійснюється викликом єдиного методу Op.Operation()

...

double average = Op.Operation(Array::Avg, AI);

...

double sum = Op.Operation(Array::Sum, AI);

...

Різниця у викликах полягає в передачі першого параметру, яким є посилання на метод екземпляру. У першому випадку передається метод екземпляру, який обчислює середнє арифметичне, за наступним синтаксисом

Array::Avg

У другому випадку передається метод екземпляру

Array::Sum

який обчислює суму.

Після запуску на виконання програма видасть наступний результат

AI = 2 4 8 -1 3 -5
average = 1.8333333333333333
sum = 11.0

 


Зв’язані теми