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);
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);
}
}
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.
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);
}
Related
Coming across a problem that I could not make a function to allow a generic return type for all the child class of a parent class.
Is there a way to create a function that allows me to return any of these children class type base on an argument?
I have the following parent class:
abstract class Number {
int res = 1;
abstract static class Builder<T extends Builder<T>> {
int res = 100;
public T setNum(int num) {
this.res = num;
return self();
}
abstract Number build();
abstract T self();
}
Number(Builder<?> builder) {
res = builder.res;
}
}
and some children class:
class One extends Number{
private int size = 1;
static class Builder extends Number.Builder<Builder> {
private int size = -1;
public Builder setSize(int size) {
this.size = size;
return self();
}
#Override
public One build() {
return new One(this);
}
#Override
protected Builder self() {
return this;
}
}
private One(Builder builder) {
super(builder);
size = builder.size;
}
}
class Two extends Number {
private String size = String.valueOf(1);
static class Builder extends Number.Builder<Builder> {
private String size;
public Builder setSize(String size) {
this.size = size;
return self();
}
#Override
public Two build() {
return new Two(this);
}
#Override
protected Builder self() {
return this;
}
}
private Two(Builder builder) {
super(builder);
size = builder.size;
}
}
Note the parent class and child classes are not done yet, but it is going to have a similar format with just more fields so this would still apply
This is something that I want to achieve:
public <T> T loadNumber(String id) {
if (id.equals('1')) {
return new ONE.Builder.build(); // this will report error right now
}
elif (id.equals('2')) {
return new TWO.Builder.build(); // this will report error right now
}
return null;
}
The problem is that type arguments are specified by the caller. Your method
public <T> T loadNumber(String id) {
can be called like
Two two = loadNumber("One");
causing the compiler to infer
Two two = loadNumber<Two>("One");
which is why the compiler expects your method implementation to conjure a T out of thin air, and is not satisfied with a One. After all, T could stand for Two, as in the example above, and One isn't Two.
Put differently, the method signature
public <T> T loadNumber(String id) {
doesn't make sense, because the method must return a T, but has no way to determine, at runtime, what T is (due to type erasure, methods can't reflect on their type parameters).
So you have two choices:
Either you return the base type
public Number loadNumber(String id) {
and have the caller, who presumably knows which type the id he passed corresponds to, cast it to that type,
or you use an ID that whose type is itself generic and describes the type it maps to:
interface Builder<P extends Number, B extends Builder<P>> {
P build();
B self();
}
interface ID<P extends Number> {
Builder<P, ?> builder();
static ID<One> one = One.Builder::new;
static ID<Two> two = Two.Builder::new;
}
and then you can declare
public <N extends Number> N loadNumber(ID<N> id) {
return id.builder().build();
}
and use it like
One one = loadNumber(ID.one);
Two two = loadNumber(ID.two);
but not
One one = loadNumber(ID.two); // compilation error
You should be able to return any child class by simply using the parent class as a return type, in your case:
public Number loadNumber(String id) {
// your code implementation
}
Now, to save this into a variable you can use the same logic and declare the variable as the parent type. After the method returns, the variable will be casted into the whatever child class instance it returned, for example in your case:
Number obj = loadNumber("1");
The obj object will cast to an instance of One class. You can test this by printing out the object class after the above line:
System.out.println(obj.getClass());
This should print out class One or the name of whatever child class you saved into the variable.
public interface Iterator<T> {
// Returns true if the iterator is valid (points to an element), false otherwise.
boolean isValid();
// Returns the current element and moves forward. This method can only be called if the iterator is valid. If the iterator points to the last element, it becomes invalid after the call.
T next();
// Returns the current element and moves backwards. This method can only be called if the iterator is valid. If the iterator points to the first element, it becomes invalid after the call.
T prev();
}
In a class that does not implement interface Iterator, how is it possible to create a method that returns Iterator<K>, when you can only create methods for an interface inside a class that implements it?
public class ABC<K> implements EFG<K>{
public Iterator<K> minIt() {
//method body
//return Iterator<K> variable
}
}
The class ABC containing the method minIt() does not implement Iterator<T>
(No classes implement the interface Iterator <T> )
You can use an Anonymous Class that implements the interface:
For instance:
interface Foo<T> {
T foo();
}
class Bar<T> {
T t;
public Foo<T> bar() {
return new Foo<T>() { // <-- Anonymous class implementing `Foo`
public T foo() {
return t;
}
};
}
}
Execution:
Bar<String> b = new Bar<>();
b.t = "hello"; // with a setter in real life
Foo<String> f = b.bar();
f.foo(); // will return "hello"
The other option which I think would be the most common is to use a method that returns the interface, for instance the list interface has an iterator() method even though it itself doesn't implements the Iterator interface.
List<String> list = new ArrayList<>();
Iterator<String> stringIterator = list.iterator();
Here's the implementation
Simple. By making a class that implements it. Note that you have a type that you came up with on your own and you named it Iterator. Given that java.util.Iterator exists, this is a really bad idea. You should pick another name.
public class ABC<K> implements EFG<K> {
// Let's say this contains the items that can be iterated over.
private List<K> list = new ArrayList<K>();
class MyIterator implements my.pkg.Iterator<K> {
private int position = 0;
#Override public boolean isValid() {
return position > -1 && position < list.size();
}
#Override public K next() {
if (!isValid()) throw new NoSuchElementException();
return list.get(position++);
}
#Override public K prev() {
if (!isValid()) throw new NoSuchElementException();
return list.get(position--);
}
}
public Iterator<K> minIt() {
return new MyIterator<K>();
}
}
Note that classes that you put in classes can only be constructed in instance contexts within that class: They have a 'secret' field of your outer's type. Hence why the code in MyIterator can access the list field of your outer class.
Java has 'anonymous inner class literal' syntax which lets you shorten this: Instead of explicitly declaring class MyIterator, you can also write:
public Iterator<K> minIt() {
return new your.pkg.Iterator<K>() {
private int position = 0;
#Override public boolean isValid() {
// same code goes here as the previous snippet
}
};
}
This anonymous inner class form is a lot more common. It's just syntax sugar - a shorter way to write the same thing.
How can I get the values of an "enum" in a generic?
public class Sorter<T extends Enum<?>> {
public Sorter() {
T[] result = T.values(); // <- Compilation error
}
}
On the other hand, I can query the values() for Enum class:
enum TmpEnum { A, B }
public class Tmp {
void func() {
T[] result = TmpEnum.values(); // <- It works
}
}
Class::getEnumConstants
You cannot directly get it from T because generics are erased by the Java compiler so at runtime it is no longer known what T is.
What you can do is require a Class<T> object as constructor parameter. From there you can get an array of the enum objects by calling Class::getEnumConstants.
public class Sorter<T extends Enum<T>> {
public Sorter(Class<T> clazz) {
final T[] enumConstants = clazz.getEnumConstants();
}
}
another way is using interface
public interface Sorter{
default public void sorting(){
Sorter[] list=this.getClass().getEnumConstants();
}
}
use
enum TmpEnum implements Sorter { A, B }
I'm working on code where I have to cast base class onto derived one where I have an array of generic types that are derived by the base on.
For example, I have Base and Derived1, Derived2 and I put them into Class[]{Derived1.class, Derived2.class} and I pass this array to the constructor of the class.
In this constructor, I have to create instances of these derived classes and I don't know how to do that because I get the info that Class and Base are incompatible.
Here is my code example
public abstract class Base {
public abstract Base create(String s);
}
public class Derived extends Base {
java.lang.Integer value;
private static Derived integer = new Derived();
public static Derived getInstance(){
return integer;
}
public Base create(String s) {
value = java.lang.Integer.parseInt(s);
return this;
}
}
public class Clazz {
Class<? extends Base> type;
ArrayList<Base> arrayList;
public Class<? extends Base> getType() {
return type;
}
}
public class AnotherClazz{
ArrayList<Clazz> clazzArrayList;
Class<? extends Base>[] types;
AnotherClazz(Class<? extends Base>[] args){
clazzArrayList = new ArrayList<>();
types = args; // assuming I pass 2 elements in array
String[] strings = new String[]{"1","2"};
for (int i=0; i<args.length; ++i){
if (types[i] instanceof Base){
// here i want to check validity of class
}
}
for (int i=0; i<strings.length; ++i){
clazzArrayList.get(i).arrayList.add(((types[i]) Base).getInstance().create(strings[i]));
//here i want to create instance of object from type assigned to specific column
}
}
Thanks for the help.
To check the validity, try this
if (types[i].getClass().isAssignableFrom(Base.class))
If I read the question correctly, you want to create a few instances of derived classes that all have the same constructor arguments. If that is the case, then you need to give each derived class the same constructor (it does not need to be in the base class) and use Constructor.newInstance(parameters) to create the instances. Further, since you want to ensure that each derived class extents the base class then you will want to use Class.isAssignableFrom(class). For example,
import java.lang.reflect.Constructor;
public class SO52930530 {
public abstract static class Base {
public abstract <T> T getValue();
}
public static class Derived1 extends Base {
String value;
public Derived1(String value) {
this.value = value;
}
public <T> T getValue() {
return (T) value;
}
}
public static class Derived2 extends Base {
Integer value;
public Derived2(String value) {
this.value = new Integer(value);
}
public <T> T getValue() {
return (T) value;
}
}
public static void main(String... args) throws Exception {
Class<? extends Base>[] extensions = new Class[]{Derived1.class, Derived2.class};
String[] values = new String[]{"a", "1"};
Base[] instances = new Base[values.length];
for (int i = 0; i < instances.length; i++) {
Class extension = extensions[i];
if (Base.class.isAssignableFrom(extension)) {
Constructor constructor = extension.getConstructor(String.class);
instances[i] = (Base) constructor.newInstance(values[i]);
}
}
for (int i = 0; i < instances.length; i++) {
System.out.printf("%d %s %s\n", i, instances[i].getClass(), instances[i].getValue());
}
}
}
I hope this helps.
Thanks for helping with checking validity (it works!) but I still don't get this newInstance creation because I have to read data from .csv file and my derived classes are in fact "wrappers" for primitive types like int, float, etc. and I am supposed to create new object using methods getInstance() and create(string s), so it looks like this:
public static class Derived1 extends Base { //Integer wrapper
Integer value;
public Derived1(Integer value) {
this.value = value;
}
private static Integer integer = new Integer();
public static Integer getInstance(){
return integer;
}
private Integer(){};
public Base create(String s) {
value = java.lang.Integer.parseInt(s);
return this;
}
}
and I don't know how to use Class to cast to appriopriate type.
I have a generic tree class in which each tree node holds some data. Each piece of data has one attribute of the type String. I want to sort each tree node's children alphabetically by this attribute.
The Tree class:
public class Tree<T>{
public T data;
public List<Tree<T>> children = new ArrayList<Tree<T>>();
}
Note that the tree's children are of type Tree!
An example actual type parameter for the Tree class is the following:
public class DataItem{
public String name;
}
My idea is to extend the Tree class with a sort() method and use a Comparator like the following but I am stuck at the comparison function:
public class Tree<T>{
public T data;
public List<Tree<T>> children = new ArrayList<Tree<T>>();
public void sort(){
Collections.sort(this.children,
new Comparator<Tree<T>>(){
#Override
public int compare(Tree<T> objectA, Tree<T> objectB){
//I am stuck here!
return 0;
}
}
);
for(Tree<T> child: this.children){
child.sort();
}
}
}
I have different ideas to solve this problem:
Use reflection to acces the objects' attributes and compare them.
Implement the interface Comparable in DataItem.
Use a new interface to acces the objects' attribute for comparison:
public interface GetComparisonAttribute {
public String getComparisonAttribute();
}
public class DataItem implements GetComparisonAttribute{
public String name;
#Override
public String GetComparisonAttribute(){
return this.name;
}
}
//the comparison function inside Tree<T>.sort():
public int compare(Tree<T> objectA, Tree<T> objectB){
return objectA.data.getComparisonAttribute()
.compareToIgnoreCase(objectB.data.getComparisonAttribute());
}
What is the right or best thing to do? Are there any other ways?
It may be important to be able to specify the sorting attribute.
I think it would be nice to use Collections.sort() directly on a Tree but implementing it in this recursive data structure really confuses me. A downside of doing it this way is that I cannot specify the sorting attribute.
Try this:
public class Tree<T> {
public T data;
public List<Tree<T>> children = new ArrayList<Tree<T>>();
private Class<T> type;
public Tree(Class<T> t) {
type = t;
}
public void sort(){
Collections.sort(this.children,
new Comparator<Tree<T>>(){
#Override
public int compare(Tree<T> objectA, Tree<T> objectB){
if (type==DataItem.class)
{
DataItem diA = (DataItem) (objectA.data);
DataItem diB = (DataItem) (objectB.data);
return diA.name.compareTo(diB.name);
}
else
throw new IllegalArgumentException();
}
}
);
for(Tree<T> child: this.children){
child.sort();
}
}
}
You should pass the type T of the class Tree when you create it. Then you can downcast to DataItem and sort the list according to the filed you like. You can check of course also against other type parameters aside from DataItem.
public void sort(final Comparator<? super T> dataComparator)
{
Collections.sort(this.children,
new Comparator<Tree<T>>()
{
#Override
public int compare(Tree<T> treeA, Tree<T> treeB)
{
return dataComparator.compare(treeA.getData(), treeB.getData());
}
}
);
for(Tree<T> child: this.children)
{
child.sort(dataComparator);
}
}
void test()
{
Tree<DataItem> tree = new Tree<>();
tree.sort(new Comparator<DataItem>()
{
#Override
public int compare(DataItem dataA, DataItem dataB)
{
return dataA.getName().compareTo(dataB.getName());
}
});
}
In java8, this can be simplified as
public void sort(final Comparator<? super T> dataComparator)
{
Collections.sort(this.children,
Comparator.comparing(Tree::getData, dataComparator));
for(Tree<T> child: this.children)
{
child.sort(dataComparator);
}
}
void test()
{
Tree<DataItem> tree = new Tree<>();
tree.sort( Comparator.comparing(DataItem::getName) );
}