Unraveling Java: Essential Foundations to Master Object-Oriented Programming!
Tags: java, programming, beginners, webdev
Published: 2023-12-05 01:07:28


**# JAVA**

**Welcome to the fascinating world of Java programming! This course is an exciting journey for those who wish to explore one of the most versatile and widely used programming languages in software development.**

## Data Types

In Java, there are different data types you can use to store values.

### Primitive Types:

1. **Integers:**
   - `byte`: 8 bits, stores integers from -128 to 127.
   - `short`: 16 bits, stores integers from -32,768 to 32,767.
   - `int`: 32 bits, stores integers from -2,147,483,648 to 2,147,483,647.
   - `long`: 64 bits, stores integers from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

2. **Floating Point:**
   - `float`: 32 bits, stores single-precision floating-point numbers.
   - `double`: 64 bits, stores double-precision floating-point numbers (recommended for general use).

3. **Boolean:**
   - `boolean`: stores true or false values (`true` or `false`).

4. **Characters:**
   - `char`: 16 bits, stores a single Unicode character.

### Reference Types:

5. **String:**
   - `String`: stores a sequence of characters.

6. **Objects:**
   - Custom data types created by you or available in libraries, like classes, interfaces, etc.

### Example Usage:

```java
public class DataTypesExample {
    public static void main(String[] args) {
        // Primitive types
        byte age = 30;
        int number = 12345;
        double price = 99.99;
        boolean isTrue = true;
        char letter = 'A';

        // Strings
        String name = "John";

        // Console output
        System.out.println("Age: " + age);
        System.out.println("Number: " + number);
        System.out.println("Price: " + price);
        System.out.println("Is it true? " + isTrue);
        System.out.println("Letter: " + letter);
        System.out.println("Name: " + name);
    }
}
```

**# Variables**

In Java, variables are storage locations containing data manipulated by the program. Each variable has an associated data type and a name that identifies it within the scope where it was declared. Here are the key points about variables in Java:

### Variable Declaration:

1. **Basic Syntax:**
   - To declare a variable in Java, you specify the data type followed by the variable name and optionally an initial value.

   Example:
   ```java
   int age; // Declaration of an integer variable
   double price = 99.99; // Declaration of a double variable with initial value
   ```

2. **Initialization:**
   - Variables can be initialized when declared or later in the code.

   Example:
   ```java
   int number; // Declaration
   number = 10; // Later initialization
   ```

### Variable Types:

1. **Primitive Variables:**
   - Store direct primitive values.
   - Examples: `int`, `double`, `boolean`, `char`, `byte`, `short`, `long`, `float`.

2. **Object References:**
   - Refer to objects in memory.
   - Examples: `String`, objects of custom classes, interfaces.

### Rules for Variable Names:

1. Can contain letters, numbers, dollar signs `$`, and underscores `_`.
2. Must start with a letter, dollar sign `$`, or underscore `_`.
3. Cannot contain white spaces.
4. Cannot be reserved keywords.

### Example Usage:

```java
public class VariablesExample {
    public static void main(String[] args) {
        // Declaration and initialization of variables
        int age = 30;
        double height = 1.75;
        String name = "Mary";

        // Using the variables
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("Height: " + height);
    }
}
```

**Variables in Java are used to store temporary or permanent data, depending on your needs. They play a fundamental role in manipulating and storing information during program execution.**

# Conditional Statements

In Java, conditional statements allow you to make decisions based on specific conditions. The most common structures are `if`, `else if`, and `else`.

### `if`:

The `if` statement checks if a condition is true and executes a block of code if the condition is true.

```java
int number = 10;

if (number > 0) {
    System.out.println("The number is positive.");
}
```

### `if` - `else`:

The `if` and `else` are used together to provide an alternative path if the `if` condition is false.

```java
int number = -5;

if (number > 0) {
    System.out.println("The number is positive.");
} else {
    System.out.println("The number is not positive.");
}
```

### `if` - `else if` - `else`:

You can chain multiple conditions using `else if` to check different scenarios.

```java
int number = 0;

if (number > 0) {
    System.out.println("The number is positive.");
} else if (number < 0) {
    System.out.println("The number is negative.");
} else {
    System.out.println("The number is zero.");
}
```

### Ternary Operator:

Another way to perform conditional operation is using the ternary operator `? :`.

```java
int number = 10;
String result = (number % 2 == 0) ? "Even" : "Odd";
System.out.println(result); // Output: Even
```

### Switch:

The `switch` statement is used to select one of many code blocks for execution based on the value of a specific expression.

