Ковариантного типы параметров

1 декабря 2004 Технология Совет типы Ковариантное Вернуться представлен пример использования этой новой J2SE 5.0 объекте. Это средство позволяет создавать методы в подклассе, которые возвращают объект, тип которого является подтипом, что возвращенное методом его замещает. В следующий совет вы увидите, трудности, связанные с возможностью продления этого методу параметров.

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

Основным механизмом, изложенных в отзыве декабря началось с двумя парами классов. В этот совет, давайте упростить классов:

class A {}
class B extends A {}

Теперь определим класс, супер, что содержит метод, который возвращает объект типа:


   class Super {

      public A someMethod(){

      return new A();

      }

   }

Затем нужно создать класс, Sub, который расширяет Super. В версии J2SE 1.4 и предыдущих версиях, вы не можете переопределить зотеМеЫюй (), изменив его тип возвращаемого значения. В частности, следующий код не будет составлять:


   class Sub extends Super {

      public B someMethod() {

      return new B();

      }

   }

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

someMethod() in Sub cannot override someMethod() in Super;
attempting to use incompatible return type.

В J2SE 5.0, этот код компилируется и узкий тип Б правовой тип обмен на зотеМеЫюй () в подклассе, суб.

Можно ли выполнять аналогичные сужения типа для параметра метода? Давайте попробуем путем создания "Круг жизни", например, с Продовольственной и животных интерфейсов:


   interface Food {

      int glycemicIndex();

   }



   interface Animal {

      void eat(Food food);

   }

Есть никаких проблем в реализации интерфейса питания, как следующий класс, Трава, показывает:


   class Grass implements Food {

      public int glycemicIndex() {

         return 20// this is a guess, don't base your diet 

                    // on this

      }

   }

Антилопа это животное, которое ест продукты питания и она сама пища для животных, таких, как лев. Вот версии компилируемые классы, модель антилопы и льва. Классы реализуют есть () метод, объявленный в интерфейсе Животное:


   class Antelope implements Food, Animal {

      public void eat(Food food) {

      }



      public int glycemicIndex() {

         return 5// this is a guess, don't base your diet 

                   // on this

      }

   }



   class Lion implements Animal {

    public void eat(Food food) { }

   }

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


   class Antelope implements Food, Animal {

      public void eat(Grass food) {

      }



      public int glycemicIndex() {

         return 5// this is a guess, don't base your diet 

                   // on this

      }

   }



    class Lion implements Animal {

       public void eat(Antelope food) { }

    }

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

Antelope is not abstract and does not override abstract
method eat(Food) in Animal
Lion is not abstract and does not override abstract method
eat(Food) in Animal

Решение включает в себя использование генериков. Начните с декларацией генериков, и объявить есть (), так что его аргументы, по крайней мере типа Еда:


   public interface Food {

      int glycemicIndex();

   }



   public interface Animal <F extends Food> {

      public void eat(F food);

   }

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


   public class Grass implements Food {

      public int glycemicIndex() {

         return 20//this is a guess, don't base your diet 

                    // on this

      }

   }

Осуществление антилоп и Льва теперь можно указать тип пищи, что каждое животное может съесть:


   public class Antelope implements Food, Animal<Grass> {

      public int glycemicIndex() {

         return 5//this is a made up number

      }



      public void eat(Grass food) {

      }

   }



   public class Lion implements Animal<Antelope> {



      public void eat(Antelope food) {

      }

   }

Теперь Вы можете пользоваться этими классами, опять же с использованием дженериков


   class Example {

      static <F extends Food> void feed

        (Animal<F> animal, F food) {

            animal.eat(food);

        }



      public static void main(String... args) {

         feed(new Lion()new Antelope());

      }

   }

Существует ничего не построили в J2SE 5.0 для автоматической обработки ковариантной типы параметров таким же образом, что ковариантной типы возвращения в настоящее время размещены. Можно, однако, последовать примеру в этом совете, чтобы использовать дженерики чтобы обеспечить расширение типа передается в качестве параметра метода.

Copyright (C) 2004-2005 Sun Microsystems, Inc
Все права защищены.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>