Domanda

I am getting an error I don't understand on this code (marked in comments):

public class Symbol {
    private String name;
    public Symbol(String name) { this.name = name }
    public String name() { return name; }
}

public class Terminal extends Symbol {
    public Terminal(String name) { super(name); }
}

public class NonTerminal extends Symbol {
    public NonTerminal(String name) { super(name); }
}

public class Rule {
    private NonTerminal lhs;
    private Class<? extends Symbol>[] rhs;

    public Rule(NonTerminal lhs, Class<? extends Symbol>... rhs) {
        this.lhs = lhs;
        this.rhs = rhs;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(lhs.name());
        sb.append(" ->");
        for( int i = 0; i < rhs.length; i++ ) {
            sb.append(' ');
            sb.append(rhs[i].name()); <<<<< ERROR!
            // Get this error: The method name() is undefined for the type Class<capture#1-of ? extends Symbol>

            // Tried: sb.append(((Symbol)rhs[i]).name());
            // Got error: Cannot cast from Class<capture#1-of ? extends Symbol> to Symbol

        }
        sb.append(';');
        return sb.toString();
    }
}

The error is given by the Java editor in Eclipse, not at compile time.

In words: I want to be able to get a list of Symbols, either Terminals or NonTerminals and be able to use them according to their class.
My understanding, so far, was that Class<? extends Symbol> will do for any objet of type Symbol or derived from Symbol.

So my questions are:

  1. Why the public method name(), defined in Symbol class, cannot be invoked. In fact all elements in the list are Symbols or derived from Symbol?

  2. What is the correct way to invoke name() from the array elements?

EDIT I corrected sligthly the code so (with the changes required by the accepted answer) it is a working example. The changes are to change every occurrence of

Class<? extends Symbol>

to

Symbol

The test I used to check the answer is:

    Terminal t1 = new Terminal("t1");
    Terminal t2 = new Terminal("t2");
    Terminal t3 = new Terminal("t3");

    NonTerminal exp = new NonTerminal("exp");
    NonTerminal nt1 = new NonTerminal("nt1");
    NonTerminal nt2 = new NonTerminal("nt2");
    NonTerminal nt3 = new NonTerminal("nt3");

    Rule r1 = new Rule(exp, t1, nt2, t3);

    Log.v(TAG, "The rule is: " + r1.toString());

The log file shows:

01-15 10:18:11.335: V/MainActivity(1732): The rule is: exp -> t1 nt2 t3;

È stato utile?

Soluzione

Class<? extends Symbol> is a reflection class - it stores a definition of a class that's a Symbol or one of its sub-classes.

In your example, you want to store instances of Symbol (or one of its subclasses). Just define your array like this:

public class Rule {
    private NonTerminal lhs;
    private Symbol[] rhs;

    public Rule(NonTerminal lhs, Symbol... rhs) {
        this.lhs = lhs;
        this.rhs = rhs;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top