Cannot call an Anonymous Class Method

≡放荡痞女 提交于 2021-02-04 20:46:07

问题


I'm trying to call a method, setPostal(String post) I made from an anonymous class, but for some reason the compiler doesnt even recognize it in main. Any reason why this is? Part of my code (address is an inner class of Student):

Student

public class Student implements Gradeable, Cloneable {
    String name;
    int id;
    Address address;

    public Student() {
        name = "unknown";
        address = new Address();
    }

    public Student(String name, int id, Integer... option) {
        this.name = name;
        this.id = id;
        if (option.length > 0) {
            if (option[0] > 0) {
                address = new Address() {
                    String postal;

                    public void setPostal(String post) {
                        postal = post;
                    }

                    @Override
                    public String toString() {
                        return "Street: " + street + " | number: " + number
                                + " | town: " + town + " | province: " + province
                                + " | Postal Code: " + postal;
                    }
                };
            }
        } else {
            address = new Address();
        }
    }

    Address getAddress() {
        return address;
    }

    void setAddress(Address address) {
        this.address = address;
    }

    public static void main(String[] args) throws CloneNotSupportedException, InterruptedException {
        Student test = new Student("ryan", 41254, 1);
        test.getAddress().setPostal("L1G 6h9") // Compiler: Cannot resolve symbol 'setPostal'
    }
}

Address

public class Address implements Cloneable {
    String street;
    int number;
    String town;
    String province;
    String zip;

    public Address() {

    }

    public Address(String street, int number, String town,
                   String province, String zip) {
        this.street = street;
        this.number = number;
        this.town = town;
        this.province = province;
        this.zip = zip;
    }

    String getStreet() {
        return street;
    }

    int getNumber() {
        return number;
    }

    String getTown() {
        return town;
    }

    String getProvince() {
        return province;
    }

    String getZip() {
        return zip;
    }

    @Override
    public String toString() {
        return "Street: " + street + " | number: " + number
                + " | town: " + town + " | province: " + province
                + " | ZIP: " + zip;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Address)
            if (((Address) obj).getStreet().equals(street)
                    && ((Address) obj).getNumber() == number
                    && ((Address) obj).getTown().equals(town)
                    && ((Address) obj).getProvince().equals(province)
                    && ((Address) obj).getZip().equals(zip)){
                System.out.println("Address equal");
                return true;
            }
        System.out.println("Address not equal");
        return false;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

回答1:


Presumably, whatever Address is, it doesn't have a setPostal(String) method.

Instance methods, at compile time, are resolved based on the type of the value on which they are invoked.

You're invoking it

test3.getAddress().setPostal("L1G 6h9") //Compiler: Cannot resolve symbol 'setPostal'

on an expression of type Address, which doesn't have such a method, regardless of the fact that a subtype (the anonymous subclass) does.


The only way (minus reflection) to invoke a method that is declared only in an anonymous class is to invoke the method on the value returned by the anonymous class instance creation expression.

new Address() {
    String postal;
    public void setPostal(String post) {
        postal = post;
    }

    @Override
    public String toString() {
        return "Street: " + street + " | number: " + number
                        + " | town: " + town + " | province: " + province
                        + " | Postal Code: " + postal;
        }
    }
}.setPostal("whatever");



回答2:


The type of the expression test3.getAddress() is Address, which means you can only call methods that are declared in the Address class (or a supertype of it).

The compiler doesn't figure out that at run time, this expression is going to evaluate to be an object of your special anonymous class. It's not the compiler's job to run your program for you, so it can work out the class of every object you might use. So the new method setPostal (which appears to only exist in your anonymous class) can't be used here.




回答3:


Anonymous classes are a bad idea. Try to create a concrete class, then instantiate that.

You can declare this inside your class to hide it from the outside.

public class Student implements Gradeable, Cloneable {
    // ...
    private static class PostalAddress extends Address {
        String postal;

        public PostalAddress {
            super();
        }        

        public void setPostal(String post) {
            postal = post;
        }

        @Override
        public String toString() {
            return "Street: " + street + " | number: " + number
                + " | town: " + town + " | province: " + province
                + " | Postal Code: " + postal;
        }
    }
    // ...
}

Then use it

public Student(String name, int id, Integer... option) {
    this.name = name;
    this.id = id;
    if (option.length > 0) {
        if (option[0] > 0) {
            address = new PostalAddress();
        }
    } else {
        address = new Address();
    }
}

Then all you have to do is cast the address in test.

public static void main(String[] args) throws CloneNotSupportedException, InterruptedException{
   Student test = new Student("ryan", 41254, 1);
   ((PostalAddress) test.getAddress()).setPostal("L1G 6h9");
}

Note: if option.length > 0 but option[0] <= 0, your address object will be null.




回答4:


For those getting:

"Cannot find symbol" FUNCTION_NAME_HERE.

When trying to use an anonymous inner class on the fly:



WRONG: error: cannot find symbol "myMethod"

Object t = new Object(){ 
    public void myMethod(){
        System.out.println("[METHOD]");
    };;
};;
t.myMethod();

BECAUSE:

Though method exists, your anonymous object is downcasted to Object, which does NOT have method.


WRONG: error: cannot find symbol "myMethod"

class Test{};
Test t = new Test(){
    public void myMethod(){
        System.out.println("[METHOD]");
    };;
};;
t.myMethod();

BECAUSE:

Same reason as previous. (But we are on the right track.)



CORRECT:

abstract class Test{ abstract public void myMethod(); }
Test t = new Test(){
    public void myMethod(){
        System.out.println("[METHOD]");
    };;
};;
t.myMethod();

Congratulations:

You've created a class on the fly in which there can only be one instance.

Usage: Small helper functions in a function.



来源:https://stackoverflow.com/questions/27929613/cannot-call-an-anonymous-class-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!