Type System

Rules

Type Polymorphism

Generics

  • Generics are parameterized types in Java.
  • This allows types like Integer, String or user-defined types to be a parameter to methods, classes or interfaces.
  • One of the ways of doing Generic Programming in Java (Java provides Metaprogramming capabilities too).
Types
  • Generic classes
  • Generic methods
  • Generic interfaces
Defining
Naming convention
  • T – Type
  • E – Element
  • K – Key
  • N – Number
  • V – Value
Classes
class Test<T> {
	T obj;
	Test(T obj) { this.obj = obj; }
	public T useT() { return this.obj; }
}

Multiple types

class Test<T, U>{
	T obj1;
	U obj2;
	
	Test(T obj1, U obj2){
		this.obj1 = obj1;
		this.obj2 = obj2;
	}
}
Methods
class Test {
	static <T> void genericMethod(T element){
		// element...
}
Usage
  • Generics work only with reference types

    Test<int> obj = new Test<int>(20); //compile time error
    
  • They work with primitive arrays since those are also references.

    ArrayList<int[]> a = new ArrayList<>();
    
  • Generic types maintain type safety. Different types behave differently. For example, you can't assign a generic initialized with Integer to a generic initialized with String.

Generic Programming#Compile time checks
Bounded Types

Allows to place constraints on generic types.

  • Single bound
    public class Calculator<T extends Number> {
        public double square(T number) {
            return number.doubleValue() * number.doubleValue();
        }
    }
    
  • Multiple bounds
        public class Utility<T extends Comparable<T> & Serializable> {
          public void print(T obj) {
              System.out.println(obj);
          }
      }
    
Wildcard Types
  • Unbounded wildcards (?): Represents any type - when type parameter doesn't matter
    public class Utility<T extends Comparable<T> & Serializable> {
        public void print(T obj) {
        }
    }
    
  • Upper-bounded: Specifies the parent class - type parameter can be subclass of the specified bound
        public double sum(List<? extends Number> list) {
          for (Number num : list) {
      	
          }
      //...
      }
    
  • Lower-bounded: Specifies the child class - type parameter can be super class of the specified bound
        public void addElements(List<? super Integer> list) {
          list.add(1);
          list.add(2);
      	}
    

Type Conversion/Casting

Boxing Unboxing

  • Conversion from Wrapper class to primitive type and vice-versa
  • Syntax
    • No notation required

Primitive conversion

Type Systems#Narrowing Conversion

Type Systems#Explicit Casting

Syntax

Need to explicitly state that we're fine with the resulting loss of information

float b;
int a = (int) b;

//show(int a)

show((int)b);
Type Systems#Widening Conversion

Type Systems#Implicit Casting

Syntax

No notation required

Why? Moving to larger primitive types - does not loose any information.

int a = 34;
float b = a;
double c = b;
Numeric Promotion in inter-type operations

It is necessary both numeric operands are compatible in size in an operation. If not, they're converted.

Here's how that happens (Rules)

  • If one operand is double, float or long the other promoted to double, float or long respectively
  • Else both are considered int

Object Type Conversion

Type Systems#Upcasting

Type Systems#Implicit Casting

Type Systems#Downcasting
Syntax
  • Type Systems#Explicit Casting

  • Same as narrowing conversion in primitive data types

    float a = 10.5;
    int b = (int) a;
    
    print(a) -10.5
    print(b) -10
    
    Animal animal = new Animal();
    Cat cat = (Animal) animal;
    
  • Another way

    Animal animal = new Animal();
    
    if (Cat.class.isInstance(animal)) {
    	Cat cat = Cat.class.cast(animal);
    }
    

  

###### [[Issues#Class Cast Exception|ClassCastException]]
That is why it is advised to use *instanceOf* check before downcasting.
- instanceOf
	Used to avoid the ClassCastException by checking if the object belongs to a certain type

```java
//Example
if (animal instanceof Cat) {
	((Cat) animal).meow();
}

//case 1
Dog dog = new Dog();
Animal animal = dog;

if(Cat.class.instanceOf(animal)) -false

//case 2

Cat cat = new Cat();
Animal animal = cat;
cat.meow();
Cat.class.instanceOf(animal) -true

String Conversion

  • Conversion from primitive type to String

  • Done through lang.java.lib.classes.wrappers which override the toString() method

  • Syntax

    Integer a = 130;
    String s = a.toString();
    
  • Conversion from String to primitive type

  • Each wrapper class has a parse method → parseXXX()

  • Syntax

    int a = Integer.parseInt(s);
    byte b = Byte.parseByte(s);
    //Exception
    //Since String is made of chars anyway
    //considering the String is made of a single character
    char c = s.charAt(0)
    



## Characteristics

- Type safety: [[Type Systems#Strong Typing]]
- Type checking: [[Type Systems#Static Type Checking]]
- Type Compatibility: [[Type Systems#Nominal Typing (Name-based Typing)]]


## References

- [Generics in Java - GFG](https://www.geeksforgeeks.org/generics-in-java/)

© 2025 All rights reservedBuilt with Flowershow Cloud

Built with LogoFlowershow Cloud