Sunteți pe pagina 1din 56

CSE 135

Week 8

By
Javed Siddique
Introduction
 Inheritance and polymorphism are key concepts
of Object Oriented Programming
 Inheritance facilitates the reuse of code
 A subclass inherits members (data and methods)
from all its ancestor classes
 The subclass can add more functionality to the
class or replace some functionality that it
inherits.
 Polymorphism simplifies code by automatically
using the appropriate method for a given object.
 Polymorphism also makes it easy to extend
Inheritance
 A superclass corresponds to a general class, and
a subclass is a specialization of the superclass.
 E.g. Account, Checking, Savings.
 Behavior and data common to the subclasses is
often available in the superclass.
 E.g. Account number, owner name, data opened.
 Each subclass provides behavior and data that is
relevant only to the subclass.
 E.g. Minimum balance for checking a/c, interest rate
and computation for savings account.
 The common behavior is implemented once in
the superclass and automatically inherited by the
subclasses.
Defining Classes with Inheritance

 Case Study:
 Suppose we want implement a class roster that
contains both undergraduate and graduate students.
 Each student’s record will contain his or her name,
three test scores, and the final course grade.
 The formula for determining the course grade is
different for graduate students than for undergraduate
students.
Modeling Two Types of Students

 There are two ways to design the classes


to model undergraduate and graduate
students.
 We can define two unrelated classes, one for
undergraduates and one for graduates.
 We can model the two kinds of students by using
classes that are related in an inheritance hierarchy.
 Two classes are unrelated if they are not
connected in an inheritance relationship.
 NOTE: all classes inherit from Object
Classes for the Class Roster
 For the Class Roster sample, we design three
classes:
 Student
 UndergraduateStudent
 GraduateStudent
 The Student class will incorporate behavior and
data common to both UndergraduateStudent
and GraduateStudent objects.
 The UndergraduateStudent class and the
GraduateStudent class will each contain
behaviors and data specific to their respective
objects.
Creating a subclass
 We use the keyword extends in the class
