Overloading Methods
In Java it is possible to define two or more methods within the same class that share the same name, as long as their parameter declarations are different. When this is the case, the methods are said to be overloaded and the process is referred to as method overloading
Method overloading is one of the forms of polymorphism.
The process of creating more than one method in a class with the same name is called polymorphism
When an overloaded method is invoked, Java use the type and or number of arguments as its guide to determine which version of the overloaded method to actually call.
The following program shows method overloading
class Box{ double length; double breadth; double height; void setData(double l){ length=l; breadth =l; height = l; } void setData(double l,double h){ length=l; breadth =l; height = h; } void setData(double l, double b, double h){ length = l; breadth = b; height = h; } double getVolume(){ return length*breadth*height; } } public class BoxDemo { public static void main(String[] args) { Box b1 = new Box(); Box b2 = new Box(); Box b3 = new Box(); b1.setData(10); b2.setData(10,8); b3.setData(10, 8, 5); System.out.println("The volume b1="+b1.getVolume()); System.out.println("The volume b2="+b2.getVolume()); System.out.println("The volume b3="+b3.getVolume()); } }
The output of the above program is:
The volume b1=1000.0
The volume b2=800.0
The volume b3=400.0
Overloading Constructors
Like methods, constructors can also be overloaded. Doing so allows you to construct objects in a variety of ways. In fact, for most real world classes, the overloaded constructors are common. For example, consider the following program:
class Box{ double length; double breadth; double height; Box(){ length=0; breadth =0; height = 0; } Box(double l){ length=l; breadth =l; height = l; } Box(double l,double h){ length=l; breadth =l; height = h; } Box(double l, double b, double h){ length = l; breadth = b; height = h; } double getVolume(){ return length*breadth*height; } } public class BoxDemo { public static void main(String[] args) { Box b1 = new Box (); Box b2 = new Box (7); Box b3 = new Box (10,8); Box b4 = new Box (10, 8, 5); System.out.println ("The volume of b1="+b1.getVolume ()); System.out.println ("The volume of b2="+b2.getVolume ()); System.out.println ("The volume of b3="+b3.getVolume ()); System.out.println ("The volume of b3="+b4.getVolume ()); } }
The output of the above program is:
The volume of b1=0.0
The volume of b2=343.0
The volume of b3=800.0
The volume of b3=400.0
Using objects as parameter
We can pass object as parameter in method or constructor just like basic data type.
Let us consider the following example that passes one argument to constructor:
class Box{ double length; double breadth; double height; Box(){ length=0; breadth =0; height = 0; } Box(Box ob){ length = ob.length; breadth = ob.breadth; height = ob.height; } Box(double l, double b, double h){ length = l; breadth = b; height = h; } double getVolume(){ return length*breadth*height; } } public class BoxDemo { public static void main(String[] args) { Box b1 = new Box(); Box b2 = new Box(10,8,5); Box b3 = new Box(b2); //Cloning of b1 System.out.println("The volume of b1="+b1.getVolume()); System.out.println("The volume of b2="+b2.getVolume()); System.out.println("The volume of b3="+b3.getVolume()); } }
The output of above program is:
The volume of b1=0.0
The volume of b2=400.0
The volume of b3=400.0
Let consider one more example that passes object as argument in method
class Time{ int hour; int minute; int second; public Time(){ hour =0; minute = 0; second=0; } public Time(int h, int m, int s){ hour = h; minute = m; second = s; } public void display(){ System.out.println(hour+":"+minute+":"+second); } public boolean equals(Time t){ if(t.hour==hour&&t.minute==minute&&t.second==second) return true; else return false; } } public class TimeDemo { public static void main(String[] args) { Time t1 = new Time(2,30,20); Time t2 = new Time(2,30,20); if(t1.equals(t2)) System.out.println("Time t1 and Time t2 are same"); else System.out.println("Time t1 and Time t2 are not same"); } }
The output of above program is:
Time t1 and Time t2 are same
Returning Objects
A method can return any type of data, including class types that we create. Let us consider the following example:
class Time{ int hour; int minute; int second; public Time(){ hour =0; minute = 0; second=0; } public Time(int h, int m, int s){ hour = h; minute = m; second = s; } public void display(){ System.out.println(hour+":"+minute+":"+second); } public Time getSum(Time t){ Time temp = new Time(); temp.second = t.second+second; temp.minute = temp.second/60; temp.second = temp.second%60; temp.minute = temp.minute+t.minute+minute; temp.hour = temp.minute/60; temp.minute = temp.minute%60; temp.hour = temp.hour+t.hour+hour; return temp; } } public class Relational { public static void main(String[] args) { Time t1 = new Time (2, 30, 20); Time t2 = new Time (4, 40, 50); Time t3 = new Time (); t3 = t1.getSum (t2); System.out.println ("The sum time is: "); t3.display (); } }
The output of the above program is:
The sum time is:
7:11:10
Recursion
Java supports recursion. Recursion is the process of defining something in terms of itself. As it relates to Java programming, recursion is the attribute that allows a method to call itself. A method that calls itself is said to be recursive.
The classic example of recursion is the computation of the factorial of a number. The factorial of a number N is the product of all the whole numbers between 1 and N. for example, 3 factorial is 1*2 *3 or 6.
Consider the following program to compute factorial of a number.
class Factorial { public int fact (int n){ int result; if(n==1) return 1; result = n*fact(n-1); return result; public class Recursion { public static void main(String[] args) { Factorial f = new Factorial (); System.out.println ("The factorial of 5 = "+fact (5)); } } } }
The output of above program is:
The factorial of 5 =120
Introducing Access Control
Member access control is achieved through the use of three access modifiers: public, private and protected.
When a member of a class is modified by the public modifier, that member can be accessed by any other code in our program. This includes methods defined inside other classes.
When a member of a class is specified as private, that member can be accessed only by other members of its class. Thus, methods in other classes cannot access a private member of another class.
When no access specifier is used, then by default the member of a class is public.
The following program shows how public and private access specifiers are used.
class Test{ int a; public int b; private int c; void setC(int i){ c = i; } int getC(){ return c; } } class AccessTest { public static void main(String[] args) { Test t = new Test(); t.a = 10; t.b = 20; //t.c = 30; Error t.setC(30); System.out.println("a = "+t.a); System.out.println("b = "+t.b); System.out.println("c = "+t.getC()); } }
The output of the above program is:
a = 10
b = 20
c = 30
Understanding static
Normally, a class member must be accessed only in conjunction with an object of its class. However, it is possible to create a member that can be used itself, without reference to a specific instance. To create such a member, we precede keyword static in its normal declaration. When a member is declared static, it can be accessed before any objects of its class are created, and without reference to any object.
We can declare both methods and variables to be static.
The most common example of a static member is main (). The main () method is declared as static because it must be called before any objects exist.
Instance variables declared as static are global variables. When objects of its class are declared, no copy of static
variable is made. Instead, all instances of the class share the same static variable
Methods declared as static have several restrictions
- They can only call other static methods
- They must only access static data
- They cannot refer to this or super in any way.
If we need to do computation in order to initialize our static variables, we can declare a static block which gets executed exactly once, when the class is first loaded. Let us consider the following example.
class UseStatic{ static int a; static int b; static void display(){ System.out.println("a = "+a); System.out.println("b = "+b); } static{ System.out.println("Static block started"); a = 10; b =a*2; } public static void main(String[] args) { System.out.println("Main Block started"); display(); } }
Outside of the class in which they are defined, static methods and variables can be used independently of any object. We need only specify the name of their class followed by the dot operator. We use the following general form
classname.method ();
Let us consider the following example:
class UseStatic { static int num =10; static void display(){ System.out.println("The value of num = "+num); } void incrementByTen(){ num = num+10; } } class StaticDemo{ public static void main(String[] args) { System.out.println("Main Block started"); UseStatic s1 = new UseStatic(); s1.incrementByTen(); UseStatic s2 = new UseStatic(); s2.incrementByTen(); UseStatic.display(); } }
The output of the above program:
Main Block started
The value of num = 30
Use of Final keyword
In Java keyword final has three uses
- Using final to create the equivalent of the named constants: Variable can be declared as a final to prevent its contents from being modified that is similar as const in C and C++/C# etc.
final double PI = 3.1416
- Using final to prevent Method Overloading: The methods declared as a final can’t be overridden. The final keyword can be used as modifier at the starting of the method declaration to disallow it being overridden. Example:
class A{ final void meth(){ System.out.println("This is a final method");} } class B extends A{ void meth(){ System.out.println ("Illegal"); } }
Here the method meth() is declared as final and it can’t be overridden in B. If we attempt to do so a computer generates the error.
- Using final to prevent Inheritance: Some time we may like to prevent the class being further subclassed for security purpose. A class that can’t be sub classed is called a final class. This is achieved in Java using the keyword final: Example
final class A{
……….
……….
}
class B extends A{ //Error : can’t subclass A
……….
……….
}
Arrays Revisited
One important point to note here is that arrays are implemented as objects. There is one special attribute of array that is size of array can be determined using the instance variable length. All arrays have this variable, and it will always hold the size of the array.
The following program demonstrates the length of array.
class ArrayLength { public static void main(String[] args) { int a1[] = {1,2,3,4,5,9,0,11,20}; System.out.println ("The length of array is = "+a1.length); for(int i=0;i<a1.length;i++){ System.out.print (a1[i]+" "); } } }
The output of above program is:
The length of array is = 9
1 2 3 4 5 9 0 11 20
Exploring the String Class
String is probably the most commonly used class in Java’s class library. The obvious reason for this is that strings are a very important part of programming.
The first thing to understand about strings is that every string that we create is an actually an object of type String. Even string constants are actually String objects. For example, in the statement
System.out.println (“This is a string , too”);
the string “ This is a String, too” is a String constant
The second thing to understand about strings is that objects of type String are immutable; that is, once a String object is created, its contents cannot be altered.
String can be constructed in a variety of ways. The easiest way is to use a statement like this:
String myString = “This is s test”;
The following program demonstrates use of string
public class StringDemo { public static void main(String[] args) { String str1 = "First String"; String str2 = "Second String"; String str3 = str1+" "+"and"+" "+str2; System.out.println (str1); System.out.println ("The length of str1="+str1.length ()); System.out.println (str2); System.out.println ("The length of str1="+str2.length ()); System.out.println (str3); System.out.println ("The length of str1="+str3.length ()); } }
The output above program is:
First String
The length of str1=12
Second String
The length of str1=13
First String and Second String
The length of str1=30
We can have arrays of strings, just like we can have arrays of any other types of objects. For example let us consider the following program:
public class StringDemo { public static void main(String[] args) { String str[] = {"One","Two", "Three","Four","Five"}; for(int i=0;i<str.length;i++){ System.out.println("str["+i+"]: "+str[i]); } } }
The output of above program is:
str[0]: One
str[1]: Two
str[2]: Three
str[3]: Four
str[4]: Five
Command Line Arguments
Sometimes we need to pass information into a program when we run it. This is accomplished by passing command line arguments to main (). A command line argument is the information that directly follows the program’s name on the command line when it is executed. To access the command line arguments inside a Java program is quite easy—- they are stored as strings in the String array passed to main().
The following program shows use of command line arguments:
public class CommandLine { public static void main(String[] args) { int count,i=0; String str; count = args.length; System.out.println("Number of arguments = "+count); while(i<count) { str = args[i]; i = i+1; System.out.println(i+":"+"Java is "+str+"!"); } } }
If we compile and run the above program with the command line as follows:
Java CommandLine simple Object-Oriented Distributed Robust Secure Portable Multithreaded Dynamic
Upon execution, the command line arguments Object-Oriented ……. are passed to the program through the array args. That is the element args[0] contains Simple, args[1] contains Object-oriented, and so on.
The output of the above program will be:
Number of arguments = 8
1 : Java is Simple!
2 : Java is Object-Oriented!
3: Java is Distributed!
4: Java is Robust!
5 : Java is Secure!
6 : Java is Portable!
7 : Java is Multithreaded!
8 : Java is Dynamic!
Introducing Nested and Inner Classes
It is possible to define a class within another class; such classes are known as nested classes. The scope of nested class is bounded class is bounded by the scope of its enclosing class. Thus, if class B is defined within class A, then B is known to A, but not outside of A. A nested class has access to the members including private members of the class in which it is tested. However, the enclosing class does not have access to the members of the nested class.
There are two types of nested classes: static and non-static.
A static nested class is one which has the static modifier applied. It accesses the members of its enclosing class through an object. That is, it cannot refer to members of its enclosing class directly. Because of this restriction, static nested classes are seldom used.
The most important type of nested class is the inner class. A inner class is a non static nested class. It has access to all of the variables and methods of its outer class and may refer to them directly. It is fully within the scope of the enclosing class. The following
class Outer{ int outerX=100; void test(){ Inner in = new Inner(); in.display(); } class Inner{ void display(){ System.out.println("Display outerX:"+outerX); } } } class InnerClassDemo { public static void main(String[] args) { Outer outer = new Outer(); outer.test(); } }
Varags: Variable Length Arguments
J2SE 5 has added a new feature that simplifies the creation of methods that need to take a variable number of arguments. This feature is called varags and it is short for variable-length arguments. A method that takes a variable number of arguments is called a variable arity method or simply a varargs method.
A variable length argument is specified by three periods (…). The general form is:
static void vaTest(int…v);
The syntax tells compiler that vaTest ( ) can be called with zero or more arguments. As a result, v is implicitly declared as an array of type int[]. The parameter v is accessed using the normal array syntax.
Let us consider the following program
public class VarArgsDemo { static void vaTest(int...v){ System.out.println("Number of arguments: "+v.length); for(int x:v) System.out.println(x+" "); } public static void main(String[] args) { vaTest(10); vaTest(10,20); vaTest(10,20,30); } }
The output of above program is:
Number of arguments: 1
10
Number of arguments: 2
10
20
Number of arguments: 3
10
20
30
Overloading Varag Method
We can overload a method that takes a variable length argument. Let us consider the following method.
public class VarArgsDemo { static void vaTest (int...v) { System.out.println ("Number of arguments: "+v.length); for(int x:v) System.out.println (x+" "); } static void vaTest(boolean...v){ System.out.println ("Number of arguments "+v.length); for(boolean b:v) System.out.println (b+" "); } public static void main (String[] args) { VaTest (10, 20, 30); vaTest (true, false, true); } }
The output of above program is:
Number of arguments: 3
10
20
30
Number of arguments 3
true
false
true
Varargs and Ambiguity
Somewhat unexpected errors can result when overloading method that takes a variable length argument. These errors involve ambiguity because it is possible to create an ambiguous call to an overloaded varags method. For example, consider the following program:
public class VarArgsDemo { static void vaTest(int...v){ System.out.println("Number of arguments: "+v.length); for(int x:v) System.out.println(x+" "); } static void vaTest(boolean...v){ System.out.println("Number of arguments "+v.length); for(boolean b:v) System.out.println(b+" "); } public static void main(String[] args) { vaTest(10,20,30); vaTest(true, false,true); vaTest(); } }
This program will not compile because of the call vaTest(). Because the call is inherently ambiguous.