Ссылки на методы. Виды ссылок на методы. Ссылка на статический метод. Ссылка на метод экземпляра
Содержание
- 1. Ссылки на методы. Связь лямбда-выражений со ссылками на методы. Виды ссылок на методы
- 2. Ссылка на статические методы
- 3. Ссылка на методы экземпляра
- Связанные темы
Поиск на других ресурсах:
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
⇑
Связанные темы
⇑