Lesson 10.6 Packages
Overriding Inherited Methods
This lesson will teach you how to override an inherited method, and how to distinguish between the four types of methods that a subclass can contain: inherited methods, extended methods, overridden methods, and overloaded methods.
In the first two sections of this lesson you worked with inherited methods. An inherited method is a method that exists in the superclass, but not in the subclass.
You learned to add new methods to your class. These extended methods existed in your subclass, but not in the superclass.
You worked with overloaded methods. An overloaded method is a method that has the same name as another method in its class but a different signature. A method may also be an overloaded method if it has the same name as one if the inherited methods, but a different signature.
Finally, an overridden method is a method that has the same name as an inherited method, and an identical signature. You can only override a method that exists in the superclass, never a method that exists in the same class. Creating two methods in the same class with the same name and signature is illegal.
Use the flowchart above to help you determine whether a method is overloaded, overridden, or unrelated.
Overriden Methods
Overridden methods are important because overriding is the mechanism that enables the object oriented feature of polymorphism. When different subclasses can have different implementations of the same procedure, this allows them to respond to exactly the same message in different ways.
You've already put overriding to work when you wrote your own versions of the inherited init() and paint() methods. Overriding these methods allows your subclass of Applet to act differently than other subclasses of Applet.
The browser has no way of knowing what your applet is actually going to do, it just sends it the init() and paint() messages. On the other hand, if you make a mistake and write a paint() method like this:
public void paint()
{
//
} |
it will never be called, because you're writing an overloaded version of paint() [different signature] rather than an overridden version.
Why Override?
Why would you ever want to override a method? One good reason is if the superclass doesn't know the appropriate behavior, but it does know that some action is called for.
A CardGame superclass, for instance, doesn't know whether it will be called upon to deal a Canasta hand or a hand of SevenCardCarribeanStudPoker, but it does know that the deal() method is necessary.
That's how the paint() method works. The Component class doesn't know whether it will have to paint a Button or a Label or a MoneyLabel, but it knows the paint() method will be necessary.
A second reason for overriding an inherited method is if you need to do some additional work, tacked on to what the original superclass method already does.
When this occurs, you can call the superclass method using this syntax:
and then take whatever additional action you like. You can call the superclass method first or afterward. Unlike the super() method, used in constructors, this syntax can be used anywhere.
Overriding Component Methods
Just as we looked at the commonly used inherited Component class methods getBounds() and getSize(), we're going to look at two commonly overridden Component methods: getPreferredSize() and getInsets().
Preferred Size
When a FlowLayout or BorderLayout layout manager decides how big to make a component, it calls its getPreferredSize() method. [In Java 1.0, the perferredSize() method is used instead.]
The getPreferredSize() method returns a Dimension object containing the width and height that the component would "like" to be. The BorderLayout layout manager will disregard portions of this information--depending upon where the component is being placed--and the GridLayout layout manager will ignore all of it. In FlowLayout, however, you can put the information to good use.
Here are a couple of examples.
The FixedSizeButton Class
One of the problems with Java's Button class, at least when placed in a FlowLayout-controlled container, is that the size of the button varies according to the text placed on the button.
Sometimes, that can look really sloppy. When presenting a pair of OK and Cancel buttons, for instance, it looks better to have two fixed-size buttons than a tiny OK button and a larger Cancel button. A fixed-size button class will allow you to easily accomplish that.
Here are the steps to create your own FixedSizeButton class:
- Extend the Button class and add fields to allow the user to store the preferred width and height.
- Write a constructor that accepts width and height as well as a String to place on the face of the button.
- Override the getPreferredSize() method returning a new Dimension object initialized with width and height.
Step 1: Extend the Button class
This part is easy. You might want to provide default values for the height and width fields to facilitate the default constructor when you get 'round to it.
Here's what your FixedSizeButton class should look like with this done:
| import java.awt.*;
public class FixedSizeButton
extends Button
{
// Private fields -------------------
private int width = 75, height = 25;
} |
Step 2: Write a Constructor
You want the constructor to take a String and two int arguments, one for the width and one for the height. In your constructor, use super() along with the String to construct your Button object. Then, initialize the width and height fields.
Here's what your class should look like at this point:
| import java.awt.*;
public class FixedSizeButton
extends Button
{
public FixedSizeButton(String label,
int width,
int height)
{
super(label); // Create Button
this.width = width;
this.height = height;
}
// Private fields -------------------
private int width = 75, height = 25;
}
|
Step 3: Override the getPreferredSize() Method
This part is, if possible, even easier than the first two. All you have to do is construct a new Dimension object using the fields width and height, and return that from the getPreferredSize() method.
Here's what the final class should look like:
| import java.awt.*;
public class FixedSizeButton
extends Button
{
public FixedSizeButton(String label,
int width,
int height)
{
super(label); // Create Button
this.width = width;
this.height = height;
}
public Dimension getPreferredSize()
{
return new Dimension(width, height);
}
// Private fields -------------------
private int width = 75, height = 25;
}
|
Once you're done, you can try out your new FixedSizeButton with a small sample program like TestFSB.java, shown running here. Note the Cancel and OK buttons.
The SingleRowLabel Class
Here's a second example that shows how you can override a method, but still call the superclass method as well.
When using FlowLayout, it would be nice if you could create a Label that takes up an entire row, no matter how long or short its text is.
The SingleRowLabel class does just that by:
- Overridding getPreferredSize();
- Calling super.getPreferredSize() to find the correct height of the Label.
- Calling getSize() to find the width of the Label's container, and using that as the Label's width.
Here's the source code for the SingleRowLabel class:
|
SingleRowLabel.java
|
| import java.awt.*;
public class SingleRowLabel extends Label
{
public SingleRowLabel(String s, int align)
{
super(s, align);
}
public Dimension getPreferredSize()
{
if (getParent() != null)
{
// Width same as container
int w = getParent().getSize().width;
// Height computed by superclass method
int h = super.getPreferredSize().height;
return new Dimension(w, h);
}
else
return super.getPreferredSize();
}
}
Here's the TestSRL.java program which makes three Label variables, and initializes them with SingleRowLabel objects:
|
Changing Insets
Overriding the getInsets() method [or insets() in Java 1.0] allows you to change one of the most annoying characteristics of Java's container classes.
If you use a GridLayout or a BorderLayout, you can change the spacing between components, but you can't change the border around the outside of your container. Changing a component's Insets allows you to fix that.
The Insets class is a little like Rectangle and Dimension. It has four public fields: top, left, bottom and right. You construct a new Insets object like this:
| new Insets(5, 10, 7, 10); |
This new object now has a top value of 5, a left and right value of 10, and a bottom value of 7.
When you override the getInsets() method, you just construct an Insets object, using this constructor, and return it.
BorderPanel
Let's put this to work creating a Panel that allows you to specify the width of the Insets through a setBorder() method. Call the class BorderPanel and add the following features:
- Create a new class called BorderPanel extending Panel. Add a protected int field called border.
- Add a method called setBorder() that takes an int, and sets the field border.
- Add a getInsets() method that creates, and returns, a new Insets object, using border for all four Insets values.
This is simple enough to do without step-by-step instructions. When you're finished, you should have a class that looks like this:
|
The BorderPanel Class
|
| import java.awt.*;
public class BorderPanel extends Panel
{
// 2. A setBorder method
public void setBorder(int newB)
{
border = newB;
}
// 3. A getInsets() method
public Insets getInsets()
{
return new Insets(border, border,
border, border);
}
// 1. Protected fields
protected int border;
}
Here's an applet TestBP.java, that creates two BorderPanel objects, p1 on the left and p2 on the right. It then calls both objects' setBorder() method, passing 5 to p1 and 15 to p2. The GridLayout used for the Buttons in the BorderPanel is identical in both cases.
|
Something to Talk About
Using BorderPanel.java, can you write a constructor that allows you to specify a border width when you construct the BorderPanel object?
This is the last section of this lesson.
|