Unit 7: A Closer Look at Methods and classes
Overloading Methods If two or more method in a class have same name but different parameters, it is known as method overloading.
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
In order to overload a method, the parameter lists of the methods must differ in either of these:
Number of parameters:
add(int a, int b)
add(int a, int b, int c) Data type of parameters:
add(int x, int y) add(int x, float y) Sequence of data type of parameters
add(int p, float q) add(float m , int n)
Method overloading is one of the ways that Java supports polymorphism.
When an overloaded method is invoked, Java uses the type and/or number of arguments as its guide to determine which version of the overloaded method to actually call. Thus, overloaded methods must differ in the type and/or number of their parameters.
While overloaded methods may have different return types, the return type alone is insufficient to distinguish two versions of a method.
When Java encounters a call to an overloaded method, it simply executes the version of the method whose parameters match the arguments used in the call.
// Method overloading by changing data type of parameters class Calculate {
void sum (int a, int b) {
System.out.println("sum is"+(a+b)) ; }
void sum (float a, float b){
System.out.println("sum is"+(a+b)); }
public static void main (String[] args){ Calculate cal = new Calculate();
cal.sum (8,5); //sum(int a, int b) is method is called. cal.sum (4.6f, 3.8f); //sum(float a, float b) is called. }
Overloading Constructors
In addition to overloading normal methods, you can also overload constructors
Constructor overloading is a concept of having more than one constructor with different parameters list, in such a way so that each constructor performs a different task. They are differentiated by the compiler by the number of parameters in the list and their types. Constructor overloading is done to construct object in different ways.
//Java program to overload constructors in java class Student{
int id; String name; int age;
//creating two arg constructor Student(int i, String n){ id = i;
name = n; }
//creating three arg constructor Student(int i,String n,int a){ id = i;
name = n; age=a; }
void display(){
System.out.println(id+" "+name+" "+age); }
publicstatic void main(String args[]){ Student s1 = new Student(111,"Kamal"); Student s2 = new Student(222,"Abiral",25); s1.display();
s2.display(); }
Using Objects as Parameters
So far, we have only been using simple types as parameters to methods. However, it is both correct and common to pass objects to methods
Example:
//class Demo class Demo { int a, b;
Demo (int i,int j) {
a=i; b=j; }
// here obj is an object of tpe Demo and is passed as parameter //returns true if obj is equal to the invoking object
boolean equalTo(Demo obj){
if (obj.a == a && obj.b == b ) return true; else return false; } } //class PassObj class PassObj {
public static void main(String[] args){ Demo ob1 = new Demo(100,22);
Demo ob2 = new Demo(-1 ,-1); Demo ob3 = new Demo(100 ,22) ; boolean test1,test2;
test2 = ob1.equalTo(ob3);
System.out.println("Ob1 == ob2: "+ test1); System.out.println("ob1 ==ob3: "+test2); }
}
As you can see, the equalTo( ) method inside Demo compares two objects for equality and returns the result. That is, it compares the invoking object with the one that it is passed. If they contain the same values, then the method returns true. Otherwise, it returns false. Notice that the parameter o in equalTo( ) specifies Demo as its type. Although Demo is a class type created by the program, it is used in just the same way as Java’s built-in types
Note: Objects can also be passed as parameters of constructor as in method. Programming Task :
Create a class “Money” having two attributes “rupee” and “paisa” of type int and three methods: setMoney() - to set the values , displayMoney() – to display the values and addMoney(). The method addMoney() should have two parameters of type Money and it should compute the sum of those. Create another class “MoneyTest” having main method. Now create three objects of Money class inside main , initialize two of them using
class Money{ int rupee; int paisa;
void setMoney( int r, int p){ rupee =r;
paisa =p; }
void displayMoney(){
System.out.println(rupee+" RUPEE" + " "+ paisa+ " PAISA"); }
void addMoney(Money m1,Money m2){ this.paisa = m1.paisa+m2.paisa; this.rupee = this.paisa/100; this.paisa = this.paisa%100; this.rupee = this.rupee+m1.rupee+m2.rupee; } }
public class MoneyTest {
public static void main(String[] args) { Money bag1 = new Money();
bag3.addMoney(bag1, bag2);
System.out.println("Money in bag3"); bag3.displayMoney();
A closer look at arguments passing
In general, there are two ways that a computer language can pass an argument to a subroutine.
The first way is call-by-value. This approach copies the value of an argument into the formal parameter of the subroutine. Therefore, changes made to the parameter of the subroutine have no effect on the argument.
The second way an argument can be passed is call-by-reference. In this approach, a reference to an argument (not the value of the argument) is passed to the parameter. Inside the subroutine, this reference is used to access the actual argument specified in the call. This means that changes made to the parameter will affect the argument used to call the subroutine.
As you will see, although Java uses call-by- value to pass all arguments, the precise effect differs between whether a primitive type or a reference type is passed.
Output:
As you can see, the operations that occur inside meth( ) have no effect on the values of a and b used in the call; their values here did not change to 30 and 10.
Output:
As you can see, in this case, the actions inside meth( ) have affected the object used as an argument.
Returning Objects
A method can return any type of data, including class types that you create. For example, in the following program, the incrByTen( ) method returns an object in which the value of a is ten greater than it is in the invoking object.
Output:
As you can see, each time incrByTen( ) is invoked, a new object is created, and a reference to it is returned to the calling routine.
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 method.
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 which is equal to 6. Here is how a factorial can be computed by use of a recursive method:
The output
then multiplied by 2 (the value of n in the second invocation). This result (which is 2) is then returned to the original invocation of fact( ) and multiplied by 3 (the original value of n ). This yields the answer, 6. You might find it interesting to insert println( ) statements into fact( ), which will show at what level each call is and what the intermediate answers are.
Recursive versions of many routines may execute a bit more slowly than the iterative equivalent because of the added overhead of the additional method calls. Many recursive calls to a method could cause a stack overrun (stack overflow). Because storage for parameters and local variables is on the stack and each new call creates a new copy of these variables, it is possible that the stack could be exhausted. If this occurs, the Java run-time system will cause an exception.
The main advantage to recursive methods is that they can be used to create clearer and simpler versions of several algorithms than can their iterative relatives
Output:
Introducing access control
As you know, encapsulation links data with the code that manipulates it. However, encapsulation provides another important attribute: access control. Through encapsulation, you can control what parts of a program can access the members of a class. By controlling access, you can prevent misuse. For example, allowing access to data only through a well-defined set of methods, you can prevent the misuse of that data.
The access modifiers in java specifies accessibility (scope) of a data member, method, constructor or class.
There are four access modifiers in java which are : 1. Default Access Modifier - No Keyword 2. Private Access Modifier - private 3. Protected Access Modifier – protected 4. Public Access Modifier – public
Modifier Description
Private Declarations are visible within the class only
Default Declarations are visible only within the package (package private)
When a member of a class is modified by public, then that member can be accessed by any other code.
When a member of a class is specified as private, then that member can only be accessed by other members of its class.
When no access modifier is used, then by default the member of a class is public within its own package, but cannot be accessed outside of its package.
When private modifier is used, then that member can only be accessed by the members of same class and the members of sub classes.
Why java main method is public?
Because it is called by code that is outside the program—that is, by the Java run-time system.
Notes:
A class cannot be private or protected except nested class.
Let’s consider two packages : “mypackage1” and “ mypackage2” “mypackage1” contains three classes P1C1 , P2C2 and Pack1Main “mypackage2” contains a class Pack2Main
File: Pack1Main.java
File: Pack2Main.java
Understanding static [static keyword]
There will be times when you will want to define a class member that will be used independently of any object of that class. 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 by itself, without reference to a specific instance. To create such a member, precede its declaration with the keyword static.
The static can be:
Variable (also known as a class variable) Method (also known as a class method) Block
Nested class
When a member is declared static, it can be accessed before any objects of its class are created, and without reference to any object.
You can declare both methods and variables to be static. The most common example of a static member is main( ). main( ) is declared as static because it must be called before any objects exist.
Instance variables declared as static are, essentially, global variables. When objects of its class are declared, no copy of a static variable is made. Instead, all instances of the class share the same static variable.
Static variable
The static variable can be used to refer to the common property of all objects (which is not unique for each object), for example, the company name of employees, college name of students, etc.
The static variable gets memory only once in the class area at the time of class loading. If you need to do computation in order to initialize your static variables, you can declare a static block that gets executed exactly once, when the class is first loaded.
Advantage of static variable
Static method
If you apply static keyword with any method, it is known as static method. A static method belongs to the class rather than the object of a class.
A static method can be invoked without the need for creating an instance of a class. A static method can access static data member and can change the value of it. A static method can only directly call other static method (s).
//Java Program to demonstrate the use of a static method. package examples;
class Bank{
int staff_id; String staff_name;
static String office_name = "WoW Bank"; static long office_phone = 977123456;
//static method to change the value of static variable static void changePhone(long phn){
office_phone = phn; }
//constructor to initialize the variables Bank(int id, String n){
staff_id = id; staff_name = n; }
//method to display values void display(){
System.out.println("Office Name: "+ office_name +"\t" +"Office Phone: "+ office_phone+"\t"
+"Staff id: "+ staff_id +"\t" +"Staff name: "+ staff_name); }
}
//Test class to create and display the values of object public class TestStaticMethod{
public static void main(String args[]){ //creating objects
Bank stf1 = new Bank(101,"Ram"); Bank stf2 = new Bank(104,"Shyam"); //calling display method
stf1.display(); stf2.display();
Bank.changePhone(977654321);//calling change method //again calling display method
stf1.display(); stf2.display(); }
Static Block
Is used to initialize the static data member.
Accessing static members of a class
Outside of the class in which they are defined, static methods and variables can be used independently of any object.
To do so, you need only specify the name of their class followed by the dot operator. For example, if you wish to call a static method from outside its class, you can do so using the following general form: Classname.method( )
Here, Classname is the name of the class in which the static method is declared. As you can see, this format is similar to that used to call non-static methods through
object-reference variables.
A static variable can be accessed in the same way—by use of the dot operator on the name of the class.
Classname.staticVariableName
This is how Java implements a controlled version of global methods and global variables. Why is the Java main method static?
Introducing final [final keyword]
final keyword is a non-access modifier
The final keyword in java is used to restrict the user. The java final keyword can be used in many context. Final can be:
o variable (field) o method
o class
A field can be declared as final. Doing so prevents its contents from being modified, making it, essentially, a constant. This means that you must initialize a final field when it is declared. You can do this in one of two ways: First, you can give it a value when it is declared. Second, you can assign it a value within a constructor. The first approach is the most common.
In addition to fields, both method parameters and local variables can be declared final. Declaring a parameter final prevents it from being changed within the method. Declaring a local variable final prevents it from being assigned a value more than once. The keyword final can also be applied to methods and class.
If we make any variable as final, we cannot change the value of final variable (It will be constant) [final variable once assigned a value can never be changed.] If we make any method as final, we cannot override it.
If we make any class as final, we cannot extend it ( i.e. we cannot create subclass)
NOTE: final variables are declared in upper case (convention ) The following program will produce compile time error
class Bike{
final int SPEED_LIMIT=50;//final variable void run(){
SPEED_LIMIT =110; // We cannot reassign the value to final variable . ERROR occurs ! }
publicstatic void main(String args[]){ Bike mybike=new Bike9();
obj.run(); }
//Program to show the use of final variable package examples;
import java.util.Scanner; public class MyCircle { final double PI = 3.14; double r;
void getRad(){
Scanner sc = new Scanner(System.in);
System.out.println("Enter the radius of circle:"); r = sc.nextDouble();
}
void circleArea(){ double a = PI*r*r;
System.out.println("Area of circle is = "+a); }
public static void main(String[] args) { MyCircle c1 = new MyCircle();
c1.getRad(); c1.circleArea(); }
}
Arrays Revisited
Output:
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 a nested class is bounded by the scope of its enclosing class. Thus, if class B is defined within class A, then B does not exist independently of A. A
nested class has access to the members, including private members, of the class in which it is nested.
However, the enclosing class does not have access to the members of the nested class. A nested class that is declared directly within its enclosing class scope is a member of its enclosing class.
It is also possible to declare a nested class that is local to a block. Types of Nested classes
There are two types of nested classes: static and non-static.
A static nested class is one that has the static modifier applied. Because it is static, it must access the non-static members of its enclosing class through an object. That is, it cannot refer to non-static members of its enclosing class directly. Because of this restriction, static nested classes are seldom used.
There are two types of nested classes non-static and static nested classes.The non-static nested classes are also known as inner classes.
1. Non-static nested class (inner class) 1.1 Member inner class
Type Description
Member Inner Class
A class created within class and outside method.
Anonymous Inner Class
A class created for implementing interface or extending class. Its name is decided by the java compiler.
Local Inner Class
A class created within method.
Static Nested Class
A static class created within class.
Nested Interface
An interface created within class or interface.
Java inner class or nested class is a class which is declared inside the class or interface.
We use inner classes to logically group classes and interfaces in one place so that it can be more readable and maintainable.
Additionally, it can access all the members of outer class including private data members and methods.
Advantages
Nested classes represent a special type of relationship that is it can access all the members (data members and methods) of outer class including private.
Nested classes are used to develop more readable and maintainable code because it logically group classes and interfaces in one place only.
Code Optimization: It requires less code to write.
Difference between nested class and inner class in Java
Examples of nested classes Example 1: Static Nested class
Syntax:
class Outer_Class_Name {
static class Nested_class_Name { }
} Code:
--- public class Outer {
static class Nested_Demo { public void my_method() {
System.out.println("This is my nested class"); }
}
public static void main(String args[]) {
Outer.Nested_Demo nested = new Outer.Nested_Demo(); nested.my_method();
} }
--- Example 2: Non Static Nested Class ( Inner Class)
Syntax:
class Outer_Demo { class Inner_Demo { }
Code:
--- class Outer_Demo {
int num; // inner class
private class Inner_Demo { public void print() {
System.out.println("This is an inner class"); }
}
// Accessing the inner class from the method within void display_Inner() {
Inner_Demo inner = new Inner_Demo(); inner.print();
} }
public class My_class {
public static void main(String args[]) { // Instantiating the outer class
Outer_Demo outer = new Outer_Demo(); // Accessing the display_Inner() method. outer.display_Inner();
} }
Inner classes are also used to access the private members of a class
To instantiate the inner class, initially you have to instantiate the outer class. Syntax to do so is as follows :
Outer_Class_Name outer = new Outer_Class_Name();
Outer_Class_Name.Inner_Class_Name inner = outer.new Inner_Class_Name();
//Program to demonstrate accessing the Private Members using inner class class Outer_Demo {
// private variable of the outer class private int num = 175;
// inner class
public class Inner_Demo { public int getNum() {
System.out.println("This is the getnum method of the inner class");
return num; }
} }
public class My_class2 {
public static void main(String args[]) { // Instantiating the outer class
Outer_Demo outer = new Outer_Demo(); // Instantiating the inner class
Outer_Demo.Inner_Demo inner = outer.new Inner_Demo(); System.out.println(inner.getNum());
Example 3 : Local inner class example
In Java, we can write a class within a method and this will be a local type. Like local variables, the scope of the inner class is restricted within the method.
public class Outerclass {
// instance method of the outer class void my_Method() {
int num = 23;
// method-local inner class class MethodInner_Demo { public void print() {
System.out.println("This is method inner class "+num); }
} // end of inner class
// Accessing the inner class
MethodInner_Demo inner = new MethodInner_Demo(); inner.print();
}
public static void main(String args[]) { Outerclass outer = new Outerclass(); outer.my_Method();
Example 4: Anonymous Inner Class
!!Note: Please do not go through this before having concept of inheritance, abstract class and interface in java.
An inner class declared without a class name is known as an anonymous inner class. In case of anonymous inner classes, we declare and instantiate them at the same time. Generally, they are used whenever you need to override the method of a class or an interface. The syntax of an anonymous inner class is as follows –
AnonymousInner an_inner = new AnonymousInner() { public void my_method() {
... ... } }; Example program : --- abstract class AnonymousInner {
public abstract void mymethod(); }
public class Outer_class {
public static void main(String args[]) {
AnonymousInner inner = new AnonymousInner() { public void mymethod() {
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 you create is actually an object of type String. Even string constants are actually String objects. For example, in the statement
the string "This is a String, too" is a String object.
The second thing to understand about strings is that objects of type String are
immutable; once a String object is created, its contents cannot be altered. While this may seem like a serious restriction, it is not, for two reasons:
o If you need to change a string, you can always create a new one that contains the modifications.
o Java defines peer classes of String, called StringBuffer and StringBuilder, which allow strings to be altered, so all of the normal string manipulations are still available in Java.
Strings can be constructed in a variety of ways. The easiest is to use a statement like this: Once you have created a String object, you can use it anywhere that a string is allowed.
For example, this statement displays myString:
Java defines one operator for String objects: +. It is used to concatenate two strings. For example, this statement
The String class contains several methods that you can use. Here are a few. o You can test two strings for equality by using equals( ).
o You can obtain the length of a string by calling the length( ) method. o You can obtain the character at a specified index within a string by calling
charAt( ).
o The general forms of these three methods are shown here: boolean equals(secondStr) int length( )
Using Command-Line Arguments
Sometimes you will want to pass information into a program when you 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 a String array passed to the args parameter of
main( ).
The first command-line argument is stored at args[0], the second at args[1], and so on.
All command-line arguments are passed as strings. You must convert numeric values to their internal forms manually
Varargs: Variable-Length Arguments
Beginning with JDK 5, Java has included a feature that simplifies the creation of methods that need to take a variable number of arguments. This feature is called varargs and it is short for variable-length arguments.
Prior to JDK 5, variable-length arguments could be handled two ways. One using overloaded method (one for each) and another put the arguments into an array, and then pass this array to the method. Both of them are potentially error-prone and require more code. The varargs feature offers a simpler, better option.
A method that takes a variable number of arguments is called a variable-arity method, or simply a varargs method.
The varrags allows the method to accept zero or multiple arguments.
The varargs uses ellipsis i.e. three dots after the data type. Syntax is as follows: return_type method_name(data_type... variableName){ //body
}
the … causes the parameter to be treated as an array of the specified type
A method can have “normal” parameters along with a variable-length parameter. However, the variable-length parameter must be the last parameter declared by the method
In this case, the first three arguments used in a call to doIt( ) are matched to the first three parameters. Then, any remaining arguments are assumed to belong to vals
Rules for varargs:
While using the varargs, you must follow some rules otherwise program code won't compile. The rules are as follows:
There can be only one variable argument in the method. Variable argument (varargs) must be the last argument. These are invalid
void method(String... a, int... b){}//Compile time error
// Java program to demonstrate varargs class Test1
{
// A method that takes variable number of intger // arguments.
static void fun(int ...a) {
System.out.println("Number of arguments: " + a.length);
// using for each loop to display contents of a for (int i: a)
System.out.print(i + " "); System.out.println();
}
public static void main(String args[]) {
// Calling the varargs method with different number // of parameters
fun(100); // one parameter fun(1, 2, 3, 4); // four parameters fun(); // no parameter }
// Java program to demonstrate varargs with normal arguments class Test2
{
// Takes string as a argument followed by varargs static void myMethod(String str, int ...a)
{
System.out.println("String: " + str);
System.out.println("Number of arguments is: "+ a.length); // using for each loop to display contents of a
for (int i: a)
System.out.print(i + " "); System.out.println();
}
public static void main(String args[]) {
// Calling myMethod() with different parameter myMethod("Tribhuvan University ", 100, 200); myMethod("CSIT", 1, 2, 3, 4, 5);
myMethod("BIM"); }
Overloading Vararg Methods
Overloading allows different methods to have same name, but different signatures where signature can differ by number of input parameters or type of input parameters or both. We can overload a method that takes a variable-length argument
We can overload a method that takes a variable-length argument by two ways. First, the types of its vararg parameter can differ.
This is the case for vaTest(int …) and vaTest(boolean …). Remember, the … causes the parameter to be treated as an array of the specified type. Therefore, just as you can overload methods by using different types of array parameters, you can overload vararg methods by using different types of varargs. In this case, Java uses the type difference to determine which overloaded method to call.
The second way to overload a varargs method is to add one or more normal parameters. This is what is done with vaTest(String, int …). In this case, Java uses both the number of arguments and the type of the arguments to determine which method to call. In this case, Java uses both the number of arguments and the type of the arguments to determine which method to call.
These two ways can be summarized as :
1. Overloading Methods with only Varargs parameters:
In this case, Java uses the type difference to determine which overloaded method to call. If one method signature is strictly more specific than the other, then Java chooses it without an error.
2. Overloading Methods with Varargs alongwith other parameters :
Varargs and Ambiguity
In this program, the overloading of vaTest( ) is perfectly correct. However, this program will not compile because of the following call:
Because the vararg parameter can be empty, this call could be translated into a call to vaTest(int …) or vaTest(boolean …). Both are equally valid. Thus, the call is inherently ambiguous.
Here is another example of ambiguity. The following overloaded versions of vaTest( ) are inherently ambiguous even though one takes a normal parameter:
Although the parameter lists of vaTest( ) differ, there is no way for the compiler to resolve the following call: