На этом шаге мы поговорим про захват подстановок
Рассмотрим следующий метод, меняющий местами составные элементы пары:
public static void swap(Pair<?> p) {...}
Подстановка не является переменной типа, поэтому знак ? нельзя указывать вместо типа. Иными словами, следующий код не скомпилируется:
public static void swap(Pair<?> p) { ? t = p.getFirst(); p.setFirst(p.getSecond()); p.setSecond(t); }
В связи с этим возникает затруднение, поскольку при перестановке нужно временно запоминать первый составной элемент пары. Для решения данной проблемы можно воспользоваться следующим способом - написать вспомогательный метод, как это написано ниже:
public static <T> void swapHelper(Pair<T> p) { T t = p.getFirts(); p.setFirst(p.getSecond()); p.setSecond(t); }
Тогда метод swap() выглядит следующим образом:
public static void swap(Pair<?> p) { swapHelper(p); }
В данном случае параметр обобщенного типа T захватывает подстановку во вспомогательном методе swapHelper(). Неизвестно, какой именно тип обозначает подстановка, но это совершенно определенный тип. Поэтому определение <T>swapHelper() имеет конкретный смысл, когда обобщение T обозначает этот тип.
Ниже приведем пример использования подстановочных типов.
import java.util.Date; import java.util.GregorianCalendar; /** * Класс, инкапсулирующий информацию о сотруднике * */ public class Employee { private String name; private double salary; private Date hireDay; /** * Конструктор класса * @param name имя сотрудника * @param salary зарплата сотрудника * @param hireDay дата начала работы сотрудника * */ public Employee(String name, double salary, Date hireDay) { this.name = name; this.salary = salary; this.hireDay = hireDay; } /** * Конструктор класса * @param name имя сотрудника * @param salary зарплата сотрудника * @param year год начала работы сотрудника * @param month месяц начала работы сотрудника * @param day день начала работы сотрудника * */ public Employee(String name, double salary, int year, int month, int day) { this.name = name; this.salary = salary; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); this.hireDay = calendar.getTime(); } /** * Метод для получения имени сотрудника * @return имя сотрудника * */ public String getName() { return name; } /** * Метод для получения зарплаты сотрудника * @return зарплата сотрудника * */ public double getSalary() { return salary; } /** * Метод для получения даты приема на работу сотрудника * @return дата приема на работу сотрудника * */ public Date getHireDay() { return hireDay; } /** * Метод для изменения зарплаты на заданное количество процентов * @param byPercent количество процентов, на которое будет изменена * зарплата сотрудника * */ public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; this.salary += raise; } /** * Переопределенный метод toString для вывода информации о сотруднике * @return информация о сотруднике * */ @Override public String toString() { return "name = " + name + ", salary = " + salary + ", hireDay = " + hireDay; } }
/** * Класс, инкопсулирующий информацию о менеджере. Данный класс является наследником * класса Employee. В классе Manager дополнительно хранится сумма премии * @see Employee * */ public class Manager extends Employee { /** * Размер премии * */ private double bonus; /** * Конструктор класса Manager. Переопределяет конструктор класса Employee * @param name имя сотрудника * @param salary зарплата сотрудника * @param year год начала работы сотрудника * @param month месяц начала работы сотрудника * @param day день начала работы сотрудника * */ public Manager(String name, double salary, int year, int month, int day) { super(name, salary, year, month, day); bonus = 0; } /** * Функция для установки размера премии * @param bonus размер премии * */ public void setBonus(double bonus) { this.bonus = bonus; } /** * Функция для получения размера премии менеджера * @return размер премии * */ public double getBonus() { return bonus; } /** * Функция для получения заплаты менеджера с учетом премии * @return зарплата менеджера * */ @Override public double getSalary() { double baseSalary = super.getSalary(); return baseSalary + bonus; } /** * Переопределенный метод toString для вывода информации о менеджере * @return информация о менеджере * */ @Override public String toString() { return "name = " + getName() + ", salary = " + getSalary() + ", hireDay = " + getHireDay(); } }
/** * Класс для хранения двух значений * @see PairAlg * */ public class Pair<T> { private T first; private T second; /** * Конструктор класса Pair по умолчанию * */ public Pair() { } /** * Конструктор класса Pair * @param first первое значение * @param second второе значение * */ public Pair(T first, T second) { this.first = first; this.second = second; } /** * Функция для устовки первого значения * @param first первое значение * */ public void setFirst(T first) { this.first = first; } /** * Функция для устовки второго значения * @param second второго значение * */ public void setSecond(T second) { this.second = second; } /** * Функция для получения первого значения * @return первое значение * */ public T getFirst() { return first; } /** * Функция для получения второго значения * @return второе значение * */ public T getSecond() { return second; } }
/** * Класс для работы с парой значений * @see Pair * */ public class PairAlg { /** * Функция для проверки наличия пустых значений в паре * @return true если пустое значение есть в паре, и false - в противном случае * */ public static boolean hasNulls(Pair<?> p) { return p.getFirst() == null || p.getSecond() == null; } /** * Функция для смены местами значений пары * @param p пара значений * */ public static void swap(Pair<?> p) { swapHelper(p); } /** * Вспомогательная функция для обмена значений пары местами * @param p пара значений * */ private static <T> void swapHelper(Pair<T> p) { T tmp = p.getFirst(); p.setFirst(p.getSecond()); p.setSecond(tmp); } }
/** * Главный класс программы * */ public class PairTest { public static void main(String[] args) { /*Создадим два объекта типа Manager*/ Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15); Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15); /*Создадим и выведем пару менеджеров*/ Pair<Manager> buddies = new Pair<>(ceo, cfo); printBuddies(buddies); /*Установим для каждого менеджера его пермию*/ ceo.setBonus(1000000); cfo.setBonus(500000); /* Найдем менеджера с минимальной и максимальной премией. После чего выведем нужную пару */ Manager[] managers = {ceo, cfo}; Pair<Employee> result = new Pair<>(); minmaxBonus(managers, result); Employee first = result.getFirst(); Employee second = result.getSecond(); System.out.println("first: " + first.getName() + ", second: " + second.getName()); /* Найдем менеджера с максимальной и минимальной премией. После чего выведем нужную пару */ maxminBonus(managers, result); first = result.getFirst(); second = result.getSecond(); System.out.println("first: " + first.getName() + ", second: " + second.getName()); } /** * Функция для вывода значений пары * @param p пара значений * */ public static void printBuddies(Pair<? extends Employee> p) { Employee first = p.getFirst(); Employee second = p.getSecond(); System.out.println(first.getName() + " and " + second.getName() + " are buddies."); } /** * Функция для получения сотрудников, которые имеют минимальный и максимальный * размер премии * @param a массив менеджеров * @param result здесь будет результат работы функции * */ public static void minmaxBonus(Manager[] a, Pair<? super Manager> result) { if (a == null || a.length == 0) { return; } Manager min = a[0]; Manager max = a[0]; for (int i = 1; i < a.length; i++) { if (min.getBonus() > a[i].getBonus()) { min = a[i]; } if (max.getBonus() < a[i].getBonus()) { max = a[i]; } } result.setFirst(min); result.setSecond(max); } /** * Функция для получения сотрудников, которые имеют минимальный и максимальный * размер премии. Отличие ее от функции minmaxBonus в том, что в результате * сначала хранится максимальный, а потом минимальный элемент * @param a массив менеджеров * @param result здесь будет результат работы функции * */ public static void maxminBonus(Manager[] a, Pair<? super Manager> result) { minmaxBonus(a, result); PairAlg.swap(result); } }
Проект можно взять здесь
Рис..
На следующем шаге мы начнем говорить про коллекции