Page cover image

📑OOP Fundamentals, Constructors, Methods, and Memory Management

Basic Java programming notes covering fundamental concepts like Object-Oriented Programming, constructors, method overloading, and more. Handy reference for Java learners.

Java Object Oriented Programming

Programming Paradigms:

  1. Procedural

  2. Functional !

  3. Object-Oriented !

  4. Event Driven

  5. Logic

  6. Aspect-Oriented

OOP vs Functional

In Object-Oriented, Programming Languages, we Take Data & Behaviour in a Single Object.

IN Functional, we take a totally different Approach. We assume that the data & behaviour are entirely separate.

We can solve the problem with both of them. Only the Code will look different.

  • OOP ⇒ Graphical User Interface or Games.

  • Functional ⇒ High Level of Reliability

We can use Event Driven, where it performs well, and OOP where it performs well.


Which Programming Paradigm is Better:

It Depends, who you are. It depends which problem you are solving.


Problem Solving:

Process of defining a Problem, identifying and comparing different solutions, and picking the one that best solves that problem with respect to the context and constraints.


Procedural Programming:

  1. When our main is bloated, means it’s very heavy and we are calling many functions or procedures, our main class will be fatty.

  2. Just because you are using some classes and objects doesn’t mean that you are doing OOP.

  3. It’s way more than using classes and objects.

  4. Symptoms of PP, you will end up with a bunch of methods where they have a bunch of parameters.

  5. So, if you are constantly calling methods and passing arguments, you are definitely doing PP.


Object-Oriented Language:

Objects and Objects interact with Each other.

For example, it’s like a Car Engine. Where it is functional because of all the small parts it contains.

OOP is exactly the same. If any small part is not working, just put it out and change it.

Principles of OOP:

  1. Encapsulation: Bundle the Data and Methods that operate on the data in a single unit.

  2. For example, when we have too big methods and many calls with many arguments.

  3. Just try to Encapsulate things.

  4. Like by creating another class and then with initiating the instance and doing big things or calculations from that.


Principal of OOP:

  1. Abstraction: Reduce Complexity by Reducing Unnecessary Details in our classes.

  2. For example, it’s like a remote control, where we don't need to interact with the inner parts, like transistors and other components. We just use the buttons to interact with the TV.

  3. We really don’t care about the inner part.

  4. In Abstraction, we want to hide the implementation of a class and treat it like a black box.

Benefits:

  1. Reduced Complexity [Divide code into smaller parts]

  2. Easier Maintenance

  3. Code Reuse

  4. Faster Development


Here is a good Example to Differentiate Procedural Programming from OOP:

Simple Problem-Solving with Procedural Programming:

  1. In this approach, we make many calls and pass many arguments.

  2. After encapsulation, it becomes easier to use.

  3. However, input verification for the variables is not implemented, risking program integrity.

  4. Using lengthy if statements to validate inputs might not be ideal.

  5. Instead, setters and getters can be employed.

  6. By marking variables as private and creating methods for getting and setting variables, we ensure the ability to validate and sanitize values as needed.

public class Main {
    public static void main(String[] args) {
        int baseSalary = 50_000;
        int hourlyRate = 20;
        int extraHour = 10;

        int finalSalary = getSalary(baseSalary, hourlyRate, extraHour);
        System.out.println(finalSalary);
    }

    public static int getSalary(int baseSalary, int hourlyRate, int extraHour) {
        return baseSalary + (hourlyRate * extraHour);
    }
}

Same Program with OOP (Encapsulation):

// MAIN.JAVA
public class Main {
    public static void main(String[] args) {

        Employee akash = new Employee();
        akash.setHourlyRate(20);
        akash.setBaseSalary(50_000);
        System.out.println(akash.getSalary(10));
    }
}

// EMPLOYEE.JAVA
public class Employee {
    private int baseSalary;
    private int hourlyRate;

    public int getSalary(int extraHour) {
        return baseSalary + (hourlyRate * extraHour);
    }

    public void setBaseSalary(int baseSalary) {
        this.baseSalary = baseSalary;
    }

    public void setHourlyRate(int hourlyRate) {
        this.hourlyRate = hourlyRate;
    }
}

Now, with Setters and Getters:

// MAIN.JAVA
public class Main {
    public static void main(String[] args) {

        Employee akash = new Employee();
        akash.setHourlyRate(20);
        akash.setBaseSalary(50_000);
        System.out.println(akash.getSalary(10));
    }
}

// EMPLOYEE.JAVA
public class Employee {
    private int baseSalary;
    private int hourlyRate;

