The next two examples (a class describing a set of Employees employed in a factory, and a class describing a subset of Employees which are Manager in the same factory, represent an example to show the expressive power of Inheritance in Java. In
particular, the class Manager is defined as subclass of Employee, in order to reuse the software written for the Employee class.
public class EmployeeTest
{ public static void main (String[] args) { Employee[] staff = new Employee[3];
staff[0] = new Employee("Antonio Rossi", 2000000, 1, 10, 1989);
staff[1] = new Employee("Maria Bianchi", 2500000, 1, 12, 1991);
staff[2] = new Employee("Isabel Vidal", 3000000, 1, 11, 1993);
int i;
for (i = 0; i < 3; i++) staff[i].raiseSalary(5);
for (i = 0; i < 3; i++) staff[i].print();
}}
class Employee
{ public Employee(String n, double s, int day, int month, int year) { name = n;
salary = s;
hireday = day;
hiremonth = month;
hireyear = year; } public void print()
{ System.out.println(name + " " + salary + " "
+ hireYear());
}
public void raiseSalary(double byPercent) { salary *= 1 + byPercent / 100;
}
public int hireYear() { return hireyear;
}
private String name;
private double salary;
private int hireday;
private int hiremonth;
private int hireyear;
}
Antonio Rossi 2100000.0 1989
Maria Bianchi 2625000.0 1991
Isabel Vidal 3150000.0 1993
import java.util.*;
public class ManagerTest
{ public static void main (String[] args) { Employee[] staff = new Employee[3];
staff[0] = new Employee("Antonio Rossi", 2000000, 1, 10, 1989);
staff[1] = new Manager("Maria Bianchi", 2500000, 1, 12, 1991);
staff[2] = new Employee("Isabel Vidal", 3000000, 1, 11, 1993);
int i;
for (i = 0; i < 3; i++) staff[i].raiseSalary(5);
for (i = 0; i < 3; i++) staff[i].print();
}}
class Employee
{ public Employee(String n, double s, int day, int month, int year)
{ name = n;
salary = s;
hireday = day;
hiremonth = month;
hireyear = year;
}
public void print()
{ System.out.println(name + " " + salary + " "
+ hireYear());
}
public void raiseSalary(double byPercent) { salary *= 1 + byPercent / 100;
}
public int hireYear() { return hireyear;
}
private String name;
private double salary;
private int hireday;
private int hiremonth;
private int hireyear;
}
class Manager extends Employee
{ public Manager (String n, double s, int d, int m, int y) { super(n, s, d, m, y);
secretaryName = "";
}
public void raiseSalary(double byPercent)
{ // add 1/2% bonus for every year of service GregorianCalendar todaysDate =
new GregorianCalendar();
int currentYear = todaysDate.get(Calendar.YEAR);
double bonus = 0.5 * (currentYear - hireYear());
super.raiseSalary(byPercent + bonus);
}
public String getSecretaryName() { return secretaryName;
}
private String secretaryName;
}
Antonio Rossi 2100000.0 1989
Maria Bianchi 2712500.0 1991
Isabel Vidal 3150000.0 1993
Inheritance
• FUNDAMENTAL PROPERTY (Subtyping): every object in a derived class can be used in all contexts in which it is possible to use the objects of the superclass. (is-a relationship).
e.g. as a parameter of a method, if this parameter has the type of the superclass.
A manager is-a employee.
• It is possible to assign an object of the subtype to one of the supertype, but not vice versa.
Employee[] staff = new Employee[3];
staff[0] = new Employee("Antonio Rossi",
2000000, 1, 10, 1989);
staff[1] = new Manager("Maria Bianchi",
2500000, 1, 12, 1991);
staff[2] = new Employee("Isabel Vidal",
3000000, 1, 11, 1993);
.. ..
Manager boss = staff[0]; // error
• The reason is that in general a subclass contains more fields/methods, and these are necessary in some contexts in which an object of the subclass may
occur.
Shadowing, overriding
• Shadowing Variables which have the same name are shadowed (hidden) by variables with the same name in the subclass.
Overriding Methods with the same name and same parameters types are overridden in the subclass.
• Variable and Methods access If we consider an object O in the hierarchy, the access is attempted first to the methods and variables of such object.
If a variable or a method is not defined at this level, then the superclass is searched for, and so on.
• So, shadowed variables and overridden methods will not be used in the subclass.
It is still possible to access the shadowed variable/overridden methods directly from the subclass, by means of the super operator
•
Polymorphism The access to the appropriate method when sending a message
to an object, depends on its type.
OBJECT
COMPONENT SYSTEM MATH
CONTAINER BUTTON LIST
PANEL
APPLET
A FRAGMENT OF THE SYSTEM CLASSES HIERARCHY
Abstract Classes
• It is possible to define abstract methods, which only specify the type of the arguments, whithout providing an implementation.
• If a class contains an abstract method, then it is an abstract class.
• A class can also be declared abstract even if it does not contain abstract methods
• abstract classes cannot be instantiated.
• A subclass of an abstract class may provide an implementation for each abstract method
If it does then it can be instantiated, otherwise it becomes an abstract class too.
Example: Abstract Class
• Let us implement a number of shape classes Rectangle
Square Ellipse Triangle
…
What do they have in common? What can we factorize?
Common methods: area()
circumference()
However, areas and circumferences are computed in different ways for different shapes.
Thus, we can only reasonably define an abstract class for the common functions
abstract class Shape{
public abstract double area();
public abstract double circumference();
}
class Circle extends Shape{
protected double r;
protected static final double PI=3.14;
protected double area(){return PI*r*r;}
… }
class Rectangle extends Shape{
… }
Note that the modifier 'protected' has been used in class Circle.
'protected' double r means that r is accessible and modifiable
from a subclass, while it is not modifiable from another external
class. A private component would not be modifiable in a subclass.
INTERFACES
• Multiple inheritance as in C++ is not allowed in Java. The
language designers have proposed interfaces as a way to recover most of the features of multiple inheritance.
• An interface is similar to an abstract class, with the restriction that all its methods must be abstract.
• So, all methods in an interface are implicitly abstract.
• Any variable declared in the interface must be static and final (so, they must be constants).
• A class can be subclass of a single superclass and implement several
interfaces.
INTERFACES
• Imagine that we want to define a “generic” ordering procedure, which should work for any class of objects, provided it is possible to define an ordering on such objects.
• We may try with abstract classes:
abstract class Sortable
{ public abstract int compare(Sortable b);
public static void shell_sort(Sortable[] a) { …
Shell sort body …
} }
• So, for instance if we want to order employees by their salary:
class Employee extends Sortable { …
public int compare(Sortable b) {Employee eb = (Employee) b;
if (salary<eb.salary) return -1;
if (salary>eb.salary) return +1;
return 0;}
} }
class OrderedEmployeeTest {
public static void main()
{Employee[] staff = new Employee[10];
…
Sortable.shell_sort(staff);
… }
}
Problem with multiple inheritance: INTERFACES
Imagine that we want to order the Managers in a similar way:
class Managers extends Employee extends Sortable Extending two classes in Java is forbidden (no multiple inheritance!).
So, we need interfaces and polymorphism.
Solution: use a combination of extends + interfaces.
We transform the abstract Sortable into an interface.
class Managers extends Employee implements Sortable{
public int compare(Sortable b) {
{Manager eb = (Manager) b;
if (salary<eb.salary) return -1;
if (salary>eb.salary) return +1;
return 0;}
} }
interface Sortable{
public int compare(Sortable b);
}
class Sort
{ public static void shell_sort(Sortable[] V){
…. body “SHELL_SORT”....}
}
class ManagerOrderingTest{
public static void main(){
…
Manager[] a = new Manager[100];
…
Sort. shell_sort(a);
….
}
One full example follows:
import java.util.*;
public class ManagerTest
{ public static void main (String[] args) { Employee[] staff = new Employee[3];
staff[0] = new Employee("Antonio Rossi", 2000000, 1, 10, 1989);
staff[1] = new Manager("Maria Bianchi", 2500000, 1, 12, 1991, "Segr1");
staff[2] = new Employee("Isabel Vidal", 3000000, 1, 11, 1993);
int i;
for (i = 0; i < 3; i++) staff[i].raiseSalary(5);
for (i = 0; i < 3; i++) staff[i].print();
Manager[] a = new Manager[5];
a[1]=new Manager("Linda Bianchi", 2500000, 1, 12, 1991, "Segr1");
a[0]=new Manager("Isabel Vidal", 3000000, 1, 11, 1993, "Segr2");
a[2]=new Manager("Giulio Rossi", 3500000, 1, 10, 1994, "Segr1");
a[3]=new Manager("Carla Berni", 2800000, 1, 11, 1995, "Segr3");
a[4]=new Manager("Emma Verdi", 3100000, 1, 11, 1992, "Segr2");
System.out.println("Ordinamento di un vettore di 5 Manager");
Sort.bubbleSort(a);
for (i = 0; i < a.length; i++) a[i].print();
}}
class Employee
{ public Employee(String n, double s, int day, int month, int year)
{ name = n;
salary = s;
hireday = day;
hiremonth = month;
hireyear = year;
}
public void print()
{ System.out.println(name + " " + salary + " "
+ hireYear());
}
public void raiseSalary(double byPercent) { salary *= 1 + byPercent / 100;
}
public int hireYear() { return hireyear;
}
private String name;
protected double salary;
private int hireday;
private int hiremonth;
private int hireyear;
}
class Manager extends Employee implements Sortable { public Manager (String n, double s,
int d, int m, int y, String secretaryName)
{ super(n, s, d, m, y);
this.secretaryName = secretaryName;
}
public void raiseSalary(double byPercent) { // add 1/2% bonus for every year of service GregorianCalendar todaysDate =
new GregorianCalendar();
int currentYear = todaysDate.get(Calendar.YEAR);
double bonus = 0.5 * (currentYear - hireYear());
super.raiseSalary(byPercent + bonus);
}
public String getSecretaryName() { return secretaryName;
}
public int compare(Sortable b) {Manager eb= (Manager) b;
if (salary<eb.salary) return -1;
if (salary>eb.salary) return +1;
return 0;
}
private String secretaryName;
}
interface Sortable{
public int compare(Sortable b);
}
class Sort{
public static void bubbleSort( Sortable [ ] V )
{ //ordina in ordine crescente (o meglio: non decrescente) Sortable temp; //holding variable
int j;
boolean flag = true; // set flag to true to begin first pass
while ( flag ) {
flag= false; //set flag to false awaiting a possible swap for( j=0; j < V.length -1; j++ )
{
if ( V[ j ].compare(V[j+1]) == 1 ) // if this test==1 then V[j]>V[j+1]
{
temp = V[ j ]; //swap elements (we want ascending sort) V[ j ] = V[ j+1 ];
V[ j+1 ] = temp;
flag = true; //shows a swap occurred }
} } } }
Result of the execution of this example:
Antonio Rossi 2100000.0 1989 Maria Bianchi 2950000.0 1991 Isabel Vidal 3150000.0 1993
Ordinamento di un vettore di 5 Manager Linda Bianchi 2500000.0 1991
Carla Berni 2800000.0 1995 Isabel Vidal 3000000.0 1993 Emma Verdi 3100000.0 1992 Giulio Rossi 3500000.0 1994