Enumeration is a common programming feature that is found in several other programming languages, it was not part of the original specification for Java. One reason for this is that enumeration is technically a convenience rather than a necessity. However, over the years, many programmers had wanted Java to support enumerations because they offer an elegant, structured solution to a variety of programming tasks. This request was granted by the release of JDK 5, which added enumerations to Java.

In its simple form, an enumeration is a list of named constants that define a new data type. An object of an enumeration type can hold only the values that are defined by the list. Thus, enumeration gives us a way to precisely define a new type of data that has a fixed number of valid values.

From a programming perspective, enumerations are useful whenever we need to define a set of values that represent a collection of items.

Enumeration Fundamentals

An enumeration is created using the enum keyword. For example, here is a simple enumeration that lists various forms of transportation

enum Transport {

CAR, TRUCK, AIRLINES, TRAIN, BOAT

}

The identifiers CAR, TRUCK, and so on are called enumeration constants, or enum constants for short. Each is implicitly declared as a public, static member of Transport. The enumeration constants’ type is the type of the enumeration in which the constants are declared, which is transport in this case.

We declare and use an enumeration variable in much the same way that you do one of the primitives types. For example, this declares tp  as a variable of enumeration type Transport

Transport tp;

Because tp is of type Transport, the only values that is can be assigned are those constants defined by the enumerations, or null, For example, this assigns tp the value AIRPLANE

tp = Transport. AIRPLANE

The following program puts all of the pieces and demonstrates the Transport enumeration

enum Transport{

    CAR, TRUCK, AIRPLANE, TRAIN, BOAT

}

public class EnumDemo {

    public static void main(String[] args) {

        Transport tp;

        tp = Transport.AIRPLANE;

        System.out.println("The value of tp is "+tp);       

        tp = Transport.TRAIN;

        if(tp == Transport.TRAIN)

        System.out.println("tp contains TRAIN");       

    }   

}

 

The output of the above program is:

The value of tp is AIRPLANE

tp contains TRAIN

Java Enumerations are class Types

Java implements enumerations as class types. Although we do not instantiate an enum using new, it otherwise acts much like other classes. The fact that enum defines a class gives powers to the Java enumeration that enumerations in other languages simply do not have. For example, you can give it constructors, add instance variables and methods and even implements interfaces. Consider the following version of Transport

enum Transport {

    CAR (65),TRUCK(55),AIRPLANE(600),TRAIN(70),BOAT(22);

    private int speed;

    Transport (int s){

        speed = s;

    }

    public int getSpeed (){

        return speed;

    }

}

public class EnumDemo {

    public static void main(String[] args) {

    System.out.println (" Typical speed for an airplane is "+Transport.AIRPLANE.getSpeed()+" miles per hour"); 

    System.out.println ("All Transport speeds : ");

    for(Transport t: Transport.values())

    System.out.println (t+" typical speed is "+t.getSpeed()+" miles per hour.");

    }

}

 

The output of the above program is:

Typical speed for an airplane is 600 miles per hour

All Transport speeds :

CAR typical speed is 65 miles per hour.

TRUCK typical speed is 55 miles per hour.

AIRPLANE typical speed is 600 miles per hour.

TRAIN typical speed is 70 miles per hour.

BOAT typical speed is 22 miles per hour

The values () and valueOf () methods

All enumerations automatically have two predefined methods: values () and valueOf (). Their general forms are shown here:

public static enum type[] values()

public static enum type valueOf(String str)

The values() method returns an array that contains a list of the enumeration constants. The valueOf () method returns the enumeration constant whose value corresponds to the string passed in str. In both cases, enum type is the type of the enumeration. The following program demonstrates the values() and valueOf() methods.

enum Transport{

    CAR,TRUCK,AIRPLANE,TRAIN,BOAT

}

public class EnumDemo {

    public static void main(String[] args) {

        Transport tp;

        System.out.println ("Here are all Transport Constants");

        Transport[] allTransports = Transport.values();

        for(Transport t:allTransports)

        System.out.println(t);       

        tp = Transport.valueOf("AIRPLANE");

        System.out.println("tp now contains "+tp);

    }

}

 

The output of above program is:

Here are all Transport Constants

CAR

TRUCK

AIRPLANE

TRAIN

BOAT

tp now contains AIRPLANE

Enumerations Inherit Enum

