Java With Us
Home   |   Tutorial   |   Programs  

Java Tutorial

Introduction to Java
Hello World Program
Variables and Data types
More about data types
Displaying text using print and println
Displaying text using printf
Java Comments
Naming conventions for Identifiers
Mathematical operations in Java
Taking input from the user

Classes and Objects
Introduction to object oriented programming
The constituents of a Class
Creating objects and calling methods
Get and Set Methods
Default constructor provided by the compiler
Access Specfiers
Scope and lifetime of Variables
Call by value and Call by Reference

A few more topics
Casting
Class as a reference data type
Constants or literals
Final variables
Increment and decrement operators
Manipulating Strings
Operators
Overloading constructors and methods
Static methods and variables
The Java API
The Math class
this keyword
Wrapper classes

Control Structures
Control Statements
Repetition statements
Nested loops
Formulating algorithms
Branching Statements

Arrays
Arrays introduction
Processing arrays using 1oops
Searching and sorting arrays
Array of objects
Multi dimensional arrays
Taking input as command line arguments
Using ellipsis to accept variable number of arguments

Inheritance
Inheritance introduction
Relation between a super class and sub class
Final classes and methods
The protected access specifier
Class Object

Polymorphism
Introduction
Interfaces
Packages
Abstract classes and methods

Exception handling
Exception handling introduction
Exception hierarchy
Nested try catch blocks
Throwing exceptions


Class Object

The Object class lies at the root of every hierarchy. In other words, every class is a direct or an indirect superclass of the Object class. If we do not specify a superclass using the extends keyword, the default is the Object class, otherwise the Object class becomes an indirect superclass due to multilevel inheritance.

class A {
}

A extends Object implicitly.

The Object class has certain useful methods, notable among them being the equals() methods. Since, every class is either a direct or an indirect superclass of the Object class, these methods can be invoked on any object and a reference of any object can be assigned to an Object type variable, including an array type.

Object obj = new int[5];
Object s = new Student ("Sai", 19, 97);

We can also create an object of the Object type using the constructor. However, such an object finds no useful application.

Object obj= new Object();

The Object class defines 11 methods, five of these are used in the context of multithreading which we will see when we deal with multithreading. We shall now look at some of the remaining methods.

The equals() method has the following header.

public boolean equals(Object obj)

This method is used to compare two objects. It basically returns the boolean result of == operated on the two objects, one of them being the object on which this method is invoked and the other is the one passed as an argument. In other words, it returns true only if the variable on which this method is invoked and the variable that is passed as an argument refer to the same object in memory. When the argument passed is null, the result is false. Look at the following example:

Student s1 = new Student ( "Sai", 19, 100 );
Student s2= new Student ( "Sai", 19, 100 );
Student s3=s1;
Student s4=null;
Student s5=null;
Student s6;
boolean res1=s1.equals(s2); // false
boolean res2=s1.equals(s3); // true
boolean res3=s1.equals(s4); // false
boolean res4=s1.equals(null); // false
boolean res5=s4.equals(s5); // NullPointerException thrown at runtime since s4 is null
boolean res6=s4.equals(s6); // compilation error, s6 is not initialised
boolean res7=s6.equals(s1); // compilation errors, s6 is not initialised
boolean res8=null.equals(s1); // compilation errors, null type cannot not be dereferenced

Note that even though s1 and s2 are similar in content, they both are different objects. Hence, the equals() method has returned false.

This method can be overridden or overloaded by a class to compare the contents of the objects instead of checking the references. For example, the String class which is widely used has this method overridden to compare the contents of the Strings rather than check if the two variables point to the same String. We can also provide suitable implementation for the Person and Student class which we have defined. However, one should be careful while either overloading or overriding the equals() method. Shown below are what constitutes the overloaded version and what constitutes an overridden version:

public boolean equals ( Object obj ) // overridden version
public boolean equals ( Student s ) // overloaded version

The recommended way is to provide an overloaded version instead of an overridden version. In that case when the equals() method is invoked with a Student argument, the call is resolved to the method provided. If the argument passed is not a Student object, then the call gets resolved to the other version inherited from Object which checks for references and would surely return false. Given below is the overloaded version:

