Restricting Generics to a super class of a particular class
In declaration of the class, we specified a constraint “T super Number”
Subclass of Generics
class ColorPrinter<T> extends Printer<T> or Class ColorPrinter extends Printer<String> in case 2 you need to extend a specific type of printer rather than generic type</String></T></T>
Restricting Generics to Subclass
MyListRestricted<T> - We can use the class MyListRestricted with any class extending (any sub class of) Number - Float, Integer, Double etc.</T>
Type Erasure
Type erasure means that generic type information is not available to the JVM at runtime, only compile time. The reasoning behind major implementation choice is simple – preserving backward compatibility with older versions of Java. When a generic code is compiled into bytecode, it will be as if the generic type never existed. This means that the compilation will: Replace generic types with objects Replace bounded types (More on these in a later question) with the first bound class Insert the equivalent of casts when retrieving generic objects.
Child Constructor Rules
Order of Initialization: Always call the parent constructor before initializing the child class’s own members. Constructor Visibility: Ensure the parent constructor is accessible from the child class. If the parent constructor is not public or protected, it might not be accessible. No Implicit Super Call: If the parent class does not have a default constructor (no args constructor), you must explicitly call one of its constructors.
Generic Method
static <X> X doSomething(X number){ X result = number; //do something with result return result; } Integer i = 5; Integer k = doSomething(i);</X>
Constructor Rules
A constructor must have the same name as the class in which it is defined. It does not have a return type, not even void. If no constructor is explicitly defined, the Java compiler provides a default constructor with no arguments. A class can have multiple constructors with different parameter lists (constructor overloading). A constructor can call another constructor in the same class using this(). This must be the first statement in the constructor A constructor can call a constructor from the superclass using super(). This must also be the first statement in the constructor. If a constructor does not explicitly call a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass (super()). If the superclass does not have a no-argument constructor, you must explicitly call a superclass constructor with arguments using super(arguments).
Nested Classes
There are 4 types of Nested classes (LISA)
Static Nested Classes: Defined with the static keyword.
Inner Classes: Non-static nested classes.
Local Classes: Defined within a method – Really, Who needs that!
Anonymous Classes: Classes without a name, defined and instantiated in a single statement.
public class OuterClass {
private int outerValue = 10;
public class InnerClass {
public void display()
{
System.out.println(“Outer value: “ + outerValue);
}
}
public static class StaticNestedClass
{
public void display() {
System.out.println(“Static nested class”);
}
}
public void methodWithLocalClass() {
class LocalClass { public void display() {
System.out.println(“Local class inside method”);
}
}
LocalClass local = new LocalClass(); local.display();
}
public void methodWithAnonymousClass() { Runnable r = new Runnable() { @Override public void run() { System.out.println(“Anonymous class”); } }; new Thread(r).start(); } }
Multiple Classes in same file
Yes, multiple Java classes can be defined in the same file, but there are some rules and best practices to follow: Only One Public Class: If you have a public class, there can be only one public class in the file, and the file name must match the name of the public class. Additional Classes: Any additional classes in the same file must not be public. They can be package-private (default), protected, or private. While it’s technically possible to include multiple classes in one file, it’s generally considered good practice to have each class in its own file. This makes the code easier to find, read, and maintain. public class Main { public static void main(String[] args) { Helper helper = new Helper(); System.out.println(helper.getMessage()); } } class Helper { String getMessage() { return “Hello, World!”; } }
Why Static Classes Java
Static Class is a nested class with the static modifier:
Key points:
It is nested inside another class.
It can be instantiated without an instance of the outer class.
Outer.Nested n = new Outer.Nested();
n.hello();
We use static nested classes to:
Avoid unnecessary references to the outer class.
Group related classes logically.
Reduce memory overhead as outer class need not be instantiated
Make instantiation independent of an outer instance.
Why Inner Classes
If a class is only relevant to one outer class, you can group it inside:
Inner classes can access private fields and methods of the outer class:
class Outer {
private int x = 10;
class Inner {
void printX() {
System.out.println("x = " + x); // can access private field
}
} }Records
public record Person(String name, int age) {}
This line defines an immutable class
Introduced from Java 14
Person person = new Person(“Alice”, 30);
Nested Records
public record Person(String name, int age, Address address) {
public record Address(String street, String city) {}
}
Person.Address addr = new Person.Address(“Main St”, “Paris”);
Person person = new Person(“Alice”, 30, addr);
System.out.println(person);
System.out.println(person.name()); // Alice
Nested records can be static or non-static, but in practice, they’re usually static.
They behave like any other record: immutable, with auto-generated constructor, getters, equals(), hashCode(), toString().
Nested records are perfect for modeling immutable hierarchical data structures, like JSON or DTOs.
@Builder annotation with nested records
@Builder
public record Person(String name, int age, Address address) {
@Builder
public record Address(String street, String city) {}
}
Both Person and Address are records. Both have @Builder annotations.
Person person = Person.builder()
.name(“Alice”)
.age(30)
.address(Person.Address.builder()
.street(“Main St”)
.city(“Paris”)
.build())
.build();