tobahhh
tobahhh

Reputation: 381

How to make a method a parameter for a constructor

While making a small game in Java, I stumbled upon the keyListener class, which asks for three methods when instanced (keyTyped, keyPressed, and keyReleased), as below:

JFrame.addKeyListener(new KeyListener(){
    public void keyTyped(KeyEvent evnt) {
    //blah
    }
    public void keyPressed(KeyEvent evnt) {
    //blah
    }
    public void keyReleased(KeyEvent evnt) {
    //blah
    }
});

How can I get a class I am making on my own accept methods as a parameter as above?

Upvotes: 1

Views: 386

Answers (4)

tobahhh
tobahhh

Reputation: 381

I know that it is weird to answer my own question, but...

I figured it out. You have to make your class abstract, and you can declare abstract methods to make methods "parameters" to have it behave like a KeyListener declaration. Abstract methods are declared like this:

    abstract ReturnType name(Parameter p);

and behave exactly like methods when called. For a full example:

    //The abstract keyword enables abstract methods to work with this class.
    abstract class Foo {
        //Just a random variable and a constructor to initialize it
        int blah;
        public Foo(int blah) {
            this.blah = blah;
        }
        //An abstract method 
        abstract void doStuff();
        //Example with a parameter
        abstract void whatDoIDoWith(int thisNumber);
        //A normal method that will call these methods.
        public void doThings() {
            //Call our abstract method.
            doStuff();
            //Call whatDoIDoWith() and give it the parameter 5, because, well... 5!
            whatDoIDoWith(5);
        }
    }

When you try to instance an abstract class like a normal class, Java will freak out.

    Foo f = new Foo(4);

What you will have to do is something like this:

    Foo f = new Foo(4) {
        @Override
        void doStuff() {
            System.out.println("Hi guys! I am an abstract method!");
        }
        @Override
        void whatDoIDoWith(int thisNumber) {
            blah += thisNumber;
            System.out.println(blah);
        }
     }; //Always remember this semicolon!

Note that you need to include all of the abstract methods here, not just some of them. Now, let's try this:

    public class Main {
        public static void main(String[] args) {
            //Instance foo.
            Foo f = new Foo(4) {
                @Override
                void doStuff() {
                    System.out.println("Hi guys! I am an abstract method!");
                }
                @Override
                void whatDoIDoWith(int thisNumber) {
                    blah += thisNumber;
                    System.out.println(blah);
                }
            };
            //Call our method where we called our two abstract methods.
            foo.doThings();
        }
    }

This prints the following to the console:

    Hi guys! I am an abstract method!
    9

Upvotes: 0

Thomas
Thomas

Reputation: 88707

new KeyListener() { ... } actually creates an anonymous inner class that implements KeyListener. As such it can access any visible field of the class that created it as well as any local final variable inside the method that called the constructor.

Example:

class Outer {
  int x;

  void initUI( final int z) {
    final int y = 0;        
    int nope = 1; //you can't access this since it is neither final nor a field like x

    JFrame.addKeyListener( new KeyListener() {
      public void keyTyped(KeyEvent evnt) {
        System.out.println( x + y + z ); //you can access all of them
      }
    });
  }
}

If you want to provide a constructor for your key listener you'll need to explicitly define a class, as anonymous classes can't have custom constructors. That means you'd have to do something like this (attention: pseudo code):

class Outer {
  void initUI() {
    JFrame.addKeyListener( new InnerKeyListener( myParam ) );
  }

  class InnerKeyListener implements KeyListener {
    InnerKeyListener( Param p ) {
    }

    ...
  }
}

Of course you can put the inner class into a separe file as well or make it a static inner class.

Upvotes: 1

0x5453
0x5453

Reputation: 13589

Technically, those methods aren't parameters here. The only parameter is the one anonymous instance of a KeyListener.

KeyListener is an interface that requires those 3 methods to be implemented.

If you want to define your own interface, it looks similar to a class:

public interface SomeInterface {
    public void foo();
    public int bar(int x);
}

Then you can use it anonymously (like in your example), or by implementing it in a class:

public class MyClass implements SomeInterface {
    // ...
}

Upvotes: 1

gottfred
gottfred

Reputation: 97

It's not accepting methods as a parameter. You're declaring an anonymous class and passing that as a parameter into the addKeyListener method.

Upvotes: 0

Related Questions