    public int getSalary(int extraHour) {
        return baseSalary + (hourlyRate * extraHour);
    }

    public void setBaseSalary(int baseSalary) {
        if (baseSalary <= 0)
            throw new IllegalArgumentException("Bru, You Can't use a negative Salary");
        this.baseSalary = baseSalary;
    }

    public void setHourlyRate(int hourlyRate) {
        if (hourlyRate <= 0)
            throw new IllegalArgumentException("Bru, You Can't use a negative No.");
        this.hourlyRate = hourlyRate;
    }

    public int getBaseSalary() {
        return baseSalary;
    }

    public int getHourlyRate() {
        return hourlyRate;
    }
}

Class:

  1. A Blueprint for Creating Objects.

  2. Fields are Variables in The class.

  3. If We don’t initialize the Reference Types, by default they are null.

  4. this is a reference to the current object.

Objects:

An instance of a class.


Constructors:

  1. To function our program, it’s compulsory to assign and give values to base salary and the hourly rate.

  2. When we've assigned those values, our method will work very well.

  3. However, what if someone else uses this program and forgets to assign these values?

  4. Then our program will be in a bad state, and the result will obviously be bad.

  5. When we initialize a class object with new Employee(), it works like a method.

  6. But we didn’t create that; it’s Java that created that whole function to initiate our class.

  7. So, after initializing, the numbers will be zero, booleans will be false, and references will be null.

  8. When we have created the constructor, Java will not create any other method by itself.


Constructors Overloading:

  1. Technically, constructors are also methods.

  2. We can reuse constructors within a class by using this.


Static Members:

In OOP, a class can have two types of members: Static Members & Instance Members.

  1. Instance Members are the fields, methods, or constructors within a class, containing data and functionalities specific to each instance.

  2. They belong to each instance/object created from the class.

  3. Access to instance members is through the object's name, followed by the member's name.

Static members, however, have different characteristics:

  1. Static Members are accessed using the class name itself, not through an instance.

  2. Declaring a member as static allows it to be accessible using the class name directly: ClassName.member.

  3. Static members are used to represent concepts that don't need to be tied to a specific instance but are common to all instances or to represent something at a single place.

  4. Static methods or fields can only access other static elements within the class, as they belong to the class rather than an instance.

  5. It's possible to create an object of the same class within a static method if needed.

  6. The main method in Java is also static to allow the Java Runtime Environment (JRE) to execute it without creating a new object.


Method Overloading:

When programming in Java, method overloading refers to the ability to create multiple methods in the same class with the same name but with different parameters. This feature allows you to define methods that perform similar tasks but accept different inputs or have different behaviors.

  1. Argument Variety: Overloading permits multiple methods in a class with the same name but differing parameters.

  2. Multiple Signatures: Methods have the same name but vary by the type, number, or order of parameters.

  3. Use Cases: Useful when methods perform similar actions but operate on different data types or require different input combinations.

  4. No Default Parameters: Unlike some other languages, Java doesn’t support default parameter values, so overloading becomes essential to handle different scenarios without excessive method names.

For instance, you could have multiple methods named calculateSalary, where each method might take different parameters or behave differently based on the inputs provided.


Garbage Collection:

In Java, automatic memory management occurs through garbage collection. Objects that are no longer referenced or in use are automatically removed from memory.


Coupling:

Coupling refers to the level of dependency between different classes in a software system.

  1. Interdependence of Classes: Coupling indicates how much one class relies on another.

  2. Impact of Changes: Higher coupling makes systems more interconnected. A change in one class might require changes in other dependent classes.

  3. Reducing Complexity: To mitigate issues related to high coupling, mark less-used methods or fields as private.

  4. Minimizing Impact: By privatizing less frequently used methods or fields, the main codebase remains less complex.

  5. Abstraction Implementation: Utilizing abstraction by exposing only essential methods or fields in the interface, reducing unnecessary complexity.

  6. Selective Usage: When multiple methods exist in a class but only a few are essential in the main program, keeping the non-essential ones private avoids coupling with the main code.


Exceptions:

Exceptions are classes within the Java library that handle error conditions in a program.

  1. Throwing Exceptions: In Java, exceptions can be thrown using the throw keyword.

  2. Customized Error Handling: For instance, in the code snippet below, an IllegalArgumentException is thrown when a negative salary is attempted to be set:

public void setBaseSalary(int baseSalary){
    if (baseSalary <= 0)
        throw new IllegalArgumentException("Bru, You Can't use a negative Salary");
    this.baseSalary = baseSalary;
}

