Обеспечение типовой безопасности с помощью обобщений. Обобщенные интерфейсы. Примеры
Содержание
- 1. Типовая безопасность. Обеспечение типовой безопасности с помощью обобщений. Пример
- 2. Обобщенный интерфейс. Особенности использования
- 3. Пример объявления и использования обобщенного интерфейса с одним параметром типа
- 4. Простой пример объявления обобщенного интерфейса и его использование в обобщенном классе, который использует 3 параметра типа T1, T2, T3
- Связанные темы
Поиск на других ресурсах:
1. Типовая безопасность. Обеспечение типовой безопасности с помощью обобщений. Пример
Основное преимущество обобщений – обеспечение типовой безопасности. Если в программе используются обобщения и содержится некорректный код приведения типов (например, приведение строки в число), то компилятор фиксирует ошибку на этапе компиляции а не на этапе выполнения. Если ошибка найдена на этапе компиляции, то это лучше чем определение ошибки на этапе выполнения. Генерирование ошибки на этапе выполнения есть недопустимым.
В языке Java суперклассом для всех классов есть класс Object. Это дает возможность объявлять ссылки на тип Object и использовать их для приведения к любому типу. Однако, такой подход не обеспечивает типовой безопасности, в результате чего ошибки будут компилироваться и возникать на этапе выполнения, а это есть недопустимо.
Пример. В примере показаны следующие преимущества применения обобщений в сравнении с использованием ссылки на тип Object:
- при использовании обобщений для базовых типов (int, double, float и других) не нужно выполнять явное приведение типа. При использовании ссылки на тип Object явное приведение есть обязательным;
- при использовании обобщений обеспечивается типовая безопасность (ошибки несовместимого присваивания определяются на этапе компиляции). При использовании ссылки на тип Object типовая безопасность не обеспечивается (ошибки несовместимого присваивания определяются на этапе выполнения).
Заданы два класса:
- класс ClassObject – использует ссылку на тип Object. Поскольку тип Object есть базовым для всех типов (классов), то эту ссылку можно привести к любому другому типу;
- обобщенный класс ClassGen<T>, использующий параметризованный тип T.
// Класс, который использует ссылку на тип Object class ClassObject { // Некоторое значение - имеет тип Object private Object value; // Конструктор ClassObject(Object _value) { value = _value; } // Методы доступа Object GetValue() { return value; } void SetValue(Object _value) { value = _value; } } // Обобщенный класс - обеспечивает типовую безопасность, // ошибка возникает на этапе компиляции, а не на этапе выполнения. class ClassGen<T> { private T value; // Конструктор public ClassGen(T value) { this.value = value; } // Методы доступа public T GetValue() { return value; } void SetValue(T value) { this.value = value; } }
В третьем классе Test реализованы два статических метода Test_ClassObject() и TestClassGen(). В этих методах нарочно выполняется ошибочная операция присваивания числу objInt строки objString
objInt = objString;
здесь
- objInt – объект типа Integer (число);
- objString – объект типа String (строка).
В методе Test_ClassGen() эта ошибочная операция обнаруживается на этапе компиляции. То есть, выполнение программы не состоится, пока эта ошибка не будет исправлена. В этом случае срабатывает механизм типовой безопасности.
В методе Test_ClassObject() ошибка обнаруживается на этапе выполнения (этап компиляции не определяет ошибку). То есть механизм типовой безопасности не срабатывает. А это недопустимо.
public class Test { // Метод, который тестирует класс, в котором объявляется ссылка типа Object public static void Test_ClassObject() { // Создать экземпляр типа Integer и присвоить переменной типа int его значение ClassObject objInt = new ClassObject(25); int vInt = (Integer)objInt.GetValue(); // здесь нужно явное приведение типов // Создать экземпляр типа String ClassObject objString = new ClassObject("Hello"); String vString = (String)objString.GetValue(); // здесь также нужно явное приведение типов // Присвоить переменной типа Integer значение переменной типа String objInt = objString; // здесь компилятор ошибки не выдает - это неправильно int value = (Integer)objInt.GetValue(); // ошибка на этапе выполнения!!! } // Класс, использующий механизм обобщений public static void Test_ClassGen() { // Создать экземпляр типа Integer ClassGen<Integer> objInt = new ClassGen<Integer>(25); int vInt = objInt.GetValue(); // здесь не нужно явное приведение типов // Создать экземпляр типа String ClassGen<String> objString = new ClassGen<String>("Hello"); String vString = objString.GetValue(); // здесь также не нужно явное приведение типов // Присвоить типу Integer значение типа String objInt = objString; // ошибка на этапе компиляции - срабатывает типовая безопасность } public static void main(String[] args) { // Вызов методов тестирования Test_ClassObject(); Test_ClassGen(); } }
⇑
2. Обобщенный интерфейс. Особенности использования
В языке Java допускается объявлять интерфейс, который использует один или несколько обобщенных типов. Общая форма объявления обобщенного интерфейса с именем InterfaceName, который использует тип T, следующая:
interface InterfaceName<T> {
...
}
Общая форма обобщенного интерфейса, который использует несколько обобщенных типов, следующая:
interface InterfaceName<T1, T2, ..., TN> {
...
}
здесь
- InterfaceName – имя обобщенного интерфейса, который использует типы T1, T2, …, TN.
⇑
3. Пример объявления и использования обобщенного интерфейса с одним параметром типа
В примере объявляется один обобщенный интерфейс IValue<T> и обобщенный класс Value<T>. Интерфейс и класс получают параметром тип T. В интерфейсе объявляется метод Show(), реализуемый в классе. Класс содержит внутреннюю переменную value.
В классе GenInterface реализованы две статических функции, демонстрирующие использование интерфейса IValue<T> и класса Value<T>.
// Интерфейс, использующий один параметр типа T interface IValue<T> { // Методы доступа к значению T GetValue(); void SetValue(T value); // Метод Show() - выводит информацию о значении void Show(); } // Обобщенный класс, реализующий интерфейс IValue<T> class Value<T> implements IValue<T> { // Внутренние переменные класса T value; // Конструктор public Value(T _value) { value = _value; } // Реализация методов интерфейса public T GetValue() { return value; } public void SetValue(T value) { this.value = value; } // Реализация метода Show() интерфейса public void Show() { System.out.println("value = " + value); } } public class GenInterface { // Метод, получающий ссылку на интерфейс IValue public static void ShowValue(IValue ref) { ref.Show(); } public static void main(String[] args) { // 1. Объявить ссылку на интерфейс IValue<T> IValue<Double> refV; // 2. Создать экземпляр класса Value<T> Value<Double> obj = new Value<Double>(5.88); // 3. Проверка метода GetValue() класса Value<T> double t = obj.GetValue(); System.out.println("t = " + t); // t = 5.88 // 4. Проверка метода SetValue() obj.SetValue(7.777); t = obj.GetValue(); System.out.println("t = " + t); // t = 7.777 // 5. Проверка метода Show() obj.Show(); // value = 7.777 // 6. Вызов статического метода ShowValue() с параметром ссылки на интерфейс refV refV = obj; // Присвоить ссылке адрес экземпляра класса Value<T> ShowValue(refV); // value = 7.777 // 7. Вызов статического метода ShowValue() с параметром экземпляра obj ShowValue(obj); // value = 7.777 } }
Результат выполнения программы
t = 5.88 t = 7.777 value = 7.777 value = 7.777 value = 7.777
⇑
4. Простой пример объявления обобщенного интерфейса и его использование в обобщенном классе, который использует 3 параметра типа T1, T2, T3
Данный пример есть демонстрацией объявления и использования обобщенных интерфейсов в языке Java.
В примере продемонстрировано использование обобщенного интерфейса с именем MyInterface. Интерфейс объявляет методы, которые оперируют тремя типами T1, T2, T3. Также объявляется класс MyClass<T1, T2, T3>, реализующий интерфейс MyInterface<T1, T2, T3>. В классе объявляются три внутренние переменные, которые имеют соответственно типы T1, T2, T3.
// Интерфейс, использующий 3 обобщенных типа interface MyInterface<T1, T2, T3> { // В интерфейсе указываются методы, которые используют типы T1, T2, T3 // Вернуть значение переменных типов T1, T2, T3 T1 GetT1(); T2 GetT2(); T3 GetT3(); // Установить значения переменных типов T1, T2, T3 void SetT1(T1 obj); void SetT2(T2 obj); void SetT3(T3 obj); // Метод вывода значений переменных void Print(String text); } // Класс, реализующий интерфейс MyInterface<T1, T2, T3>. // В объявлении класса обязательно нужно указывать имена типов T1, T2, T3. class MyClass<T1, T2, T3> implements MyInterface<T1, T2, T3> { // Внутренние переменные класса T1 var1; T2 var2; T3 var3; // Конструктор класса public MyClass(T1 var1, T2 var2, T3 var3) { this.var1 = var1; this.var2 = var2; this.var3 = var3; } // Методы, которые объявлены в интерфейсе MyInterface<T1, T2, T3> public T1 GetT1() { return var1; } public T2 GetT2() { return var2; } public T3 GetT3() { return var3; } public void SetT1(T1 var1) { this.var1 = var1; } public void SetT2(T2 v2) { var2 = v2; } public void SetT3(T3 v3) { this.var3 = v3; } public void Print(String comment) { System.out.println(comment); System.out.println("var1 = " + var1); System.out.println("var2 = " + var2); System.out.println("var3 = " + var3); } } public class GenInterface { public static void main(String[] args) { // Демонстрация использования обобщенного интерфейса MyInterface<T1, T2, T3> // 1. Объявить ссылку на интерфейс, который использует типы Integer, Character и Long MyInterface<Integer, Character, Long> ref; // 2. Объявить экземпляр класса MyClass, который обрабатывает типы Integer, Character, Long MyClass<Integer, Character, Long> obj = new MyClass<Integer, Character, Long>(25, 'z', 3223232332L); // 3. Получить значение типа Integer (int) - метод GetT1() int vInt = obj.GetT1(); System.out.println("vInt = " + vInt); // 4. Получить значение типа Character (char) - метод GetT2() char vChar1 = obj.GetT2(); Character vChar2 = obj.GetT2(); // так тоже можно System.out.println("vChar1 = " + vChar1); System.out.println("vChar2 = " + vChar2); // 5. Получить значение типа Long (long) - метод GetT3() long vLong; vLong = obj.GetT3(); System.out.println("vLong = " + vLong); // 6. Вывести все внутренние переменные - метод Print() obj.Print("-----------------"); } }
Результат выполнения программы
vInt = 25 vChar1 = z vChar2 = z vLong = 3223232332 ----------------- var1 = 25 var2 = z var3 = 3223232332
⇑
Связанные темы
- Обобщения. Параметризованные типы. Обобщенные классы интерфейсы, методы
- Обобщения. Ограниченные типы. Метасимвольные аргументы. Примеры
⇑