Object-Oriented Programming

In Java, object-oriented programming involves around a few key concepts: classes, objects, data members, methods, and inheritance.

Class: A class is a template from which you can create objects. The definition of the class includes the formal specifications for the class and any data and methods in it. Example:

Object: An object is an instance of a class, much as a variable is an instance of a data type. You can think of a class as the type of an object and you can think of the object as an instance of a class. Objects encapsulate methods and variables. Example:

Data member: it is those variable that are part of a class, and they're how you store the data the object uses.

Method: it is a function built into a class or object. Example:

Inheritance: It is the of driving one class, called the drive class, from another, called the base class, and bring able to make use of the base class's methods in the derive class.

Example: There are two Java files one is cal.java and another is appClass.java

cal.java file contains -

public class cal //Here cal is a Class
{
public int c=2; // Here c is a Variable or Data Member declared in class cal
public int calculate(int a, int b){ // Here calculate is a Method declared in class cal
return a+b;
}
}

appClass file contains -

public class appClass //Here appClass is the main class because it contains main(String[] args
{
public static void main(String[] args)
{
int y;
cal cal1= new cal(); //Here cal1 is a Object of class cal
y=cal1.calculate(7,cal1.c); //Here cal1 takes the functionality of the method (calculate) and value of the variable (c) of class cal
System.out.println(y);
}
}

Output -

9

Some other important concepts are,

Command-line Arguments Passed to Main:

Constructors:

Overloading Methods:

Overloading Constructors:

Passing Objects to Methods:

Declaring and Defining Class:

Syntax:

[access] class classname [extends ...] [implements ...]
{
// class definition goes here.
}

Ex. We'll make just create a very simple class named printer that defines one method, print. When i call the print method, it displays the message "Hello from Java!" on the console.

class printer
{
public void print()
{
System.out.println("Hello from Java!");
}
}
public class app
{
public static void main( String[] args)
{
printer printer1 = new printer();
printer1.print();
}
}

=> Take a moment to study this example; note that I'm declaring and defining two classes, printer and app, in the same file here. Only one class can be public in one file, and that's app in this case. The file, itself, must be named after that class, which here means the containing file must be app.java.

Ex. We can also divide this example into two files, one for each class. Here's printer.java:

class printer
{
public void print()
{
System.out.println("Hello from Java!");
}
}

And here's app.java:

import printer;
public class app
{
public static void main( String[] args)
{
printer printer1 = new printer();
printer1.print();
}
}

Creating Instance Variables:

we can store data in classes in two ways - as instance variables or as class variables.

Syntax:

[access] class classname [extends ...] [implements ...]
{
[access] type instance_variable1;
... ... ... ...
... ... ... ...
[access] type instance_variableN;
}

Ex. We'll create a class named Date that holds a String instance variable named data_string, which in turn holds the text "Hello from Java!":

class Data
{
public String data_string = "Hello from Java!";
}
public class app
{
public static void main( String[] args)
{
Data data=new Data();
String string=data.data_string;
System.out.println(string);
}
}

Setting Variable Access:

You can use an access specifier - called access in the following code - to set the visibility of a class's data members as far as the rest of the program is concerned.

Syntax:

[access] class classname [extends ...] [implements ...]
{
[access] type instance_variable1;
... ... ... ...
... ... ... ...
[access] type instance_variableN;
}

=> The possible value for access are public, private and protected. When you declare a class member public, it's accessible from anywhere in your program. If you declare it private, it's accessible only in the class it's member of. If you declare it protected, it's available to the current class, other classes in the same package. If you don't use an access specifier, the default access is that the class member is visible to the class it's a member of, to classes derived from that class in the same package, and to other classes in the same package.

Ex. if we wanted to make the instance variable data_string private to the Data class created in the previous topic, we can declare it private,

class Date
{
private String data_string = "Hello from Java!";
}
public class app
{
public static void main( String[] args)
{
Data data=new Data();
String string=data.data_string;
System.out.println(string);
}
}

