简体   繁体   中英

“error: cannot find symbol ” when calling a Method defined using Generics

After reading through the Generics info I am attempting a simple sample and encountering the following error.

MyClass.java:32: error: cannot find symbol
System.out.println("X = " + temp.x);
^
symbol: variable x
location: variable temp of type T
where T is a type-variable:
T extends Object declared in method tryThis(T)
1 error

Without the reference to "temp.x" it compiles which leads me to believe the definition is correct but possibly the way the variable is referenced is the issue. Or it could be the actual implementation is wrong. Not sure.

The main class has a method which can be called by either of the 2 inner classes. When called, the method attempts to access the variable specific to the inner class that called it.

public class MyClass {
    public class InnerClass1 {
        int x = 100;
        public void runThis() {
            tryThis(this);
            return;
        }
    }

    public class InnerClass2 {
        int x = 200;
        public void runThis() {
            tryThis(this);
            return;
        }
    }

    public static void main(String[] args) {
        MyClass x = new MyClass();
    }

    private <T> void tryThis(T temp) {
        System.out.println("X = " + temp.x);
    }
}
symbol: variable x
location: variable temp of type T
where T is a type-variable:
T extends Object declared in method tryThis(T)
^^^^^^^^^^^^^^^^

Without further specification, eg <T extends InnerClass1> , the only thing that is known about T within that method is that it extends Object , and for Object , the attribute x is not defined.

Maybe you should define a common super-class for those two classes, and declare x in that super-class.

In order to get the value x from each class dynamically, you can define a common interface or abstract class for InnerClass1 and InnerClass2 to implement or extend . This allows the inheritance of methods and variables. Seeing that both holds a value of type T , let us create an interface called ValueHolder<T> :

interface ValueHolder<T> {
    public T getValue();
}

Both the InnerClass1 and InnerClass2 will need to implement this interface:

public class InnerClass1 implements ValueHolder<Integer> {
    private int x = 100;

    @Override
    public Integer getValue() {
        return this.x;
    }
}

public class InnerClass2 implements ValueHolder<String> {
    public String x = "200";

    @Override
    public String getValue() {
        return this.x;
    }
}

As you can see, InnerClass1 implements ValueHolder<Integer> , meaning the inherited getValue methods return type will be Integer . The same goes for InnerClass2 , which implements ValueHolder<String> .

Change your tryThis as follows:

private <T> void tryThis(ValueHolder<T> temp) {
    System.out.println("Value = " + temp.getValue());
}

Now each value can be printed like this:

Generics g = new Generics();
g.tryThis(new InnerClass1());
g.tryThis(new InnerClass2());

Output:

X = 100
X = 200

T in

private <T> void tryThis(T temp)</code>

is just a placeholder for any class. The compiler knows nothing more about it, so it knows nothing about the symbol x as well.

To accomplish what you are trying to do, you would need something like this:

public class Generics {

    abstract class MyClass {
        int x;
    }

    public class InnerClass1 extends MyClass {
        InnerClass1() {
            super.x = 100;
        }

        public void runThis() {
            tryThis(this);
            return;
        }
    }

    public class InnerClass2 extends MyClass {
        InnerClass2() {
            super.x = 200;
        }

        public void runThis() {
            tryThis(this);
            return;
        }
    }

    public static void main(String[] args) {
        Generics x = new Generics();

        x.new InnerClass1().runThis();
        x.new InnerClass2().runThis();
    }

    private <T extends MyClass> void tryThis(T temp) {
        System.out.println("X = " + temp.x);
    }

}

However, you would not need Generics for this specific case:

    private void tryThis2(MyClass temp) {
        System.out.println("X = " + temp.x);
    }

would accomplish the same.

Generics are very complex, although they look easy to use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM