I'll get straight into it. Below is a code snippet from my GeneralSearch class I am implementing in an AI application for solving a word puzzle. I am wondering how to instantiate the subclass within the abstract class. I feel I have implemented all relevant abstract methods in my BreadthFirstSearch class as well as its constructor calling its super-constructor. (Nested subclass)
I understand you cant instantiate an abstract class but from previous threads and information you can instantiate a subclass with an abstract super-class.
I try the following calls to no avail:
GeneralSearch bfs = new BreadthFirstSearch(now.getState(), info); //Correct parameters
OR.
GeneralSearch bfs = GeneralSearch.BreadthFirstSearch(now.getState(), info);
Errors received:
1)BreadthFirstSearch cannot be resolved to a type
2)The method BreadthFirstSearch(WordState, WordNodeInfo) is undefined for the type GeneralSearch
I cant seem to get a working instantiation for the subclass so I can perform such searches. If anyone could shed some light on my confusion and understanding that would be great. (Code below)
public abstract class GeneralSearch {
NodeInfo nodeInfo;
ArrayList unvisited, visited;
public GeneralSearch (State startState, NodeInfo nodeInfo) {
this.nodeInfo = nodeInfo;
unvisited = new ArrayList();
unvisited.add(new Node(startState, new Actions()));
visited = new ArrayList();
}
public Node search() {
Actions moves;
Action move;
//Iterating through arrayList for unvisited and possible arcs
Node visit, successor;
if(unvisited.isEmpty()) return null;
while( !unvisited.isEmpty() ) {
visit = select();
if(nodeInfo.isGoal(visit)) return visit;
moves = visit.getState().getActions();
Iterator<Action> it = moves.iterator();
while(it.hasNext()) {
successor = (Node) visit.clone();
move = it.next();
successor.getState().update(move);
insert(successor);
}
visited.add(visit);
}
return null;
}
public abstract Node select ();
public abstract void insert (Node node);
public class BreadthFirstSearch extends GeneralSearch {
public BreadthFirstSearch(State startState, NodeInfo nodeInfo) {
super(startState, nodeInfo);
}
public Node select() {
return (Node) visited.get(0);
}
public void insert(Node node) {
unvisited.add(node);
}
}
}
Put the BreadthFirstSearch class in a separate file, outside of the GeneralSearch class.
If you want to keep it there, try instantiating GeneralSearch.BreadthFirstSearch instead of just BreadthFirstSearch, but I'm not even sure it's possible to have a subclass within it's own parent.
In your second try you're missing a new statement:
GeneralSearch bfs = new GeneralSearch.BreadthFirstSearch(now.getState(), info);
Related
The function overall should be like this:
Work() of NodeManager is a blocking method that call doYouWork(counter) on Node[0], and wait
until method WorkDone() it's called by doyourWork()
Node[i] do some work, simulated by Thread.sleep, then if counter is > 0, call doYourWork on the
next Node (Nodes order is 0..9->0), or if counter is <=0 Node call the method WorkDone of NodeManager
My problem is that i can't call WorkDone in the class Node without instantiate an object of NodeManager, and i can't even declare WorkDone a static method because then i can't call NotifyAll.
What should i do?
public class NodeManager implements NodeManager {
private final int N_NODES = 10;
private static Node[] nodes;
private int _counter;
public NodeManager(int counter)
{
nodes = new Node[N_NODES];
this._counter = counter;
for(int i=0; i<N_NODES ;)
{
nodes[i] = new Node(i, ++i);
}
Work(_counter);
}
public static Node[] getNodes() {
return nodes;
}
#Override
public synchronized void Work(int counter) {
nodes[0].doYourWork(counter);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void WorkDone() {
notifyAll();
}
}
and this is Node class
public class Node extends AbstractNode {
private int _id;
private int _next_id;
private Node[] nodes;
public Node(int id, int next_id) {
this._id = id;
this._next_id = next_id;
if(id == 9)
this._next_id = 0;
}
#Override
public void doYourWork(int counter) {
Random rand = new Random();
long millis = rand.nextInt((150-100) + 1) + 100;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(counter > 0) {
nodes = NodeManager.getNodes();
nodes[_next_id].doYourWork(--counter);
}
else {
//NodeManager.WorkDone(); i would do this
}
}
}
I'm going to address a few things about your code first, then see if I can't get to the meat of a solution.
First, please take a peek at Java naming standards. Class names should be UpperCase, as you've done, but method names should be lowerCase, which you seem to do inconsistently.
Second, this is rather odd: public class NodeManager implements NodeManager
You have both a class and an interface named NodeManager. That seems like a really, really bad naming scheme.
Also, this loop makes me squeamish:
for(int i=0; i<N_NODES ;)
{
nodes[i] = new Node(i, ++i);
}
This is a future bug waiting to happen. While the code is doing what you want now, this is a dangerous pattern. Nearly always your for-loops should auto-increment inside the for() part. Doing it embedded like this is going to bite you in the ass if you make a habit of this. Please be careful.
And then you also did this:
public Node(int id, int next_id) {
this._id = id;
this._next_id = next_id;
if(id == 9)
this._next_id = 0;
}
Gross. Pass in the proper next_id. Your node shouldn't magically know you're making 10 of these guys. See previous comment about how you're initializing these guys.
As for your solution...
Let's start with NodeManager. You need to decide if you're dealing with static or non-static fields. You're mixing and matching what you're doing. Some of your fields are static, some are not.
Here's what I would do.
1a. I would eliminate the static in the field definitions in NodeManager.
1b. Or, if it's appropriate, I would apply the Singleton pattern to NodeManager, and make it possible to only have 1.
I would make it so Node doesn't know a thing about NodeManager.
Now, how do you do #2?
2a. Define an interface called something like NotifyWhenDone. It has a method called workDone.
2b. Node implements NotifyWhenDone.
2c. Pass NodeManager to doYourWork()
2d. doYourWork() expects not a NodeManager object, but a NotifyWhenDone object.
2e. Then instead of NodeManager.workDone(), you call objectToNotify.workDone().
Or there's another solution.
Take a look at promises. It's complicated, but it's a GREAT way to do this. Do a Google of Java Promise. It's really probably the right way.
So I have a class:
public static class AVLTreeNode <E extends Comparable<E>> extends BST.TreeNode<E> {
protected int height;
public AVLTreeNode(E e) {
super(e);
}
}
That extends another class:
public static class TreeNode<E extends Comparable<E>> {
protected E element;
protected TreeNode<E> left;
protected TreeNode<E> right;
public TreeNode(E e) {
element = e;
}
}
And I am creating an ArrayList of type TreeNode, and trying to cast it to AVLTreeNode:
public void balancePath(E e) {
ArrayList<TreeNode<E>> path = path(e);
for (int i = path.size() - 1; i >= 0; i--) {
AVLTreeNode<E> a = (AVLTreeNode<E>)(path.get(i));
//continued code not important...
Note that my path method returns an ArrayList of type TreeNode<E>. But when I try to cast the node that I get at position i in the list to AVLTreeNode<E> (a subtype of TreeNode) I get a ClassCastException.
What is the problem here?
Edit Here is the full stack trace
Exception in thread "main" java.lang.ClassCastException: com.jeffsite.chapter27.BinarySearchTree$TreeNode cannot be cast to com.jeffsite.chapter29.AVLTree$AVLTreeNode
at com.jeffsite.chapter29.AVLTree.balancePath(AVLTree.java:102)
at com.jeffsite.chapter29.AVLTree.insert(AVLTree.java:19)
at com.jeffsite.chapter29.TestAVLTree.main(TestAVLTree.java:10)
It isn't a safe thing to cast because it is true that every AVLTreeNode is a TreeNode, but it is not necessarily true that every TreeNode is a AVLTreeNode. You could your List only hold AVLTreeNode(s), by changing from
ArrayList<TreeNode<E>> path = path(e);
to
List<AVLTreeNode<E>> path = path(e);
But I you should program to an interface (that's why List instead of ArrayList), so I think you really want
List<TreeNode<E>> path = path(e);
and then you can use
TreeNode<E> a = path.get(i);
And if you must know
if (a instanceof AVLTreeNode) {
// now you can cast a
AVLTreeNode<E> b = (AVLTreeNode<E>) a;
}
It depends on the what path returns. If the the path method/func returns a List of TreeNode then the conversion is not possible as the AVLTreeNode has extra params involved.
You can create the ArrayList or List of AVLTreeNode which should help solve the problem at hand (Only in the case path (method) returns the same).
ArrayList<AVLTreeNode<E>> path = path(e);
Can you show the path method, this dummy method works:
public ArrayList<? extends TreeNode<E>> path(E e) {
AVLTreeNode<E> tn = new AVLTreeNode<E>(e);
ArrayList<AVLTreeNode<E>> list = new ArrayList<AVLTreeNode<E>>();
list.add(tn);
return list;
}
I got two prepared classes, one for 'List'(linked list) and one for 'ListNode', and they asked my (for homework) to create a recursive 'showRev' methods for the 'List' class that uses another 'showRev' method of ListNode class...
What this method should do is show the list but from the end to start, the opposite of show.
So I need two methods, but that the 'List' one will use the 'ListNode' one.
This is my code:
public class List {
private ListNode firstNode;
private ListNode lastNode;
private String name;
public List()
{
this("list");
}
public List(String listName)
{
name=listName;
firstNode=lastNode=null;
}
.
.
.
.//there are more methods here
.
.
.
public void showRev()
{
//what do you suggest?
}
And this is the ListNode class:
public class ListNode {
Object data;
ListNode nextNode;
public ListNode(Object o)
{
this(o,null);
}
public ListNode(Object o,ListNode node)
{
data=o;
nextNode=node;
}
public Object getObject()
{
return data;
}
public ListNode getNext()
{
return nextNode;
}
public void show ()
{
System.out.println(this.getObject());
if (this.nextNode != null) {
this.nextNode.show();
}
}
public void showRev ()
{
// what do you suggest?
}
}
Since this is homework, I'm not going to give you an answer, but rather give you some ideas that should lead you to an answer.
When you want to solve a problem with recursion, you break down your problem into one or more smaller instances of the same problem.
In this case, you have a List. You can break that down into "the first node" and "the rest of the list". The "rest of the list" is a smaller instance of the same problem.
If your problem is to display the List in reverse order, and you already had a magic way to display "the rest of the list" in reverse order, then how could you solve the problem? This will take a little thought. If you get stuck, try thinking about lists of just two or three elements.
If you can figure that out, then you have the answer. The "magic way" to display the rest of the list will be a recursive call. Then all you need to do is figure out when to stop (the "base case"): at what point do you want the method to stop calling itself recursively?
You can have your method do something like this to print reverse list via recursion.
public void showRev(ListNode node)
{
if (node != null) {
showRev(node.nextNode);
System.out.println(node.data);
};
}
First of all, this is part of a homework assignment, so please keep that in mind when answering.
So I am attempting to use a generic LinkedList class, which a CustomerList class inherits from. All code below is written by me and not given as part of the assignment.
I have written the customer type, which works successfully. The code shouldn't be needed, as the problem does not have to do with that class. It has 3 int fields, and a method to print it's info.
public void printCustomerInfo() {
System.out.println([int field 1, 2, 3]);
}
The issue has to do with the insert method (I believe) of the generic LinkedList class. It takes in a object of the determined class, and inserts it in the list in front of the current LinkedList object.
It does this by creating a copy of the current LinkedList object, setting that as the nextList, and then modifying the data of the current LinkedList object to the given dataIn.
Here is the code for the LinkedList class:
public class LinkedList<T> {
T data;
protected LinkedList<?> nextList;
public LinkedList() {
data = null;
nextList = null;
}
public boolean isEmpty() {
return (null == nextList);
}
public LinkedList<?> getNextList() {
return nextList;
}
public void insert(T dataIn) {
System.out.println("dataIn passed to insert method: \t" + dataIn);
LinkedList<T> tempList = new LinkedList<T>();
tempList.data = this.data;
tempList.nextList = this.nextList;
this.nextList = tempList;
this.data = dataIn;
System.out.println("data field of current object: \t\t" + data);
}
#SuppressWarnings("unchecked")
public T delete() {
T tempDump = data;
data = (T) nextList.data;
nextList = nextList.nextList;
return tempDump;
}
public void printInfo() {
if (isEmpty()) {
System.out.println("-END-");
} else {
System.out.println(data);
nextList.printInfo();
}
}
}
The CustomerList class extends it, and sets the data type to customer.
Here is the code:
public class CustomerList extends LinkedList<Customer> {
Customer data;
public void printInfo() {
if (isEmpty()) {
System.out.println("-END-");
} else {
data.printCustomerInfo();
nextList.printInfo();
}
}
}
Finally, the testing object:
public class GeneralTesting {
public static void main(String[] args) throws InterruptedException {
// Test LinkedList class
System.out.println(" - Create CustomerList and test methods");
CustomerList rList = new CustomerList();
System.out.println(" - Create a customer to store in the list");
Customer dude = new Customer(10, 65);
dude.setTimeServed(120);
System.out.println("proof that customer object exists: \t" + dude);
System.out.println(" - Insert customer into the list");
System.out.println("---method call: insert---");
rList.insert(dude);
System.out.println("---method end: insert----");
System.out.println("data in the list after return: \t\t" + rList.data);
}
}
This is what the console prints:
- Create CustomerList and test methods
- Create a customer to store in the list
proof that customer object exists: assignment3.Customer#3c250cce
- Insert customer into the list
---method call: insert---
dataIn passed to insert method: assignment3.Customer#3c250cce
data field of current object: assignment3.Customer#3c250cce
---method end: insert----
data in the list after return: null
As far as I can tell/understand, it is a scoping problem. Perhaps I am assigning the variable at a level that is ignored as the method resolves. I have run onto a similar issue before, and was able to resolve it, but cannot figure this out. Unfortunately, my prof is out town for next couple days, so I am looking for help here.
I just tried to make a method that simply sets the data field to a passed in object:
public void setData(T dataIn) {
this.data = dataIn;
}
Even this did not change the data from null. I know this must be due to not understanding Java generics correctly, so any pointers you can give, (and online resources to read) would be very appreciated.
Here's a hint. If you declare a data member in both the parent LinkedList class, and in the child class, the child member will overshadow the parent class's version.
if possible please post some sample codes. Because we have a project wherein we need to set up locations within a map, and connect those locations with a line. Other than we also need to have a starting and end point in which we need to find a path going from the designated starting to the end point.
import java.util.*;
class Node {
Node(Object object) {
this.object=object;
}
Object object;
List<Node> children=new ArrayList<Node>();
public String toString() {
return object.toString();
}
static void traverse(Node node) {
System.out.println(node);
for(Node child:node.children)
traverse(child);
}
}
public class Main {
public static void main(String[] args) {
Node root=new Node("root");
root.children.add(new Node("child 1"));
root.children.add(new Node("child 2"));
Node.traverse(root);
}
}
Please if you did not read about Dijkstra, its the first you have to do if you wanna find a method to get the best(the shortest) route between two nodes...