header to declare that it is a subclass:
 public class GraduateStudent extends Student {
 Student is the superclass, or parent class, or
base class.
 A parent of (a parent of …) is an ancestor class.
 GraduateStudent is the subclass, child, or
derived class.
 A child of (a child of ….) is a descendent class.
 If a class does have the extend keyword, then it
derives from the Object class.
Example: Student
class Student {
protected final static int NUM_OF_TESTS = 3;
protected String name;
protected int[] test;
protected String courseGrade;

public Student( ) {
this("No Name");
}
public Student(String studentName) {
name = studentName;
test = new int[NUM_OF_TESTS];
courseGrade = "****";
}
public String getCourseGrade( ) {
return courseGrade;
}
public String getName( ) {
return name;
}
public int getTestScore(int testNumber) {
return test[testNumber-1];
}
public void setName(String newName) {
name = newName;
}
public void setTestScore(int testNumber, int testScore) {
test[testNumber-1] = testScore;
}
}
Example: GraduateStudent

class GraduateStudent extends Student{

public void computeCourseGrade() {


int total = 0;

for (int i = 0; i < NUM_OF_TESTS; i++) {


total += test[i];
}

if (total / NUM_OF_TESTS >= 80) {


courseGrade = "Pass";
} else {
courseGrade = "No Pass";
}
}
}
Example: UndergraduateStudent

class UndergraduateStudent extends Student{

public void computeCourseGrade() {


int total = 0;

for (int i = 0; i < NUM_OF_TESTS; i++) {


total += test[i];
}

if (total / NUM_OF_TESTS >= 70) {


courseGrade = "Pass";
} else {
courseGrade = "No Pass";
}
}
}
Inheritance Hierarchy
Student

+ NUM_OF_TESTS
# name
New visibility # test
modifier: # # courseGrade
protected + Student(): void
+ Student(String): void
+ getCourseGrade(): String
+ getName(): String
+ getTestScore(int): int
+ setName(String): void
+ setTestScore(int, int): void

UndergraduateStudent GraduateStudent

+ computeCourseGrade(): String + computeCourseGrade(): String


Overriding
 All non-private members of a class are inherited by
derived classes
 This includes instance and class members
 A derived class may however, override an inherited
method
 Data members can also be overridden but should be avoided
since it only creates confusion.
 To override a method, the derived class simply defines a
method with the same name, number and types of
parameters.
 An overridden method cannot change the return type!
 A subclass may overload any method (inherited or
otherwise) by using the same name, but different
signature.
Overriding and overloading
Sup
methodA(){
Sup sup = new Sup(); }
Sub sub = new Sub(); methodA(int i){
int i=9; }
char c = 'c'; overloaded
Overloaded & Auto cast
sup.methodA(); inherite
d Sub
methodA(){
sup.methodA(i);
overridden }
methodA(char c){
}
sub.methodA();
overridden & overloaded
sub.methodA(i);

sub.methodA(c);

sup.methodA(c);
Limiting inheritance and overriding
 If a class is declared to be final, then no
other classes can derive from it.
 public final class ClassA

 If a method is declared to be final, then no


derived class can override this method.
 A final method can be overloaded in a derived
class though.
 public final void methodA()
The protected Modifier
 The modifier protected makes a data member or
method visible and accessible only to instances
of the class and descendant classes.
 public data members and methods are
accessible to everyone.
 private data members and methods are
accessible only to instances of the class.
 protected is similar to:
 public for descendant classes
 private for any other class
Inheritance and Member Accessibility
 We use the following visual representation of
inheritance to illustrate data member accessibility.
public Super :Super
protected Instances
private

:Sub
:Super
This shows the inherited
Sub components of the
✔ Accessible superclass are part of
✘ Inaccessible the subclass instance

Class Hierarchy
The Effect of the Visibility Modifiers
public :Super
protected ✔ Accessible
private ✔ ✘ Inaccessible

:Client ✘

:Sub
:Super

Accessibility from


a Client method ✘
Only public members, those defined ✔
for the class and those inherited, are ✘
visible from outside. All else is ✘
hidden from the outside.
Accessibility of Super from Sub
public
protected
private

:Sub
Accessibility from a method :Super
of the Sub class ✔



From a method of the Sub, ✔
everything is visible except ✔
the private members of
its super class.
Accessibility from Another Instance
 Data members accessible from an instance are
also accessible from other instances of the same
class.

one:ClassA two:ClassA
This could be private,
✔ Protected, or public.

Inheritance and Constructors
 Unlike members of a superclass, constructors of
a superclass are not inherited by its subclasses.
 As always, each class that does not define a
constructor is automatically given a default
constructor.
 In addition, in each constructor of a derived class,
we must make a call to the constructor of the
base class by calling: super();
 This must be the first statement in the constructor.
 If this statement is not present, the compiler
automatically adds it as the first statement.
 You may optionally call some other constructor of
the base class, e.g.: super( “some string” );
Constructors and inheritance
 The constructor for each class can be used to
initialize the variables defined in that class.
 For all classes, calls to the constructors are
chained all the way back to the constructor for
the Object class.
 Recall that it is also possible to call another
constructor of the same class using the this
keyword.
 However, this must also be the first statement of
the constructor!
 A constructor cannot call another constructor of
the same class and the base class.
Constructors
Sup
Sup
public Sup(){ public Sup(){
} super();
public Sup(int i){ }
} public Sup(int i){
super();
Sup sup1, sup2; }
Sub sub1, sub2, sub3;
Sub sup1 = new Sup();
public Sub(){ sup2 = new Sup(7); Sub Added
this(‘x’); public Sub(){ by the
} sub1 = new Sub(); this(‘x’); compiler
public Sub(char c){ sub2 = new Sub(‘y’); }
… sub3 = new Sub(5); public Sub(char c){
} super();
public Sub(int i){ …
super(i); }
… public Sub(int i){
} super(i);

}
Super keyword
 The super keyword is a call to the constructor of
the parent class.
 It can also be used to call a method of the parent
class:
 super.methodA();
 This can be useful to call an overridden method.
 Similarly, it can be used to access data members
of the parent.
super keyword example.

Sub
Sup methodA(){
methodA(){ }
} methodB(){
methodA(int i){ methodA();
} this.methodA();
super.methodA();
methodA(7);
methodA(‘x’);
}
Question
 Which method is executed for each of these
calls?
Sup sup = new Sup();
Sub sub = new Sub();
int i=9; Sup
char c='c'; methodA(){
String s=“test” }
methodA(int i){
sub.methodA(); }

sub.methodA(i);
Sub
sub.methodA(s); methodA(String s){
}
sup.methodA(c); methodA(int j){
}
Polymorphism
 Polymorphism allows a single variable to refer
to objects from different subclasses in the
same inheritance hierarchy
 For example, if Cat and Dog are subclasses of
Pet, then the following statements are valid:
Pet myPet;

myPet = new Dog();


...
myPet = new Cat();
Creating the roster Array
 We can maintain our class roster using an
array, combining objects from the Student,
UndergraduateStudent, and
GraduateStudent classes.
Student roster = new Student[40];
...
roster[0] = new GraduateStudent();
roster[1] = new UndergraduateStudent();
roster[2] = new UndergraduateStudent();
...
State of the roster Array
 The roster array with elements referring to
instances of GraduateStudent or
UndergraduateStudent classes.
Sample Polymorphic Message
 To compute the course grade using the roster
array, we execute
for (int i = 0; i < numberOfStudents; i++) {
roster[i].computeCourseGrade();
}

•If roster[i] refers to a GraduateStudent, then the


computeCourseGrade method of the GraduateStudent class
is executed.
•If roster[i] refers to an UndergraduateStudent, then the
computeCourseGrade method of the UndergraduateStudent
class is executed.
Dynamic Binding
 At compile time, it is not known which
version of a polymorphic method will get
executed
 This is determined at run-time depending upon
the class of the object
 This is called dynamic (late) binding
 Each object of a subclass is also an object
of the superclass. But not vice versa!
 Do not confuse dynamic binding with
overloaded methods.
Object Type
 Consider the inheritance hierarchy:
 Object ← A ← B
 An object of class B is also an object of classes A
and Object.
 Thus we can use objects of class B wherever we
can use objects of class A.
 The reverse is not true.
 A reference of type A can refer to an object of
type B. However if we want to access the
functionality of B on that object, we have to type
cast to type B before doing that.
Polymorphism example
Sup
methodA(){
Sub sub = new Sub(); } Note: sup.methodB( )
Sup sup;
will not compile.
sup = sub;
sup.methodA();
Sub
((Sub)sup).methodB(); methodA(){ Casting to Sub will work,
}
Sub sub1 = (Sub)sup; but a runtime exception
methodB(){
sub1.methodA();
} (ClassCastException) will
sub1.methodB(); be thrown if the object
is not really a Sub object.
sub1
sub
sup

:Sub
Example
Sup
Sub sub = new Sub();
methodA(){
Sup sup; }
methodA(String[] s){
sup = sub; }
sup.methodA();

((Sub)sup).methodA();
Sub
sub = (Sub)sup;
methodA(int i){
sub.methodA(); }
methodA(){
sub.methodA(“test”); }
The instanceof Operator
 The instanceof operator can help us
discover the class of an object at runtime.
 The following code counts the number of
undergraduate students.
new undergradCount = 0;
for (int i = 0; i < numberOfStudents; i++) {
if ( roster[i] instanceof UndergraduateStudent ) {
undergradCount++;
}
}
Abstract Superclasses and Methods

 When we define a superclass, we often do


not need to create any instances of the
superclass.
 Depending on whether we need to create
instances of the superclass, we must
define the class differently.
 We will study examples based on the
Student superclass defined earlier.
Definition: Abstract Class
 An abstract class is a class
 defined with the modifier abstract OR
 that contains an abstract method OR
 that does not provide an implementation of an inherited abstract
method

 An abstract method is a method with the keyword


abstract, and it ends with a semicolon instead of a
method body.
 Private methods and static methods may not be declared
abstract.

 No instances can be created from an abstract class.


Case 1
 A Student must be Undergraduate or
Graduate

 If a student must be either an undergraduate


or a graduate student, we only need instances
of UndergraduateStudent or GraduateStudent.

 Therefore, we should define the Student class


so that no instances may be created of it.
Example: Abstract classes
abstract class Student {
protected final static int NUM_OF_TESTS = 3; class UndergraduateStudent extends Student {
protected String name; public void computeCourseGrade() {
protected int[] test; int total = 0;
protected String courseGrade; for (int i = 0; i < NUM_OF_TESTS; i++) {
total += test[i];
}
public Student( ) { if (total / NUM_OF_TESTS >= 70) {
this("No Name"); courseGrade = "Pass";
} } else {
public Student(String studentName) { courseGrade = "No Pass";
name = studentName; }
test = new int[NUM_OF_TESTS]; }
courseGrade = "****"; }
}
public String getCourseGrade( ) { class GraduateStudent extends Student {
return courseGrade; public void computeCourseGrade() {
} int total = 0;
public String getName( ) { for (int i = 0; i < NUM_OF_TESTS; i++) {
return name; total += test[i];
} }
public int getTestScore(int testNumber) { if (total / NUM_OF_TESTS >= 80) {
return test[testNumber-1]; courseGrade = "Pass";
} } else {
public void setName(String newName) { courseGrade = "No Pass";
name = newName; }
} }
public void setTestScore(int testNumber, int testScore)
} {
test[testNumber-1] = testScore;
}
}
Abstract example (contd.)
 Non-private members of the abstract parent class are inherited.
 Note: constructors are not inherited! Default constructor calls super!

public class Test {

public static void main(String[ ] args){


Student s;
GraduateStudent g; Cannot instantiate
UndergraduateStudent u;
abstract class.
s = new Student();
g = new GraduateStudent(“John”);
g = new GraduateStudent();
u = new UndergraduateStudent(); Error: constructor not
System.out.println(g.getName());
inherited!
System.out.println(u.getName());
} Inherited from abstract
} parent class.
Case 2
 Student does not have to be
Undergraduate or Graduate.
 In this case, we may design the Student
class in one of two ways.
 We can make the Student class instantiable.
 We can leave the Student class abstract and
add a third subclass, OtherStudent, to handle
a student who does not fall into the
UndergraduateStudent or GraduateStudent
categories.
Which Approach to Use?

 The best approach depends on the


particular situation.

 When considering design options, we can


ask ourselves which approach allows
easier modification and extension.
Inheritance versus Interface
 The Java interface is used to share common
behavior (only method headers) among the
instances of different classes.
 Inheritance is used to share common code
(including both data members and methods)
among the instances of related classes.
 In your program designs, remember to use the
Java interface to share common behavior. Use
inheritance to share common code.
 If an entity A is a specialized form of another
entity B, then model them using inheritance.
Declare A as a subclass of B.
Interface vs inheritance

Interface Inheritance

Data members? Yes


No
Methods? Yes
Only headers -- no body
Keyword extends
implements
Multiple? No
Yes
Instantiable? Yes (if not abstract)
No
 An interface essentially provides
compliance with some desired behavior.
 Inheritance allows sharing of code.
Introduction to Data Structures
 A data structure is a specific organization
of data for efficiency or ease of coding.
 E.g. an array allows us to manage a large
number of similar items.
 Many different types of data structures are
used in programming.
 CS251 deals only with this topic!
 We will look at two example data structures
 Linked list
 Queue
Linked List
 Recall that an array’s capacity is fixed once
it is created or initialized.
 The LinkedList class in java.util used a
linked list to implement a variable size list
of objects.
 How does this work?
 We will study it by creating our own version
of the LinkedList class which can store a
list of objects of any class in order.
Objective
 The linked list will allow us to
 Create an empty list.
 Add items to the end of the list.
 Delete items from the end of the list.
 Iterate through the list from beginning to end.
 Note: no position indexing in this version.
 Our linked list will be implemented as a chain of
Node objects.
 Each Node object will have
 An Object data member that is the value stored at that
position.
 A reference to the next node in the list.
The Node Class
class Node {
private Node next;
private Object content;

public void Node() { :Node


next = null;
next
content = null;
} content
public Object getContent(){
return content;
}
public void setContent(Object c){
content = c;
}
public Node getNext(){
return next;
}
public void setNext(Node nextNode){
next = nextNode;
}
}
The LinkedList class
class LinkedList {
private Node head;
private Node iterator;
public void startScan throws Exception (){
public void LinkedList() { if(head == null)
head = null; throw new Exception(“Empty List”);
iterator = null; else
iterator = head;
}
}
public void addToHead(Object c){
public boolean hasMore(){
Node n = new Node();
if(iterator.next == null)
n.setContent(c);
return false;
n.setNext(head);
else
head = n;
return true;
}
}
public void deleteFromHead throws Exception (){
if(head== null) public void moveAhead(){
throw new Exception(“Empty List”); iterator = iterator.getNext();
else }
head = head.getNext();
} public Object getCurrentItem throws Exception (){
public void getFromHead throws Exception (){ if(iterator == null)
if(head== null) throw new Exception(“No Current Item”);
throw new Exception(“Empty List”); return iterator.getContent();
else }
return head.getContent(); }
}
Example list

:LinkedList :Node
head content “test1”
iterator next
LinkedList list;
list = new LinkedList();
:Node
String s;
s = “test1”; content “test2”
List.addToHead(s); s
s = “test2”;
next
list.addToHead(s);
s = “test3”; :Node
list.addToHead(s);
content “test3”
next
Scan list

:LinkedList :Node
head content “test1”
iterator next


:Node
list.startScan();
s = (String) content “test2”
s
list.getCurrentItem(); next
System.out.println(s);
while(list.hasMore()){ :Node
list.moveAhead();
content “test3”
s = (String)
list.getCurrentItem(); next
System.out.println(s);
}
Deletion list

:LinkedList :Node
head content “test1”
iterator next

:Node
content “test2”
s
next

list.deleteFromHead(); :Node
content “test3”
next
Queue
 A similar Node class can be used to
implement another data structure called a
First-In-First-out (FIFO) queue.
 A FIFO queue is often used by operating
systems for processes, requests, etc.
 In a FIFO queue, items are added at one
end and deleted from the other end.
 For this we need to have pointers going in
both directions: Node2
The Node2 Class
class Node2 {
private Node2 next, prev;
private Object content;

public void Node2() {


next = null;
prev = null;
content = null; :Node2
}
public Object getContent(){ next
return content; content
}
public void setContent(Object c){ prev
content = c;
}
public Node2 getNext(){
return next;
}
public void setNext(Node2 nextNode){
next = nextNode;
}
public Node getPrev(){
return prev;
}
public void setPrev(Node2 prevNode){
prev = prevNode;
}
}
The FifoQ class
class FifoQ {
private Node2 head, tail;

public void FifoQ() {


head = null;
tail = null;
}
public void addToQ(Object c){
Node2 n = new Node2();
n.setContent(c);
n.setNext(head);
head.setPrev(n);
head = n;
}
public void deleteFromQ throws Exception (){
if(tail== null)
throw new Exception(“Empty Queue”);
if(tail.getPrev() == null){
tail = null;
head = null;
} else {
tail = tail.getPrev();
tail.setNext(null);
}
}
Example q

:Node2
:FifoQ
next
FifoQ q; tail content “test1”
q = new FifoQ(); head prev
String s;
s = “test1”; :Node2
q.addToQ(s); next
s = “test2”; content “test2” s
q.addToQ(s); prev
while(!q.isEmpty())
q.deleteFromQ();
Example q

:Node2
:FifoQ
FifoQ q; next
tail content “test1”
q = new FifoQ();
head prev
String s;
s = “test1”;
:Node2
q.addToQ(s);
s = “test2”; next
content “test2”
q.addToQ(s);
prev
while(!q.isEmpty())
q.deleteFromQ();

S-ar putea să vă placă și