```java
int dayOfWeek = 3;
String dayName;

switch (dayOfWeek) {
    case 1:
        dayName = "Sunday";
        break;
    case 2:
        dayName = "Monday";
        break;
    // And so on for other cases
    default:
        dayName = "Invalid day";
}

System.out.println("Today is " + dayName);
```

**These conditional structures allow you to control the flow of your program based on different conditions, which is essential for decision-making logic.**

# Arrays

In Java, arrays are data structures that store a fixed set of elements of the same type.

### Array Declaration:

```java
// Declaration of an array of integers with 5 elements
int[] numbers; // or int numbers[];
```

### Initializing an Array:

There are several ways to initialize an array in Java:

1. **Direct Initialization:**

   ```java
   int[] numbers = {1, 2, 3, 4, 5}; // Direct initialization with values
   ```

2. **Initialization with `new` operator:**

   ```java
   int[] numbers = new int[5]; // Initialization with an array of size 5
   ```

### Accessing Array Elements:

Array

 elements are accessed using a zero-based index.

```java
int[] numbers = {1, 2, 3, 4, 5};
int firstNumber = numbers[0]; // Accessing the first element (index 0)
int thirdNumber = numbers[2]; // Accessing the third element (index 2)
```

### Iterating Over an Array:

To traverse the elements of an array, you can use a `for` loop or `for-each` loop:

1. **`for` Loop:**

   ```java
   int[] numbers = {1, 2, 3, 4, 5};

   for (int i = 0; i < numbers.length; i++) {
       System.out.println(numbers[i]);
   }
   ```

2. **`for-each` Loop:**

   ```java
   int[] numbers = {1, 2, 3, 4, 5};

   for (int number : numbers) {
       System.out.println(number);
   }
   ```

### Multidimensional Arrays:

Java also supports multidimensional arrays, like two-dimensional arrays.

```java
// Declaration and initialization of a two-dimensional array (matrix)
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

int element = matrix[1][2]; // Accessing the element in the second row and third column (indices 1 and 2)
```

**Arrays in Java have a fixed size after initialization, and the size must be specified at the time of creation or initialization. Manipulating arrays offers many possibilities to store and access data in a structured way in your Java programs.**


# ArrayList


`ArrayList` in Java is an implementation of the `List` interface that provides a dynamic data structure to store elements. Unlike conventional arrays, an `ArrayList` can grow or shrink automatically to accommodate adding or removing elements.

### Importing the ArrayList Class:

```java
import java.util.ArrayList;
```

### Creating an ArrayList:

```java
ArrayList<String> nameList = new ArrayList<>();
```

### Adding Elements:

```java
nameList.add("Alice");
nameList.add("Bob");
nameList.add("Carol");
```

### Accessing Elements:

```java
String firstName = nameList.get(0); // Accessing the first element (index 0)
```

### Iterating Over an ArrayList:

```java
for (String name : nameList) {
    System.out.println(name);
}
```

### Removing Elements:

```java
nameList.remove("Bob"); // Removes the element "Bob"
// or
nameList.remove(1); // Removes the element at index 1
```

### Checking the Size of the ArrayList:

```java
int size = nameList.size(); // Returns the size of the list
```

### Arrays vs. ArrayList:

Arrays have a fixed size after creation, while `ArrayList` can grow or shrink dynamically. The choice between them depends on your program's needs. If you need a flexible data structure that can be easily modified, `ArrayList` is more convenient. If you need a structure with a fixed size, a conventional array might be more appropriate.

### Typing in ArrayList:

**The `ArrayList` is generic, which means you can specify the type of elements it will contain within the angle brackets `<type>` (e.g., `ArrayList<String>` for a list of strings). This helps prevent type errors during compilation and provides more type safety during execution.**




# Loops


In Java, there are several ways to create loops to execute a block of code repeatedly.

### 1. `for` Loop:

The `for` loop is used when you know exactly how many times you want to iterate.

```java
for (int i = 0; i < 5; i++) {
    System.out.println(i);
}
```

### 2. `while` Loop:

The `while` loop is used when you want to execute a block of code while a specific condition is true.

```java
int counter = 0;
while (counter < 5) {
    System.out.println(counter);
    counter++;
}
```


### 3. `do-while` Loop:

The `do-while` loop is similar to `while` but ensures that the code block executes at least once, even if the condition is false.

```java
int counter = 0;
do {
    System.out.println(counter);
    counter++;
} while (counter < 5);
```

### 4. `for-each` Loop (for iterating over arrays and collections):

