Home > other >  how to return different type from same function using inhertinace?
how to return different type from same function using inhertinace?

Time:10-23

for example, I want to create a parent class Node, and subclasses IntegerNode and CharacterNode. and try to find if a value already exists in a list without knowing what the type of values are. for that, I will send my Node object and during runtime, I want to get the appropriate value.

there is a way to do that without using an instance of?

public class CharNode extends Node {

    private Character charNode;

    CharNode(char digit){
        this.charNode = digit;
    }
    
    Character getValue(){
        return charNode;
    }
}


public class IntegerNode extends Node {
    private Integer integerNode;

    IntegerNode(int number){
        this.integerNode = number;
    }

    Integer getValue(){
        return integerNode;
    }
}



public class Node {

    Node getNode();
}




  boolean isExists(List<Node> list, Node value){
   ///// Here I want to check if the value inside the node already exists in that list without checking the type. It can be Lists of characters or a list of integers.

}

CodePudding user response:

The easiest way to do that is to implement the equals method for both classes:

// equals for the CharNode class
public boolean equals(final Object o) {
  if (this == o) return true;
  if (o == null || getClass() != o.getClass()) return false;
  // add here the logic specific to each class
  return this.charNode.equals(((CharNode)o).charNode);
}
// equals for the IntegerNode class
public boolean equals(final Object o) {
  if (this == o) return true;
  if (o == null || getClass() != o.getClass()) return false;
  // add here the logic specific to each class
  return this.integerNode.equals(((IntegerNode)o).integerNode);
}

After that you'll be able to use the list.contains(node) method

CodePudding user response:

I've changed your classes a bit, so it's easier to work with them.

public abstract class Node<T> {

    public abstract T getValue();

    // I guess you implemented this method, but didn't copy it in your example.
    //Node getNode();
    
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Node<?> otherNode = (Node<?>) o;
        T value = getValue();
        if (value == null) return otherNode.getValue() == null;
        return getValue().equals(otherNode.getValue());
    }
    
    // If you implement eqauls you should also always implement hashCode.
    public int hashCode() {
        T value = getValue();
        return value != null ? value.hashCode() : 0;
    }
}

public class CharNode extends Node<Character> {

    private Character value;

    public CharNode(char value){
        this.value = value;
    }
    
    @Override
    public Character getValue(){
        return value;
    }
}

public class IntegerNode extends Node<Integer> {
    
    private Integer value;

    public IntegerNode(int value){
        this.value = value;
    }

    @Override
    public Integer getValue(){
        return value;
    }
}

Node is now abstract and has a abstract method getValue added to it. Any class that inherits from Node is now forced to implement getValue. Additionally I added simple implementations of equals & hashCode. In your case you would probably only need equals, but not implementing hashCode when implemeneting equals is very bad practice and can break classes that rely on a working implementation.

Now just iterate over the list and check equals every time.

public boolean isExists(List<? extends Node<?>> list, Node<?> value) {
    for (Node<?> node : list) {
        if (node.equals(value)) {
            return true;
        }
    }
    return false;
}

Or use List.contains which does the same for us.

public boolean isExists(List<? extends Node<?>> list, Node<?> value) {
    return list.contains(value);
}

Here is an example for using a list of CharNodes.

CharNode sNode = new CharNode('s');
CharNode cNode = new CharNode('c');
IntegerNode oneNode = new IntegerNode(1);
IntegerNode twoNode = new IntegerNode(2);
List<CharNode> charNodes = Arrays.asList(sNode, cNode);
System.out.println(isExists(charNodes, new CharNode('s'))); // true
System.out.println(isExists(charNodes, new CharNode('x'))); // false

You can also create a list of nodes with mixed types.

List<Node<?>> allNodes = Arrays.asList(sNode, cNode, oneNode, twoNode);
System.out.println(isExists(allNodes, new CharNode('s'))); // true
System.out.println(isExists(allNodes, new IntegerNode(1)));  // true
System.out.println(isExists(allNodes, new CharNode('x'))); // false

You can use Node.getValue() to get the value, but without knowing the type of getValue() there is only so much you can do.

Object nodeValue = allNodes.get(3).getValue();
System.out.println(nodeValue); // 2

As you mentioned you can use instanceof to get the type and write codefor each instanceof check, but there is a much better solution: Add another method in your Node class and implement appropriate behavior for this method in your children.

CodePudding user response:

Try this.

static abstract class Node {
    protected Object value;

    public Node(Object value) {
        this.value = value;
    }

    public Object getValue() {
        return value;
    }
}

static class CharacterNode extends Node {

    public CharacterNode(char value) {
        super(value);
    }
}

static class IntegerNode extends Node {

    public IntegerNode(int value) {
        super(value);
    }
}

public static void main(String[] args) {
    List<Node> nodes = List.of(new CharacterNode('a'), new IntegerNode(3));
    for (Node node : nodes)
        if (node.getValue().equals(3))
            System.out.println("found value 3");
}

output:

found value 3
  • Related