Classes and Objects:
Class:
A class is a named group of properties (fields/attributes) and functions (methods).
It serves as a template for creating objects.
A class creates a new data type that can be used to instantiate objects.
It defines the structure and behavior of objects that belong to it.
Object:
An object is an instance of a class, representing a specific entity in a program.
When you declare an object of a class, you are creating an instance of that class.
Each object occupies space in memory and has its own unique identity.
Properties of Objects:
Objects are characterized by three essential properties:
State: Represents the current values of the object's attributes (data).
Identity: Distinguishes one object from another; it's where the object's value is stored in memory.
Behavior: Describes the actions or operations that an object can perform.
Logical vs. Physical:
A class is a logical construct, that defines the structure and behavior of objects.
An object has a physical reality, occupying space in memory and representing a specific instance of a class.
Let's illustrate the concepts of state, identity, and behavior with a simple example using a hypothetical Car class:
// The state of an object refers to the values stored in its attributes
// or member variables. In the context of a Car object, the state could
// include attributes such as make, model, color, and speed.
class Car {
String make;
String model;
String color;
int speed;
// The behavior of an object refers to the actions or operations that it
// can perform. These actions are typically defined by methods or member
// functions associated with the object's class.
// Continuing with the Car example, the behavior of a Car object could
// include methods like accelerate(), brake(), and changeColor()
void accelerate() {
// function
}
void brake() {
// function
}
void changeColor(String newColor) {
// function
}
}
// The identity of an object distinguishes it from other objects and represents
// its unique reference or location in memory. In Java, each object has a unique
// identity that is provided by its memory address.
// However, as Java abstracts memory management, you typically
// don't work directly with memory addresses.
// Instead, you can use object references to refer to individual objects.
Car myCar = new Car();
Constructors:
Constructors are special methods used for initializing objects.
They are invoked when an object is created using the
new
keyword.Once defined, the constructor is automatically called when the object is created, before the new operator completes.
Constructors look a little strange because they have no return type, not even void.
This is because the implicit return type of a class’ constructor is the class type itself.
Default Constructor:
A constructor with no parameters.
If no constructor is explicitly defined in a class, Java provides a default constructor.
Example:
// We dont have to make a constructor it is the by default constructor // It uses the parameter // CLASS public class Student { // data members, properties or instance variables int rno = 1; String name = "Demo"; float marks = 1.0f; public static void main(String[] args) { Student mydemo = new Student(); System.out.println(mydemo.rno); System.out.println(mydemo.name); System.out.println(mydemo.marks); } } // Output: 1 Demo 1.0
Parameterized Constructor:
A constructor with parameters.
Used to initialize object properties with specified values.
Example:
public class Student { // data members, properties or instance variables int rno = 1; String name = "Demo"; float marks = 1.0f; Student (int rno,String name,float marks) { this.rno = rno; this.name = name; this.marks = marks; } public static void main(String[] args) { Student mydemo = new Student(1,"ABC",5.5f); System.out.println(mydemo.rno); System.out.println(mydemo.name); System.out.println(mydemo.marks); } } // Output 1 ABC 5.5
Copy Constructor:
A constructor that takes an object of the same class as a parameter and initializes a new object with the same values.
Helps in creating a new object with the same state as an existing object.
Example:
public class Student { // data members, properties or instance variables int rno = 1; String name = "Demo"; float marks = 1.0f; Student (int rno,String name,float marks) { this.rno = rno; this.name = name; this.marks = marks; } Student (Student other){ this.rno = other.rno; this.name = other.name; this.marks = other.marks; } public static void main(String[] args) { Student mydemo = new Student(1,"ABC",5.5f); System.out.println(mydemo.rno); System.out.println(mydemo.name); System.out.println(mydemo.marks); Student xyz = new Student(mydemo); System.out.println(xyz.rno); System.out.println(xyz.name); System.out.println(xyz.marks); } } // Output 1 ABC 5.5 1 ABC 5.5
Chained Constructors:
Calling one constructor from another using
this()
keyword.Helps in code reuse and reducing redundancy.
Example:
public class Student { // data members, properties or instance variables int rno = 1; String name = "Demo"; float marks = 1.0f; Student (int rno,String name,float marks) { this.rno = rno; this.name = name; this.marks = marks; } Student (Student other){ this.rno = other.rno; this.name = other.name; this.marks = other.marks; } Student () { this (22,"Default One",5.4f); } public static void main(String[] args) { Student xyz = new Student(); System.out.println(xyz.rno); System.out.println(xyz.name); System.out.println(xyz.marks); } } // Output 22 Default One 5.4
Parameters and Arguments:
Parameters are variables defined by a method that receive values when the method is called. Arguments are values passed to a method when it is invoked.
public class HelloWorld {
public static void main(String[] args) {
int x = 2;
// Calling the method 'Square' and passing 'x' as an argument
int ans = Square(x);
System.out.println(ans);
}
// Method definition with a parameter 'x'
// 'x' here is a parameter
public static int Square(int x){
return x * x;
}
}
The 'this' Keyword:
The
this
keyword is used inside a method to refer to the current object.It allows methods to access and manipulate the object's fields and methods.
Similar to self keyword in Python.
public class Student { Student (int rno,String name,float marks) { this.rno = rno; this.name = name; this.marks = marks; } }
How to access instance variables?
The dot operator links the name of the object with the name of an instance variable. Although commonly referred to as the dot operator, the formal specification for Java categorizes the '.' as a separator.
class Car {
String brand;
String model;
int year;
void displayInfo() {
System.out.println("Brand: " + brand);
System.out.println("Model: " + model);
System.out.println("Year: " + year);
}
}
public class Main {
public static void main(String[] args) {
// Creating an instance of the Car class
Car myCar = new Car();
// Using dot operator to set the values of object fields
myCar.brand = "Toyota";
myCar.model = "Camry";
myCar.year = 2022;
// Using dot operator to call the method of the object
myCar.displayInfo();
}
}
New Keyword:
Car myCar = new Car();
The 'new' keyword dynamically allocates(that is, allocates at run time) memory for an object & returns a reference to it. This reference is, more or less, the address in memory of the object allocated by the new. This reference is then stored in the variable.
Thus, in Java, all class objects must be dynamically allocated.
Dynamic Memory Allocation and Object References in Java
Box myBox //Declaration
new Box(); //Instantiation
myBox = new Box(); // Assigned
Declaration:
Box myBox;
- At this stage, you're only declaring a reference variable
myBox
of typeBox
. No memory has been allocated yet.
- At this stage, you're only declaring a reference variable
Instantiation:
new Box();
This is where memory is allocated for the
Box
object. Thenew
keyword is responsible for this allocation.Once
new Box()
is executed, memory is allocated on the heap for a newBox
object.The
new
operator returns the address (reference) of the newly allocated memory.
Assignment:
Box myBox = new Box();
Now, the reference returned by
new Box()
is assigned to the reference variablemyBox
.So,
myBox
now holds the address of the newly createdBox
object in the heap.
Object Reference:
Once memory is allocated, the reference variable holds the memory address (reference) of the actual object. This reference allows you to access and manipulate the object.
Box myBox = new Box(); // Here myBox is the reference variable (object reference) // Box() is the by-default constructor
Safety of References:
Unlike pointers in languages like C or C++, Java's references cannot be manipulated to point to arbitrary memory locations. This ensures safety and prevents unauthorized memory access.
Java references are managed by the JVM, and you cannot perform low-level memory operations like you can with pointers.
Object Assignment and Sharing:
Assigning one reference variable to another does not create a new object. Instead, both reference variables point to the same object in memory.
Box b1 = new Box(); Box b2 = b1; // b2 references the same object as b1
Effects of Object Sharing:
Changes made to the object through one reference variable are reflected when accessed through the other reference variable, as they both point to the same object.
Changes made via
b1
will affect the object accessed throughb2
, and vice versa.class Box { int width; int height; public Box() { width = 0; height = 0; } public Box(int width, int height) { this.width = width; this.height = height; } } public class ObjectSharingExample { public static void main(String[] args) { // Creating two Box objects Box b1 = new Box(10, 20); Box b2 = b1; // b2 references the same object as b1 // Modifying b2's width b2.width = 30; // Displaying the values of b1 and b2 System.out.println("b1: width = " + b1.width + ", height = " + b1.height); System.out.println("b2: width = " + b2.width + ", height = " + b2.height); // Modifying b1's height b1.height = 50; // Displaying the values of b1 and b2 again System.out.println("After modifying b1's height:"); System.out.println("b1: width = " + b1.width + ", height = " + b1.height); System.out.println("b2: width = " + b2.width + ", height = " + b2.height); } }
The 'final' Keyword:
Field Declaration:
A field can be declared as
final
, preventing its contents from being modified, essentially making it a constant.Example:
public class Main { public static void main(String[] args) { final int FILE_OPEN = 2; FILE_OPEN = 3; //error } } // Output java: cannot assign a value to final variable FILE_OPEN
Immutability:
final
guarantees immutability only when instance variables are primitive types, not reference types.If an instance variable of a reference type is
final
, the reference to an object will never change, but the value of the object itself can change.public class Student { Student () { this (22,"Default One",5.4f); } Student (int rno,String name,float marks) { this.rno = rno; this.name = name; this.marks = marks; } } public static void main(String[] args) { // final int FILE_OPEN = 2; // FILE_OPEN = 3; final Student check = new Student(); check.name = "AbhayGRT"; // this will work System.out.println(check.name); check.name = "AbhayGRT"; System.out.println(check.name); check = new Student(); // but this will not } } // Output Default One AbhayGRT java: cannot assign a value to final variable check
The finalize()
Method:
Finalization:
Java provides a mechanism called finalization to perform actions when an object is about to be reclaimed by the garbage collector.
To add a finalizer to a class, you define the
finalize()
method. It's called by the Java runtime just before the object is garbage-collected.Garbage collection in Java is automatic and managed by the Java Virtual Machine (JVM).
The JVM decides when to run the garbage collector based on various factors such as memory pressure, object allocation rate, etc.
Unlike in languages like C++, where you can explicitly call the destructor or deallocate memory, Java does not provide a way to directly invoke the garbage collector.
Example:
public class GarbageCollectorExample { public static void main(String[] args) { // Creating a large number of MyObject instances for (int i = 0; i < 1000000; i++) { new MyObject(); // Creating and discarding MyObject instances } } // Inner class representing an object static class MyObject { // Override the finalize() method to define finalization behavior @Override protected void finalize() throws Throwable { System.out.println("Object is Destroying"); // Finalization behavior } } }