SearchingTopJava inheritance

Java inheritance

Inheritance in Java is very similar to that in Grace, and in fact we have been using it from the beginning with our main programs (classes that extend WindowController and in the last section with classes that extend Thread).

Before we get into the nitty gritty of inheritance, let me remind you about the visibility declarations in Java. If a variable or method is declared to be public, then it is accessible to anyone who has a reference to the object. If it is declared to be private then it is only accessible inside the class that defines it. If it is declared to be protected, then it is accessible inside the class that defines it or in any subclass.1 Thus protected is very similar to Grace's confidential.

To this point we have insisted that you declare all of the instance variables in Java to be private. However, you should declare them to be protected if you wish them to be accessible to subclasses. Never make an instance variable public. Instead if you want read or write access to a variable to be public, declare a getter or setter method to access them. (This is what Grace does for you automatically when you declare a variable to be readable or writable.)

In Java we write extends rather than inherits and the initialization code for the superclass is invoked in the constructor of the subclass. Here is a simple example in Java. First the superclass:

// A FramedDisplay is a composite graphic intended to serve 
// as a frame in which a program can display various forms 
// of information.
public class FramedDisplay {
   private static final int BORDER = 3; // Border thickness 
   private static final int ROUNDNESS = 5; // Corner roundess
   
   // Colors used for the frame
   private static final Color BORDERCOLOR = Color.GRAY; 
   private static final Color HIGHLIGHTCOLOR = Color.RED;
   
   private FilledRoundedRect body; // The background 
   private FilledRoundedRect border; // The border
   
   // Create the display areaÕs background and border and set 
   // their colors appropriately
   public FramedDisplay( double x, double y,
                                  double width, double height, DrawingCanvas canvas ) {
        border = new FilledRoundedRect( x, y,
                                        width, height,
                                        ROUNDNESS, ROUNDNESS,
                                        canvas );
   
        body = new FilledRoundedRect( x + BORDER, y + BORDER,
                                      width - 2*BORDER, height - 2*BORDER,
                                      ROUNDNESS, ROUNDNESS,
                                      canvas );
   
        border.setColor( BORDERCOLOR );
    }
   
    // Change the border's color to make it stand out 
    public void highlight( ) {
        border.setColor( HIGHLIGHTCOLOR );
    }
   
    // Restore the standard border color 
   public void unHighlight( ) {
       border.setColor( BORDERCOLOR );
   } 
}

Here is the code for the subclass:

// A FramedText object displays a specified text message on a 
// background framed by a distinct border.
public class FramedText extends FramedDisplay {

   // Color used for the text
   private static final Color TEXTCOLOR = Color.WHITE;
   
   private Text message; // The message displayed 
   private Location frameCenter; // Where message belongs
   
   // Create a FramedText object displaying the text ÕcontentsÕ 
   // at the position and with the dimensions specified.
   public FramedText( String contents, double x, double y,
                                double width, double height, DrawingCanvas canvas ) {
        // construct the frame
        super( x, y, width, height, canvas );
                                
        // Construct and appropriately position the message 
        frameCenter = new Location( x + width/2, y + height/2 ); 
        message = new Text ( contents, x, y, canvas ); 
        message.setColor( TEXTCOLOR );
        positionContents();
   }
        
    // Position the message to center it in the frame 
    private void positionContents() {
        message.moveTo( frameCenter );
        message.move( -message.getWidth()/2, -message.getHeight()/2 );
    }
    
    // Change the font size used 
    public void setTextSize( int size ) {
        message.setFontSize( size );
        positionContents();
    } 
}

In Grace we would have started the body of the method with inherits framedDisplay..... However in Java we add extends FrameDisplay to the class header. We invoke the initialization code in Java by inserting a super constructor as the first statement in the constructor of the subclass. The statement super( x, y, width, height, canvas ); invokes the superclass (FramedDisplay) constructor. The rest of the body of the constructor initializes the new instance variables introduced in the subclass, though it could have also modified the initialization of instance variables of the superclass, if they were declared to be protected. In this case we did not need to access them, so all the variables in the superclass were declared to be private.

