0

I am trying right now to dig into anonymous classes and one question was just arised I'd prefer not to refer to much details and to pose my question straightforward: How can I invoke the method sizzle() in the following anonymous class:

public class Popcorn {
    public void pop() {
        System.out.println("popcorn");
    }
}

class Food {
    Popcorn p = new Popcorn() {
        public void sizzle() {
            System.out.println("anonymous sizzling popcorn");
        }

        public void pop() {
            System.out.println("anonymous popcorn");
        }
    };

    public void popIt() {
        p.pop(); // OK, Popcorn has a pop() method
        p.sizzle(); // Not Legal! Popcorn does not have sizzle()
    }
}

It is known and definite in polymorphism rules that a refernce of a superclass cannot invoke methods of subclass without downcasting (even if it refers to an object of the given subclass). However in the above case what is the "key" to invoke the sizzle() method?

4

3 回答 3

2

The sizzle() method simply cannot be accessed from the outside, because the class is anonymous.

The p reference is a type Popcorn, and that doesn't define sizzle().

Anonymous classes are meant to be one-shot, and are heavily used in some design patterns (like Observer) because Java doesn't have first class function, ie you can't pass function objects around.

于 2012-12-04T22:48:47.197 回答
2

I kind of didn't expect this to work, but it does:

new Object() {
    public void foo() {}
}.foo();

The above will compile and work as expected. The explanation is that the type of the expression new Object() {} is the anonymous type that expression defines, not Object. However, you can't have a variable (or method parameter) of that type, which means that you can't invoke the method anywhere else except chained after the new expression.

Since this doesn't really solve your (unsolvable) problem, I admit it's more of a supplementary answer.

于 2012-12-05T01:28:50.420 回答
1

When you call p.sizzle(), you need to have the p variable to be of a type that has the sizzle() method. The only way is to use a subclass or an interface. You can even cast, if you don't want to change the type of p, but you can't cast to a anonymous type.

If you need that class only inside the Food class, you should declare it in there

class Food {
    EdiblePopcorn p = new EdiblePopcorn() {

        @Override
        public void sizzle() {
            System.out.println("anonymous sizzling popcorn");
        }

        @Override
        public void pop() {
            System.out.println("anonymous popcorn");
        }
    };

    public void popIt() {
        p.pop(); // OK, Popcorn has a pop() method
        p.sizzle(); // Also legal! EdiblePopcorn now has sizzle()
    }

    private abstract class EdiblePopcorn extends Popcorn {
        // if the sizzle body is always the same, you can declare it here.
        void sizzle();
    }
}
于 2012-12-04T22:54:46.073 回答