Although we cannot explicitly inherit a superclass when declaring an enum, all enumerations implicitly inherit one: java.lang. Enum. This class defines several methods that are available for use by all enumerations. Most often we will not need to use these methods, but there are two that we may find interesting: ordinal () and compareTo ()

The ordinal () method obtains a value that indicates an enumeration constant’s position in the list of constants. This is called its ordinal value. The ordinal () method is shown here.

final int ordinal().

It returns the ordinal value of the invoking constant. Ordinal values begin at zero. Thus, in the Transport enumeration, CAR has an ordinal value of zero; TRUCK has an ordinal value of 1. AIRPLANE has an ordinal value of 2, and so on.

We can compare the ordinal value of two constants of the same enumeration by using the compareTo () method. It has this general form:

final int compareTo (enum type e)

If the invoking constant has an ordinal value less than e’s, then compareTo () returns a negative value. If the two ordinal values are the same, then zero is returned.

 If the invoking constant has an ordinal value greater than e’s, then compareTo () returns a positive value.

The following program demonstrates ordinal () and compareTo().

enum Transport{

    CAR,TRUCK,AIRPLANE,TRAIN,BOAT

}

public class EnumDemo1 {

    public static void main(String[] args) { 

        Transport tp1,tp2,tp3,tp4;

        System.out.println("Here are all Transport constants and their ordinal values");

        for(Transport t :Transport.values())

        System.out.println(t+ " "+t.ordinal());

        tp1 = Transport.AIRPLANE;

        tp2 = Transport.BOAT;

        tp3 = Transport.TRAIN;

        tp4 = Transport.AIRPLANE;

        if(tp1.compareTo(tp2)<0)

        System.out.println (tp1+" comes before "+tp2);

        if(tp1.compareTo(tp2)>0)

        System.out.println (tp2+"comes before "+tp1);

        if(tp1.compareTo(tp4)==0)

        System.out.println (tp1+" equals "+tp4);

    }

}

 

The output of the above program is:

Here are all Transport constants and their ordinal values

CAR 0

TRUCK 1

AIRPLANE 2

TRAIN 3

BOAT 4

AIRPLANE comes before BOAT

AIRPLANE equals AIRPLANE

Type Wrappers

Java uses primitive types such as int, double, to hold the basic data types supported by the language. Primitive types, rather than objects, are used for these quantities for the sake of performance. Using objects for these basic types would add an unacceptable overhead to even the simplest of calculation. Thus, the primitive types are not part of the object hierarchy, and they do not inherit Object.

Despite the performance benefits offered by the primitive types, there are times when we will need an object representation. For example, we cannot pass a primitive type by reference to a method. Also, many of the standard data structures implemented by Java operate on an object, which means that we cannot use these data structures to store primitive types. To handle these situations, Java provides type wrappers, which are classes that encapsulate a primitive type within an object. These type wrappers are Double, Float, Integer, Short, Byte, Character and Boolean.

Wrapper class : In java language everything is object but Primitive data types are not objects. So, we need a conversion from primitive data type to object .For this conversion java provides Wrapper classes. So, wrapper classes are those that wrap or enclose primitive types and give an appearance of an object. Java provides 8 wrapper classes that are inside java.lang package and represent 8 primitive data types that is those classes are similar to primitive data types but starting with capital letter. Following list shows the wrapper class with their primitive data types.

Primitive data types Wrapper class
   Byte Byte
  Short Short
  int Integer
  Long Long
  Float Float
  Double Double
  Char Character
  Boolean Boolean

Importance of Wrapper classes

There are mainly two uses with wrapper classes.

  1. To convert simple data types into objects, that is, to give object form to a data type; here constructors are used.
  2. To convert strings into data types (known as parsing operations), here methods of type parseXXX() are used.

Program that demonstrate the conversion from primitive data type to object using wrapper class

public class WrappingUnwrapping{