Memory Allocation:

In Java, memory is managed in two primary areas: the Heap and the Stack.

  1. Primitive Types in Stack: Variables storing primitive types are placed in the stack.

  2. Objects in Heap: Heap memory is allocated for objects created in Java.

  3. Reference Addresses: The stack also holds references to objects residing in the heap.

  4. Allocation Process: When initializing an object, like var textBox1 = new TextBox(), Java first allocates memory for the object itself in the heap.

  5. Stack Reference: Subsequently, the variable textBox1 (containing the address of the object) is placed in the stack.

  6. Object Accessibility: The objects data is stored in the heap, while the stack holds references for accessing the objects.

This separation helps in managing memory efficiently and allows Java to handle memory allocation for different types of data structures.


Classes:

public class TextBox {
}

// public is an identifier for this class, indicating that other classes can use it.
//When we want to change a variable within a class while in a method, or when we want to modify a field, we can use .this in the code, as demonstrated below:
public String text;

public void setText(String text) {
    this.text = text;
}

//When there are no parameters, we can simply reference the variable name without using text.

Creating Objects:

To instantiate a class and create an instance, we typically write:

TextBox text2 = new TextBox();

// However, to improve code readability, Java offers the 'var' keyword to infer the type from the right side, eliminating redundancy:

var text = new TextBox();
// It simplifies the code while maintaining the same functionality.

Objects Duplicate:

var text2 = new TextBox();
var text1 = text2; // text2 points to the address of the object, so text1 is the same object.
text1.setText("Yeah Baby");
System.out.println(text2.text.toUpperCase());

Quiz:

  1. What is the difference between a class and an object?

    ⇒ A class is a blueprint or template for creating objects. An object is an instance of a class.

  2. What does instantiating mean?

    ⇒ Instantiating means creating an instance of a class: new Customer()

  3. What is the difference between stack and heap memory? How are they managed?

    ⇒ Stack is used for storing primitive types (numbers, boolean and character) and variables that store references to objects in the heap. Variables stored in the stack are immediately cleared when they go out of scope (eg when a method finishes execution). Objects stored in the heap get removed later on when they’re no longer references. This is done by Java’s garbage collector.

  4. What are the problems of procedural code? How does object-oriented programming help solve these problems?

    ⇒ Big classes with several unrelated methods focusing on different concerns and responsibilities. These methods often have several parameters. You often see the same group of parameters repeated across these methods. All you see is procedures calling each other passing arguments around.

    By applying object-oriented programming techniques, we extract these repetitive parameters and declare them as fields in our classes. Our classes will then encapsulate both the data and the operations on the data (methods). As a result, our methods will have fewer parameters and our code will be cleaner and more reusable.

  5. What is encapsulation?

    ⇒ Encapsulation is the first principle of object-oriented programming. It suggests that we should bundle the data and operations on the data inside a single unit (class).

  6. Why should we declare fields as private?

    ⇒ How we store data in an object is considered an implementation detail. We may change how we store the data internally. Plus, we don’t want our objects to go into a bad state (hold bad data). That’s why we should declare fields as private and provide getters and or setters only if required. These setters can ensure our objects don’t go into a bad state by validating the values that are passed to them.

  7. What is abstraction?

    ⇒ Abstraction is the second principle of object-oriented programming. It suggests that we should reduce complexity by hiding the unnecessary implementation details. As a metaphor, think of the remote control of your TV. All the complexity inside the remote control is hidden from you. It’s abstracted away. You just work with a simple interface to control your TV. We want our objects to be like our remote controls.

  8. What is coupling?

    ⇒ Coupling represents the level of dependency between software entities (eg classes). The more our classes are dependent on each other, the harder it is to change them. Changing one class may result in several cascading and breaking changes.

  9. How does the abstraction principle help reduce coupling?

    ⇒ By hiding the implementation details, we prevent other classes from getting affected when we change these details. For example, if the logic board and transistors inside a remote control change from one model to another, we’re not affected. We still use the same interface to work with our TV. Also, reducing these details and exposing fewer methods makes our classes easier to use. For example, remote controls with fewer buttons are easier to use

  10. What are constructors?

    ⇒ Constructors are called when we instantiate our class. We use them to initialize our objects. Initialization means putting an object into an early or initial state (eg giving it initial values).

  11. What is method overloading?

    ⇒ Method overloading means declaring a method with the same name but with different signatures. The number, type and order of its parameters will be different.

  12. What are static methods?

    ⇒ Static methods are accessible via classes, not objects.


Last updated

Was this helpful?