Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Обобщенный подкласс. Ошибки неоднозначности. Ограничения на статические члены. Ограничения обобщенных массивов. Ограничения обобщенных исключений




Обобщенный подкласс

Абсолютно приемлемо, когда суперклассом для обобщенного класса выступает класс необобщенный. Например, рассмотрим программу:

// Необобщенный класс может быть суперклассом

// для обобщенного подкласса.

// Необобщенный класс.

class NonGen {

int num;

NonGen(int i) {

num = i;

}

int getnum() {

return num;

}}

// Обобщенный подкласс.

class Gen< T> extends NonGen {

T ob; // Объявление объекта типа T

// Передать конструктору объект

// типа T.

Gen(T o, int i) {

super(i);

ob = o;

}

// Возвращает ob.

T getob() {

return ob;

}}

// Создать объект Gen.

class HierDemo2 {

public static void main(String args[]) {

// Создать объект Gen для String.

Gen< String> w = new Gen< String> (" Добро пожаловать", 47);

System. out. print(w. getob() + " " );

System. out. println(w. getnum());

}}

Результат работы этой программы показан ниже:

Добро пожаловать 47

Обратите внимание на то, как в этой программе Gen наследуется от NonGen:

class Gen< T> extends NonGen {

Поскольку NonGen — необобщенный класс, никакие аргументы типа не указываются. То есть даже если Gen объявляет тип-параметр T, он не требуется (и не может быть использован) NonGen. То есть Gen наследуется от NonGen обычным способом. Никаких специальных условий не требуется.

Ошибки неоднозначности

Включение в язык обобщений породило новый тип ошибок, от которых вам нужно защищаться: неоднозначность (ambiquity). Ошибки неоднозначности случаются, когда очистка порождает два внешне разных обобщенных объявления, разрешаемых в виде одного очищенного типа, что вызывает конфликт. Вот пример, который включает перегрузку методов:

// Неоднозначность порождается очисткой перегруженных методов.

class MyGenClass< T, V> {

T ob1;

V ob2;

//...

// Эти два перегруженных метода неоднозначны

// и не скомпилируются.

void set(T o) {

ob1 = o;

}

void set(V o) {

ob2 = o;

}

}

Обратите внимание, что MyGenClass объявляет два обобщенных типа: T и V. Внутри MyGenClass предпринимается попытка перегрузить set() на основе параметров T и V.

Это выглядит резонным, потому что кажется, что T и V — разные типы. Однако здесь возникают две проблемы неоднозначности.

Первая — судя по тому, как написан MyGenClass, нет требования, чтобы T и V были разными типами. Например, в принципе совершенно корректно сконструировать объект MyGenClass следующим образом:

MyGenClass< String, String> obj = new MyGenClass< String, String> ()

В этом случае T и V будут заменены String. Это делает обе версии set() идентичными, что, конечно же, представляет собой ошибку.

Вторая, более фундаментальная проблема состоит в том, что очистка типов приводит обе версии метода к следующему виду:

void set(Object o) { //...

То есть перегрузка set(), как пытается сделать MyGenClass, в действительности неоднозначна.

Ошибки неоднозначности бывает трудно исправить. Например, если вы знаете, что V всегда будет неким подтипом String, то можете попытаться исправить MyGenClass, переписав его объявление следующим образом:

class MyGenClass< T, V extends String> { // почти OK!

Это позволит скомпилировать MyGenClass, и вы даже сможете создавать экземпляры объектов этого класса примерно так:

MyGenClass< Integer, String> x = new MyGenClass< Integer, String> ();

Это работает, потому что Java может аккуратно определить, когда какой метод должен быть вызван. Однако неоднозначность возникнет, когда вы попытаетесь выполнить строку:

MyGenClass< String, String> x = new MyGenClass< String, String> ();

В этом случае, поскольку и T, и V являются String, то какую версию set() нужно вызвать?

Честно говоря, в предыдущем примере было бы лучше использовать два метода с разными именами, вместо того чтобы перегружать set(). Часто разрешение неоднозначности требует реструктуризации кода, потому что неоднозначность свидетельствует о концептуальной ошибке в дизайне.

Ограничения на статические члены

Никакой static-член не может использовать тип параметра, объявленный в его классе. Например, все static-члены этого класса являются недопустимыми:

class Wrong< T> {

// Неверно, нельзя создать статические переменные типа T.

static T ob;

// Неверно, ни один статический метод не может использовать T.

static T getob() {

return ob;

}

// Неверно, ни один статический метод не может иметь доступ

// к объекту типа T.

static void showob() {

System. out. println(ob);

}}

Несмотря на то что вы не можете объявить static-члены, которые используют тип параметра, объявленный в окружающем классе, вы можете объявлять обобщенные static методы, определяющие их собственные параметры типа, как это делалось ранее в настоящей главе.

Ограничения обобщенных массивов

Существуют два важных ограничения обобщений, касающиеся массивов. Во-первых, вы не можете создать экземпляр массива, чей базовый тип — параметр типа. Во-вторых, вы не можете создать массив специфичных для типа обобщенных ссылок.

Ограничения обобщенных исключений

Обобщенный класс не может расширять Throwable. Это значит, что вы не сможете создать обобщенных классов исключений.

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...