   public static void main(String args[]) {          

         byte grade = 2;

          int marks = 50;

         float price = 8.6f;                                           

         double rate = 50.5;

          Byte g1 = new Byte(grade);                     

         Integer m1 = new Integer(marks);

         Float f1 = new Float(price);

         Double r1 = new Double(rate);       

          System.out.println("Values of Wrapper objects (printing as objects)");

         System.out.println("Byte object g1:  " + g1);

         System.out.println("Integer object m1:  " + m1);

         System.out.println("Float object f1:  " + f1);

         System.out.println("Double object r1:  " + r1);                          

          byte bv = g1.byteValue();               

         int iv = m1.intValue();

         float fv = f1.floatValue();

         double dv = r1.doubleValue();       

          System.out.println("Unwrapped values (printing as data types)");

         System.out.println("byte value, bv: " + bv);

         System.out.println("int value, iv: " + iv);

         System.out.println("float value, fv: " + fv);

         System.out.println("double value, dv: " + dv);

   }

}

 

Autoboxing

Java has two very helpful features: autoboxing and auto unboxing. These features were not part of the original specification for Java, but were added by JDK 5. Autoboxing/unboxing greatly simplifies and streamlines code that must convert primitive types into objects and vice versa.  Because such situations are frequently found in java code, the benefits of autoboxing/unboxing affect nearly all Java programmers.

Autoboxing Fundamental

 Autoboxing is the process by which a primitive type is automatically encapsulated (boxed) into its equivalent type wrapper whenever an object of that type is needed. There is no need to explicitly construct an object. Autoboxing is the process by which the value of a boxed object is automatically extracted (unboxed) from a type wrapper when its value is needed. There is no need to call a method such as intValue () or doubleValue ().

The addition of autoboxing and auto unboxing greatly streamlines the coding of several algorithms. It also helps prevent autoboxing. It is not necessary to manually construct an object in order to wrap a primitive type. We need only assign that value to a type wrapper reference. Java automatically constructs the object for us. Let us consider the following example

public class AutoBox {

    public static void main(String[] args){

        Integer iob = 100;

        int i=iob;

        System.out.println(i+" "+iob);

    }   

}

 

The output of above program is:

100 100

Autoboxing and Methods

In addition to the simple case of assignments, autoboxing automatically occurs whenever a primitive type must be converted into an object, and auto unboxing takes place whenever an object must be converted into a primitive type. Thus, autoboxing/unboxing might occur when an argument is passed to a method or when a value is returned by a method. For example, consider the following.

public class AutoBox {

    static void m(Integer v){

        System.out.println("m() received" +v);

    }

    static int m2(){

        return 10;

    }

    static int m3(){

        return 99;

    }

    public static void main(String[] args){

        m(99);

        Integer iob = m2();

        System.out.println("Return value from m3() is "+iob);

        int i = m3();

        System.out.println("Return value from m3() is "+i);

        iob = 100;

        System.out.println("The square root of iob is "+Math.sqrt(iob));

       }   

}

 

The output of the above program is:

m() received99

Return value from m3() is 10

Return value from m3() is 99

The square root of iob is 10.0

Autoboxing/Unboxing occurs in Expressions

In general, autoboxing and unboxing take place whenever a conversion into an object or from an object to is required. This applies to expression. Within an expression, a numeric object is automatically unboxed. The outcome of the expression is reboxed, if necessary. For example, consider the following code.

public class AutoBox {   

    public static void main(String[] args){

        Integer iob,iob2;

        int i;

        iob = 99;

        System.out.println("Original value of iob: :"+iob);

        ++iob;

        System.out.println("After ++iob :"+iob);

        iob+=10;

        System.out.println("After iob +=10 :"+iob);

        iob = iob/10;

        System.out.println("After iob/10 :"+iob);

       }  

}

 

The output of the above program is:

Original value of iob: :99

After ++iob :100

After iob +=10 :110

After iob/10 :11

Autoboxing/Unboxing helps Prevent Errors

In addition to the convenience that it occurs, autoboxing/unboxing can also help prevent error. For example, consider the following program:

class UnboxingError{

public static void main(String args[]){

Integer iob = 1000;

int I = iob.byteValue();

System.out.println(i);

}

}

 

This program displays not the expected value of 1000 but -24. The reason is that the value inside iob is manually unboxed by calling byteValue (), which cause the truncation of the value stored in iob, which is 1,000. This results in the garbage of -24 being assigned to i. Autoboxing prevents this type of error because the value in iob will always auto unbox into a value compatible with int.

 Annotations (Metadata): Another feature added to Java by JDK 5 is the annotation. It enables us to embed supplement information (an annotation) into source file. For example, we might annotate a method with information about its version status. This information does not change the actions of a program. However, various tools can use this information, during both development and deployment. For example, an annotation might be processed by source code generator, by the compiler or by a development tool. The term metadata is also used to refer to this feature, but the term annotation is the descriptive and more commonly used