Java requires that the first statement of every constructor be a call to a super constructor, aside from one very important exception. If a class has a parameterless constructor, and the first line of its subclass constructor does not contain a call to a super constructor, then Java will automatically insert a call to the parameterless super constructor. This exception explains why we did not need to insert a call to a super constructor in classes extending Thread or WindowController. In the case of WindowController we do not even need to write the constructor at all. The system automatically runs the parameterless constructor for WindowController, which initializes the canvas and other instance variables from the superclass.

As in Grace, if you wish to request a method definition of some m from the superclass, you can just write super.m(...).

As mentioned earlier, a Java class can only extend a single class, but it may implement as many interfaces as desired.

Just as in Grace, an interface may extend one or more existing interfaces. Where in Grace we wrote

type T = U & type {
     n(..) -> V
}

In Java we would write the same expression as

public interface T extends U {
     V n(...)
}

Examples in the objectdraw library in Java include Drawable2DInterface and Drawable1DInterface both extending DrawableInterface. Also Resizable2DInterface extends Drawable2DInterface. As in Grace, if an expression has an interface type then it also has all of its super interface types. Thus if an object has type Drawable2DInterface then it also has type DrawableInterface. Like classes, one interface is only a subinterface of another if it declared to be an extension of it.

That is we use the same extends clause to extend both classes and interfaces. However we use implements to indicate that a class provides elements of an interface.

Because classes can also be used as types in Java, if an expression has a type corresponding to a class then it also has the type of any superclass. Thus in our example above, if obj represents a FramedText then it also has type FramedDisplay

maketopicSummary

Here is a brief summary of what must be done to convert a Grace program to Java:

  1. You must put a semicolon at the end of lines in Java. However, never put a semicolon before a { or after a }. Proper indenting is optional (but required by your instructors). Use the Format command under the Source menu in Eclipse.
  2. Parameterless method declarations and requests must include () even though there are no parameters. This is how Java tells the difference between a method and an instance variable.
  3. Every Java class must be in a separate file.
  4. Every instance variable, constant, and method must have a visibility annotation. For now, use one of private and protected. Do not put these in front of local variables.
  5. Types are written before the identifiers in declarations of variables and methods. E.g., int x = 5; and public void onMouseClick(Location point).
  6. Rather than a single Number type, Java has many. The type int is a primitive type holding integers, while double refers to numbers with decimal points. An int can be easily used as a double, but to convert a double to an int you must use a type cast: (int)myDouble or Math.round(myDouble, depending on whether you want to truncate the value or round it.
  7. The Java types int, double, and boolean are primitive types, which mean that you may not make method requests of them. Object types should always be written with initial letter capitalized (e.g., FramedRect).
  8. Java is statically typed, so every identifier introduced must be given a type: either a class or an interface. Interfaces are like Grace types, with no implementation information.
  9. Assignments to variables are written with = instead of :=.
  10. Constants are written in all caps and are declared as static final if they are the same for all objects of the class. If they depend on parameters to the class or method, just declare them as final.
  11. Uninitialized instance variables are given the value 0 (if a primitive type) or null (if an object type). If you forget to initialize an instance variable you will get a "null pointer error" when you attempt to access it. Local variables are not automatically initialized. You must make sure to initialize them.
  12. In Java we use keyword this in place of self. If this is the receiver of a method request you may leave out this. If a method parameter and an instance variable of the same class have the same name, placing a "this." before the variable makes it refer to the instance variable. A common idiom is using the same name for a constructor parameter and instance variable and then using this in front of the instance variable when initializing it.
       class C {
          ...
          private String strVal;
          ...
          public C(String strVal) {
              this.strVal = strVal;  // right side is the parameter, left side is instance variable
          }
          ...
      }
    
  13. You may overload methods and class constructors in Java (i.e., have more than one constructor or method with the same name). To be legal you must be able to distinguish between them with the number and types of parameters.
  14. There are minor differences in the names of methods in the Java objectdraw library compared to Grace. Keep the objectdraw API documentation open at
    http://www.cs.pomona.edu/classes/cs051/handouts/objectdraw-api.html.

SearchingTopJava inheritance