=> Now, if we try to access the data_string instance variable in another class, as i do previously in the app class, the Java compiler will object:

Output:

app.java:10: data_string has private access in Data
String string=data.data_string;
^
1 error

Table: Scope by specifier (x=in scope).

Location Private No Modifier Protected Public
Same class X X X X
Subclass in the same package X X X
Non subclass in the same package X X X
Subclass in another package X X
Non-subclass in another package X

Creating Class Variable:

The value in a class variable is shared by all objects of that class, which means it will be the same for all objects. You declare a variable as static keyword.

Syntax:

[access] class classname [extends ...] [implements ...]
{
[access] static type instance_variable1;
... ... ... ...
... ... ... ...
[access] static type instance_variableN;
}

Ex. We create a class named data with a class data variable named intdata.

class data
{
public static int intdata=0;
}
public class app
{
public static void main( String[] args)
{
data a, b;
a = new data();
b = new data();
a.intdata = 1;
System.out.println("The Value of b.intdata = "+ b.intdata);
}
}

Output:

The Value of b.intdata = 1b

If you need to perform some calculation to initialize static variables, you can do so in a static code block, which you label with the static keyword; that code is executed joust once, when the class is first loaded.

Ex.

class data
{
public static int intdata =1;
public static int doubleintdata;

static
{
doubleintdata = 2 * intdata;
}
}

public class app
{
public static void main( String[] args)
{
data a;
a = new data();
System.out.println("The value of a.doubleintdate = "+ a.doubleintdata);
}
}

Output:

The value of a.doubleintdate = 2

Creating Methods:

We've been using methods even since printing out our first message with System.out.println, so we're certainly familiar with the concept. A method is a code block that you can transfer control to and so execute that code.

Ex.

class printer
{
public void print()
{
System.out.println("Hello from Java!");
}
}
public class app
{
public static void main( String[] args)
{
printer printer1 = new printer();
printer1.print();
}
}

Setting Method Access:

Ex. we add a private method to the printer class developed over the last few topics. This method may only be called from other methods in the printer class.

class printer
{
public void print()
{
internal_use_only();
}
private void internal_use_only()
{
System.out.println("Hello from Java!");
}
}

public class app
{
public static void main(String[] args)
{
printer printer1 = new printer();
printer1.print();
}
}

Output:

Hello from Java!

=> When you call the printer class's print method, it makes use of the internal_use_only method, which is inaccessible outside the object, to do the actual printing.

Passing Parameters to Methods:

When you declare a method, you can specify a comma-separated list of parameters that you want to pass to that method in the parentheses following the method's name.

Syntax:

[access] [static] type method1 ([type parameter_name1 [, type parameter_name1 . . .]])
{

}

The values passed to the method will then be accessible in the body of the method, using the named we've given them in the parameter list.

Ex. We pass the string to print to the print method. We declare the method like this so that Java knows it will accept one parameter - a String object named s:

class printer
{
public void print( String s)
{
System.out.println(s);
}
}

public class app
{
public static void main(String[] args)
{
(new printer()).print("Hello from Java!");
}
}

Output:

Hello from Java!

Note: If you have more than one parameter to pass, you can specify multiple parameters in the parameter list, separated by commas.

Command-line Arguments passed to Main:

A special array is passed as a parameter to the main method in applications - an array of String objects that holds the command-line arguments the user specified when starting Java.

C:\> java app Now is the time

=> In this case, the first element of the array passed to main will hold "Now", the second "is", the third "the" and the fourth "time".

Ex. This application will print out all the command-line arguments passed to it by looping over the String array passed as a parameter to the main method.

public class app
{
public static void main(String[] args)
{
System.out.println("Command line arguments ...");
for( int index=0 ; index < args.length ; index++ ) {
System.out.println("Argument "+ index +" = "+ args[index]);
}
}
}

Output:

C:\jdk1.3\myproject>java app Hello from Java !

