Core Java Object-Oriented Programming Concepts: Abstraction, Inheritance, and Polymorphism
Object-Oriented Programming Fundamentals
Object-oriented programming organizes software around the interaction of data structures and the operations performed on them.
Clases and Objects
A class serves as a blueprint for creating objects, defining both their state (attributes) and behavior (methods).
Defining a Class
public class Feline {
String identifier;
int yearsOld;
void consumeFood() {
System.out.println("The cat eats fish!");
}
}
This Feline class defines two attributes (identifier, yearsOld) and one behavior (consumeFood).
Creating Objects from a Class
public static void main(String[] args) {
Feline myCat = new Feline();
myCat.consumeFood();
}
Class Details: Encapsulation
The this Keyword
Within instance methods and constructors, this refers to the current object and helps differentiate instance variables from local parameters.
private String petName;
public void assignName(String petName) {
this.petName = petName;
}
Constructors
Constructors initialize new objects. Java provides a default no-argument constructor unless you define any constructors explicitly.
public class Feline {
private String identifier;
private int yearsOld;
public Feline() {}
public Feline(String identifier, int yearsOld) {
this.identifier = identifier;
this.yearsOld = yearsOld;
}
void consumeFood() {
System.out.println("The cat eats fish!");
}
}
Constructors can be overloaded. Many IDEs provide shortcuts (like Alt+Insert) to generate constructors.
Encapsulation Implementation
Encapsulation restricts direct access to an object's data, using private fields with public getter and setter methods for controlled modification.
public class Feline {
private String identifier;
private int yearsOld;
public Feline() {}
public Feline(String identifier, int yearsOld) {
this.identifier = identifier;
this.yearsOld = yearsOld;
}
public String getIdentifier() { return identifier; }
public void setIdentifier(String identifier) { this.identifier = identifier; }
public int getYearsOld() { return yearsOld; }
public void setYearsOld(int yearsOld) {
if (yearsOld > 0 && yearsOld < 30) { // Validation logic
this.yearsOld = yearsOld;
}
}
void consumeFood() {
System.out.println("The cat eats fish!");
}
}
Access modifiers define visibility:
private: Accessible only within the class- Default (no modifier): Accessible within the same package
protected: Acessible within the same package and subclassespublic: Accessible from anywhere
Extended Topic: Variable Arguments
Variable arguments (varargs) allow a method to accept zero or more arguments of a specified type.
public class Calculator {
public int calculateSum(int... values) {
int result = 0;
for (int value : values) {
result += value;
}
return result;
}
}
Varargs Rules
- Zero or more arguments are allowed
- Arguments can be passed as an array
- Varargs are implemented as arrays internally
- Varargs must be the last parameter in the parameter list
- Only one varargs parameter is permitted per method
Example with mixed parameters:
public class ReportCard {
public String generateReport(String studentName, double... grades) {
double total = 0;
for (double grade : grades) {
total += grade;
}
return studentName + " has a total score of: " + total;
}
}
Class Details: Inheritance
Inheritance enables a class (subclass) to acquire the fields and methods of another class (superclass), promoting code reuse.
public class Human {
private String name;
private int age;
public void consume() {
System.out.println("Eating");
}
}
public class Male extends Human {
private String facialHair;
public void urinate() {
System.out.println("Standing while urinating");
}
}
Java supports single inheritance (one direct parent class). The Object class is the ultimate ancestor of all classes.
The super Keyword
The super keyword references the immediate parent class, allowing access to its members and constructors.
public void urinate() {
super.consume(); // Calls parent's method
System.out.println("Standing while urinating");
}
In constructors, super() must be the first statement if used. this() and super() cannot coexist in the same constructor.
Method Overriding
Method overriding occurs when a subclass provides its own implementation of a method already defined in its superclass.
public class Vehicle {
private String type = "Generic Vehicle";
public void displayType() {
System.out.println(type);
}
}
public class Car extends Vehicle {
private String type = "Automobile";
@Override
public void displayType() {
System.out.println(type);
super.displayType();
}
}
Class Details: Polymorphism
Polymorphism enables objects of different classes to be treated as objects of a common superclass, typically through inheritance and method overriding.
Polymorphism Example
public class Creature {
private String species;
public Creature() {}
public Creature(String species) { this.species = species; }
public String getSpecies() { return species; }
public void setSpecies(String species) { this.species = species; }
public void consume() {
System.out.println("Consuming food");
}
}
public class Canine extends Creature {
@Override
public void consume() {
System.out.println(getSpecies() + " eats bones");
}
}
public class Rodent extends Creature {
@Override
public void consume() {
System.out.println(getSpecies() + " eats cheese");
}
}
Using Polymorphism
public class MainTest {
public static void main(String[] args) {
Creature animal1 = new Canine();
animal1.setSpecies("Husky");
animal1.consume();
Creature animal2 = new Rodent();
animal2.setSpecies("Jerry");
animal2.consume();
}
}
Output:
Husky eats bones
Jerry eats cheese
Polymorphism is often used with methods that accept superclass parameters:
public static void demonstrateBehavior(Creature creature) {
creature.consume();
}
Polymorphism Rules
- For member variables: Reference type determines access (compile-time and runtime)
- For instance methods: Reference type determines compilation check, object type determines execution (runtime polymorphism)
Accessing Subclass-Specific Methods
To invoke methods unique to a subclass, you must cast the reference to the subclass type.
public class Bird extends Creature {
@Override
public void consume() {
System.out.println("Bird eats seeds");
}
public void fly() {
System.out.println("Bird is flying");
}
}
public class MainTest {
public static void main(String[] args) {
Creature creatureRef = new Bird();
creatureRef.consume();
// Downcasting with type checking
if (creatureRef instanceof Bird) {
Bird birdRef = (Bird) creatureRef;
birdRef.fly();
}
}
}