Question

Here I have a simple class that extends a class in the ACM graphics library called GRect. Grect is a basic rectangle that can be drawn to a GCanvas (Also part of ACM). What I want to achieve is a new object that is a rectangle, but has an attached label that moves with the rectangle.

In my code, I have created a class named labeledRect that extends GRect, and contains an instance variable "rectLabel" that is of type GLabel, that is initialized in labeledRects constructor. I want to override some of GRect's methods so that when labledRect is moved, rectLabel moves with it.

My issue is that despite "rectLabel" being declared as an instance variable, and initialized in the constructor, it becomes NULL in the overridden method "setLocation". I have also attempted to initialize "rectLabel" at declaration, but the same problem occurs.

import acm.graphics.*;

public class labeledRect extends GRect {

    //GLabel declared as an instance variable
    public GLabel rectLabel;

    public labeledRect(double x, double y, double width, double height, String theLabel) {
        //Call GRect constructor
        super(x, y, width, height);

        //Label initialized. 
        //Location setting and adding to the canvas works fine here. 
        rectLabel = new GLabel(theLabel);
        rectLabel.setLocation(
                    x + (width / 2) - (rectLabel.getWidth() / 2),
                    y + (height / 2) + (rectLabel.getAscent() / 2.2));
    }

    public void setLocation(double x, double y)
    {
        //Setting GRect's location. Works correctly./
        super.setLocation(x, y);

        //Attempt to set the label's location 
        //and get a NullPointer exception for rectLabel
        rectLabel.setLocation(
                super.getX() - (rectLabel.getWidth() / 2),
                super.getY() - (rectLabel.getHeight() / 2));
    }
}
Was it helpful?

Solution

It's hard to reason about exactly what might be setting the variable to null given that it's a public field. That's the first thing you should change. Fields should almost always be private.

Next, you say setLocation is an overridden method - is it called in the GRect constructor by any chance? If so, that will be called before the value is set within the labeledRect constructor, which could well be the cause of your problem.

In Java, the superclass constructor is executed before any of the code in the subclass - both before instance variable initializers and the constructor body. All variables will have their default values. This is why it's a bad idea to call virtual methods from constructors.

(As an aside, the name labeledRect doesn't follow Java naming conventions.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top