98.93K
Категория: ПрограммированиеПрограммирование

Обобщение

1.

2.

Пример матрицы
public class Matrix{
private int[] array;

}

3.

Пример матрицы
public class Matrix<T> {
private T[] array;
public Matrix(T[] array) {
this.array = array.clone();
}
public static void main(String[] args) {
Matrix<Double> doubleMatrix = new Matrix<>(new Double[2]);
Matrix<Integer> integerMatrix = new Matrix<>(new Integer[4]);
Matrix<Byte> byteMatrix = new Matrix<>(new Byte[7]);
}
}

4.

Что такое обобщения?
Обобщения - это параметризованные типы.
Параметризованные типы позволяют объявлять классы, интерфейсы и
методы, где тип данных, которыми они оперируют, указан в виде
параметра.
Используя обобщения, можно создать единственный класс, например,
который будет автоматически работать с разными типами данных.
Классы, интерфейсы или методы, имеющие дело с параметризованными
типами, называются обобщениями, обобщенными классами или
обобщёнными методами.
Обобщения добавили в язык безопасность типов.

5.

Ключевые моменты объявления класса
Matrix<Integer> integerMatrix - Integer является аргументом типа.
Java не создает разные версии класса Matrix или любого другого
обобщенного класса. Имеется только одна версия класса Matrix,
которая существует в прикладной программе.
Обобщения работают только с объектами!
Gen<int> strOb =new Gen<int> (53) ;
// Ошибка, нельзя использовать //примитивные типы

6.

Ключевые моменты объявления класса
Т обозначает имя параметра типа.
Это имя используется в качестве заполнителя вместо которого в
дальнейшем подставляется имя конкретного типа, передаваемого
классу Matrix при создании объекта.
Это означает, что обозначение Т применяется в классе Matrix всякий
раз, когда требуется параметр типа.
Всякий раз, когда объявляется параметр типа, он указывается в
угловых скобках.

7.

Ключевые моменты объявления класса
Обобщенные типы отличаются в зависимости от типоваргументов:
doubleMatrix = integerMatrix; // Не верно!
Несмотря на то, что doubleMatrix и integerMatrix имеют тип
Matrix<T>, они являются ссылками на разные типы, потому что
типы их параметров отличаются.

8.

Обобщенный класс с двумя
параметрами типа
public class TwoGen<T, V> {
private T obT;
private V obV;
public TwoGen(T obT, V obV) {
this.obT = obT;
this.obV = obV;
}
public void showTypes() {
System.out.println("Тип T: " + obT.getClass().getName());
System.out.println("Тип V: " + obV.getClass().getName());
}
public T getObT() {
return obT;
}
public V getObV() {
return obV;
}
}

9.

Использование обобщенного класса с двумя
параметрами типа
public class SimpleGen {
public static void main(String[] args) {
TwoGen<Integer, String> twoGen = new TwoGen<>(88, "Generics");
twoGen.showTypes();
System.out.println("Значение T: " + twoGen.getObT());
System.out.println("Значение V: " + twoGen.getObV());
}
}

10.

Ограниченные типы
Указывая параметр типа, можно наложить ограничение сверху в виде
верхней границы, где объявляется суперкласс, от которого должны
быть унаследованы все аргументы типов.
С этой целью вместе с параметром указывается ключевое слово
extends:
class Gen <Т extends Superclass>
Параметр типа Т может быть заменен только указанным
суперклассом или его подклассами.

11.

Пример использования ограниченного
типа
public class Average<T extends Number> {
private T[] array;
public Average(T[] array) {
this.array = array;
}
public double average() {
double sum = 0.0;
for (T value : array) {
sum += value.doubleValue();
}
return sum / array.length;
}
}

12.

Пример использования ограниченного
типа
public class AverageDemo {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
Average<Integer> integerAverage = new Average<>(intArray);
System.out.println("Среднее значения для Integer "
+ integerAverage.average());
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
Average<Double> doubleAverage = new Average<>(doubleArray);
System.out.println("Среднее значения для Double "
+ doubleAverage.average());
// Не откомпилируется,
// потому что String не является наследником Number
/* String[] strArray = {"1", "2", "3", "4", "5"};
Average<String> strAverage = new Average<>(strArray);
System.out.println("Среднее значения для String “
+ strAverage.average());*/
}
}

