java left logo
java middle logo
java right logo
 

Home arrow Java SE Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 3947
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Covariant Parameter Types E-mail
User Rating: / 12
PoorBest 

This Tech Tip reprinted with permission by java.sun.com

The December 1, 2004 Tech Tip Covariant Return Types presented an example of using this new J2SE 5.0 facility. This facility allows you to create methods in a subclass that return an object whose type is a subtype of that returned by the method it overrides. In the following tip you will see the difficulties involved in extending this capability to method parameters.

The example discussed here was provided by Sun Engineer Peter von der Ahé, and is based on a suggestion he received from computational theologist Gilad Bracha. The intent is to demonstrate that although there are good reasons for implementing covariant return types, implementing covariant method parameters is unsound.

The basic mechanism outlined in the December tip began with two pairs of classes. In this tip, let's simplify the classes:

   class A {}

   class B extends A {}

Now, define a class, Super, that contains a method that returns an object of type A:

   class Super {
      public A someMethod(){
      return new A();
      }
   }

Next, create a class, Sub, that extends Super. In J2SE 1.4 and previous releases, you could not override someMethod() by changing its return type. In particular, the following code would not compile:

   class Sub extends Super {
      public B someMethod() {
      return new B();
      }
   }

Previous to J2SE 5.0, the compiler would issue a message like this:


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

In J2SE 5.0, this code compiles and the narrower type B is a legal return type for the someMethod() method in the subclass, Sub.

Is it possible to perform a similar narrowing of type for a method parameter? Let's try by creating a "circle of life" example with the Food and Animal interfaces:

   interface Food {
      int glycemicIndex();
   }

   interface Animal {
      void eat(Food food);
   }

There are no problems in implementing the Food interface, as the following class, Grass, shows:

   class Grass implements Food {
      public int glycemicIndex() {
         return 20// this is a guess, don't base your diet 
                    // on this
      }
   }

An antelope is an animal that eats food and it is itself food for an animal such as a lion. Here are versions of compilable classes that model the antelope and lion. The classes implement the eat() method declared in the Animal interface:

   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) { }
   }

The problem with this is that the code allows an Antelope and a Lion to eat anything of type Food. You might be tempted to try the following to restrict the Antelope to only eat objects of type Grass, and the Lion to only eat objects of type Antelope:

   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) { }
    }

Unfortunately, however, this will no longer compile. You are allowed to add the method with the signature eat(Grass food) to the Antelope class, but you cannot declare that Antelope implements Food. That's because you are not implementing the signature declared in the interface. Your compiler issues a warning that includes something like this.


   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

A solution involves the use of Generics. Start with the declaration of Generics, and declare eat() so that its argument is at least of type Food:

   public interface Food {
      int glycemicIndex();
   }

   public interface Animal <F extends Food> {
      public void eat(F food);
   }

This now more accurately represents the idea that an object of type Animal eats a particular type of Food. The implementation of Grass does not need to change:

   public class Grass implements Food {
      public int glycemicIndex() {
         return 20//this is a guess, don't base your diet 
                    // on this
      }
   }

The implementation of Antelope and of Lion can now specify the type of Food that each Animal can eat:

   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) {
      }
   }

You can now exercise these classes, again by employing generics:

   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());
      }
   }

There is nothing built into J2SE 5.0 to automatically handle covariant parameter types in the same way that covariant return types are now accommodated. You can, however, follow the pattern in this tip to employ generics to allow for extending the type being passed as a parameter to a method.

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.


 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.