Module 2 and Inheritance
Module 2 and Inheritance
class Vehicle {
int passengers; // number of passengers
int fuelCap; // fuel capacity in gallons
int mpg; // fuel consumption in miles per gallon
}
DECLARING OBJECTS
✔ Obtaining objects of a class is a two-step process.
✔ First, you must declare a variable of the class type. This variable does not define an object. Instead, it is
simply a variable that can refer to an object.
✔ Second, you must acquire an actual, physical copy of the object and assign it to that variable. This
can be done by using the new operator.
✔ The new operator dynamically allocates (that is, allocates at run time) memory for an object and
returns a reference to it.
✔ This reference is, more or less, the address in memory of the object allocated by new.
Vehicle minivan; // declare reference to object
minivan
minivan = new Vehicle( ); // allocate a Vehicle object
minivan
Vehicle object
car2
After this fragment executes, car1 and car2 will both refer to the same object. The assignment of
car1 to car2 did not allocate any memory or copy any part of the original object. It simply makes
car2 refer to the same object as does car1. Thus, any changes made to the object through car2 will
affect the object to which car1 is referring, since they are the same object.
car1.mpg=26;
✔ When the following statements are executed display the same value
26 System.out.println(car1.mpg);
System.out.println(car2.mpg);
✔ Although car1 and car2 both refer to the same object, they are not linked in any other way.
Vehicle car1= new Vehicle( );
Vehicle car2= car1;
Vehicle car3= new Vehicle( );
car2=car3;
✔ After this statement executes car2 refers to the same object as car3. The object referred to by
car1 is exchanged.
Methods
✔ A method contains the statements that define its actions.
This is the general form of a method:
type name(parameter-list) {
// body of method
}
✔ Here, type specifies the type of data returned by the method. This can be any valid type, including class
types that you create. If the method does not return a value, its return type must be void.
✔ The parameter-list is a sequence of type and identifier pairs separated by commas. Parameters are
essentially variables that receive the value of the arguments passed to the method when it is called. If
the method has no parameters, then the parameter list will be empty.
class AddMeth {
public static void main(String[] args) {
Vehicle minivan = new Vehicle();
Vehicle sportscar = new Vehicle();
int range1, range2;
✔ When a method is called, program control is transferred to the method. When the method terminates,
control is transferred back to the caller, and execution resumes with the line of code following the call.
✔ When a method uses an instance variable that is defined by its class, it does so directly, without explicit
reference to an object and without use of the dot operator.
Returning a value:
✔ Methods that have a return type other than void return a value to the calling routine using the
following form of the return statement:
return value;
Here, value is the value returned.
// Use a return value.
class Vehicle {
int passengers; // number of passengers
int fuelCap; // fuel capacity in gallons
int mpg; // fuel consumption in miles per gallon
// Return the range.
int range( ) {
return mpg * fuelCap;
}
}
class RetMeth {
public static void main(String[ ] args) {
Vehicle minivan = new Vehicle( );
Vehicle sportscar = new Vehicle( );
int range1, range2;
// assign values to fields in minivan
minivan.passengers = 7;
minivan.fuelCap = 16;
minivan.mpg = 21;
// assign values to fields in sportscar
sportscar.passengers = 2;
sportscar.fuelCap = 14;
sportscar.mpg = 12;
// get the ranges
range1 = minivan.range();
range2 =
sportscar.range();
System.out.println("Minivan can carry " + minivan.passengers +“with range of " + range1 + " miles");
System.out.println("Sportscar can carry " + sportscar.passengers + “with range of "+range2 + " miles");
}
}
Using parameters:
✔ It is possible to pass one or more values to a method when the method is called.
✔ Parameters allow a method to be generalized. That is, a parameterized method can operate on a
variety of data and/or be used in a number of slightly different situations.
✔ There are two important things to understand about returning values:
• The type of data returned by a method must be compatible with the return type specified by the
method. For example, if the return type of some method is boolean, you could not return an integer.
• The variable receiving the value returned by a method must also be compatible with the return
type specified for the method.
// A simple example that uses a parameter.
class ChkNum {
// Return true if x is even.
boolean isEven(int x) {
if((x% 2) == 0) returntrue;
else return false;
}
}
class ParmDemo {
public static void main(String[ ] args) { ChkNum e = new ChkNum( );
if(e.isEven(10)) System.out.println("10 is even.");
if(e.isEven(9))
System.out.println("9 is even.");
if(e.isEven(8)) System.out.println("8 is even.");
}
}
A method can have more than one parameter. Simply declare each parameter, separating one
from the next with a comma.
class Factor {
// Return true if a is a factor of b.
boolean isFactor(int a, int b) {
if( (b % a) == 0) return true;
else return false;
}
}
class IsFact {
public static void main(String[] args) {
Factor x = new Factor( );
if(x.isFactor(2, 20)) System.out.println("2 is factor");
if(x.isFactor(3, 20)) System.out.println("this won't be displayed");
}
}
CONSTRUCTORS:
✔ Java allows objects to initialize themselves when they are created. This automatic initialization is
performed through the use of a constructor.
✔ A constructor initializes an object immediately upon creation. It has the same name as the class in which
it resides and is syntactically similar to a method. Once defined, the constructor is automatically called
immediately after the object is created, before the new operator completes.
// A simple constructor.
class MyClass
{ int x;
MyClass( ) {
x = 10;
}
}
class ConsDemo {
public static void main(String[ ] args) {
MyClass t1 = new MyClass( );
MyClass t2 = new MyClass( );
System.out.println(t1.x + " " + t2.x);
}
}
Parameterized Constructors
✔ Parameters are added to a constructor in the same way that they are added to a method: just
declare them inside the parenthesis after the constructor’s name.
// A parameterized constructor.
class MyClass {
int x;
MyClass(int i) {
x = i;
}
}
class ParmConsDemo {
public static void main(String[ ] args) {
MyClass t1 = new MyClass(10);
MyClass t2 = new MyClass(88);
System.out.println(t1.x + " " + t2.x);
}
}
class VehConsDemo {
public static void main(String[] args) {
// construct complete vehicles
Vehicle minivan = new Vehicle(7, 16, 21);
Vehicle sportscar = new Vehicle(2, 14,
12); double gallons;
int dist = 252;
gallons = minivan.fuelNeeded(dist);
System.out.println("To go " + dist + " miles minivan needs " +
gallons + " gallons of fuel.");
gallons = sportscar.fuelNeeded(dist);
System.out.println("To go " + dist + " miles sportscar needs " +
gallons + " gallons of fuel.");
}
}
class MyClass {
int x;
MyClass( int x) {
x = x;
}
}
class ConsDemo {
public static void main(String[ ] args) {
MyClass t1 = new MyClass(10);
MyClass t2 = new MyClass(88);
System.out.println(t1.x + " " + t2.x);
}
}
Output is 0 0
If we use this key word we can gain access to the hidden instance variables
class MyClass {
int x;
MyClass( int x) {
this.x = x;
}
}
class ConsDemo {
public static void main(String[ ] args) {
MyClass t1 = new MyClass(10);
MyClass t2 = new MyClass(88);
System.out.println(t1.x + " " + t2.x);
}
}
O/P is 10 88
Garbage Collection
✔ Since objects are dynamically allocated by using the new operator, you might be wondering how such
objects are destroyed and their memory released for later reallocation. In some languages, such as C++,
dynamically allocated objects must be manually released by use of a delete operator.
✔ Java takes a different approach; it handles deallocation automatically. The technique that accomplishes
this is called garbage collection.
✔ When no references to an object exist, that object is assumed to be no longer needed, and the memory
occupied by the object can be reclaimed.
✔ Garbage collection only occurs sporadically (if at all) during the execution of your program. It will not
occur simply because one or more objects exist that are no longer used.
The finalize( ) Method
✔ Sometimes an object will need to perform some action when it is destroyed.
✔ To handle such situations, Java provides a mechanism called finalization. By using finalization, you can
define specific actions that will occur when an object is just about to be reclaimed by the garbage
collector.
✔ To add a finalizer to a class, you simply define the finalize( ) method. The Java run time calls that
method whenever it is about to recycle an object of that class. Inside the finalize( ) method, you will
specify those actions that must be performed before an object is destroyed.
✔ The finalize( ) method has this general form:
protected void finalize( )
{
// finalization code here
}
✔ Here, the keyword protected is a specifier that prevents access to finalize( ) by code defined outside
its class.
Access Modifiers:
✔ Encapsulation links data with the code that manipulates it. However, encapsulation provides another
important attribute: access control
✔ How a member can be accessed is determined by the access modifier attached to its declaration. Java
supplies a rich set of access modifiers.
✔ Java’s access modifiers are public, private, and protected. Java also defines a default access level.
protected applies only when inheritance is involved.
✔ 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.
✔ An access modifier precedes the rest of a member’s type specification. That is, it must begin a
member’s declaration statement. Here is an example:
public int i;
private double j;
private int myMethod(int a, char b) { //…
✔ To understand the effects of public and private access, consider the following program:
/* This program demonstrates the difference between public and private. */
class Test {
int a; // default access public
int b; // public access
private int c; // private access
// methods to access c
void setc(int i) { // set c's value
c = i;
}
int getc() { // get c's value
return c;
}
}
class AccessTest {
public static void main(String args[ ]) {
Test ob = new Test();
// These are OK, a and b may be accessed
directly ob.a = 10;
ob.b = 20;
// This is not OK and will cause an error
// ob.c = 100; // Error!
// You must access c through its methods
ob.setc(100); // OK
System.out.println("a, b, and c: " + ob.a + " " +ob.b + " " + ob.getc());
}
}
Returning objects:
✔ A method can return any type of data, including class types that you create.
// Return a String object.
class ErrorMsg {
String[] msgs = { "Output Error", "Input Error", "Disk Full", "Index Out-Of-Bounds"};
// Return the error message.
String getErrorMsg(int i) { if(i
>=0 & i < msgs.length)
return msgs[i];
else
return "Invalid Error Code";
}
}
class ErrMsgDemo {
public static void main(String[] args) {
ErrorMsg err = new ErrorMsg();
System.out.println(err.getErrorMsg(2));
System.out.println(err.getErrorMsg(19));
}
}
O/P:
Disk Full
Invalid Error Code
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.
✔ Method overloading is one of the ways that Java supports polymorphism.
✔ 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.
// Demonstrate method overloading. class
Overload {
void ovlDemo() {
System.out.println("No parameters");
}
// Overload ovlDemo for one integer parameter.
void ovlDemo(int a) {
System.out.println("One parameter: " + a);
}
// Overload ovlDemo for two integer parameters.
int ovlDemo(int a, int b) {
System.out.println("Two parameters: " + a + " " + b);
return a + b;
}
// Overload ovlDemo for two double parameters.
double ovlDemo(double a, double b) {
System.out.println("Two double parameters: " + a + " " + b);
return a + b;
}
}
class OverloadDemo {
public static void main(String[] args) {
Overload ob = new Overload();
int resI;
double resD;
// call all versions of ovlDemo()
ob.ovlDemo();
System.out.println();
ob.ovlDemo(2);
System.out.println();
resI = ob.ovlDemo(4, 6);
System.out.println("Result of ob.ovlDemo(4, 6): "
+resI); System.out.println();
resD = ob.ovlDemo(1.1, 2.32);
System.out.println("Result of ob.ovlDemo(1.1, 2.32): " +
resD);
}
}
O/P:
No parameters One
parameter: 2
Two parameters: 4 6
Result of ob.ovlDemo(4, 6): 10
Two double parameters: 1.1 2.32
✔ The difference in their return types is insufficient for the purpose of overloading.
// one ovlDemo(int a) is ok
void ovlDemo(int a) {
System.out.println("One parameter: " + a);
}
// Error. two ovlDemo(int a) are not ok even though their return types are different
int ovlDemo(int a) {
System.out.println("One parameter: " + a);
return a *a;
}
✔ Java provides certain automatic type conversions. These conversions also apply to parameters
of overloaded methods. For example consider the following:
void f(double x) {
System.out.println("Inside f(double): " + x);
}
}
class TypeConv {
public static void main(String[ ] args) {
Overload2 ob = new Overload2();
int i = 10;
double d = 10.1;
byte b = 99;
short s = 10;
float f = 11.5F;
O/P
Inside f(int) : 10
Inside f(double) : 10.1
Inside f(int) : 99
Inside f(int) : 10
Inside f(double) : 11.5
In the case of byte and short java automatically converts them to int. In the case of float the value
is converted to double and f(double) is called.
The automatic type conversions apply only if there is no direct match between a parameter and an
argument.
OVERLOADING CONSTRUCTORS:
✔ Like methods constructors can also be overloaded. This allows to construct objects in a variety of ways.
// Demonstrate an overloaded constructor.
class
MyClass{ int
x; MyClass()
{
System.out.println("Inside MyClass().");
x = 0;
}
MyClass(int i) {
System.out.println("Inside MyClass(int).");
x = i;
}
MyClass(double d) {
System.out.println("Inside MyClass(double).");
x = (int) d;
}
MyClass(int i, int j) { System.out.println("Inside
MyClass(int, int)."); x = i * j;
}
}
class OverloadConsDemo { t2 = new MyClass(88); MyClass t3 =
public static void main(String[] args) { new MyClass(17.23); MyClass t4 =
MyClass t1 = new MyClass(); MyClass new MyClass(2, 4);
System.out.println("t1.x: " + t1.x); O/P:
System.out.println("t2.x: " + t2.x); Inside MyClass().
System.out.println("t3.x: " + t3.x); Inside MyClass(int).
System.out.println("t4.x: " + t4.x); Inside MyClass(double).
Inside MyClass(int, int).
t1.x: 0 t2.x: 88
t3.x: 17
t4.x: 8
}
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 by itself, without reference to a specific instance.
✔ To create such a member, precede its declaration with the keyword static.
✔ 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.
static variables:
✔ 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.
O/P:
ob1.x: 10
ob2.x: 20
ob1.sum(): 29
ob2.sum(): 39
ob1.sum(): 110
ob2.sum(): 120
static Methods:
✔ Methods declared static are, essentially, global methods. They are called independently of any object.
Instead a static method is called through its class name.
✔ Methods declared as static have several restrictions:
• They can only directly call other static methods.
• They can only directly access static data.
• They cannot refer to this or super in any way.
static Blocks:
✔ A static block is executed when the class is first loaded. Thus, it is executed before the class can
be used for any other purpose.
INHERITANCE:
Basics:
✔ Java supports inheritance by allowing one class to incorporate another class into its declaration. This
is done by using extends keyword.
✔ In java a class that is inherited is called a superclass. The class that does the inheriting is called a
subclass.
✔ The general form of a class declaration that inherits a superclass is shown here: class
subclass-name extends superclass-name {
// body of class
}
✔ We can only specify one superclass for any subclass that we create. Java does not support the
inheritance of multiple superclasses into a single subclass.
✔ A major advantage of inheritance is that once we had created a superclass that defines the atteibutes
common to a set of objects, it can be used to create any number of more specific subclasses.
✔ The following program creates a superclass called TwoDShape and subclass called Triangle
// A class for two-dimensional objects. class
TwoDShape {
double width;
double height;
void showDim()
{
System.out.println("Width and height are " + width + " and " + height);
}
}
// A subclass of TwoDShape for triangles.
class Triangle extends TwoDShape
{ String style;
double area() {
return width * height / 2;
}
void showStyle() {
System.out.println("Triangle is " + style);
}
}
class Shapes {
public static void main(String[] args) {
Triangle t1 = new Triangle();
Triangle t2 = new
Triangle(); t1.width = 4.0;
t1.height = 4.0;
t1.style = "filled";
t2.width = 8.0;
t2.height = 12.0;
t2.style = "outlined";
System.out.println("Info for t1: ");
t1.showStyle();
t1.showDim();
System.out.println("Area is " + t1.area());
System.out.println();
System.out.println("Info for t2: ");
t2.showStyle();
t2.showDim();
System.out.println("Area is " + t2.area());
}
}
USAGE OF super:
✔ Both the superclass and subclass have their own constructors.
✔ Constructors for the superclass construct the superclass portion of the object, and the constructor for the
subclass constructs the subclass part.
✔ When both the superclass and the subclass define constructors, the process is a bit complicated
because both the superclass and subclass constructors must be executed. In this case we need to use
super keyword.
✔ super has two general forms. The first calls the superclass constructor. The second is used to access a
member of the superclass that has been hidden by a member of a subclass.
✔ super( ) must always be the first statement executed inside a subclass constructor.
class TwoDShape {
private double width;
private double height;
// Parameterized constructor.
TwoDShape(double w, double h)
{
width = w; height = h;
}
// Accessor methods for width and height.
double getWidth() { return width; }
void showDim() {
System.out.println("Width and height are " + width + " and " + height);
}
}
// A subclass of TwoDShape for triangles. class
Triangle extends TwoDShape {
private String style;
Triangle(String s, double w, double h) {
super(w, h); // call superclass constructor
style = s;
}
double area() {
return getWidth() * getHeight() / 2;
}
void showStyle() {
System.out.println("Triangle is " + style);
}
}
class Shapes4 {
public static void main(String[] args) {
Triangle t1 = new Triangle("filled", 4.0, 4.0);
Triangle t2 = new Triangle("outlined", 8.0, 12.0);
System.out.println("Info for t1: "); t1.showStyle();
t1.showDim();
System.out.println("Area is " + t1.area());
System.out.println();
System.out.println("Info for t2: ");
t2.showStyle();
t2.showDim();
System.out.println("Area is " + t2.area());
}
}
✔ A reference variable for one class type cannot normally refer to an object of another class type.
// This will not compile. class
X{
int a;
X(int i) { a = i; }
}
class Y
{ int a;
Y(int i) { a = i; }
}
class IncompatibleRef {
public static void main(String[] args) {
X x = new X(10);
X x2;
Y y = new Y(5);
x2 = x; // OK, both of same type
x2 = y; // Error, not of same type
}
}
✔ When show( ) is invoked on an object of type B, the version of show( ) defined within B is used.
✔ If you wish to access the superclass version of an overridden method, you can do so by using
super.
class B extends A
{ int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
}
O/P:
i and j: 1 2
k: 3
✔ Method overriding occurs only when the names and the type signatures of the two methods are identical.
If they are not, then the two methods are simply overloaded. For example, consider this modified version
of the preceding example:
/* Methods with differing signatures are overloaded and not overridden. */ class A
{
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j);
}}
// Create a subclass by extending class A. class
B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
// overload show() void
show(String msg) {
System.out.println(msg + k);
}
}
class Overload {
public static void main(String[] args) {
B subOb = new B(1, 2, 3);
subOb.show("This is k: "); // this calls show() in B
subOb.show(); // this calls show() in A
}
}
O/P:
this is k: 3 i and
j: 1 2
DYNAMIC METHOD DISPATCH:
✔ Method overriding forms the basis for one of Java’s most powerful concepts: dynamic method dispatch.
Dynamic method dispatch is the mechanism by which a call to an overridden method is resolved at run
time, rather than compile time. Dynamic method dispatch is important because this is how Java
implements run-time polymorphism.
✔ When an overridden method is called through a superclass reference, Java determines which version of
that method to execute based upon the type of the object being referred to at the time the call occurs.
Thus, this determination is made at run time.
✔ When different types of objects are referred to, different versions of an overridden method will be called.
In other words, it is the type of the object being referred to (not the type of the reference variable) that
determines which version of an overridden method will be executed.
// Demonstrate dynamic method dispatch.
class Sup {
void who() {
System.out.println("who() in Sup");
}
}
class Sub1 extends Sup {
void who() {
System.out.println("who() in Sub1");
}
}
class Sub2 extends Sup {
void who() {
System.out.println("who() in Sub2");
}
}
class DynDispDemo {
public static void main(String[] args) {
Sup superOb = new Sup();
Sub1 subOb1 = new
Sub1(); Sub2 subOb2 =
new Sub2(); Sup supRef;
supRef =
superOb;
supRef.who();
supRef = subOb1;
supRef.who();
supRef = subOb2;
supRef.who();
}
}
O/P:
who() in Sup who()
in Sub1 who() in
Sub2
Abstract Methods:
✔ If you want a class to contain a particular method but you want the actual implementation of that
method to be determined by child classes, you can declare the method in the parent class as abstract.
✔ abstract keyword is used to declare the method as abstract.
✔ You have to place the abstract keyword before the method name in the method declaration.
✔ An abstract method contains a method signature, but no method body.
✔ Instead of curly braces an abstract method will have a semi colon ( ; ) at the end.
✔
✔
// A Simple
demonstration of
abstract. abstract class
A{
abstract void callme();
// concrete methods are still allowed in
abstract classes void callmetoo() {
System.out.println("This is a concrete method.");
}
}
class B extends A {
void callme() {
System.out.println("B's implementation of callme.");
}
}
class AbstractDemo {
public static void
main(String
args[]) { B b =
new B();
b.callme(); b.callmetoo()
;
}
}
Using final
✔ To prevent a method from being overridden or a class from being inherited by using the
keyword final.
final prevents overriding:
✔ To disallow a method from being overridden, specify final as a modifier at the start of its
declaration. Methods declared as final cannot be overridden. The following fragment
illustrates final:
class A {
final void meth() {
System.out.println("This is a final method.");
}
}
class B extends A {
void meth() { // ERROR!
Can't override.
System.out.println("Illega
l!");
}
}