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