Module 5: Enumerations, Autoboxing, Generics and
Annotations
Object Oriented Programming with JAVA (MOJCA203)
Textbook Reference: Herbert Schildt, Java The Complete Reference, 9th Edition, Chapter
12
1. Enumerations
1.1 Enumeration Fundamentals
An enumeration is a list ofnamed constants that define a new data type. Enumerations are
created using the enum keyword. Once you define an enumeration, you can create a
variable ofthat type, and its values can only be one ofthe enumeration constants.
Syntax:
java
enum EnumName {
CONSTANT1, CONSTANT2, CONSTANT3;
}
Example — Days ofthe Week
java
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class WorkingDayCheck {
public static void main( String[] args) {
for ( Day d : Day. values() ) {
if ( d == Day. SATURDAY | | d == Day. SUNDAY) {
System. out. println( d + " is NOT a working day") ;
} else {
System. out. println( d + " is a working day") ;
}
}
}
}
Key points:
Each enum constant is implicitly public static final .
Enum constants are compared using == or .equals() .
An enum can be used inside a switch statement.
1.2 The values() and valueOf() Methods
Every enum automatically has two useful methods:
Method Description
values() Returns an array containing a list ofthe enumeration constants, in the order
they are declared.
valueOf(String Returns the enumeration constant whose value corresponds to str . An
str) exact match is required, otherwise a IllegalArgumentException is
thrown.
General form:
java
static enum- type[] values()
static enum- type valueOf( String str)
Example — Canteen Food Items
java
enum FoodItem {
PIZZA( false) , BURGER( false) , SALAD( true) ,
CHICKEN_WRAP( false) , FRUIT_BOWL( true) ;
private boolean vegetarian;
FoodItem( boolean vegetarian) {
this. vegetarian = vegetarian;
}
boolean isVegetarian() {
return vegetarian;
}
}
public class Canteen {
public static void main( String[] args) {
for ( FoodItem item : FoodItem. values() ) {
System. out. println( item + " - " +
( item. isVegetarian() ? " Vegetarian" : " Non- Vegetarian") ) ;
}
// valueOf() demonstration
FoodItem chosen = FoodItem. valueOf(" SALAD") ;
System. out. println(" Selected item: " + chosen + ", Vegetarian: " + chos
}
}
1.3 Java Enumerations Are Class Types
Unlike enumerations in C/C++, a Java enum defines a class type. This means an enum can
have:
Constructors
Instance variables and methods
Its own body
Rules:
Each enum constant is an object ofits enum type.
When you define a constructor for an enum, it is called automatically each time an
enum constant is created.
Enum constructors are always private (or default), since they can only be called from
within the enum itself.
An enum can implement interfaces but cannot extend another class (it implicitly
extends [Link] ).
Example — Employee Types with Health Insurance Eligibility
java
enum EmployeeType {
FULL_TIME(" Eligible for health insurance") ,
PART_TIME(" Eligible for health insurance") ,
INTERN(" Not eligible") ,
CONTRACT(" Not eligible") ;
private String insuranceStatus;
// enum constructor - implicitly private
EmployeeType(String insuranceStatus) {
this. insuranceStatus = insuranceStatus;
}
boolean isInsuranceEligible() {
return this == FULL_TIME | | this == PART_TIME;
}
}
public class HRSystem {
public static void main( String[] args) {
for ( EmployeeType type : EmployeeType. values() ) {
System. out. println( type + " -> " + type. insuranceStatus +
" (" + type. isInsuranceEligible() + ") ") ;
}
}
}
Example — Subscription Plans with Multiple Fields (based on QB Module 5, [Link] 13):
java
enum SubscriptionPlan
{ BASIC( 1, false) ,
STANDARD( 2, false) ,
PREMIUM( 4, true) ,
ULTRA( 4, true) ;
private int screens;
private boolean isAdFree;
SubscriptionPlan( int screens, boolean isAdFree) {
this. screens = screens;
this. isAdFree = isAdFree;
}
int getScreens() { return screens; }
boolean isAdFree() { return isAdFree; }
}
public class Netflix {
public static void main( String[] args) {
System. out. println(" Plans with more than 2 screens & ad- free: ") ;
SubscriptionPlan best = null;
for ( SubscriptionPlan plan : SubscriptionPlan. values() ) {
if ( plan. getScreens() > 2 && plan. isAdFree() ) {
System. out. println( plan) ;
if ( best == null | | plan. getScreens() > best. getScreens() )
best = plan;
}
}
System. out. println(" Best plan: " + best) ;
}
}
1.4 Type Wrappers
Java uses primitive types ( int , char , double , boolean , etc.) for performance reasons —
but manyAPIs (like Collections) work only with objects. Wrapper classes provide a way to
wrap primitive values inside objects.
Primitive Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
All the numeric wrapper classes inherit the abstract class Number , which declares methods
like intValue() , doubleValue() , etc.
Example:
java
Integer iObj = new Integer( 100) ; // deprecated but conceptually valid
int i = iObj. intValue() ; // unwrapping
double d = iObj. doubleValue() ;
Character ch = new Character(' A' ) ;
char c = ch. charValue() ;
1.5 Autoboxing
Autoboxing is the automatic conversion that the Java compiler performs between
primitive types and their corresponding object wrapper classes. The reverse process is
called unboxing.
java
int primitive = 10;
Integer wrapped = primitive; // autoboxing: int - > Integer
int back = wrapped; // unboxing: Integer - > int
Autoboxing also applies automatically when:
Passing a primitive as a parameter to a method expecting the corresponding wrapper
object.
Assigning a primitive value to an object reference ofthe wrapper type.
In expressions and array elements.
Autoboxing and Methods: Autoboxing lets you pass a primitive type to a method that
expects an object, and lets a method return a primitive that is automatically boxed into an
object.
Example:
java
public class AutoboxDemo {
// method expects an Integer object - > autoboxing happens automatically whe
static void display( Integer value) {
System. out. println(" Boxed value: " + value) ;
}
// returns Integer, but return statement uses a primitive int - > autoboxed
static Integer square( int n) {
return n * n; // autoboxing on return
}
public static void main( String[] args) {
display( 25) ; // autoboxing: int literal - > Integer
Integer result = square( 6) ; // 36 gets autoboxed into an Integer
int val = result; // unboxing back to int
System. out. println(" Square: " + result) ;
System. out. println(" Unboxed: " + val) ;
// Autoboxing in collections ( common real use case)
java. util. List<Integer> marks = new java. util. ArrayList<>() ;
marks. add( 90) ; // int autoboxed to Integer
marks. add( 85) ;
int total = 0;
for ( int m : marks) { // Integer unboxed to int
total += m;
}
System. out. println(" Total: " + total) ;
}
}
2. Generics
2.1 What Are Generics?
Generics enable you to write classes, interfaces, and methods that operate on a type
parameter, allowing the same code to work with different data types safely. Generics
provide compile-time type safety, eliminating the need for explicit casting and reducing
the risk of ClassCastException at runtime.
Benefits:
Type-safety — errors are caught at compile time instead ofruntime.
Code reusability — a single generic class works for multiple data types.
Eliminates the need for typecasting.
2.2 A Simple Generics Example
General form ofa generic class w ith a single type parameter:
java
class ClassName<T>
{ T obj;
ClassName(T o) { obj = o; }
T getObj() { return obj; }
}
Example — Vehicle Registration System
java
class Vehicle<T> {
private T registrationNumber;
private T ownerName; // could also use a second type parameter ( see 2. 3)
private int engineCapacity;
Vehicle( T registrationNumber, T ownerName, int engineCapacity) {
this. registrationNumber = registrationNumber;
this. ownerName = ownerName;
this. engineCapacity = engineCapacity;
}
void display() {
System. out. println(" Reg No: " + registrationNumber +
", Owner: " + ownerName + ", Engine CC: " + engineCapacity) ;
}
}
public class VehicleDemo {
public static void main( String[] args) {
Vehicle<String> v1 = new Vehicle<>(" KA09MJ1234", " Ramesh", 150) ;
v1. display() ;
}
}
2.3 AGeneric Class with Two Type Parameters
A generic class can accept more than one type parameter, separated by commas: class
ClassName<T, U> { ... }
Example — LibraryResource
java
class LibraryResource<T, U>
{ private T resourceId;
private U resourceTitle;
private boolean isAvailable;
LibraryResource( T resourceId, U resourceTitle, boolean isAvailable) {
this. resourceId = resourceId;
this. resourceTitle = resourceTitle;
this. isAvailable = isAvailable;
}
void display() {
System. out. println("ID: " + resourceId + " | Title: " + resourceTitle +
" | Available: " + isAvailable) ;
}
}
public class LibrarySystem {
public static void main(String[] args) {
LibraryResource<Integer, String> book =
new LibraryResource<>( 101, " Java The Complete Reference", true) ;
LibraryResource<String, String> journal =
new LibraryResource<>(" J- 45", " IEEE Transactions", false) ;
book. display() ;
journal. display() ;
}
}
Example — Patient Records
java
class Patient<T, U> {
T id;
U name;
double temperature;
Patient( T id, U name, double temperature) {
this. id = id;
this. name = name;
this. temperature = temperature;
}
void display() {
System. out. println(" Patient ID: " + id + ", Name: " + name +
", Temp: " + temperature + " °F") ;
}
}
public class Hospital {
public static void main( String[] args) {
Patient<Integer, String> p1 = new Patient<>( 1, " Anita", 98. 6) ;
Patient<String, String> p2 = new Patient<>(" P- 002", " Rahul", 101. 2) ;
p1. display() ;
p2. display() ;
}
}
2.4 The General Form ofa Generic Class
java
class GenericClassName<T1, T2, . . . , Tn> {
// T1, T2, . . . Tn act as placeholders for actual types
// supplied when an object of the class is created
}
// Object creation:
GenericClassName<Type1, Type2, . . . , TypeN> obj = new GenericClassName<>(. . . ) ;
T , U , E , K , V are conventional (but not mandatory) type-parameter names.
Type parameters cannot be primitive types ( int , char ) — only reference/wrapper
types are allowed (e.g. Integer , not int ).
Bounded type parameters can restrict the types that may be used, e.g. <T extends
Number> .
Example —
java
class Order<T, U>
{ private T orderId;
private U customerName;
private double price;
Order( T orderId, U customerName, double price) {
this. orderId = orderId;
this. customerName = customerName;
this. price = price;
}
void display() {
System. out. println(" Order#" + orderId + " by " + customerName + " = ₹"
}
}
public class ECommerce {
public static void main( String[] args) {
Order<Integer, String> o1 = new Order<>( 501, " Kiran", 2499. 0) ;
Order<String, String> o2 = new Order<>(" ORD- 77X", " Meena", 899. 50) ;
o1. display() ;
o2. display() ;
}
}
2.5 Creating Generic Methods
Individual methods can also be made generic, even inside a non-generic class. The type
parameter list appears before the return type ofthe method.
General form:
java
<T> returnType methodName( T parameter) { . . . }
Example — Generic method to find maximum oftwo values:
java
public class GenericMethodDemo {
// Generic method – works for any Comparable type
static <T extends Comparable<T>> T findMax(T a, T b) {
return ( a. compareTo( b) > 0) ? a : b;
}
public static void main( String[] args) {
System. out. println(" Max int: " + findMax( 45, 78) ) ;
System. out. println(" Max double: " + findMax( 3. 14, 2. 71) ) ;
System. out. println(" Max string: " + findMax(" Mango", " Apple") ) ;
}
}
Example — Generic printStats-style method (overloading concept, extended with
generics):
java
public class ArrayUtil {
// generic method that works with any array of Comparable elements
static <T extends Comparable<T>> T findLargest(T[] arr) {
T max = arr[0] ;
for ( T item : arr) {
if ( item. compareTo( max) > 0) max = item;
}
return max;
}
public static void main( String[] args) {
Integer[] nums = {12, 45, 3, 89, 21};
String[] names = {" Zara", " Amit", " Divya"};
System. out. println(" Largest number: " + findLargest( nums) ) ;
System. out. println(" Largest ( alphabetically last) name: " + findLargest
}
}
SLT — Som e Generic Restrictions (to remember):
You cannot create an instance ofa type parameter, e.g. T obj = new T(); is illegal.
You cannot create an array ofa generic type in most cases, e.g. T[] arr = new T[10];
is illegal.
Generic class type parameters cannot be used in static members, since static
members belong to the class, not to a specific parameterized instance.
You cannot use primitive types as type arguments — use wrapper classes instead.
3. Annotations
3.1 Annotation Basics
An annotation is created via an @interface declaration. Annotations provide metadata
about a program element (class, method, field, etc.) that can be processed at compile time or
retrieved at run time through reflection. Annotations do not directly affect program
execution, but tools and frameworks can act upon the information they carry.
Defining a custom annotation:
java
import java. lang. annotation. *;
@Retention( RetentionPolicy. RUNTIME) // makes the annotation available at run
@Target( ElementType. METHOD) // restricts where the annotation may be
@interface TrainerInfo {
String trainerName() ;
String employeeId() ;
double moduleVersion() ;
}
Key meta-annotations used when defining custom annotations:
Meta- Purpose
annotation
@Retention Specifies how long the annotation is retained ( SOURCE , CLASS , or RUNTIME ).
Must be RUNTIME to read it via reflection.
@Target Restricts the kind ofelement ( METHOD , FIELD , TYPE , etc.) the annotation can
be applied to.
@Inherited Allows a subclass to inherit an annotation from its superclass.
@Documented Includes the annotation in generated Javadoc.
3.2 Obtaining Annotations at Run Time by Use ofReflection
The [Link] package (specifically the Method , Class , and Field classes) is
used to inspect annotations at run time.
Example — Corporate Training System
java
import java. lang. annotation. *;
import java. lang. reflect. *;
@Retention( RetentionPolicy. RUNTIME)
@Target( ElementType. METHOD)
@interface TrainerInfo {
String trainerName() ;
String employeeId() ;
double moduleVersion() ;
}
class TrainingModule {
@TrainerInfo( trainerName = " Suresh Kumar", employeeId = " EMP101", moduleVer
public void conductJavaModule() {
System. out. println(" Conducting Java Training Module. . . ") ;
}
@TrainerInfo( trainerName = " Divya Rao", employeeId = " EMP205", moduleVersio
public void conductDatabaseModule() {
System. out. println(" Conducting Database Training Module. . . ") ;
}
}
public class ReflectionDemo {
public static void main( String[] args) throws Exception {
Class<?> cls = TrainingModule. class;
for ( Method m : cls. getDeclaredMethods() ) {
if ( m. isAnnotationPresent( TrainerInfo. class) )
{ TrainerInfo info = m. getAnnotation( TrainerInfo. class) ;
System. out. println(" Method: " + m. getName() ) ;
System. out. println(" Trainer: " + info. trainerName() ) ;
System. out. println(" Employee ID: " + info. employeeId() ) ;
System. out. println(" Module Version: " + info. moduleVersion() )
}
}
}
}
Example — Banking Audit System
java
import java. lang. annotation. *;
import java. lang. reflect. *;
@Retention( RetentionPolicy. RUNTIME)
@Target( ElementType. METHOD)
@interface AuditInfo {
String auditorName() ;
String auditId() ;
String level() ;
}
class BankTransaction {
@AuditInfo( auditorName = " R. Sharma", auditId = " AUD- 901", level = " High")
public void processTransfer() {
System. out. println(" Processing fund transfer. . . ") ;
}
}
public class AuditReflectionDemo {
public static void main( String[] args) throws Exception {
Method method = BankTransaction. class. getMethod(" processTransfer") ;
if ( method. isAnnotationPresent( AuditInfo. class) ) {
AuditInfo audit = method. getAnnotation( AuditInfo. class) ;
System. out. println(" Transaction reviewed by: " + audit. auditorName(
System. out. println(" Audit ID: " + audit. auditId() + ", Level: " + a
}
}
}
3.3 Built-in Annotations
Java provides several standard annotations in [Link] and [Link] :
Annotation Description
@Override Indicates that a method overrides a method in its superclass; compiler
checks this and reports an error ifnot true.
@Deprecated Marks a program element as obsolete; compiler generates a warning if
it is used.
@SuppressWarnings Instructs the compiler to suppress specific warnings (e.g. unchecked ,
deprecation ).
@FunctionalInterface Indicates that an interface is intended to be a functional interface
(exactly one abstract method).
@SafeVarargs Suppresses "unsafe" warnings for varargs methods that use generics.
Example:
java
class Base {
void show() { System. out. println(" Base show() ") ; }
}
class Derived extends Base
{ @Override
void show() { System. out. println(" Derived show() ") ; }
@Deprecated
void oldMethod() { System. out. println(" This method is outdated") ; }
@SuppressWarnings(" unchecked")
void useRawList() {
java. util. List list = new java. util. ArrayList() ;
list. add(" Sample") ;
}
}
Quick Revision Summary
Concept Key Idea
Enum Fundamentals enum defines a fixed set ofnamed constants
Concept Key Idea
values() / valueOf() Iterate constants / convert String → constant
Enums as Class Types Enums can have constructors, fields, methods; implicitly extend Enum
Type Wrappers Object representation ofprimitives ( Integer , Double , etc.)
Autoboxing Automatic primitive ⇌ wrapper conversion done by the compiler
Generics Type-safe, reusable classes/methods using type parameters <T>
Generic Class (2 params) class Name<T, U> { ... }
Generic Methods <T> returnType method(T param)
Annotations Metadata via @interface ; read at run time using reflection
Built-in Annotations @Override , @Deprecated , @SuppressWarnings , etc.