13.

Ключевые моменты использования
ограниченного типа
В виде ограничения можно накладывать не только тип
класса, но и тип интерфейса.
public class MyClass<T extends Serializable>

14.

Ключевые моменты использования
ограниченного типа
class Gen < T extends MyClass & MyInterface1 & MyInterface2>
Ограничение может включать в себя как тип класса, так и типы одного или
нескольких интерфейсов.
2. Тип класса должен быть задан первым.
3. Накладывая на обобщенный тип ограничение, состоящее из класса и одного
или нескольких интерфейсов, для их объединения следует воспользоваться
логической операцией &:
4. Таким образом, любой тип, передаваемый параметру Т, должен быть
подклассом, производным от класса MyClass и реализующим интерфейсы
MyInterface1 и MyInterface2.
1.

15.

Применение метасимвольных
аргументов
Integer[] intArray = {1, 2, 3, 4, 5};
Average2<Integer> iob = new Average2<>(intArray);
System.out.println("Среднее значения для Integer " + iob.average());
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
Average2<Double> dob = new Average2<>(doubleArray);
System.out.println("Среднее значения для Double " + dob.average());
System.out.print("Средние значения для iob и dob ");
if (iob.sameAvg(dob)) {
System.out.println("одинаковые.");
} else {
System.out.println("разные.");
}
Так как Average параметризованный тип, какой тип параметра вы
укажете для Average, когда создадите параметр метода типа
Average?

16.

Применение метасимвольных
аргументов
!! Это не сработает!
public boolean sameAvg(Average<T> ob) {
return average() == ob.average();
}

17.

Пример применения метасимвольного
аргумента
Чтобы создать обобщенную версию метода sameAvg(), следует
воспользоваться
другим
средством
обобщений
Jаvа

метасимвольным аргументом.
Метасимвольный аргумент обозначается знаком ? и представляет
неизвестный тип.
Пример:
boolean sameAvg(Average<?> ob) {
return average() == ob.average();
}

18.

Метасимвольный аргумент
Метасимвол не оказывает никакого влияния на тип создаваемых
объектов класса Average. Это определяется оператором extends в
объявлении класса Average.
Метасимвол просто совпадает c любым достоверным объектом
класса Average.

19.

Ограниченные метасимвольные
аргументы
Метасимвольные аргументы могут быть ограничены почти таким же
образом, как и параметры типов.
Ограничивать метасимвольный аргумент особенно важно при
создании обобщенного типа, оперирующего иерархией классов.

20.

Пример применения метасимвольного
аргумента
public class Average2<T extends Number> {
private T[] array;
public Average2(T[] array) {
this.array = array.clone();
}
public double average() {
double sum = 0.0;
for (T value : array) {
sum += value.doubleValue();
}
return sum / array.length;
}
public boolean sameAvg(Average2<?> ob) {
return average() == ob.average();
}
}

21.

Пример применения метасимвольного
аргумента
public class AverageDemo2 {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
Average2<Integer> iob = new Average2<>(intArray);
System.out.println("Среднее значения для Integer " + iob.average());
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
Average2<Double> dob = new Average2<>(doubleArray);
System.out.println("Среднее значения для Double " + dob.average());
Float[] floatArray = {1.0F, 2.0F, 3.0F, 4.0F, 5.0F};
Average2<Float> fob = new Average2<>(floatArray);
System.out.println("Среднее значения для Float " + fob.average());
System.out.print("Средние значения для iob и dob ");
if (iob.sameAvg(dob)) {
System.out.println("одинаковые.");
} else {
System.out.println("разные.");
}
System.out.print("Средние значения для iob и fob ");
if (iob.sameAvg(fob)) {
System.out.println("одинаковые.");
} else {
System.out.println("разные.");
}
}

22.

Создание обобщенного метода
В методах обобщенного класса можно использовать параметр типа, а
следовательно, они становятся обобщенными относительно
параметра типа.
Но можно объявить обобщенный метод, в котором непосредственно
используется один или несколько параметров типа.
Более того, можно объявить обобщенный метод, входящий в
необобщенный класс.

23.

