views:

54

answers:

5

Here I found this code:

import java.awt.*;
import javax.swing.*;


public class FunWithPanels extends JFrame {

    public static void main(String[] args) {
        FunWithPanels frame = new FunWithPanels();
        frame.doSomething();
    }

    void doSomething() {
        Container c = getContentPane();

        JPanel p1 = new JPanel();
        p1.setLayout(new BorderLayout());
        p1.add(new JButton("A"), BorderLayout.NORTH);
        p1.add(new JButton("B"), BorderLayout.WEST);

        JPanel p2 = new JPanel();
        p2.setLayout(new GridLayout(3, 2));
        p2.add(new JButton("F"));
        p2.add(new JButton("G"));
        p2.add(new JButton("H"));
        p2.add(new JButton("I"));
        p2.add(new JButton("J"));
        p2.add(new JButton("K"));

        JPanel p3 = new JPanel();
        p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS));
        p3.add(new JButton("L"));
        p3.add(new JButton("M"));
        p3.add(new JButton("N"));
        p3.add(new JButton("O"));
        p3.add(new JButton("P"));

        c.setLayout(new BorderLayout());
        c.add(p1, BorderLayout.CENTER);
        c.add(p2, BorderLayout.SOUTH);
        c.add(p3, BorderLayout.EAST);

        pack();
        setVisible(true);
    }
}

I do not understand how "doSomething" use the fact that "frame" is an instance of the class JFrame. It is not clear to me because there is no reference to "this" in the code for the method "doSomething".

ADDED:

Maybe this is related. In this code:

import java.awt.*;
 import java.applet.Applet;
 public class ButtonGrid extends Applet {
     public void init() {
         setLayout(new GridLayout(3,2));
         add(new Button("1"));
         add(new Button("2"));
         add(new Button("3"));
         add(new Button("4"));
         add(new Button("5"));
         add(new Button("6"));
     }
 }

In the "init" method we use methods "setLayout" and "add" and we do not bind them to a particular object (for example objectName.setLayout(...)). Why is that?

+2  A: 

This because this is implicit in the search path of the compiler. The compiler will look for a variable in this order:

  1. A local variable in the current block
  2. A local variable in an outer block
  3. A method parameter
  4. A field in the current class (i.e. relative to this)
  5. A field in a parent class
Aaron Digulla
+1  A: 

If I am not misunderstanding something, the answer is trivial:

The compiler does not need the this. qualifier to detect when a member of the class is being used. The only need to explicitly use this. is when there is a name clash, like in

public MyClass {
    private Foo foo;
    MyClass(Foo foo) {
        this.foo = foo;
    }
}

Update: Apparently I did indeed misunderstand the question... although I am apparently not alone with it.

Anyway, doSomething() calls getContentPane(), which is a method of JFrame, and pack() and setVisible() from the JFrame parent class, Window. However, that in itself would not make it necessary for FunWithPanels to extend JFrame, since all these methods are public, accessible to anyone.

I believe the author thought that FunWithPanels is a specialized type of JFrame, this is why it became a subclass. This way FunWithPanels can be used anywhere where a generic JFrame is required. See the Liskov Substitution Principle for more explanation. (Note: this may or may not be good class design, but I can't say much about it without knowing the context).

Péter Török
It is not a problem for me to understand when a member of the class is used. It is clear to me that at some point we call method "doSomething" and it does something. I do not understand why we declared the class as an extension of the JFrame and then we do not use this fact. We create an object ("frame") of this class and then do not call any methods of this class. We also do not modify any state of this object. We do not use any properties of states of the object.
Roman
@Roman see my update.
Péter Török
+1  A: 

I do not understand how "doSomething" use the fact that "frame" is an instance of the class JFrame

because FunWithPanels extends JFrame, and every method you define in FunWithPanels will be called on an instance of FunWithPanels.

Webbisshh
Yes, but I could not figure out at which point the code in the "doSomething" use the fact that the object belongs to the class extending JFrame.
Roman
doSomeThing belongs to a class FunWithPanels which extends JFrame, so it will always "use the fact" that the object on which it will be called is FunWithPanels. Using "this" or not is code convention.
Webbisshh
+3  A: 

While this is not used, the method makes frequent use of JFrame methods, notably in the first line of the method where it gets the content pane Container c = getContentPane();

Using the this keyword would make the example clearer, but you don't need it.

The example could be rewritten as:

import java.awt.*;
import javax.swing.*;


public class FunWithPanels extends JFrame {

    public static void main(String[] args) {
        FunWithPanels frame = new FunWithPanels();
        frame.doSomething();
    }

    void doSomething() {
        Container c = this.getContentPane();

        // .. snip unaltered code

        this.pack();
        this.setVisible(true);
    }
}

This is fully equivalent.

Kris
OK. I think I starting to understand. If we write "getContentPane()" we actually mean "this.getContentPane()"?
Roman
Yes. As Aaron Digulla points out the compiler resovles it looking at the scopes in widening order. For class methods, this can be omitted. For class variables 'this' may be required if a local variable has the same name.
Kris
+1  A: 

There's an implicit usage of this in this line:

Container c = getContentPane();

getContentPane() is equivalent to this.getContentPane() here.

Joachim Sauer