this - keyword

In general, this refers to the current instance of the class.


Object Creation

Every class in Java has at least one constructor method, which has the same name as the class.

The purpose of a constructor is to perform any necessary initialisation for the new object.

If you don't define a constructor, Java provides a default constructor that takes no arguments and performs no special initialisation.

For example,

Circle  c  =  new Circle();

Defining a Constructor

We can define one or more constructors for initialisation.

For example,

// A constructor for the circle class

public class Circle {
        public double x, y, r;

        // Our constructor method.
        public Circle(double x, double y, double r) {
                this.x = x;
                this.y = y;
                this.r = r;
        }

        public  double  circumference( ) {  
                return 2 * 3.14159 * r ; 
        }
        public  double  area ( ) {
                return  3.14159 * r * r ; 
        }
}
With the new constructor, we can initialise a circle object as below,
Circle  c =  new Circle(2.0, 5.0, 1.0);

Multiple Constructors

A class can have any number of constructor methods.
public class Circle {
        public  double  x, y;
        public  double  r;

        // Constructors

        public Circle(double x, double y, double r) {
                this.x = x; this.y = y; this.r = r;
        }
        public Circle(double r) {
                x = 0.0; y = 0.0; this.r = r;
        }
        public Circle(Circle c) {
            this.x = c.x; this.y = c.y; this.r = c.r;
        }
        public Circle() {
                x = 0.0; y = 0.0; r = 1.0;
        }


        // Methods
        public  double  circumference( ) {  
                return 2 * 3.14159 * r ; 
        }
        public  double  area ( ) {
                return  3.14159 * r * r ; 
        }
}
With the new constructors, we can initialise a circle object as below,
Circle  c1 =  new Circle(2.0, 5.0, 1.0);
Circle  c2 =  new Circle(3.5);
Circle  c3 =  new Circle( c2 );
Circle  c4 =  new Circle();


Abstract Classes

Using Abstract classes, we can declare classes that define only part of an implementation, leaving subclasses to provide specific implementation of some or all of the methods.

The benefit of an abstract class is that methods may be declared such that the programmer knows the interface definition of an object, however, methods can be implemented differently in different subclasses of the abstract class.

Some rules about abstract classes:

For example,
public abstract class Shape {
        public abstract double area();
        public abstract double circumference();
}
public class Circle extends Shape {
        protected double r;
        protected static final double PI=3.141592653;
        public Circle() { r = 1.0;}
        public Circle(double r) { this.r = r;}
        public double area(){ return PI*r*r;}
        public double circumference() { 
                        return 2*PI*r;}
        public double getRadius() { return r;}
}
public class Rectangle extends Shape {
        protected double w,h;
        public Rectangle() {w=1.0; h=1.0;}
        public Rectangle(double w, double h) { 
                 this.w = w; this.h = h; }
        public double area(){ return w*h;}
        public double circumference() { 
                        return 2*(w + h);}
        public double getWidth() { return w;}
        public double getHeight() { return h;}
}
We can now write code like this:
Shape[] shapes = new Shape[3];    // create an array to hold shapes
shapes[0] = new Circle(2.0);
shapes[1] = new Rectangle(1.0, 3.0);
shapes[2] = new Rectangle(4.0, 2.0);

double total_area = 0;
for(int i = 0; i < shapes.length; i++)
        total_area += shapes[i].area();   // compute the total area of the shapes
Some points to note:


Single Inheritance versus Multiple Inheritance


Interfaces

Interfaces are like abstract classes, but with few important differences.

All the methods defined within an interface are implicitly abstract. (We don’t need to use abstract keyword, however, to improve clarity one can use abstract keyword).

Variables declared in an interface must be static and final, that means, they must be constants.

Just like a class extends its superclass, it also can optionally implements one or more interfaces. In order to implement an interface, a class must first declare the interface in an implements clause, and then it must provide an implementation for all of the methods of the interface.

A class can implement more than one interfaces.

For example,


Using Interfaces

When a class implements an interface, instances of that class can also be assigned to variables of the interface type.

For example,


Implementing Multiple Interfaces

A class can implements more than one interfaces.

For example,


Extending Interfaces

Interfaces can have sub-interfaces, just like classes can have subclasses.

A sub-interface inherits all the abstract methods and constants of its super-interface, and may define new abstract methods and constants.

Interfaces can extend more than one interface at a time.

For example,


Method Forwarding

Suppose class C extends class A, and also implements interface X.

As all the methods defined in interface X are abstract, class C needs to implement all these methods.

However, there are three implementations of X (in P,Q,R). In class C, we may want to use one of these implementations, that means, we may want to use some or all methods implemented in P, Q or R.

Say, we want to use methods implemented in P. We can do this by creating an object of type class P in class C, and through this object access all the methods implemented in P.

Note that, in class C, we do need to define all the methods in the interface X. In the body of the methods we may simply call methods of class P via the object of class P.

This approach is also known as method forwarding.

Another example,

In Java, one of the possible solutions for diamond inheritance problem is as shown below (note that we can resolve it in many different ways),

class Z is a subclass of class X, and hence it inherits all the methods and variables from class X.

In class Z, if we want to use methods implemented in class Y, we can use method forwarding technique. That means, in class Z, we can create an object of type class Y, and via this object we can access (in class Z) all the methods defined in class Y.

Objects of class Z can be assigned to variables of type X, W and IY.


When to use Interfaces


Shadowed Variables

If we declare a field in a subclass with the same name as in its superclass, both the fields exist, but the field of the superclass can no longer be accessed by its simple name.

It is still possible to access it with some more complicated syntax, but I'm not going to tell you how since reusing names like this is a bad thing.


Overriding Methods

When a class defines a method using the same name, type, and arguments as a method in its superclass, the method in the class overrides (replaces) the method in the superclass.