Пример обобщенного метода
public class GenMethodDemo {
public static <T, V> boolean isIn(T x, V[] array) {
for (V element : array) {
if (x.equals(element)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
if (isIn(2, intArray)) {
System.out.println("2 входит в массив intArray");
}
if (!isIn(7, intArray)) {
System.out.println("7 не входит в intArray");
}
System.out.println();
String[] strArray = {"one", "two", "three", "four", "five"};
if (isIn("two", strArray)) {
System.out.println("two входит в массив strArray");
}
if (!isIn("seven", strArray)) {
System.out.println("seven не входит в массив strArray");
}
}

24.

Обобщенные конструкторы
Конструкторы также могут быть обобщенными, даже если их классы
таковыми не являются.
public class GenConstructor {
private double value;
public <T extends Number> GenConstructor(T arg) {
value = arg.doubleValue();
}
public void showValue() {
System.out.println("value: " + value);
}
}
public class GenConstructorDemo {
public static void main(String[] args) {
GenConstructor genConstructor1 = new GenConstructor(100);
GenConstructor genConstructor2 = new GenConstructor(123.5F);
genConstructor1.showValue();
genConstructor2.showValue();
}
}

25.

Обобщенные интерфейсы
В дополнение к обобщенным классам и методам вы можете объявлять обобщенные интерфейсы.
Обобщенные интерфейсы специфицируются так же, как и обобщенные классы.
public interface MyInterface<T> {
T someMethod(T t);
}
public class MyClass<T> implements MyInterface<T> {
@Override
public T someMethod(T t) {
return t;
}
public static void main(String[] args) {
MyInterface<String> object = new MyClass<>();
String str = object.someMethod("some string");
}
}

26.

Иерархии обобщенных классов
Обобщенные классы могут быть частью иерархии классов так же, как
и любые другие необобщенные классы.
То есть обобщенный класс может выступать в качестве суперкласса
или подкласса.
Ключевое отличие между обобщенными и необобщенными
иерархиями состоит в том, что в обобщенной иерархии любые
аргументы типов, необходимые обобщенному суперклассу, всеми
подклассами должны передаваться по иерархии вверх.

27.

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

28.

Пример иерархии с обобщенным
суперклассом
public class GenericSuper<T> {
private T ob;
public GenericSuper(T ob) {
this.ob = ob;
}
private T getOb() {
return ob;
}
}
public class GenericSub<T> extends GenericSuper<T> {
public GenericSub(T ob) {
super(ob);
}
}

29.

Пример использования оператора instanceof с
обобщенным типом
public class HierarchyDemo {
public static void main(String[] args) {
GenericSuper<Integer> object = new GenericSub<>(88);
if (object instanceof GenericSuper<?>) {
System.out.println("object is instance of GenericSuper");
}
if (object instanceof GenericSub<?>) {
System.out.println("object is instance of GenericSub");
}
// Ошибка компиляции - информация об обобщенном типе недоступна
// во время выполнения
/* if (object instanceof GenericSub<Integer>) {
System.out.println("object is instance of GenericSub<Integer>");
}*/
}
}

30.

Некоторые ограничения
присущие обобщениям
public class GenRestriction<T> {
private T ob;
private T[] array;
public GenRestriction(T ob, T[] array) {
// Недопустимо!!!
//оb = new Т();
//array = new Т[10];
this.ob = ob;
this.array = array;
}
1.
Нельзя создавать экземпляр
по параметру типа.
}
2. Нельзя создать экземпляр
массива,
тип
элемента
которого
определяется
параметром типа.

31.

Ограничения на обобщенные массивы
Нельзя создать массив специфических для типа обобщенных ссылок.
public class GenArrays {
public static void main(String[] args) {
// Нельзя создать массив специфичных для типа обобщенных ссылок.
// GenericSub<Integer>[] gens = new GenericSub<Integer>[10];
GenericSub<?>[] gens = new GenericSub<?>[10];
gens[0] = new GenericSub<>(34);
}
}

32.

Ограничения на статические члены
Нельзя создавать обобщенные статические переменные и методы.
Но объявить статические обобщенные методы со своими параметрами типа все же можно.
public class GenericWrongStatic<T> {
// Неверно, нельзя создать статические переменные типа Т.
//public static Т оb;
/*
}
// Неверно, ни один статический метод не может использовать Т.
public static T getOb() {
return оb;
}*/
//Но объявить статические обобщенные методы со своими параметрами типа можно
public static <V> void getOb(V v) {
System.out.println(v);
}
English     Русский Правила