Classes in Java


Java is an object oriented programming language. Almost everything in Java is an object, with its attributes and methods.

Class creates a user-defined data structure, which holds its own data members (attributes) and member functions (methods), which can be accessed and used by creating an instance of that class.

Classes are like a blueprint for objects outlining possible behaviors and states that every object of a certain type could have.

Classes are defined via the keyword class, like this:

// Define an empty class Employee
class Employee {

};

Objects/Instances

An Object is an instance of a Class. A class is like a blueprint while an instance is a copy of the class with actual values. It’s not an idea anymore, it’s an actual employee, like a person named "Andrew" who is 30 years old.

You can have many employees to create many different instances, but without the class as a guide, you would be lost, not knowing what information is required.

After a class is defined, we can create objects of the class using the new keyword like this:

// Define an empty class Employee
class Employee {

};

// inside main function:
Employee employee = new Employee();

Attributes/Properties

A class attribute is a Java variable that belongs to a class and is shared between all the objects of this class. Let's add some attributes to our Employee class:

class Employee {
	public String name;
	public int age;
};

// inside main function:
Employee emp1 = new Employee();
	
emp1.name = 'Andrew';
System.out.println(emp1.name); // prints 'Andrew'
	
Employee emp2 = new Employee();
	
emp2.age = 40;
System.out.println(emp2.age); // prints 40

We added two properties: the String name and the int age. Then, we created two different Employee objects emp1 and emp2.

The attributes of objects can be accessed and modified using the dot operator (.), like we did above with emp1.name and emp2.age.

The keyword public used inside the class is called an access specifier. name and age are public attributes, whch means they can be accessed from anywhere in the code, not just inside the class code.

Constructors

In real life, we want to set the attributes specific to each object when creating it. For example, an employee named Andrew of 30 years old and another one named Mary of 25 years old. Here the constructor comes to rescue.

A constructor is a special type of method (function) which is used to initialize the instance members of the class.

In Java the constructor method has the same name as that of its class and is always called when an object is created.

Let's add a constructor to our Employee class:

class Employee {
	public String name;
	public int age;
	
	// constructor:
	public Employee(String name, int age) {
		this.name = name;
		this.age = age;
	}
};

// inside main function:
Employee emp1 = new Employee('Andrew', 30);
	
System.out.println(emp1.name);
	
Employee emp2 = new Employee('Mary', 25);

System.out.println(emp2.age);

// prints 'Andrew' and 25 on different lines

The "this"

Every object in Java has access to its own address through an important refference called this.

The this refference is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to access and manipulate the attributes of that object, like we did above with this.name = name.

Member functions

Member functions are functions that belong to the class:

class Employee {
	public String name;
	public int age;
	
	// constructor:
	public Employee(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	//member functions:
	public void printName() {
		System.out.println(name); // it is not mandatory to use "this" to access an attribute
	}
		
	public void printEmployee() {
		printName();
		System.out.println(age);
	}
};

// inside main function:
Employee emp1 = new Employee('Andrew', 30);

emp1.printEmployee(); // prints "Andrew", 30
	
Employee emp2 = new Employee('Mary', 25);

emp2.printEmployee(); // prints "Mary", 25

As you can see, we access functions just like we access attributes: using the dot syntax (.).

The function call uses the attributes of the object it was called on. That's why the first printEmployee() prints 'Andrew' and 30 and the second prints 'Mary' and 25.


Assignment
Follow the Coding Tutorial and let's write some classes.


Hint
Look at the examples above if you get stuck.


Introduction

In this lesson, we will explore the concept of classes in Java, a fundamental aspect of object-oriented programming (OOP). Understanding classes is crucial as they form the blueprint for creating objects, which are instances of classes. This concept is widely used in various programming scenarios, from simple applications to complex systems.

Understanding the Basics

At its core, a class in Java is a user-defined data structure that encapsulates data members (attributes) and member functions (methods). These classes serve as templates for creating objects. For instance, consider a class Employee that defines attributes like name and age. By creating instances of this class, we can represent individual employees with specific names and ages.

Before diving into more complex aspects, it's essential to grasp these basic concepts. Let's start with a simple example:

// Define an empty class Employee
class Employee {
    // Attributes
    public String name;
    public int age;

    // Constructor
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Member function
    public void printEmployee() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}

// Inside main function
public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee("Andrew", 30);
        emp1.printEmployee(); // prints "Name: Andrew, Age: 30"
    }
}

Main Concepts

Let's delve deeper into the key concepts and techniques involved in working with classes in Java:

Here's how to apply these concepts:

class Employee {
    public String name;
    public int age;

    // Constructor
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Member function
    public void printEmployee() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}

// Inside main function
public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee("Andrew", 30);
        emp1.printEmployee(); // prints "Name: Andrew, Age: 30"
    }
}

Examples and Use Cases

Let's explore some examples and real-world use cases:

class Car {
    public String model;
    public int year;

    // Constructor
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }

    // Member function
    public void printCar() {
        System.out.println("Model: " + model + ", Year: " + year);
    }
}

// Inside main function
public class Main {
    public static void main(String[] args) {
        Car car1 = new Car("Toyota", 2020);
        car1.printCar(); // prints "Model: Toyota, Year: 2020"
    }
}

In this example, we define a Car class with attributes model and year. We then create an instance of the class and print its details.

Common Pitfalls and Best Practices

When working with classes, it's important to avoid common mistakes and follow best practices:

Advanced Techniques

Once you're comfortable with the basics, you can explore advanced techniques such as inheritance, polymorphism, and interfaces. These concepts allow you to create more flexible and reusable code.

class Manager extends Employee {
    public String department;

    // Constructor
    public Manager(String name, int age, String department) {
        super(name, age);
        this.department = department;
    }

    // Overriding member function
    @Override
    public void printEmployee() {
        super.printEmployee();
        System.out.println("Department: " + department);
    }
}

// Inside main function
public class Main {
    public static void main(String[] args) {
        Manager mgr1 = new Manager("Alice", 35, "HR");
        mgr1.printEmployee(); // prints "Name: Alice, Age: 35, Department: HR"
    }
}

Code Implementation

Here's a complete example demonstrating the correct use of classes in Java:

class Employee {
    public String name;
    public int age;

    // Constructor
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Member function
    public void printEmployee() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Employee emp1 = new Employee("Andrew", 30);
        emp1.printEmployee(); // prints "Name: Andrew, Age: 30"
    }
}

Debugging and Testing

When debugging and testing your code, consider the following tips:

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class EmployeeTest {
    @Test
    public void testEmployee() {
        Employee emp = new Employee("John", 28);
        assertEquals("John", emp.name);
        assertEquals(28, emp.age);
    }
}

Thinking and Problem-Solving Tips

When approaching problems related to classes, consider the following strategies:

Conclusion

In this lesson, we covered the fundamental concepts of classes in Java, including attributes, constructors, and member functions. We also explored advanced techniques, common pitfalls, and best practices. Mastering these concepts is essential for writing efficient and maintainable code in Java. Keep practicing and exploring further applications to deepen your understanding.

Additional Resources

For further reading and practice problems, consider the following resources: