Если бы я вам прямо сказал, что такое дженерики, я бы правда не смог. Вот вопрос:
Определите класс координатной точки, который может сохранять различные типы данных, такие как целые числа, типы с плавающей запятой и строковые типы.
Поскольку тип переменной поначалу неясен, легко подумать об использовании вместо него родительского класса всех типов, то есть класса Object.
Больше никакой ерунды, используйте код, чтобы отразить это
Пример 1. Используйте Object для реализации ввода неопределенного типа данных.
//Используем Object для представления неопределенных типов
общественная точка (Объект x, Объект y) {
этот.setX(х);
this.setY(у);
}
общественный недействительный setX (Объект x) {
это.х = х;
}
общедоступный объект getX() {
вернуть х;
}
общественный недействительный setY (Объект y) {
это.у = у;
}
общедоступный объект getY() {
вернуть y;
}
}
//тестовый класс
публичный класс Демо {
public static void main(String[] args) {
System.out.println("Используйте числа с плавающей запятой для представления координат: ");
Точка p = новая точка(12.23,23.21);
//Здесь класс Object преобразуется в класс Double, а затем автоматически распаковывается. Следующие два одинаковы.
System.out.println("Координаты X" + (Double)p.getX());
System.out.println("Координаты Y" + (Double)p.getY());
Система.out.println();
System.out.println("Используйте целые числа для представления координат: ");
Точка p2 = новая точка(12, 23);
System.out.println("Координаты X" + (Целое число)p2.getX());
System.out.println("Координаты Y" + (Integer)p2.getY());
Система.out.println();
System.out.println("Представление координат в виде строки: ");
Point p3 = new Point("29 градусов северной широты", "113 градусов восточной долготы");
System.out.println("Координаты X" + (String)p3.getX());
System.out.println("Координаты Y" + (String)p3.getY());
}
}
Вы должны четко понимать, какой тип вы передаете, а затем преобразовать его, прежде чем сможете его использовать.
Хотя это отвечает требованию, это также подразумевает небезопасный фактор. Почему говорят, что это неявно?
Например, мы используем new Point(12.23, «29 градусов северной широты») для создания объекта Point.
Затем используйте (Двойной), чтобы трансформировать его вниз. Каков будет результат?
Да, компиляция пройдет, но после запуска произойдет исключение преобразования типа.
Также очень просто избежать исключений преобразования классов. Просто замените объявление Object объявлением фиксированного типа (например: String x, String y), чтобы во время компиляции сообщалось об ошибке.
Тогда вы сможете найти ошибки и внести исправления.
Но тогда мы не сможем удовлетворить спрос.
Чтобы избежать угроз безопасности и заменять различные типы данных, эти талантливые люди ввели концепцию дженериков в JDK1.5.
Давайте посмотрим, как переписать приведенный выше код, используя дженерики.
Пример 2: Общий класс
публичный класс Демо {
public static void main(String[] args) {
System.out.println("Используйте числа с плавающей запятой для представления координат: ");
//После перезаписи с использованием дженериков нет необходимости выполнять нисходящее преобразование используемых данных.
Point<Double> p = новая точка<Double>(12.23,23.21);
System.out.println("Координаты X" + p.getX());
System.out.println("Координаты Y" + p.getY());
Система.out.println();
System.out.println("Используйте целые числа для представления координат: ");
Point<Целое число> p2 = новая точка<Целое число>(12, 23);
System.out.println("Координаты X" + p2.getX());
System.out.println("Координаты Y" + p2.getY());
Система.out.println();
System.out.println("Представление координат в виде строки: ");
Point<String> p3 = new Point<String>("29 градусов северной широты", "113 градусов восточной долготы");
System.out.println("Координата X" + p3.getX());
System.out.println("Координаты Y" + p3.getY());
}
}
Если мы намеренно передадим в этот момент разные типы данных:
Point<Double> p = new Point<Double>("29 градусов северной широты", 12.22);
Тогда во время компиляции будет сообщено об ошибке.
Несмотря на то, что дженерики определены, если вы не используете универсальный механизм в конструкторе, он будет обрабатывать данные как Object.
Целью этого в основном является совместимость со старыми кодами до JDK1.4, такими как
Точка p = новая точка(22.11,23.21);
Конечный результат запуска тот же, но во время компиляции будет выдано предупреждающее сообщение.
Пример 3: Универсальные методы
Как видно из приведенного выше примера, как только тип объекта указан в конструкторе, тот же тип будет использоваться во всем классе.
Наиболее типичный пример используется в среде сбора данных, например: ArrayList<Integer> al = new ArrayList<Integer>();
В настоящее время все типы объектов, работающие в Al, являются целыми.
Однако иногда мы не хотим фиксировать объект эксплуатации, а хотим более гибко использовать родовую технологию.
В настоящее время вы можете попробовать общий метод
public <E> void show(E e) {
System.out.println(e);
}
}
публичный класс Демо {
public static void main(String[] args) {
Печать р = новая печать();
п.печать(12);
p.print("привет");
p.show(новое целое число(33));
п.шоу(23);
}
}
По сути, в этом способе нет большой разницы от использования объектов Object в методах.
Более того, после JDK1.5 была добавлена функция автоматической распаковки, устраняющая необходимость трансформации вниз.
Пример 4: Общий интерфейс
//Первый способ реализации:
класс InterDemo1 реализует Inter<String> {
общественная недействительная печать (String t) {
System.out.println("печать: " + т);
}
}
//Второй способ реализации:
класс InterDemo2<T> реализует Inter<T> {
общественная недействительная печать (T t) {
System.out.println("печать: " + т);
}
}
класс Демо {
public static void main(String[] args) {
InterDemo1 id1 = новый InterDemo1();
id1.print("привет");
InterDemo2<Integer> id2 = новый InterDemo2<Integer>();
id2.print(новое целое число(23));
}
}
Существует два способа реализации универсального интерфейса. Один из них — указать универсальный тип при его реализации.
Другой вариант — по-прежнему использовать дженерики и определять универсальный тип во время построения.