The `for-each` loop is used to iterate over collections (such as arrays, lists) in a simple and efficient manner.

```java
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println(number);
}
```

### Flow Control:

Within loops, you can use `break` to exit the loop prematurely and `continue` to skip the current iteration and move on to the next.

### Nested Loop Example:

It's possible to nest loops, i.e., place one loop inside another.

```java
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.println("i: " + i + ", j: " + j);
    }
}
```

### Choosing the Loop Type:

- Use `for` when you know the number of iterations.
- Use `while` when the termination condition is not related to the number of iterations.
- Use `do-while` when you want to ensure the code block executes at least once.
- Use `for-each` to iterate over collections of elements.



# Casting


Casting in Java is the explicit conversion of one data type to another. It is used when you want to convert one data type into another compatible type. There are two types of casting in Java: **implicit casting** and **explicit casting**.

### Implicit Casting:

Occurs when there is no data loss when converting from a smaller type to a larger type. This is done automatically by Java.

Example of implicit casting:

```java
int integer = 10;
double decimal = integer; // Implicit conversion from int to double
```

### Explicit Casting:

Occurs when there is a potential data loss when converting from a larger type to a smaller type. This requires a special syntax to indicate that you are aware of the potential loss of precision.

Example of explicit casting:

```java
double decimal = 10.5;
int integer = (int) decimal; // Explicit conversion from double to int
```

### Rules for Explicit Casting:

- To perform explicit casting, you place the type in parentheses before the variable you want to convert.
- Explicit casting can lead to data loss if the value of the larger type cannot be represented by the smaller type.
- When converting from a larger type to a smaller type, you may lose precision information or even significant values.

```java
int number = 130;
byte value = (byte) number; // The value will be -126 due to overflow of a byte (-128 to 127)
```

### Considerations:

- Casting in Java can be useful when working with different data types, but it's essential to be aware of potential precision losses or value overflow when performing conversions.
- Make sure to use casting carefully to avoid type compatibility issues and loss of significant data during conversions.


# Classes



In Java, classes are fundamental building blocks used to create objects. They serve as templates or blueprints to create instances (objects) that have specific characteristics and behaviors.

### Example of a Class:

Let's create a `Person` class that represents individuals with attributes like name and age, and methods to access and modify these attributes.

```java
// Definition of the Person class
public class Person {
    // Attributes (instance variables)
    private String name;
    private int age;

    // Constructor (special method to create objects)
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Methods to access and modify attributes (getters and setters)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // Other methods of the Person class
    public void printDetails() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}
```


### Using the Class:

Now that we have the `Person` class, we can create objects (instances) of this class and use their methods and attributes.

```java
public class Main {
    public static void main(String[] args) {
        // Creating objects (instances) of the Person class
        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Bob", 25);

        // Using methods of the Person class
        person1.printDetails(); // Output: Name: Alice, Age: 30
        person2.printDetails(); // Output: Name: Bob, Age: 25

        // Modifying attributes using setters
        person1.setAge(35);
        person2.setName("Robert");

        person1.printDetails(); // Output: Name: Alice, Age: 35
        person2.printDetails(); // Output: Name: Robert, Age: 25
    }
}
```

### Key Concepts:

- **Attributes:** Represent the characteristics of objects.
- **Methods:** Define the behavior of objects.
- **Constructor:** A special method to initialize objects.
- **Encapsulation:** Use of access modifiers (`private`, `public`, `protected`) to control access to class attributes.
- **Instance:** Creating objects from a class using the `new` operator.

**Classes in Java allow you to create complex and modular structures, making it easier to create and organize programs. They are the foundation of object-oriented programming in Java and are essential for building robust and reusable applications.**


# Objects


In Java, an object is an instance of a class. A class is a model or blueprint for creating objects that have specific attributes and behaviors. Objects are created from classes using the `new` operator.

### Creating Objects:

To create an object, you need to use the `new` keyword followed by the class name and parentheses to call the class constructor.

Example of creating objects:

```java
// Person class
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println("Name: " + name);
    }
}

// Creating objects of the Person class
Person person1 = new Person("Alice");
Person person2 = new Person("Bob");
```

### Attributes and Methods:

Objects have attributes (instance variables) representing their characteristics and methods defining their behavior.

```java
// Attribute 'name' in the Person class
private String name;

// Method 'printName' in the Person class
public void printName() {
    System.out.println("Name: " + name);
}
```

### Accessing Attributes and Methods:

You can access the attributes and methods of an object using the dot operator (`.`).

