简体   繁体   中英

No access on attributes of abstract class objects in subclass methods in java

I want to write some different algorithms for different data structures(eg tree, list, array, ...). The methods of the data structures are 90% identical except for the method parameter.

public class BinaryTreeNode<T> {
    public T key;
    public BinaryTreeNode<T> leftChild;
    public BinaryTreeNode<T> rightChild;

    public boolean find(BinaryTreeNode<T> root, T key) { /* implementation */ }
}

public class ListItem<T> {
    public T key;
    public ListItem<T> next;

    public boolean find(ListItem<T> root, T key) { /* implementation */ }
}

In order not to have to write each method individually I made an abstract DataStruct<T> class

public abstract class DataStruct<T> {
    /**
    * finds the key in dataStruct
    * @param dataStruct DataStruct to look for key
    * @param key value of type T to find in dataStruct
    * @return true if key is in dataStruct else false
    */
    public abstract find(DataStruct<T> dataStruct, T key);
}

I let BinaryTreeNode<T> and ListItem<T> extend DataStruct<T>

Now my problem is to access the class attributes. I solved it like this:

public class ListItem<T> extends DataStruct<T> {
    public T key;
    public ListItem<T> next;

    @Override
    public boolean find(DataStruct<T> listItem, T key) {
        ListItem<T> tmpListItem = (ListItem<T>) listItem;
        while(tmpListItem.next != null) {
            if(tmpListItem.key == key)
               return true;
        }
    }
}

But it does not feel well coded because I had to create a temporary ListItem<T> to cast the DataStruct<T> to access the class attributes of ListItem<T> .

Is there a better way to do this?

Since the find method is not a static method, it doesn't make sense that it accepts a DataStruct<T> object and performs the search on that object. It makes more sense to perform the search on itself, which eliminates the need to cast anything:

public boolean find(T key) {
    ListItem<T> tmpListItem = this;
    while(tmpListItem.next != null) {
        if(tmpListItem.key.equals(key))
           return true;
        tmpListItem = tmpListItem.next;
    }
}

Now, it some of your methods do require a DataStruct<T> argument, and you require, for example, that the implementation of these methods in ListItem accpet only a ListItem , it will make sense to check the type of the input argument, throw an exception (or return false, or whatever makes sense) if the run-type is wrong, and perform the cast. This is a common practice in methods such as equals , which accept an Object and usually require that the run-time type be a specific type.

For example:

public boolean find(DataStruct<T> listItem, T key) {
    if (!(listItem instanceof ListItem)) {
        // decide whether to return false or throw an exception
    }
    ListItem<T> tmpListItem = (ListItem<T>) listItem;
    ...
}

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