public boolean equals(Student s) {
    if (this.name.equals(s.name) && this.age == s.age && this.marks == s.marks) {
        return true;
    } else {
        return false;
    }
}

This overloaded version checks if the name, age and marks of both the Student objects are identical and returns true or false accordingly. Note the use of this in the above method to refer to the Student object on which the equals() method is invoked with a Student argument.

We may if we wish to also override the method. The implementation would then vary slightly. First, we need to check if the object passed is of Student type. If it isn't, then there is no chance for it to be equal to the object on which the method is invoked. Hence, we return false. Otherwise, the object passed is explicitly down casted to Student type and we perform a comparison as done in the overloaded version above. The @ Override annotation below is optional but recommended.

@ Override
public boolean equals(Object obj) {
    if (!(obj instanceof Student)) {
        return false;
    } else {
        Student s = (Student) obj;
        if (this.name.equals(s.name) && this.age == s.age && this.marks == s.marks) {
            return true;
        } else {
            return false;
        }
    }
}

Note that we have use the equals() method rather than == to compares the two names which are Strings. After theses modification, the result of the equals() method call, which we have seen would now change. res1 becomes true.

Converting an object to String

public String toString()

The toString() method returns a String representation of the object on which it is invoked. This String contains the class name followed by the @ sign and the hexadecimal representation of the object. Do not bother about what hash code is.

Student s = new Student ( "Sai", 19, 100 );
String s=s.toString(); // s1=" Student@addbf1"

When we pass an object as a parameter to the print() or println() statement, the toString() method is implicitly called on the object and the String is printed on the screen.

System.out.println(s);// prints " Student@addbf1"on the screen

The toString() method can be overridden to return a better representation of the object. For example, in the case of Student class, we can return the name, age and marks of the marks along with the class name, in the following way.

@ Override
public String toString() {
    String s="Student: "+this.name+" "+this.age+" "+this.marks;
    return s;
}

Now, we may either explicitly call this method or implicitly call it by passing a Student object as a parameter as in the following code.

Student s = new Student ( "Sai", 19, 100 );
System.out.println(s);// prints "Student: Sai 19 100"

If we wish to do so, we may copy the definition of printDetails() method into the overriding toString() method and remove the printDetails() method. Since, the printDeatils() method's task is to essentially convert the object to a String.

protected void finalize() throws Throwable

We have seen how a constructor is used to create objects but nowhere did we see till come across a means to destroy the objects when they are no longer needed. This task is performed by Java's automatic garbage collector. The garbage collector looks for objects which no longer have references to them and destroys them. For example, look at the following two statements, we create a Student object named s using its constructor. In the second line, we assign null to the Student variable. null specifies that the variables s no longer points to any object. The object created earlier is now abandoned.

Student s=new Student("Sai", 19,100);
s = null;

Instead of using the statement s=null to remove the reference to the object created on the first line, you may also use the following statement which creates a new object and assigns its reference to s. So, the object referred to earlier has no references now.

s= new Student("Sai", 18,100);

There is no way we can retrieve the object created earlier. If too many such abandoned objects exist, they occupy significantly memory and waste the resources available. The automatic garbage collector of Java destroys such objects. But before doing so, three may be a need for that object to return back any resources that it has used. For example, if it had opened a file, ( we ill see later how it is done), the object needs to first close that files before destroying itself so that other objects can open that file. All such operations may be specified by overriding the finalize() method. The finalize() method defined in the class Object has an empty body. Shown below is an overridden version of this method for our Student class. This method simply states that the object is being destroyed.

@ Override
protected void finalize() throws Throwable {
    System.out.println("Object being destroyed");
}

We shall see what 'throws Throwable' means when we deal with exception handling but for now, it indicates that the method might throw Exceptions. The method finalize() should never be called explicitly. It is automatically called by the garbage collector when needed but one cannot be assured of when it will be called and if it is guaranteed to be called. We shall see after dealing with multithreading how we can realise the execution of the finalize() method. And, if we call the finalize() method, it doesn't destroy the object on which it is called. It only executes the body of the finalize method. We do have other methods: clone(), hash code() and get Class() and the multithreading related functions. In you are interested in learning about them, visit this page.

Privacy Policy