Creating and Using an Annotation

 An annotation is created through a mechanism based on the interface. Here is a simple example:

@interface MyAnno{

String str();

int val();

}

 

This declares an annotation called MyAnno. Notice the @ that precedes the keyword interface. This tells the compiler that an annotation type is being declared. Next, notice the two members str () and value (). All annotations consist solely of method declarations. However, you don’t provide bodies for these methods. Instead, Java implements these methods. Moreover, the methods act much like fields.

All annotations types automatically extend the Annotation interface. Thus, Annotation is a super-interface of all annotations. It is declared within the java.lang. annotation package.

Specifying a Retention Policy

A retention policy determines at what point an annotation is discarded. Java defines three such policies, which are encapsulated within the java.lang.annotation.RetentionPolicy enumeration. They are SOURCE, CLASS, and RUNTIME.

An annotation with a retention policy of SOURCE is obtained only in the source file and is discarded during compilation.

An annotation with a retention policy of CLASS is stored in the .class file during compilation. However, it is not available through the JVM during the run time.

An annotation with a retention policy of RUNTIME is stored in the .class file during compilation and is available through the JVM during run time. Thus, RUNTIME retention offers the greatest annotation persistence.

The retention policy is specified for an annotation by using one of Java’s built in annotations:

@Retention (retention-policy)

The following version of MYAnno uses @Retention to specify they RUNTIME retention policy. Thus, MyAnno will be available to the JVM during program execution.

@Retention (RetentionPolicy.RUNTIME)

@interface MyAnno {

String str ();

int val();

}

Obtaining Annotations at Run Time by Use of Reflection

Reflection is the feature that enables information about a class to be obtained at run time. The reflection API is contained in the Java.lang.reflect package. There are a number of ways to use reflection, and we do not examine them all here.

The first step to using reflection is to obtain a Class object that represents the class whose annotations we want to obtain. Class is one of Java’s built-in classes and is defined in java.lang. There are various ways to obtain a Class object. One of the easiest is to call getClass (), which is a method defined by Object. Its general form is shown here:

final Class getClass()

It returns the Class object that represents the invoking object.

After you have obtained a Class object, you can use its methods to obtain information about the various items declared by the class, including its annotations. If you want to obtain the annotations associated with a specific item declared within a class, you must obtain an object that represents that item. For example, Class supplies the getMethod (), getField (), and getConstructor () methods, which obtains information about a method, field, and constructor respectively. These methods return objects of type Method, Field and Constructor.

To understand the process, Let us work through an example that obtains the annotations associated with a method. To do this, we first obtain a Class object that represents the class, and then call getMethod () on that Class object, specifying the name of method. The getMethod () has this general form:

Method getMethod (String methodname, Class…..paramTypes)

The name of the method is passed in methName. If the method has arguments, then Class objects representing those types must also be specified by paramTypes. The paramTypes is a varags parameter. This means that we can specify as many parameter types as needed including zero. The getMethod() returns a Method object that represents the method. If the method can’t be found, NoSuchMethodException is thrown.

From a Class, Method, Field, or Constructor object, we can obtain a specific annotation associated with that object by calling getAnnotation (). Its general form is shown here:

Annotation getAnnotation (Class annoType)

Here, annoType is a Class object represents the annotation in which we are interested. The method returns a reference to the annotation. Using this reference, we can obtain the values associated with the annotation’s members.

Here is a program that assembles all of the pieces shown earlier and uses reflection to display the annotation associated with a method.

import java.lang.annotation.*;

import java.lang.reflect.*;

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnno {

    String str();

    int val();

}

public class Meta {

    @MyAnno(str = "Annotation Example ",val = 100)

    public static void myMeth(){   

    Meta ob = new Meta();

    try{

    Class c = ob.getClass();

    Method m = c.getMethod("myMeth");

    MyAnno anno = m.getAnnotation(MyAnno.class);

    System.out.println(anno.str()+" "+anno.val());

       

}catch(NoSuchMethodException e){

 System.out.println("Method not found ");

}

}

    public static void main(String[] args) {

    myMeth();

    }  

}

 

Annotation Example 100

Leave a Reply

Your email address will not be published. Required fields are marked *