```java
person1.printName(); // Output: Name: Alice
person2.printName(); // Output: Name: Bob
```

### Unique Instances:

Each object is a unique instance of its class. This means objects created from the same class can have different values for their attributes.

```java
person1.setName("Carol");
person1.printName(); // Output: Name: Carol
person2.printName(); // Output: Name: Bob
```

### Object References:

Variables holding objects store references to those objects in memory, not the objects themselves.

```java
Person person3 = person1;
person3.setName("Daniel");
person1.printName(); // Output: Name: Daniel (changed via reference person3)
```

### Encapsulation:

It's a common practice in Java to encapsulate object attributes using access modifiers (`private`, `public`, `protected`) and provide public methods (getters and setters) to access and modify them.

**Objects in Java are fundamental to object-oriented programming, allowing the creation of complex, modular, and reusable structures. Each object represents a distinct entity with its own state and behavior.**



# Constructors


In Java, a constructor is a special method used to initialize objects when they are created from a class. It has the same name as the class and has no return type.

### Purpose of Constructors:

- **Object Initialization:** A constructor is automatically called when an object is created using the `new` keyword. It initializes the object's state by setting values for its attributes or performing other necessary initializations.

### Types of Constructors:

1. **Default Constructor:** If a class doesn't define any constructor, Java provides a default constructor without parameters. This constructor initializes default values for the class attributes.

```java
public class MyClass {
    // Default constructor
    public MyClass() {
        // Default initialization, if needed
    }
}
```

2. **Custom Constructors:** You can define your own constructors with different parameters to initialize objects in specific ways.

```java
public class Person {
    private String name;
    private int age;

    // Custom constructor with parameters
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
```

### Using

 Constructors:

- **Automatic Invocation:** The constructor is automatically called when an object is created using `new ClassName()`.

```java
Person person = new Person("Alice", 30); // Calls the custom constructor
```

### Constructor Overloading:

You can have multiple constructors in the same class with different parameter lists. This is called constructor overloading.

```java
public class Person {
    private String name;
    private int age;

    // Constructor with one parameter
    public Person(String name) {
        this.name = name;
    }

    // Constructor with two parameters
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
```

### Using `this` in Constructors:

- `this` is used to reference the attributes of the class itself when there's ambiguity with the constructor parameters.

### Purpose of Constructors:

- **Initializing Attributes:** Setting initial values for the class attributes.
- **Ensuring Initial Values:** Ensuring the object starts in a valid state.
- **Customizing Object Creation:** Providing different ways to create objects with specific values.

**Constructors in Java are useful for initializing objects of a class according to their specific needs, allowing proper initialization of their attributes.**


# Modifiers


In Java, modifiers are keywords that provide control over access and other characteristics in classes, methods, and variables. They help define visibility, accessibility, and behavior of different elements within the code.

### Access Modifiers:

1. **public:**
   - Unrestricted access. Can be accessed from anywhere.
   
2. **private:**
   - Restricted access to the class itself. Cannot be accessed from outside the class.

3. **protected:**
   - Access allowed within the same package and by subclasses, even if they are in different packages.

4. **(default / no modifier):**
   - Access allowed only within the same package. Cannot be accessed by classes from different packages.

### Other Behavior Modifiers:

1. **static:**
   - Indicates that a method or variable belongs to the class, not individual instances.
   
2. **final:**
   - Indicates that a method, variable, or class cannot be altered or extended.
   
3. **abstract:**
   - Applied to classes or methods, indicates that the class cannot be instantiated (only its subclasses) or that a method needs to be overridden by subclasses.

4. **synchronized:**
   - Used to control concurrent access to methods or code blocks, ensuring that only one thread can access at a time.

5. **volatile:**
   - Used for variables that can be accessed by multiple threads, indicating that the variable's value can be changed by external threads.

6. **transient:**
   - Used to indicate that a field of a class should not be serialized during the serialization process.

### Example of Usage:

```java
public class Example {
    private int privateVariable;
    public static final double PI = 3.14;
    
    public void publicMethod() {
        // Method code
    }
    
    protected void protectedMethod() {
        // Method code
    }
    
    static synchronized void staticSynchronizedMethod() {
        // Method code
    }
}
```

### Considerations:

- Modifiers in Java offer control over encapsulation, inheritance, access, and other aspects of code, promoting security and modularity.
- Choosing the correct modifier depends on the design and security needs of your code. For instance, ensuring encapsulation using `private` and allowing inheritance using `protected`.
- Proper use of modifiers helps create safer classes and methods, making code maintenance and team development easier.


