DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Java
  4. Compile Time Dynamism Using Java Generics

Compile Time Dynamism Using Java Generics

Generics are a useful tool to have at hand. You can use them to simplify your code, exposing methods in a single class while adding individual generic variables.

Sumith Puri user avatar by
Sumith Puri
·
Apr. 17, 17 · Tutorial
Like (7)
Save
Tweet
Share
9.95K Views

Join the DZone community and get the full member experience.

Join For Free

github link (code samples from the article & more)
https://github.com/sumithpuri/skp-code-marathon-vientiane


this article describes the use of generics for compile-time dynamism and its usage for client related type-safety. usually, the most important aspect during sub-classing is how the override is done to achieve class-specific functionality, though with the use of the same method parameters. in certain scenarios, you might need to use class-specific parameters. coupled with this, the overridden methods might use a parameter that itself is the super class of these class-specific parameters. an example of this is methods that are exposed through some public api and then overridden in concrete implementation classes.


context of use

the description of the usage in this article is that of a very frequently occurring scenario that many of you might have faced and devised a similar solution for. the usage is explained with a simple example from the vehicle rental system.



figure 1: object relationship diagram


here, the main rental service class, rentvehiclemanager , could be either an interface or an abstract class. rentcarmanager and rentbikemanager subclass from rentvehiclemanager and override its methods with their own functionality. the implementation solutions that might have been feasible in this scenario are:

  1. using the 'factory' pattern to create manager classes.
  2. use a common hierarchy for parameters, with strict checking in methods.
  3. usage of a common hierarchy along with generics.


option 1 does provide a good solution for the instance generation of related classes but does not provide any method object parameter-related generality.

for a solution using option 2, as shown in figure 2, every overridden method will now need to include strict checking at the start of the method to see whether the argument it actually received is of the type that was expected for this class.


figure 2: class diagram (using option 2)


the interface, in this case, would look like this:

package com.sumithp.codeguru.nongeneric.vehicle;

import com.sumithp.codeguru.vehicle.domain.vehicle;

public interface rentvehiclemgr {

   public void rentout(vehicle vehicle);
   public void checkin(vehicle vehicle);
   public void diagnose(vehicle vehicle);
   public void repair(vehicle vehicle);
}


a typical implementation for the bike rental in the case of option 2 is shown here:

package com.sumithp.codeguru.nongeneric.vehicle;

import com.sumithp.codeguru.vehicle.domain.vehicle;

public class rentbikemgrimpl implements rentvehiclemgr {

   // if we don't use vehicle as the parameter here, the clients
   // will not be able to use a generalized interface to call our
   // methods.

   public void rentout(vehicle vehicle) {
      // if (vehicle instanceof bike)
         // renting out related db operations
   }

   public void checkin(vehicle vehicle) {
      // if (vehicle instanceof bike)
         // vehicle check in related db operations
   }

   public void diagnose(vehicle vehicle) {
      // if (vehicle instanceof bike)
         // self diagnose functionality of a vehicle
         // print diagnosis
   }

   public void repair(vehicle vehicle) {
      // if (vehicle instanceof bike)
         // perform pre-defined repair
         // print repair details
   }
}


option 3 is the most complete and viable alternative because the usage is more coherent by exposing the methods in a single class, each using their implementation along with their own generic variable. take a closer look at this solution.


common hierarchy using java generics

the use of generics is greatly enhanced by the 'type erasure' property. this implies that there is only compile time checking, beyond which the generic variables are erased and no runtime verification exists. this also has certain disadvantages, such as not being completely safe to be used with third-party code (or with internal code that does not use generics).

the simple change that was made to option 2 was that a new generic variable was added to each of the classes in the hierarchy. at the top level, rentvehiclemanager was declared to use any generic variable of the type that extends vehicle . a sample of the same is shown here:


package com.sumithp.codeguru.generic.vehicle;

import com.sumithp.codeguru.vehicle.domain.vehicle;

public interface rentvehiclemgr< t extends vehicle > {

   public void rentout(t vehicle);
   public void checkin(t vehicle);
   public void diagnose(t vehicle);
   public void repair(t vehicle);
}


the classes inheriting from rentvehiclemanager , in other words, rentbikemanager & rentcarmanager were modified to start using a generic variable of their own type. implementation for the car rental would look like:

package com.sumithp.codeguru.generic.vehicle;

import com.sumithp.codeguru.vehicle.domain.car;

public class rentcarmgrimpl implements rentvehiclemgr< car > {

   // can use car as parameter here, as well as allow
   // clients to have a generalized interface

   public void rentout(car car) {
      // renting out related db operations
   }

   public void checkin(car car) {
      // vehicle check in related db operations
   }

   public void diagnose(car car) {
      // self diagnose functionality of a vehicle
      // print diagnosis
   }

   public void repair(car car) {
      // perform pre-defined repair
      // print repair details
   }
}


this would mean that any client invocation of methods on the specific type of manager now would require its own specific vehicle type object to invoke the method. this would enable the manager implementor to do away with any strict checking in the methods. also, when making modifications to any of the methods from these subclasses, one does not have to worry about including instanceof checks.


the client code is cleaner and safer. a typical implementation would look like the following:

package com.sumithp.codeguru.generic.vehicle.client;

import com.sumithp.codeguru.generic.vehicle.rentbikemgrimpl;
import com.sumithp.codeguru.generic.vehicle.rentcarmgrimpl;
import com.sumithp.codeguru.generic.vehicle.rentvehiclemgr;
import com.sumithp.codeguru.vehicle.domain.bike;
import com.sumithp.codeguru.vehicle.domain.car;

public class rentgenericvehicleclient {

   public void rentbike() {

      // you want only one interface to handle all rentals
      rentvehiclemgr< bike > rentvehiclemgr;

      rentvehiclemgr = new rentbikemgrimpl();

      bike bike = new bike(104,"two",true,150);
      rentvehiclemgr.rentout(bike);

      /*
       * client cannot do this:
       *
       * vehicle vehicle = new car(104,"four",true,"petrol");
       * rentvehiclemgr.rentout(vehicle);
       *
       * even if there are no instanceof checks, all is well!
       * client is absolutely clear on what he needs to do.
       *
       */
   }

   public void rentcar() {

      // you want only one interface to handle all rentals
      rentvehiclemgr< car > rentvehiclemgr;

      rentvehiclemgr = new rentcarmgrimpl();

      car car = new car(104,"four",true,"petrol");
      rentvehiclemgr.rentout(car);

      /*
       * client cannot do the following as shown for rentbike():
       *
       * vehicle vehicle = new bike(104,"two",true,150);
       * rentvehiclemgr.rentout(vehicle);
       *
       * even if there are no instanceof checks, all is well!
       * client is absolutely clear on what he needs to do.
       *
       */
   }
}


this sort of design will definitely lead to an easier-to-maintain, easier-to-code, and — more importantly—an easier to understand implementation. these advantages are not only for the service or functionality implementors but also for consumers of the service.


conclusion

the usage of generics in this article is useful for dynamic inheritance, although only to achieve compile-time dynamism. as already mentioned, at runtime, the generic variable will be removed from these classes.

Java (programming language)

Published at DZone with permission of Sumith Puri. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How Agile Architecture Spikes Are Used in Shift-Left BDD
  • Securing Cloud-Native Applications: Tips and Tricks for Secure Modernization
  • Beyond Coding: The 5 Must-Have Skills to Have If You Want to Become a Senior Programmer
  • Key Elements of Site Reliability Engineering (SRE)

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: