Core Java Concepts: Data Structures, OOP, and Polymorphism
Data Types and Collections
Java provides several core data structures for storing and managing data.
public class CoreExamples {
public static void main(String[] args) {
// Array
int[] numberArray = new int[]{10, 20, 30};
System.out.println(numberArray[0]); // Prints 10
numberArray[2] = 40; // Modify element
// ArrayList
ArrayList<String> stringList = new ArrayList<>();
stringList.add("Alpha");
stringList.set(0, "Beta");
String element = stringList.get(0);
stringList.remove(0);
int listSize = stringList.size();
// HashMap
HashMap<String, Integer> scoreMap = new HashMap<>();
scoreMap.put("Alice", 95);
System.out.println(scoreMap.get("Alice")); // Prints 95
scoreMap.remove("Alice");
scoreMap.forEach((key, value) -> System.out.println(key + ": " + value));
// Immutable List (Java 9+)
List<String> immutableList = List.of("One", "Two", "Three");
// Immutable Map (Java 9+)
Map<String, String> immutableMap = Map.of("K1", "V1", "K2", "V2");
}
}
Object-Oriented Programming: Constructors
A constructor is a special method invoked when an object is instantiated.
- The constructor name must match the class name exactly.
- It has no return type, not even
void. - Its primary purpose is to initialize the object's member variables (fields).
- A default no-argument constructor is provided automatically if no other constructors are defined.
- Defining any constructor (e.g., a parameterized one) removes the default constructor. A no-argument constructor must then be explicitly written if needed.
- Using constructors for initialization is more convenient then setting fields individually after object creation.
Object-Oriented Programming: Static Variables
Static variables (class variables) differ from instance variables.
- A static variable belongs to the class itself, not to any specific object instance. Only one copy exists and is shared among all instances.
- An instance variable belongs to an object; each object has its own separate copy.
- Static variables are initialized when the class is loaded by the JVM. Instance variables are initialized when an object is created.
- Static variables can be accessed directly via the class name (
ClassName.variableName) or through an object reference, though the former is preferred.
Object-Oriented Programming: Static Methods
Static methods are associated with the class rather than instances.
- Use static methods for functionality that does not depend on or manipulate instance data (e.g., utility functions).
- A static method can access only static members (variables and methods) of the class. It cannot directly access instance members.
- An instance method can access both static and instance members.
- The
thiskeyword cannot be used within a static method, as there is no current object instance. - Static methods cannot be overridden in the traditional sense; method hiding may occur.
Object-Oriented Programming: Inheritance
Inheritance allows a class too acquire the properties and behaviors of another class.
- Java supports single inheritance for classes (a class can extend only one parent class).
- A subclass inherits all non-private fields and methods from its superclass.
- A subclass can override inherited methods to provide specific implementations.
- If a subclass field or method has the same name as one in the superclasss, the superclass member can be accessed using the
superkeyword (e.g.,super.methodName()). - When accessing a member, the JVM looks first in the subclass, then proceeds up the inheritance chain.
Object-Oriented Programming: Method Overriding
Overriding allows a subclass to provide a specific implementation of a method already defined in its superclass.
- The overriding method's access modifier must be at least as permissive as the overridden method's (e.g., a
protectedmethod can be overridden aspublicbut not asprivate). - The method signature (name, return type, and parameter list) must match exactly.
- Methods declared as
private,final, orstaticcannot be overridden.
Object-Oriented Programming: Constructor Chaining
When creating a subclass object, its constructor implicitly calls the superclass constructor first.
- The call to the superclass constructor (
super()) must be the first statement in a subclass constructor, if used. - The
this()keyword can be used within a constructor to call another constructor in the same class (a "brother" constructor). this()andsuper()cannot both be present in the same constructor, as each must be the first statement.
Object-Oriented Programming: Polymorphism
Polymorphism enables an object to take on many forms, typically through inheritance and method overriding.
- Requirements: an inheritance hierarchy, method overriding, and a superclass reference pointing to a subclass object.
- With a polymorphic reference, you cannot directly invoke methods that are unique to the subclass.
- Method calls are resolved at runtime based on the actual object type (dynamic binding). The overridden version in the subclass is executed.
- Field access is resolved at compile time based on the reference type. The field from the superclass is accessed.
- To invoke a subclass-specific method, the reference can be cast to the subclass type.
- Before performing a cast, use the
instanceofoperator to check the object's type to avoidClassCastException.
class Human {
String identity = "Human";
void move() {
System.out.println("Human moving...");
}
}
class Pupil extends Human {
String identity = "Pupil";
@Override
void move() {
System.out.println("Pupil running...");
}
void study() {
System.out.println("Pupil studying...");
}
}
class Instructor extends Human {
String identity = "Instructor";
@Override
void move() {
System.out.println("Instructor walking...");
}
void teach() {
System.out.println("Instructor teaching...");
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
Human ref1 = new Instructor();
Human ref2 = new Pupil();
ref1.move(); // Output: Instructor walking...
ref2.move(); // Output: Pupil running...
System.out.println(ref1.identity); // Output: Human (field from reference type)
System.out.println(ref2.identity); // Output: Human
// ref1.teach(); // Compile error: Cannot resolve method 'teach' in 'Human'
Pupil pupilObj = new Pupil();
// Casting
Pupil anotherPupilRef = (Pupil) pupilObj;
anotherPupilRef.study(); // Output: Pupil studying...
// Type checking with instanceof
if (ref1 instanceof Instructor) {
Instructor instructorRef = (Instructor) ref1;
instructorRef.teach(); // Output: Instructor teaching...
}
}
}
Interfaces
An interface defines a contract that implementing classes must fulfill.
- Fields in an interface are implicitly
public,static, andfinal(constants). - Methods declared in an interface are implicitly
publicandabstract(unless default or static). - Abstract methods in an interface cannot have a method body.
- Interfaces cannot be instantiated directly.
- A class implements an interface using the
implementskeyword. - A non-abstract class must provide concrete implementations for all abstract methods declared in the interface. Otherwise, the class itself must be declared
abstract.
Interface Method Types
Modern Java interfaces support several method types:
defaultmethods: Provide a default implementation. Implementing classes can override them.privatemethods: Helper methods usable only within the interface itself.staticmethods: Utility methods associated with the interface, callable via the interface name.