I am extending a class and also extending it's inner class but I'm getting errors trying to get the inner class through the outer child class.
public class SMONArray extends SMONArr {
public class Element extends SMONArr.Element {
protected int x, y, w, h;
protected Element(String string, Object arr) {
super(string, arr);
}
}
public Element getSelected(String key, int index) {
return get(key, index);
}
}
public class SMONArr {
protected final LinkedHashMap<String, ArrayList<Element>> arr = new LinkedHashMap<>();
public class Element {
public String key;
public Object elem;
protected Element(String string, Object arr) {
key = string;
elem = arr;
}
}
public Element get(String key, int index) {
return arr.get(key).get(index);
}
}
Like it is above I'm getting an error in the SMONArray child class getSelected
function which is:
Type mismatch: cannot convert from SMONArr.Element to SMONArray.Element
Intellij suggests to cast the returned value to Element
like this:
public Element getSelected(String key, int index) {
return (Element) get(key, index);
But like this the error goes away and I can run the program, but when I call the getSelected
function I get a different error:
Exception in thread "main" java.lang.ClassCastException: SMONArr$Element cannot be cast to SMONArray$Element
If I don't extend the inner class I have no problems but if I do, how can I then get the inner class through the outer child class?
EDIT: The array arr
in SMONArr
is populated with ArrayList
of Element
of which Element
is a String
key and an int[]
e.g. key, [1, 2, 3, 4]
is what Element
is.
intArr[j] = Integer.parseInt(strArr[j]);
linesArr.add(new Element(parts[0].trim(), intArr));
arr.put(key, linesArr);
CodePudding user response:
Add a createElement
class to your parent class:
public class SMONArr {
// ...
// Alternatively, this can be abstract (assuming you make the class abstract too)
// then it has to be overridden in subclasses.
public Element createElement(String key, Object value) {
return new Element(key, value);
}
// ...
}
then you can override this in the subclass:
public class SMONArray extends SMONArr {
// ...
// Now Element refers to the subclass.
public Element createElement(String key, Object value) {
return new Element(key, value);
}
// ...
}
and invoke createElement
instead of new Element
in the parent class. Then the cast in the subclass will work without a ClassCastException
.
You can do this without the need for the getSelected
method in subclasses, by making the SMONArr
class generic:
public abstract class SMONArr<E extends Element> {
protected final LinkedHashMap<String, ArrayList<E>> arr = new LinkedHashMap<>();
public class Element { ... }
// ...
// Now this has to be abstract.
public abstract E createElement(String key, Object value);
// ...
}
public class SMONArray extends SMONArr<SMONArray.Element> {
public class Element extends SMONArr.Element { ... }
public Element createElement(String key, Object value) {
return new Element(key, value);
}
}
CodePudding user response:
You have two element types. You have a collection in the SMONArr class that can only hold one of the types.
The call to 'get' in SMONArr class returns a SMONArr.Element, which is not a SMONArray.Element.
I don't know the context - perhaps in this case the collection is guaranteed to hold only SMONArray.Elements, in which case a cast would do the trick.
CodePudding user response:
Your issue has nothing to do with extending the inner class, you return the wrong type and don't see it because of the naming confusion.
This is what you're doing:
public class Outer1 {
class Inner1 {}
public Inner1 get() {
return new Inner1();
}
}
public class Outer2 extends Outer1 {
public class Inner2 extends Outer1.Inner1 {}
public Inner2 getSelected() {
return get();
}
}
You getSelected()
is declared as returning the subtype, but then you call the method returning the supertype.
You can change its return type to Inner1
, or in your case SMONArr.Element
.
public SMONArr.Element getSelected(String key, int index) {
return get(key, index);
}