An Introduction to Specialization/Generalization and Inheritance
With Examples in Java |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
private
members in the superclass
protected
#
extends
in the declaration of the classsuper
as the left-side operand of the
.
operator to eliminate ambiguity (if needed)super()
(which must be the
first statement in a constructor of the subclass) super()
is called explicitly,
the default constructor in the superclass will be called
(so, if there isn't one, the subclass won't compile)super()
is called explicitly,
the default constructor in the superclass will be called
(so, if there isn't one, the subclass won't compile).class
file) for an existing class.java
file) for an existing class but don't want to change it
import java.text.*; /** * A DecimalFormat that understand the notion of a "field". * That is, you can set the field width of a FieldFormat and * it will right-justify the formatted String in a field * of that width. * * Note: This version is for illustrative purposes only. * It does not override all constructors. * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class FieldFormat extends DecimalFormat { private int fieldWidth = -1; /** * Default Constructor */ public FieldFormat() { super(); } /** * Change the length of a String to fit exactly into * a field with the current width * * If the String is lengthened it will be right-justified * * @param original The original String * @return The shortened or lengthened String */ public String fitStringToField(String original) { int i; String returnString; returnString = ""; if (fieldWidth > 0) // The field width has been set { if (original.length() <= fieldWidth) // Lengthen original { for (i=1; i <= fieldWidth-original.length(); i++) { returnString += " "; } returnString += original; } else // Shorten original { returnString = original.substring(0, fieldWidth); } } else // The field width hasn't been set { returnString = original; } return returnString; } /** * Set the field width * * @param width The width of the field */ public void setFieldWidth(int width) { fieldWidth = width; } }
import java.text.*; /** * A series of questions involving the * FieldFormat class * * Note: Before testing question n, comment-out questions * before and after. Each question stands alone. */ public class FieldFormatWhatHappensAndWhy { /** * The entry point * * @param args The command line arguments */ public static void main(String[] args) { DecimalFormat decimal; FieldFormat field; String output, temp; // Question 1 decimal = new DecimalFormat(); decimal.setFieldWidth(5); output = decimal.format(12.5); System.out.println(output); // Question 2 field = new FieldFormat(); field.setMinimumIntegerDigits(3); output = field.format(12.5); System.out.println(output); // Question 3 decimal = new DecimalFormat(); decimal.setMinimumIntegerDigits(3); field = decimal; output = field.format(12.5); System.out.println(output); // Question 4 field = new FieldFormat(); field.setMinimumIntegerDigits(3); decimal = field; output = decimal.format(12.5); System.out.println(output); // Question 5 field = new FieldFormat(); field.setMinimumIntegerDigits(3); field.setFieldWidth(10); decimal = field; output = decimal.format(12.5); System.out.println(output); // Question 6 field = new FieldFormat(); field.setMinimumIntegerDigits(3); field.setFieldWidth(10); decimal = field; output = decimal.fitStringToField("12.5"); System.out.println(output); // Question 7 field = new FieldFormat(); field.setFieldWidth(20); temp = field.format(12.5); output = field.fitStringToField(temp); System.out.println(output); // Question 8 decimal = new DecimalFormat(); setupField(decimal); output = decimal.format(12.5); System.out.println(output); // Question 9 decimal = new DecimalFormat(); setupFormat(decimal); output = decimal.format(12.5); System.out.println(output); // Question 10 field = new FieldFormat(); setupField(field); output = field.fitStringToField(temp); System.out.println(output); } /** * Setup a format object * * @param formatter The format object */ private static void setupField(FieldFormat formatter) { setupFormat(formatter); formatter.setFieldWidth(20); } /** * Setup a format object * * @param formatter The format object */ private static void setupFormat(DecimalFormat formatter) { formatter.setMinimumFractionDigits(2); formatter.setMaximumFractionDigits(2); } }
import java.util.*; /** * A specialized version of the StringTokenizer that ignores the * case of the delimiters. That is, if either 'a' or 'A' is * made a delimiter then both 'a' and 'A' will be treated as * delimiters. * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class CaseInsensitiveStringTokenizer extends StringTokenizer { /** * Explicit Value Constructor * * @param str The String to tokenize * * @see java.util.StringTokenizer#StringTokenizer(java.lang.String) */ public CaseInsensitiveStringTokenizer(String str) { super(str); } /** * Explicit Value Constructor * * @param str The String to tokenize * @param delim The set of delimiters to use * * @see java.util.StringTokenizer#StringTokenizer(java.lang.String,java.lang.String) */ public CaseInsensitiveStringTokenizer(String str, String delim) { this(str, delim, false); } /** * Explicit Value Constructor * * @param str The String to tokenize * @param delim The set of delimiters to use * @param returnDelims true to return delimiters as tokens * * @see java.util.StringTokenizer#StringTokenizer(java.lang.String,java.lang.String) */ public CaseInsensitiveStringTokenizer(String str, String delim, boolean returnDelims) { // While admittedly messy, remember that the call to super() // must be in the first statement in the method super(str, delim.toLowerCase()+delim.toUpperCase(), returnDelims); } }
import java.util.*; /** * A series of questions involving the * CaseInensitiveStringTokenizer class * * Note: Before testing question n, comment-out questions * before and after. Each question stands alone. */ public class CaseInsensitiveStringTokenizerWhatHappensAndWhy { /** * The entry point * * @param args The command line arguments */ public static void main(String[] args) { CaseInsensitiveStringTokenizer insensitive; String delimiters, test, token; StringTokenizer sensitive; test = "ThisXisxaXsimplextestXIxthink"; delimiters = "x"; // Question 1 sensitive = new StringTokenizer(test, delimiters); printTokens(sensitive); // Question 2 insensitive = new CaseInsensitiveStringTokenizer(test, delimiters); printTokens(insensitive); } /** * Loop over all tokens and print them * * @param tokenizer The StringTokenizer to use */ private static void printTokens(StringTokenizer tokenizer) { String token; System.out.println("Tokens: "); while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); System.out.println(token); } System.out.println("\n"); } }
/** * A message containing emergency information * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class EmergencyMessage { private String message; /** * Construct a new EmergencyMessage * * @param message The text of the mesage * */ public EmergencyMessage(String message) { this.message = message; } /** * Return the text of this message * * @return The text of the message */ public String getMessage() { return message; } }
/** * A message containing normal emergency * information and a supplemental alert * * @version 1.0 * @author Prof. David Bernstein, James Madison University */ public class Alert extends EmergencyMessage { private String supplement; /** * Construct a new Alert * * @param message The main mesage * @param supplement The supplemental information * */ public Alert(String message, String supplement) { super(message); this.supplement = supplement; } /** * Return the supplemental information * * @return The supplemental information */ public String getSupplement() { return supplement; } }
import java.util.*; /** * A missive in an instant messaging system * * @author Prof. David Bernstein * @version 1.0 */ public class Chirp { private String delimiters; // Delimiters between words private String text; // The text of the message /** * Explicit Value Constructor * * @param typed What was typed by the user */ public Chirp(String typed) { text = typed; delimiters = " ,.;!?-\n\r"; } /** * Get the number of words in this Chirp * * @return The number of words */ public int getNumberOfWords() { int numberOfWords; StringTokenizer tokenizer; tokenizer = new StringTokenizer(text, delimiters); numberOfWords = tokenizer.countTokens(); return numberOfWords; } /** * Get the delimiters * * @return The delimiters */ public String getDelimiters() { return delimiters; } /** * Get the text of this Chirp * * @return The text */ public String getText() { return text; } }
import java.io.*; import java.util.*; /** * A missive in an instant messaging system * * Unlike a normal Chirp, an ExpandedChirp does not * contain abbreviations -- they are all expanded * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class ExpandedChirp extends Chirp { private Properties abbreviations; /** * Explicit Value Constructor * * @param typed What was typed by the user */ public ExpandedChirp(String typed) { super(typed); InputStream is; abbreviations = new Properties(); try { is = new FileInputStream("abbreviations.txt"); abbreviations.load(is); } catch (IOException ioe) { // There was a problem opening the file // containing the abbreviations } } /** * Get the text of this Chirp with all of the * abbreviations expanded * * This method overrides the version in the parent * * @return The text */ public String getText() { String tempText; // Use getText() in the parent tempText = replaceAbbreviations(super.getText()); return tempText; } /** * Replace the abbreviations in a message * * @param msg The original message */ private String replaceAbbreviations(String msg) { String replaced, token, word; StringTokenizer tokenizer; replaced = ""; tokenizer = new StringTokenizer(msg, getDelimiters(), true); while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); word = abbreviations.getProperty(token); if (word == null) replaced += token; else replaced += word; } return replaced; } }
/** * A driver for illustrating the Chirp and EnglishChirp * classes * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class ChirpDriver { /** * The entry point of the application * * @param args The command line arguments */ public static void main(String[] args) { if ((args.length > 0) && (args[0].equals("-old"))) { ExpandedChirp chirp; chirp = new ExpandedChirp("This is it. TTFN!"); System.out.println(chirp.getText()); } else { Chirp chirp; chirp = new Chirp("This is it. TTFN!"); System.out.println(chirp.getText()); } } }
@Override
super.
Chirp c; ExpandedChirp e; c = new Chirp("TTFN"); e = (ExpandedChirp)c;
Chirp
is not an ExpandedChirp
and methods might be called on e
that it
doesn't have
ClassCastException
will be thrown
final
can't be overridden by a subclassfinal
can't be specialized (i.e., a class that extends
a final
class will not compile){leaf}
after the return type{leaf}
after the nameassertEquals()
works
with int
values,
double
values, objects, etc...printf()
method in
the PrintWriter
class is passed a format
string and then a variable number of arguments of any typeassertEquals()
is overloaded and one of the versions
has Object
parametersprintf()
are String
and Object...