Command line arguments ...
Argument 0 = Hello
Argument 1 = from
Argument 2 = Java
Argument 3 = !

Return Values from Methods:

We can use the return statement in a method to return a value from the method and we indicate what the return type of the method is when we declare the method.

[access] [static] type method1 ([type parameter_name1 [, type parameter_name1 ...]])
{
.........
.........
}

Ex. The class calculator has a method named addem that takes two integers parameters, adds them, and returns the result.

class calculator
{
int addem(int opt1, int opt2)
{
return opt1 + opt2;
}
}

public class app
{
public static void main( String[] args)
{
calculator calc = new calculator();
System.out.println("Addem(2,2) = "+ calc.addem(2,2));
}
}

Output:

Addem(2,2) = 4

Creating Class Method:

To make a method into a class method, use the static keyword.

Ex. We can call the addem method directly using the class name, without creating an object at all.

class calculator
{
static int addem(int opt1, int opt2)
{
return opt1 + opt2;
}
}

public class app
{
public static void main( String[] args)
{
System.out.println("Addem(2,2) = "+ calculator.addem(2,2));
}
}

Output:

Addem(2,2) = 4

Creating Data Access Method:

You can restrict access to the data in your objects using data access methods, which must be called to fetch the data.

Ex. We can provide access to this private data member with two methods: getdata and setdata. The getdata method just returns the value in the private variable data_string.

class data
{
private String data_string="Hello from Java!";

public String getdata()
{
return
data_string;
}

public void setdata( String s)
{
if(
s.length() < 100) {
data_string = s;
}
}
}

public class app
{
public static void main( String[] args)
{
System.out.println((new data()).getdata());
}
}

Output:

Hello from Java!

Creating Constructors:

Creating a constructor for a class is easy; we just add a method to a class with the same name as the class, without any access specifier or return type.

Ex.

class data
{
private String data_string;

data()
{
data_string="Hello from Java!";
}

public String getdata()
{
return data_string;
}
}

public class app
{
public static void main( String[] args)
{
System.out.println((new data()).getdata());
}
}

Output:

Hello from Java!

Passing Parameters to Constructors:

We can pass data to constructors just as we can to other methods.

Ex.

class data
{
private String data_string;

data( String s)
{
data_string=s;
}

public String getdata()
{
return data_string;
}
}

public class app
{
public static void main( String[] args)
{
System.out.println((new data("Hello from Java!")).getdata());
}
}

Output:

Hello from Java!

Using Recursion:

Each time we calla method in java, java allocates new space on its internal stack for all the variables in the method, which means there's no reason you can't call the same method again- a new set of variables will be allocated on the stack automatically. What's more, a method can call itself in java - this is a technique called recursion.

Ex. To calculate the factorial the factorial of positive integer n, called "n!", you calculate the following:

n! = n * (n-1) * (n-2) . . . * 2 * 1

This process lends itself to recursion easily, because each stage of the recursion can calculate one multiplication in which it multiples the number it has been passed by the factorial of the number minus 1. When the number has finally been reduced to 1 through successive calls, the method simply returns and control comes back through the successive stages, performing one multiplication at each stage until all nested calls have returned and you have the factorial.

class calculator
{
public int factorial( int n )
{
if(n==1) {
return n;
}
else {
return n*factorial(n-1);
}
}
}

public class app
{
public static void main( String[] args )
{
calculator calc = new calculator();
System.out.println("6! = "+ calc.factorial(6));
}
}

Output:

6! = 720

Garbage Collection and Memory Management:

In some languages, such as C++, you use the new operator to allocate new memory and then you use the delete operator to get rid of it when you don't need it anymore. However, Java does not have a delete operator.

In Java, you have to rely on a built-in process called garbage collection. This process occurs automatically, although you can't predict when it will happen. Java, itself, will dispose of allocated memory that on longer has any references to it. To make garbage collection happen, you can set any references to an item to null.

Ex.

