Datatypes

Primitive

  • boolean: default is false
    • literals: true and false
  • byte: default is 0
    • size is 1 byte
    • range: -128 to +127
    • literals:
  • short: default is 0
    • size is 2 bytes
  • int: default is 0
    • size is 4 bytes
  • long: default is 0L or 0l
    • size is 8 bytes
  • float: default is 0.0f or 0.0F
    • size is 4 bytes
  • double: default is 0.0d or 0.0D
    • size is 8 bytes
  • char: default is \u0000
    • size is 2 bytes (16-bit unicode)
    • range is \u0000 (0) to \uffff

Non-Primitive

  • aka Derived datatypes
  • default is null
  • Examples include objects of:
    • Class
    • Array
    • Interface
    • Object
    • String

Literals

  • Integer
    • long: l or L
    • hex: 0x1a (prefix)
    • binary: 0b11010 (prefix)
  • Floating point
    • float: f or F
    • double: d or D
    • scientific: 1.234e2 (e or E)
  • Character and String
    • char: 'a' (single quotes)
    • string: "hello" (double quotes)
    • Unicode: "S\u00ED Se\u00F1or" (Sí Señor)
  • Class
    • String.class (suffix)
    • This refers to the object (of type Class) that represents the type itself.
  • In Java SE 7 and later, any number of underscore characters (_) can appear anywhere between digits in a numerical literal.
    • 9012_3456L, 3.14_15F, 0x7fff_ffff_ffff_ffffL etc.

Variables

Local Variables

  • Local variables are variables with local scope
  • They belong to method, constructor or block
  • Once execution goes out of scope the variable is destroyed
  • They cannot be static variable
  • Local Variables are not initialized with default value as described in Datatypes
  • On the other hand, fields are initialized with the default values
class HelloWorld {
    public static void main(String[] args) {
        int x;
 
        // error: variable x might not have been initialized
        System.out.println(x); // compilation error
        fun(x); // compilation error
    }
    
    static void fun(int x) {
        // do nothing
    }
}

Limits

  • Integer.MAX_VALUE

Testing datatype

  • Using reflection
a.getClass().getName()
  • Using instanceof
    • Can be used with class/sub class/parent class/interface
    • There is compile time type checking if the object and class are in the same hierarchy, else compilation fails
    • Remember: a Child cast to be a Parent, is still a Child.
    • In simple words, it checks if left object can be cast to right type successfully
// Syntax
obj instanceof Class
 
// Example classes
class Shape {}
class Circle extends Shape {}
class Rectangle extends Shape {}
 
// Testing
var circle = new Circle();
var rectangle = new Rectangle();
var shape = new Shape();
Shape circleShape = (Shape) new Circle();
 
System.out.println(circle instanceof Circle);  // true
System.out.println(circle instanceof Shape);  // true, Shape is super class
System.out.println(shape instanceof Circle); // false
System.out.println(circleShape instanceof Circle); // true
System.out.println(circleShape instanceof Rectangle); // false
 
System.out.println(circle instanceof Rectangle); // compilation error
  • Checking class relationship
Super.class.isAssignableFrom(Sub.class);
  • Checking objects relationship
superObj.getClass().isAssignableFrom(subObject.getClass());

Type inference

  • Java 10+
  • You can use var keyword which can automatically infer type based on assignment
var language = "Java"; // String

Casting

  • Types based on if target is explicitly defined or not:
    • implicit
    • explicit
  • Types based on if target is super class or subclass:
    • up-casting
    • down-casting
  • boolean cannot be casted neither implicitly or explicitly
  • Following diagram shows implicit casting
flowchart LR
byte --> short
short --> int
int --> long
long --> float
float --> double
char --> int
  • Explicit casting (reverse arrow) like long int, lose the information
  • In scenario like long float, Information may get lost
long bigLong =  1_200_000_002L;
float bigFloat = bigLong; // 1.2E9 (= 1_200_000_000)
  • Up-casting and Down-casting reference types:
    • Up-casting is implicit or explicit
    • Down-casting must be explicit
// up casting, child to parent
Shape circleShape = new Circle();
 
// down casting, parent to child
// must be done explicitly
Circle circle = (Circle) circleShape;

Memory considerations

  • All values of primitive types are stored in stack memory
  • Address of reference type is stored in stack memory itself but the address points to the address in heap memory

Wrapper Classes

  • Every primitive datatype has a corresponding wrapper class
  • Wrapper classes are final and immutable
  • Wrapper class objects can be null while primitives cannot be null
  • Collections require objects and can not work with primitives, hence wrapper classes help primitives to be used in collections
  • Never use == with wrappers since they are reference types. Always use equals() to check the equality of values. Check Integer Interning

Integer Interning

Integer i1 = 1000;
Integer i2 = 1000;
 
i1 == i2 // false
 
Integer i3 = 10;
Integer i4 = 10;
 
i3 == i4 // true

Autoboxing, Boxing and Unboxing

  • Boxing: process of converting primitive to wrapper class
  • Unboxing: process of converting wrapper class to primitive
  • Autoboxing: automatically convert primitive to wrapper class or vice versa
int primitiveInt = 42;
 
// Boxing
Integer boxedInt = Integer.valueOf(primitiveInt);
 
// Unboxing 
int primitiveInt = boxedInt.intValue(); // if boxedInt is null, then NPE
 
// Autoboxing: Primitive -> Wrapper
Integer autoBoxedInt = primitiveInt;
 
// Autoboxing: Wrapper -> Primitive
// if boxedInt is null, then NPE
// internally invokes `boxedInt.intValue()`
int autoUnboxedInt = boxedInt;
 
  • Arithmetic Operations
Integer n1 = 50;
Integer n2 = 10;
// causes internal auto-boxing into primitive and then boxing
// n1.intValue() and n2.intValue() is used internally
Integer result = n1 / n2; // autoboxing, if n2 == null, then NPE