Download Concept: Inheritance

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Concept: Inheritance
Definition: Inheritance in Java is the ability to create classes that inherit behavior and state from a “parent” class.
These classes provide additional specialization, either in state or behavior, than the parent class does. The
inheritance relationship can be thought of as the “is-a” relationship.
• Superclass - more general class that provides common state and/or behavior to the classes that inherit
from it.
• Subclass - class that uses the behavior inherited from the superclass to provide some specialized and more
specific behavior, often adding additional behaviors and/or attributes to implement that specialization.
All classes in Java inherit, either directly or indirectly, from the Object class. If a class definition does not
specifically inherit from, or extend, another class, it implicitly extends the Object class. Thus, every class in
Java defines a type that also is-a Object.
Hierarchies of Type: There are many examples of hierarchical types. One example is the taxonomic hierarchy
scientists use to classify living things, shown in Figure 1 below. Each level of the hierarchy describes specializations of the level above, while still embodying the characteristics of the levels of the hierarchy on a path up the
“tree.”
Animalia
Vertebra
Amphibia
Mammalia
Carnivora
Primates
Insectovora
Hominidae
Gorilla
Homo
Pan
Pongo
Figure 1: Abbreviated hierarchy of the animal kingdom
Figure 2 illustrates a part of the type hierarchy within the Java API. In this partial view, we can see that the
Reader (java.io.Reader), Number (java.lang.Number), and Component (java.awt.Component) inherit
directly from the Object (java.lang.Object) class. Each adds specific specialization to the very general
Object class, tailoring the parent class to meet particular needs within the context of the API.
If we compare, for example, the Number class with the Integer class, we can find 3 key differences that help
minimize the confusion between the subclass and the superclass.
• The keyword extends (found in the source code of the Integer class, as well as in the API documentation)
suggests that the Integer class extends or adds to the Number class. Indeed, if we look at the documentation
for the Number class, we find that it serves as the parent or super class for the BigDecimal, BigInteger,
Byte, Double, Float, Integer, Long, and Short classes, all of which represent numeric types.
• The Integer class adds additional fields to the Number class, allowing it to maintain a state that is
characteristic of an integer value, differentiated from floating point and other numeric types.
Object
Reader
Number
Integer
InputStreamReader
FileReader
Component
Double
BufferedReader
Container
Window
Frame
JFrame
Figure 2: Examples of inheritance and type hierarchy in the Java API
• The Integer class can do more - it has additional methods that further differentiate this class from other
numeric types.
Syntax: The primary syntactical element used to explicitly implement inheritance is the keyword extends.
class SubclassName extends SuperclassName {
// methods
// fields
}
class Cell extends JTextField {
public Cell ( int value , int row , int col ) {
super ((1 > value || 9 < value ) ? " " : Integer . toString ( value ));
this . row = row ;
this . col = col ;
setEditable (1 > value || 9 < value );
setFocusable (1 > value || 9 < value );
setVisible ( true );
}
public int getRow () { return row ; }
public int getColumn () { return col ; }
public void setValue ( int val ) {
setText ((0 == val ) ? " " : Integer . toString ( val ));
}
public int getIntValue () {
try { return Integer . parseInt ( getText ()); }
catch ( N umb erFo r mat Ex ce p ti on e ) { return 0; }
}
private int row , col ;
}
In Java GUI applications, it is common to create classes that extend the basic AWT and Swing components to
provide specific behaviors. The example in the listing above illustrates such a specialization of the JTextField
class. This particular specialization was developed for use in a Sudoku game as a data entry and display
component in the GUI for the game. Note that it has significant added capabilities: it knows what row and
column it occupies on the game board, and it knows that if it is created with a value between 1 and 9 (inclusive),
the cell represents a “given” value that cannot be changed.
Inheriting Instance Methods: When implementing an inheritance relation, you have three possible alternatives for defining methods:
1. You can override methods defined in the superclass by specifying a mathod in your class definition that
has exactly the same signature (access specifier, return type, name, and parameters). When the method is
applied to an object of the subclass type, the overriding method is invoked instead of the original method
defined in the super class.
2. Methods can be inherited from the superclass. Methods not overridden in a subclass are inherited from
the parent class. These methods may be called on any object of the subclass.
3. You can also define new methods, and usually will. This is the essence of using inheritance – you want to
use an existing, common behavior as a foundation for a specialization of that behavior. Compare the API
documentation for the Integer and Number classes.
Inheriting Instance Fields: The main difference between inheriting fields and methods is that instance fields
cannot be overridden. In general, there are only 2 cases for implementing fields in subclasses.
1. The subclass automatically inherits all instance fields from the superclass.
2. As with methods, any new fields declared in the subclass are present only in the subclass.
Inheritance vs. Composition: Composition is a very basic, and generally data-centric, means of constructing
classes of entities. Classes are built from aggregations of other objects, reusing their implementation within the
composing class. The composition relation is often referred to as the “has-a” relation, indicating that each of
the aggregated objects is a “part of ” the “whole” as represented by the composing class. For example, a Person
“has-a” Name, or a Name “is a part of ” a Person.
Inheritance, on the other hand, reuses the implementation of the parent superclass, inheriting state and behavior
from it. Inheritance involves some kind of “specialization” of the superclass to tailor its behavior to a particular
context. Thus, a Student “is-a” Person, although not all Persons are Students.
Inheritance vs. Interfaces: Inheritance is similar to the implementation of an interface, except that interfaces
do not have state or behavior. Also, interfaces are not classes, by definition, although inheritance relations can
exist between interfaces (but not between an interface and a class, either way).
Superclass Member Access: Subclasses have access to all public members of the superclass, but not to
members (either fields or methods) that are declared private. If a subclass needs access to a private member of
the superclass (generally, a field), it must use a method in the public interface of the superclass to access it.
Another kind of superclass access relates to calling superclass methods that are overridden in the subclass.
Consider the case of a “generic” BankAccount class:
public class BankAccount {
public BankAccount ( double initBal ) {
balance = initBal ;
}
public void deposit ( double amt ) { balance = balance + amt ; }
public void withdraw ( double amt ) { balance = balance - amt ; }
public double getBalance () { return balance ; }
private double balance ;
}
Note: this is a very simple bank account, with no overdraft protection at all!
Now consider a checking account, still with the same simple bookkeeping, but with the stipulation that charges
a fee for each withdrawal transaction over 10 in a statement period. The checking account is not charged with
the responsibility for keeping track of time, only to count the number of transactions, and provide a means of
calculating the service fee, given a fee per transaction. The implication of this behavior is that the withdraw
method must be redefined, overriding the method in the BankAccount class. However, the superclass does
not provide any way to set a balance, other than using the deposit and withdraw methods, and as a subclass,
CheckingAccount cannot access the private data member “balance.”
Also, if we override the withdraw method, but need to use the superclass version as well, there must be a means
of differentiating between the two methods. The solution is to use a reference to the superclass, similar to the
this reference to “this” object reference, called super. The listing below illustrates the use of super to access
a method of the superclass within an overriding method in a subclass.
public class CheckingAccount extends BankAccount {
public CheckingAccount ( double initBal ) {
super ( initBal );
transCount = 0;
}
public void withdraw ( double amt ) {
transCount ++;
super . withdraw ( amt );
}
private int transCount ;
}
There are two other things to note in this example:
• The first statement in the CheckingAccount constructor is a call to the constructor of the superclass. This
is necessary because the superclass defines a constructor that takes an argument, and does not provide a
default, or no-argument, constructor. This call must be the first statement in the constructor of a subclass.
• The CheckingAccount class does not provide alternative implementations for the other 2 BankAccount
classes (deposit and getBalance). These methods are inherited from the super class.
Memory Allocation: The subclass “contains” all of the implementation (methods and fields) of the superclass.
Figure 3 illustrates this in terms of the memory allocation of an object of the Cell class (listed above). Part of
the object’s memory image contains the fields defined in the JTextField class, while another part contains the
memory for the fields specifically declared within the Cell class.
Cell
text:String
... other fields
JTextField portion
row:int
col:int
Cell portion
Figure 3: Memory allocation within a Cell object
Subclass Constructors: A subclass constructor must initialize the superclass object within the subclass instance.
This initialization may be done explicitly or implicitly. If the superclass has a ”default” constructor (e.g., one
that has no parameters) explicit initialization is not required, as the compiler will use the default constructor
to perform the task. If the superclass does not have a default constructor, an explicit call (with appropriate
arguments) must be made to initialize the superclass. This is accomplished using the super keyword is used as
a method name (see the CheckingAccount example above and the train car example below).
public abstract class AbstractTrainCar {
public AbstractTrainCar ( String id , int weight ) {
idNumber = id ;
emptyWeight = weight ;
}
public String getIDNumber () { return idNumber ; }
public int getEmptyWeight () { return emptyWeight ; }
public abstract int getTotalWeight ();
private String idNumber ;
private int emptyWeight ;
}
public abstract class FreightCar extends AbstractTrainCar
public FreightCar ( String id , int weight ) {
super ( id , weight );
freightWeight = 0;
}
public int getTotalWeight () { return getEmptyWeight ()
public void addFreight ( int weight ) { freightWeight +=
public void removeFreight ( int weight ) { freightWeight
public boolean isHazardous () { return false ; }
{
+ freightWeight ; }
weight ; }
-= weight ; }
private int freightWeight ;
}
public class BoxCar extends FreightCar {
public BoxCar ( String id , int weight ) {
super ( id , weight );
hazardousCargo = false ;
}
public boolean isHazardous () { return hazardousCargo ; }
public void setHazardous ( boolean haz ) { hazardousCargo = haz ; }
private boolean hazardousCargo ;
}
Type Conversions: At different times, we may need to convert between types within a type hierarchy. These
conversions will either be subclass to superclass, or superclass to subclass.
• Subclass to Superclass Conversions - Since a subclass “is-a” specialization of a superclass, no extra
effort is needed to convert a subclass reference to a superclass reference.
BoxCar bcar = new BoxCar ( " 1234 D99 " , 23401);
FreightCar fcar = bcar ;
Object carObj = bcar ;
• Superclass to Subclass Conversions - In this case, you are moving from a general type to a more specific
type, e.g., increasing what you know about the referred-to object. There is a risk that the conversion is
not allowed, so the compiler requires an explicit cast to perform the conversion. The situation is much
the same as converting interface-type references to the class type implementing the interface. Java also
provides an operator (instanceof) to allow the class type of a reference to be checked. The instanceof
operator returns a true value if the object reference is an instance of the specified class and false otherwise.
This allows a programmer to check the type of a reference before attempting an explicit type cast.
if ( carObj instanceof BoxCar ) {
BoxCar box = ( BoxCar ) carObj ;
...
}
Abstract Classes: Abstract classes are used when we need or want to force a programmer to extend a class.
This may be because we cannot define all of the behaviors precisely, e.g., when some common behaviors must
be defined in more specialized classes. The AbstractTrainCar class above is an example of this case. Note
that the getTotalWeight() method is declared abstract, and that the method does not have a defined body
(just like a interface method). This requires any class that extends AbstractTrainCar to either implement
this method, or to be abstract itself. If a class has any method declared as abstract, the class itself must also
be declared abstract as well.
Another case where an abstract class can be effectively used is when a general, stereotypical definition of state
and behavior can be made for a broad class of objects, but this stereotype does not normally exist as a distinct
instance. Rather, the common state and behavior are embodied by the various specializations that do actually
exist. The FreightCar class above is an example of this. All train cars that carry freight should be able to
report the weight of the freight they are carrying, but the concept of a freight car is not one that can be identified
individually. All of the various kinds of freight cars embody the common behavior described by the FreightCar
class, but also have other characteristics that make them distinct from each other.
Abstract classes are similar to interfaces in Java because they can specify methods without providing their
implementation, and abstract classes cannot be instantiated. However, unlike interfaces, abstract classes are
classes. They can have instance fields, and methods can be implemented. Classes that inherit from an abstract
class must initialize the superclass just as if they extended a concrete class.
Final Classes: Consider this situation: you have implemented security features in your Java application, but you
know that anyone who can find out the names of the classes responsible for these features, they can extend
them and override their methods, defeating your security. How can this be prevented?
The answer is through final classes and/or methods. The final keyword, when used in a class declaration,
prevents that class from being extended. When used in a method signature, the method cannot be overridden.
The String class in the Java API is an example of a final class. This prevents someone from subclassing String
to create a mutable String class that could be used wherever a String could be, and would then violate the
expected behavior of String objects. An example of a final method might be a method to verify a password. Even
if you allowed the class containing the method to be extended, you would not want the password verification
method to be overridden. By declaring it final, this is prevented.