class Data
{
public int intdata=0;
Data()
{
intdata=1;
}
}

public class app
{
public static void main( String[] args)
{
Data d=new Data();
// Some code ...
d=null;
// Some Additional code ...
}
}

Avoiding Circular References,

Ex. In this case, class a has an internal reference to an object of class b, and class b has an internal reference to an object of class a. When the code in main sets the reference it has to one of these objects to null, these objects will continue to sit in memory until the program ends.

class a
{
b b1;
a()
{
b1=new b();
}
}

class b
{
a a1;
b()
{
a1=new a();
}
}

public class app
{
public static void main( String[] args )
{
a obj = new a();
obj = null; // Inaccessible circular reference now exist!
}
}

Garbage Collection and The finalize Method:

The garbage collector will call a method named finalize in the object, if it exist. In the method, you can execute cleanup code and it's often a good idea to get rid of any reference to other objects that the current object has in order to eliminate the possibility of circular references.

class Data
{
public int intdata=0;
SuperGiantSizeClass sgsc;
Data()
{
intdata=1;
sgsc = new SuperGiantSizeClass(100000000);
}
protected void finalize()
{
sgsc = null;
}
}

public class app
{
public static void main( String[] args )
{
Data d =new Data();
d = null;
}
}

Overloading Methods:

Method Overloading is an object-oriented technique that lets you define several different versions of a method, all with the same name, but each with a different parameter list.

Ex.

class Calculator
{
int addem( int opt1, int opt2)
{
return opt1+opt2;
}

int addem( int opt1, int opt2, int opt3)
{
return opt1+opt2+opt3;
}
}

public class app
{
public static void main(String[] args)
{
Calculator calc=new Calculator();

System.out.println("addem(2,2) = "+ calc.addem(2,2));
System.out.println("addem(2,2,2) = "+ calc.addem(2,2,2));
}
}

Output:

addem(2,2) = 4
addem(2,2,2) = 6

Overloading Constructors:

Overloading constructors works like overloading other methods. You just define the constructor a number of times, each time with a parameter list with parameters that differ from the other lists in some way.

Ex.

class data
{
private String data_string;
data( char[] c)
{
data_string = new String(c);
}
data( String s)
{
data_string = s;
}
public String getData()
{
return data_string;
}
}

public class app
{
public static void main(String[] args)
{
char chararray[]={'H','e','l','l','o'};
System.out.println(new data(chararray).getData());
System.out.println(new data("Hello from Java!").getData());
}
}

Output:

Hello
Hello from Java!

Passing Object to Methods:

When you pass an item of a simple data type to a method, Java passes a copy of the data in the item, which is called passing by value. Because the method only gets a copy of the data item, the code in the method can't affect the original data item at all.

However, when you pass an object to a method, Java actually passes a reference to the object, which is called passing by reference. Passing by reference means that the code in the method can reach the original object. In fact, any changes made to the passed object affect the original object.

Ex. We pass an object of class Data to the print method of the printer class in order to print out the data in the object.

class Data
{
public String data_string;
Data( String data)
{
data_string = data;
}
}

class printer
{
public void print(Data d)
{
System.out.println(d.data_string);
}
}

public class app
{
public static void main( String[] args)
{
Data data=new Data("Hello from Java!");
printer p=new printer();
p.print(data);
}
}

Output:

Hello from Java!

Ex. We pass an object of the Data class to a method named rewrite that changes the data_string instance variable in the object. This variable starts out with the string "Hello from Java!" in it, but the rewrite method is able to change the string to "Hello to Java!" in this code.

class Data
{
public String data_string;
Data( String s)
{
data_string = new String(s);
}
}

class Class
{
public void rewrite( Data d)
{
d.data_string = "Hello to Java!";
}
}

public class app
{
public static void main( String[] args)
{
Data d=new Data("Hello from Java!");
Class c=new Class();
c.rewrite(d);
System.out.println(d.data_string);
}
}

Output:

Hello to Java!