If a method is invoked for an object of the class, its the new definition of the method that is called, and not the superclass’s old definition.

polymorphism

An object’s ability to decide what method to apply to itself, depending on where it is in the inheritance hierarchy, is usually called polymorphism.
In the example below,

if p is an instance of class B, p.f() refers to f() in class B. However, if p is an instance of class A, p.f() refers to f() in class A. The example also shows how to refer to the overridden method using super keyword.

class A {
        int f() { return 1;}
}

class B extends A {
        int f() {                    // overrides f() in A
                return  super.f() + 1;   // invokes A.f()
        }
}

Final

A method declared with the keyword final can not be overridden.

All methods of a final class are implicitly final.

If a method is implicitly or explicitly final , the compiler can perform certain optimisations.

Fields declared as final cannot be changed.


Data Hiding and Encapsulation

We can hide the data within the class and make it available only through the methods.

This can help in maintaining the consistency of the data for an object, that means the state of an object.

Visibility Modifiers

Java provides four access modifiers (for variables/methods/classes),
private               - visible to the class only
No modifier (default) - visible to the package
protected             - visible to the package and all subclasses
public                - visible to the world
Hint : If you don't know what visibility modifier to use, make it private.  It is easy to make something more visible, but it can be very difficult to make things less visible.


Method Overloading

Defining methods with the same name and different argument or return types is called method overloading.

In Java,

a method is distinguished by its name, return type,
and by the number, type, and position of its arguments.

this - keyword (for multiple constructors)

As stated earlier, in general, this refers to an instance of the class.

For multiple constructors - this can be used from a constructor to invoke one of the other constructors of the same class.

// Constructors

        public Circle(double x, double y, double r) {
                this.x = x; this.y = y; this.r = r;
        }
        public Circle(double r) {
                this(0.0, 0.0, r);
        }
        public Circle(Circle c) {
            this(c.x, c.y, c.r);
        }
        public Circle() {
                this(0.0, 0.0, 1.0);
        }

Constructors in Extended Classes

The extended class MUST choose one of its superclass’s constructors to invoke.

We can directly invoke one of the superclass’s constructors using the super keyword.

For example,

public class GraphicCircle extends Circle {
        Color  outline, fill;

        public GraphicCircle(double x, double y,        
                                   double r, Color o, Color f) {

                super(x,y,r);
                outline = o;
                fill = f;
        }

        public void draw(Graphics g) {
                g.drawCircle(x,y,r,outline,fill)
        }
}
The super()statement must be the first statement of the new constructor.

In the first line we can call another construct of the same class using the this() syntax.

If the constructor does not start with super(...) or this(...), Java adds a super() statement before the first statement of the constructor.

Thus, constructors within a class may invoke each other, however, eventually one of them must invoke the superclass constructor method.

For example,

class A {
        public int I;
        public A() {
                // implicit call to super() here.
                // as Object is the default superclass 
                // of A , it will invoke the contructor 
                // of Object here

                I = 3;
        }
}

class B extends A {
        // constructor is not explicitly defined here
        // Java inserts default constructor here: 
        // public B() { super();}


           // .. other methods ....
}

Constructor Order Dependencies

When we create an object,
all its fields are set to their default initial values
and after that the constructor is invoked.
Each constructor has three phases: For example,
class X {
        public int a = 3;
        public int b;

        public X() {
                b = a;
        }
        
        // ... etc ...
}

class Y extends X {
        public int c = 5;
        
        public Y() {
                b = c;
        }
}
If we create an object of type Y and follow the construction step by step, the following are the values of the fields after each step (for simplicity, ignore call to the constructor of Object) :
Step      What Happens                a    b    c
-------------------------------------------------
0     Fields set to default values    0    0    0
1     Y constructor invoked           0    0    0
2     X constructor invoked           0    0    0
3     X field initialization          3    0    0
4     X constructor executed          3    3    0
5     Y field initializtion           3    3    5
6     Y constructor executed          3    5    5

Object Finalization

Just as a constructor method performs initialization for an object, a Java finalizer method performs finalization for an object.

Java garbage collection automatically frees up the memory resources used by the objects.

We can use finalize() to free up other resources - like closing files, terminating network connections, etc.

finalize takes no arguments, returns no value (ie. - void), and must be named finalize().

The Finalize method of a class does not automatically call the finalize method of the superclass (note, it's NOT like constructor method).

For example,

   .
   .
protected void finalize() {
        if (fd != null) close();
}
   .

Class Variables

Only one copy of the class variable exists regardless of the number of instances of the class.

Class variables can be used even if the class is never instantiated.

Class variables are declared with static keyword and are also called static variables .

In the following example, num_circles will indicate number of instances of the class,

public class Circle {
        static  int  num_circles = 0;
        public  double  x, y, r;

        // Constructors
        public Circle(double x, double y, double r) {
                this.x = x; this.y = y; this.r = r; 
                num_circles++ ;  }
        public Circle(double r) {
                this(0.0, 0.0, r); }
        public Circle(Circle c) {
            this(c.x, c.y, c.r); }
        public Circle() {
                this(0.0, 0.0, 1.0); }

        // Methods

         .... // The rest of the class omitted.
}

Accessing Class Variables

We can access class variables through the class, as shown below,
System.out.println("Number of circles created:" + Circle.num_circles);

Constants : A type of Class Variable

Class variable with final keyword can never be changed, just like a constant in Modula-2/C.
public  class Circle {
        public static final double PI = 3.14159265358
        public double x,y,r;

        // ... etc ...
}
For example,
double circumference = 2 * Circle.PI * radius;

Class Methods

Class methods are like class variables: For example,
double distance = Math.sqrt(dx*dx + dy*dy);