- Introduction: What is OOP?
- Part 1: OOP core concepts
- Part 2: Collections & Generics
- Part 3: Conditions & Loops
- Part 4: Console Reading & Printing
- Part 5: Exceptions & Errors Handeling
- Part 6: Serilization & Deserilization
- Part 7: How to create a full project using java
OOP stands for Object-Oriented Programming.
- Procedural programming is about writing procedures or methods that perform operations on the data.
- Object-oriented programming is about creating objects that contain both data and methods.
Source:
- 1. What is a class?
- 🧰 2. Encapsulation
- 🌐 3. Coherence
- 👁️ 4. Information hiding
- 👨👦 5. Inheritance
- 👨👦👦 6. Polymorphism
- 🗔 7. Abstraction
- 🔗 8. Coupling
- 🗍 9. Overloading
- 🗇 10. Shadowing
- 🏃 11. The Main Class
A class is a Blueprint or template that defines properties and behaviors.
- Can be:
- ⚡
static
: not an instance of the class (global variable). - 🛑
final
: constant variable.
- ⚡
- Must have visibility:
- 🌍
public
: accessible for all classes. - 🔒 default (nothing): accessible in the same package.
- 🔑
private
: accessible within the declared class. - 🛡️
protected
: accessible in the same package and subclasses.
- 🌍
- Must have a datatype:
- 🧬 Primitive: Specifies the size and type of variable:
boolean
(1 bit),byte
(1 byte),short
&char
(2 bytes),int
&float
(4 bytes),long
&double
(8 bytes).
- 🔗 Reference: A pointer that holds the address to the object.
- 🧬 Primitive: Specifies the size and type of variable:
- Have a name:
- ✨ Always start with a lowercase letter and then capitalize the first letter of every subsequent word.
- 💡 For constants (final), use uppercase with underscore (e.g.,
MAX_SIZE
).
- 🛠️ A special method used to initialize objects.
- A class can have many constructors with different parameters (overloading).
- Must have a visibility: A method can be
public
,package
,private
, orprotected
. - Must have a return type:
void
(returns nothing) or returns a value (e.g.,int
,double
,boolean
,String
,Object
...).
- Have a name:
- 📝 Methods should be verbs in mixed case with the first letter lowercase, and capitalize the first letter of each subsequent word (e.g.,
calculateTotal
).
- 📝 Methods should be verbs in mixed case with the first letter lowercase, and capitalize the first letter of each subsequent word (e.g.,
- May have parameters: The values passed to the method.
- May have local variables: Temporary variables that exist only while a method or block runs.
- Have a body: 🧠 The logic of the method.
Example:
Animal
is a class, it has aname
and arace
and it caneat()
andsleep()
.
+----------------------------+
| Animal | <-- Class name
+----------------------------+
| + name: String | <-- Attributes (properties)
| + race: String |
+----------------------------+
| + eat():void | <-- Methods (behaviors)
| + sleep():void |
+----------------------------+
class Animal {
// Class Attributes
public String name;
public String race;
// Class Constructors
public Animal() {} // default constructor
public Animal(String name) {
this.name = name; // 'this.name' refer to the instance variable
}
public Animal(String name, String race) {
this.name = name; // 'this.name' refer to the instance variable
this.race = race; // 'this.race' refer to the instance variable
}
// Class Methods
public void eat() {
System.out.println("Miam Miam!");
}
public void sleep() {
System.out.println("ZZzz...");
}
}
Putting attributes & behaviors (methods) of the same kind in one class.
Example:
The
Animal
class encapsulates attributes (name
,race
) and methods (eat()
,sleep()
) together within one class.
+----------------------------+
| Animal |
+----------------------------+
| + name: String | <-- Attributes (public)
| + race: String |
+----------------------------+
| + eat():void | <-- Methods (public)
| + sleep():void |
+----------------------------+
Intra module relationships within a class.
Example:
In the
Animal
class, thename
andrace
attributes and the methodseat()
,sleep()
andmakeSound()
are all related and belong to the same class module, showing strong intra-module cohesion.
+--------------------------------+
| Animal |
+--------------------------------+
| + name: String |
| + race: String |
+--------------------------------+
| + eat():void |
| + sleep():void |
+--------------------------------+
Hide sensitive information from the user by:
- declare class variables/attributes as private.
- provide public getters and setters to access the data.
Example:
The
name
attribute is private, and it can only be accessed or modified using the publicgetName()
andsetName()
methods.
+--------------------------------+
| Class: Animal |
+--------------------------------+
| - name: String | <-- Attributes (private)
| - race: String |
+--------------------------------+
| + eat():void | <-- Methods (public)
| + sleep():void |
| + getName():String | <-- Public getter (returns the name value)
| + setName(newName:String):void | <-- Public setter (take the new name value as an attribute and update the name value)
+--------------------------------+
class Animal {
// Class Attributes
private String name;
private String race;
// Class Constructors
public Animal() {}
public Animal(String name) {
this.name = name; // 'this.name' refer to the instance variable
}
public Animal(String name, String race) {
this.name = name; // 'this.name' refer to the instance variable
this.race = race; // 'this.race' refer to the instance variable
}
// Class Methods
public void eat() {
System.out.println("Miam Miam!");
}
public void sleep() {
System.out.println("ZZzz...");
}
// Class Getters
public String getName() {
return name;
}
public String getRace() {
return race;
}
// Class Setters
public void setName(String newName) {
this.name = newName;
}
public void setRace(String newRace) {
this.race = newRace;
}
}
Inheriting attributes and methods from one class to another.
- superclass (parent): the class being inherited from.
- subclass (child): the class that inherits from another class.
Example:
The
Dog
class inherits from theAnimal
class, so it gets theeat()
andsleep()
methods, and it can also add its own methods, likebark()
.
+--------------------------------+
| Animal |
+--------------------------------+
| - name: String | +--------------------+
| - race: String | | Dog |
+--------------------------------+ <──────────────── +--------------------+
| + eat():void | | + bark():void |
| + sleep():void | +--------------------+
| + getName():String |
| + setName(newName:String):void |
+--------------------------------+
class Dog extends Animal {
// Class constructor
public Dog(String name, String race){
super(name,race); // call the Animal super class constructor
}
public void bark() {
System.out.println("WOUF!");
}
}
Many classes related to each other by inheritance.
- Overriding: Two methods have the same name and same parameters.
Example:
Both
Dog
andCat
classes override themakeSound()
method, but each class implements it differently. The type of object determines which version of the method is called.
+--------------------------------+
| Animal | +--------------------+
+--------------------------------+ | Dog |
| - name: String | <──────────────── +--------------------+
| - race: String | | + makeSound():void | <---- makeSound print "WOUF!"
+--------------------------------+ +--------------------+
| + eat():void | +--------------------+
| + sleep():void | | Cat |
| + makeSound():void | <──────────────── +--------------------+
| + getName():String | | + makeSound():void | <---- makeSound print "MEOW!"
| + setName(newName:String):void | +--------------------+
+--------------------------------+
class Animal {
public void makeSound() {
System.out.println("Say something...");
}
}
class Dog extends Animal {
// Class constructor
public Dog(String name, String race){
super(name,race); // call the Animal super class constructor
}
@Override
public void makeSound() {
System.out.println(super.getName() + " the " + super.getRace() + ": WOUF!");
}
}
class Cat extends Animal {
// Class constructor
public Cat(String name, String race){
super(name,race); // call the Animal super class constructor
}
@Override
public void makeSound() {
System.out.println(super.getName() + " the " + super.getRace() + ": MEOW!");
}
}
Hiding certain details by:
- creating abstract classes: A class that cannot be instantiated and may have both abstract (unimplemented) and concrete (implemented) methods.
Example:
The
Animal
class is abstract with an abstract methodmakeSound()
. TheDog
class implements this method.
+--------------------------------+ +--------------------+
| Animal | | Dog |
+--------------------------------+ +--------------------+
| + eat():void | <---------------- | + makeSound():void | <-- Concrete implementation
| + sleep():void | +--------------------+
| + makeSound():void | <-- Abstract method
+--------------------------------+
abstract class Animal {
// Concrete (implemented) methods
public void eat() {
System.out.println("Miam Miam!");
}
public void sleep() {
System.out.println("ZZzz...");
}
// Abstract (unimplemented) method
public abstract void makeSound();
}
public class Dog extends Animal {
// Concrete implementation
public void makeSound() {
System.out.println("WOUF!");
}
}
- creating interfaces: An interface is a contract that defines a set of abstract methods without providing any implementation.
Example:
Animal
is an interface with tree methods:makeSound()
,eat()
andsleep()
.
+--------------------------------+ +--------------------+
| interface: Animal | | Dog | <-- Dog implement Animale interface
+--------------------------------+ +--------------------+
| + eat():void | <---------------- | + eat():void | <-- Concrete implementations
| + sleep():void | | + steep():void |
| + makeSound():void | | + makeSound():void |
+--------------------------------+ +--------------------+
interface Animal {
// Abstract (unimplemented) method
public void eat();
public void sleep();
public abstract void makeSound();
}
public class Dog implements Animal {
// Concrete implementation
public void eat() {
System.out.println("Miam Miam!");
}
public void sleep() {
System.out.println("ZZzz...");
}
public void makeSound() {
System.out.println("WOUF!");
}
}
Inter module relationships between classes (one class depends on the other).
Example:
Animal
andFood
are coupled, meaning thatAnimal
depends onFood
for some behavior or data, in that caseAnimal
eat(something:Food)
, creating a relationship between them.
+--------------------------------+
| Animal |
+--------------------------------+
| - name: String | +--------------------+
| - race: String | | Food |
+--------------------------------+ _________________ +--------------------+
| + eat(something:Food):void | | + type: String |
| + sleep():void | | + qantity: int |
| + makeSound():void | +--------------------+
+--------------------------------+
class Food {
private String type;
private int quantity;
// Class constructor
public Food(String type, int quantity){
this.type = type;
this.quantity = quantity;
}
// Class Getters
public String getType() {
return type;
}
public int getQuantity() {
return quantity;
}
}
public class Animal {
public void eat(Food something) {
System.out.println(name + " the " + race + ": Miam Miam! *eats "+something.getQuantity()+" "+something.getType()+"*");
}
}
Two or more methods in the same class have the same name but different parameters (signature).
Example:
The
Addition
class has severaladd()
methods with different parameters (int
anddouble
), which allows different combinations of input.
+------------------------------+
| Addition |
+------------------------------+
| + add(int, int):int |
| + add(double, double):double |
| + add(int, int, int):int |
+------------------------------+
class Addition {
public int add(int nbr1, int nbr2) {
return nbr1 + nbr2;
}
public double add(double nbr1, double nbr2) {
return nbr1 + nbr2;
}
public int add(int nbr1, int nbr2, int nbr3) {
return nbr1 + nbr2 + nbr3;
}
}
Variable declared within a specific scope has the same name as a variable declared in an outer scope.
Example:
The InnerScope method
add()
has avalue
variable that shadows thevalue
variable declared in the OuterScope classAddition
, meaning the InnerScope version takes precedence within its scope.
class Addition {
public int value = 5; // Class-level variable
public int add(int nbr1, int nbr2) {
int value = nbr1 + nbr2; // Method variable, shadows the class-level variable
return value;
}
}
The Main
class typically contains the entry point to a Java program, the main()
method. This is where the program starts executing.
Example:
The
Main
class demonstrates how to create instances of anAddition
classe, call methodsadd()
, and access attributevalue
.
public class Main {
public static void main(String[] args) {
Addition addition = new Addition();
System.out.println(addition.add(1,2));
System.out.println(addition.value);
System.out.println(addition.add(1.5,2.5));
System.out.println(addition.add(1,2,3));
}
}
Collection of elements of the same datatypes with a fixed size that start at index 0.
Example:
MyArray
is a collection of 3 integers.
import java.util.Arrays; // Import the Arrays class
public class Main {
public static void main(String[] args) {
int[] MyArray = new int[3]; // Create an array with 3 elements
MyArray[0] = 1; // Set the first element to 1
MyArray[1] = 2; // Set the second element to 2
MyArray[2] = 3; // Set the third element to 3
System.out.println("The Array contains: " + MyArray.length + " elements"); // Access the size of the array
System.out.println("Element at index 0: " + MyArray[0]); // Access the first element
System.out.println("Element at index 1: " + MyArray[1]); // Access the second element
System.out.println("Element at index 2: " + MyArray[2]); // Access the third element
}
}
+---------+---------+---------+
| Index 0 | Index 1 | Index 2 |
+---------+---------+---------+
| 1 | 2 | 3 |
+---------+---------+---------+
Attribute | ArrayList |
---|---|
Structure | A resizable array implementation in the java.util package. |
Storage | Elements are stored in a contiguous block of memory, like an array. |
Access Time | Fast random access using an index. |
Insertions & Deletions | Slower for operations in the middle or beginning of the list because elements need to be shifted. |
Use Case | Good for scenarios where you need fast access to elements but don't frequently insert/remove items in the middle. |
Example:
MyArrayList
is a collection of integers with dynamic sizing.
import java.util.ArrayList; // Import the ArrayList class
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
// Initialize an ArrayList with elements using Arrays.asList()
ArrayList<Integer> myArrayList = new ArrayList<>(Arrays.asList(1, 2, 3));
// Print the contents of the ArrayList
System.out.println(myArrayList); // Output: [1, 2, 3]
}
}
Attribute | LinkedList |
---|---|
Structure | A doubly linked list implementation in the java.util package. |
Storage | Elements are stored in nodes, each containing a data element and pointers to the next and previous nodes. |
Access Time | Slower random access because you have to traverse from the start or end. |
Insertions & Deletions | Faster insertions and deletions since it only requires updating node references. |
Use Case | Suitable when you need frequent insertions and deletions, especially in the middle of the list. |
Example:
MyLinkedList
is a collection of integers that supports efficient insertions and deletions.
import java.util.LinkedList; // Import the LinkedList class
public class Main {
public static void main(String[] args) {
LinkedList<Integer> myLinkedList = new LinkedList<>(); // Create a LinkedList of integers
myLinkedList.add(1); // Add 1 to the LinkedList
myLinkedList.add(2); // Add 2 to the LinkedList
myLinkedList.add(3); // Add 3 to the LinkedList
System.out.println("The LinkedList contains: " + myLinkedList.size() + " elements");
System.out.println("Element at index 0: " + myLinkedList.get(0)); // Access the first element
System.out.println("Element at index 1: " + myLinkedList.get(1)); // Access the second element
System.out.println("Element at index 2: " + myLinkedList.get(2)); // Access the third element
myLinkedList.remove(1); // Remove the element at index 1
myLinkedList.set(1, 2); // Update the new element at index 1 to 2 instead of 3
System.out.println(myLinkedList); // Output: [1, 2]
}
}
+---------+---------+---------+
| Index 0 | Index 1 | Index 2 |
+---------+---------+---------+
| 1 | 2 | 3 |
+---------+---------+---------+
# after removing index 1
+---------+---------+
| Index 0 | Index 1 |
+---------+---------+
| 1 | 3 |
+---------+---------+
# after updating index 1 to 2
+---------+---------+
| Index 0 | Index 1 |
+---------+---------+
| 1 | 2 |
+---------+---------+
Attribute | Iterator |
---|---|
Structure | An interface that provides a way to traverse a collection sequentially without exposing the underlying structure. |
Methods | hasNext() : Checks if there are more elements in the collection.next() : Returns the next element in the collection.remove() : Removes the current element from the collection (optional operation). |
Use Case | Useful when you need to iterate through a collection, such as a List , Set , or Map . |
Example:
Using an Iterator to traverse a LinkedList.
import java.util.LinkedList; // Import the LinkedList class
import java.util.Iterator; // Import the Iterator interface
public class Main {
public static void main(String[] args) {
LinkedList<Integer> myLinkedList = new LinkedList<>(); // Create a LinkedList of integers
Iterator<Integer> iterator = myLinkedList.iterator(); // Get an iterator for the LinkedList
while (iterator.hasNext()) {
System.out.println(iterator.next()); // Print each element
}
}
}
Attribute | Queue |
---|---|
Structure | An interface that represents a First-In-First-Out (FIFO) data structure. |
Methods | add() / offer() : Add elements to the end of the queue.remove() / poll() : Remove elements from the front of the queue.peek() : Retrieve the element at the front without removing it. |
Use Case | Ideal for scenarios where you need to manage elements in the order they are processed, like task scheduling, handling requests, or buffering. |
Example:
Using a Queue to handle tasks.
import java.util.LinkedList; // Import the LinkedList class
import java.util.Queue; // Import the Queue interface
public class Main {
public static void main(String[] args) {
Queue<Integer> taskQueue = new LinkedList<>(); // Create a Queue using LinkedList
taskQueue.add(1); // Add task 1 to the Queue
taskQueue.add(2); // Add task 2 to the Queue
taskQueue.add(3); // Add task 3 to the Queue
System.out.println("The Queue contains: " + taskQueue.size() + " tasks");
System.out.println("Processing task: " + taskQueue.poll()); // Remove and process the first task
System.out.println("Next task to process: " + taskQueue.peek()); // Peek the next task without removing it
}
}
Objects or functions in a Generic
class can be generalized with any datatype.
Example:
MyClass
is a class with 2 Generic Objectsobject1
of typeT
andobject2
of typeI
.
class MyClass <T, I> {
private T object1; // Generic Object
private I object2;
// Constructor
public MyClass(T object1, I object2){
this.object1 = object1;
this.object2 = object2;
}
// Getters
public T getT(){
return this.object1;
}
public I getI(){
return this.object2;
}
// Setters
public void setT(T object1){
this.object1 = object1;
}
public void setI(T objec2){
this.object2 = object2;
}
}
public class Main {
public static void main(String[] args) {
MyClass<Double, String> myClass1 = new MyClass<>(20.5, "object2");
MyClass<String, Integer> myClass2 = new MyClass<>("object1", 20);
System.out.println("Class1 Object1: " + myClass1.getT()); // output: Class1 Object1: 20.5
System.out.println("Class1 Object2: " + myClass1.getI()); // output: Class1 Object1: object2
System.out.println("Class2 Object1: " + myClass2.getT()); // output: Class1 Object1: object1
System.out.println("Class2 Object2: " + myClass2.getI()); // output: Class1 Object1: 20
}
==
: to compare if two values are equal.!=
: to compare if two values are not equal.object1.equals(object2)
: to compare objects.&&
: AND comparator.||
: OR comparator.
Example:
public class Main {
public static void main(String[] args) {
int number = 10;
if (number >= 10) {
System.out.println("The number is greater than 10.");
} else if (number < 10 && number > 5) {
System.out.println("The number is between 5 and 10.");
} else {
System.out.println("The number is 5 less.");
}
}
}
Example:
public class Main {
public static void main(String[] args) {
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Another day");
}
}
}
Get and set data.
Example:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> myArrayList = new ArrayList<>();
// Initialize an ArrayList
for (int nbr = 1; nbr <= 10; nbr++){
myArrayList.add(nbr);
}
// Print the contents of the ArrayList
for (int i = 0; i < myArrayList.size(); i++){
System.out.println(myArrayList.get(i));
}
}
}
Get data only.
Example:
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> myArrayList = new ArrayList<>(Arrays.asList(1, 2, 3));
// Print the contents of the ArrayList
for (int element : myArrayList){
System.out.println(element);
}
}
}
Cannot or can be executed.
Example:
public class Main {
public static void main(String[] args) {
int counter = 0;
while (counter < 3) {
System.out.println("Counter: " + counter);
counter++;
}
}
}
Execute at least once.
Example:
public class Main {
public static void main(String[] args) {
int counter = 0;
do {
System.out.println("Counter: " + counter);
counter++;
} while (counter < 3);
}
}