# Inheritance


In Java, inheritance is one of the fundamental principles of object-oriented programming, allowing a class to inherit attributes and methods from another class. It facilitates code reuse and the creation of hierarchies between classes.

### Inheritance Syntax:

```java
// Parent Class (or Superclass)
public class Animal {
    public void makeSound() {
        System.out.println("Generic animal sound.");
    }
}

// Child Class (or Subclass) that overrides the makeSound method
public class Dog extends Animal {
    public void bark() {
        System.out.println("Woof woof!");
    }
}
```

- `Animal` is the parent class (superclass) containing the `makeSound` method.
- `Dog` is the child class (subclass) that inherits from `Animal` and adds the `bark` method.

### `extends` Keyword:

- `extends` is used to create an inheritance relationship between classes.

```java
public class Dog extends Animal {
    // ...
}
```

### Inheriting Attributes and Methods:

- The child class inherits all non-private attributes and methods from the parent class.
- The child class can add new methods and attributes, as well as override existing methods if needed.

### Example of Usage:

```java
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.makeSound(); // Output: Generic animal sound.
        myDog.bark();      // Output: Woof woof!
    }
}
```

### Method Overriding:

- A subclass can override a method from the superclass to provide its own implementation.

```java
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof woof! (overridden)");
    }
}
```

### Considerations about Inheritance:

- Inheritance is an "is-a" relationship (e.g., a dog is an animal).
- It aids in code reuse, making it easier to create class hierarchies and avoiding repetition.
- A class can inherit from only one direct superclass (Java does not support multiple inheritance of classes).
- Ensuring that the inheritance relationship is logical and that the subclass is truly a specialized version of the superclass is essential for a solid class design.

**Inheritance in Java is a powerful concept allowing the creation of class hierarchies, facilitating reuse and extension of functionalities. However, it should be used carefully to maintain clear and cohesive code design.**


# Polymorphism

Polymorphism is a fundamental concept in object-oriented programming that allows objects of different classes to be treated as objects of a common class. In Java, polymorphism is implemented through two mechanisms: method overloading (multiple methods with the same name in a class but with different parameters) and method overriding (methods in related classes that have the same signature).

### Method Overriding Polymorphism:

In overriding, a child class provides a specific implementation for a method that is already defined in its parent class. This allows an object of the child class to be treated as an object of the parent class, but with the execution of the child class's specific method.

Example:

```java
// Parent Class (Superclass)
class Animal {
    public void makeSound() {
        System.out.println("Generic animal sound.");
    }
}

// Child Class (Subclass) that overrides the makeSound method
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof woof!");
    }
}
```

Now you can do something like this:

```java
Animal myDog = new Dog();
myDog.makeSound(); // Output: Woof woof!
```

### Polymorphism with Interfaces:

Interfaces in Java also support polymorphism. If a class implements an interface, you can treat objects of that class as objects of the interface.

```java
// Interface
interface Noisy {
    void makeSound();
}

// Interface Implementation
class Dog implements Noisy {
    @Override
    public void makeSound() {
        System.out.println("Woof woof!");
    }
}
```

### Method Overloading Polymorphism:

In overloading, multiple methods can have the same name but with different parameter lists. This allows you to call the same method with different argument types.

Example:

```java
class Calculator {
    public int sum(int a, int b) {
        return a + b;
    }

    public double sum(double a, double b) {
        return a + b;
    }
}
```

The

 call can be made polymorphically:

```java
Calculator calc = new Calculator();
int resultInt = calc.sum(5, 10);
double resultDouble = calc.sum(3.5, 2.7);
```

### Advantages of Polymorphism:

- **Flexibility:** Allows the same code to handle objects of different classes uniformly.
- **Maintainability:** Facilitates adding new classes without changing existing code.
- **Readability:** Makes the code more readable and expressive.

**Polymorphism is a powerful feature of object-oriented programming that promotes flexibility and code reuse. It is commonly used in Java and is employed in conjunction with concepts like inheritance and interfaces to create more modular and extendable systems.**


Congratulations on finishing the read! It's quite an achievement to have dedicated time and effort to learn about the basic concepts of Java.

Remember to stay updated. Technology is ever-evolving, and new concepts, tools, and techniques are always emerging. Keep up with blogs, forums, conferences, and online courses to stay informed about trends and advancements in the field.

In summary, keep learning, practicing, and challenging yourself. Programming is an exciting journey filled with possibilities. Good luck with your future explorations in the tech field!

### By Francisco Inoque 🫶