I am trying to clone an object without using any library.
The object has other objects/arrays/matrixes in it.
So I developed some methods to clone those as well.
They are working fine when I am cloning arrays/matrixes that are not inside the object.
These are the methods:
public static int[] cloneArray(int[] array){
int i = 0;
int[] clone = new int[array.length];
while (i < array.length){
clone[i] = array[i];
i++;
}
return clone;
}
public static int[][] cloneMatrix(int[][] matrix){
int[][] clone = new int[matrix.length][matrix[0].length];
for (int i = 0;i<matrix.length;i++)
for(int j = 0;j<matrix[0].length;j++)
clone[i][j] = matrix[i][j];
return clone;
}
However, when I want to clone an object, the references of the array/matrix stay the same, as you can check in the output on the bottom of the post.
This is the constructor I have:
public State(int parentStateID, int stateID, int[][] board, int[] pieces, int points, int acquiredPoints){
State.parentStateID = parentStateID;
State.stateID = stateID;
State.currentBoard = cloneMatrix(board); //here takes place the matrix cloning
State.currentPieces = cloneArray(pieces); //here takes place the array cloning
State.totalPoints = points;
State.acquiredPoints = acquiredPoints;
}
And this is the cloning method:
public static State cloneState(State state){
int[][] currentBoard = state.getCurrentBoard();
int[] currentPieces = state.getCurrentPieces();
int totalPoints = state.getTotalPoints();
int acquiredPoints = state.getAcquiredPoints();
int parentStateID = state.getParentStateID();
int stateID = state.getStateID();
State clone = new State(parentStateID,
stateID,
currentBoard,
currentPieces,
totalPoints,
acquiredPoints);
return clone;
}
To better visualize the output, here are the arrays and matrix:
public static int piecesList[] = {1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
public static int piecesList2[] = {2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
public static int piecesList3[] = {3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
private static int[][] map = {{0,1,2,3,4},{5,6,7,8,9},{10,11,12,13,14},{15,16,17,18,19},{20,21,22,23,24}};
Here is the verification code:
int[][] state2 = cloneMatrix(map);
state2[0][0] = 1;
System.out.println("map.original " + map[0][0]);
System.out.println("map.clone " + state2[0][0]);
System.out.println("");
System.out.println("");
int[] pc = cloneArray(piecesList);
pc[24] = 1;
System.out.println("pieces.original " + piecesList[24]);
System.out.println("pieces.clone " + pc[24]);
System.out.println("");
System.out.println("");
State newState = setFirstState();
State clonedState = cloneState(newState);
clonedState.setCurrentPieces(piecesList2);
System.out.println("newState.pieceslist: "+newState.getCurrentPieces()[0]);
System.out.println("clonedState.pieceslist: "+clonedState.getCurrentPieces()[0]);
System.out.println("piecesList.original: "+piecesList[0]);
System.out.println("");
newState.setCurrentPieces(piecesList3);
System.out.println("newState.pieceslist: "+newState.getCurrentPieces()[0]);
System.out.println("clonedState.pieceslist: "+clonedState.getCurrentPieces()[0]);
System.out.println("piecesList.original: "+piecesList[0]);
And here is the output:
map.original 0
map.clone 1
pieces.original -1
pieces.clone 1
//as you can check in the next two cases, the change takes effect in both the original state, and the cloned state
newState.pieceslist: 2
clonedState.pieceslist: 2
piecesList.array variable: 1
newState.pieceslist: 3
clonedState.pieceslist: 3
piecesList.array variable: 1
Been trying to solve this issue for over 12 hours, without much success...
I have tried libraries as well as serialization with no success...
Help is much appreciated!
The problem with your code is that the fields (not shown) obviously are static, as can be told from your constructor:
public State(int parentStateID, int stateID, int[][] board, int[] pieces, int points, int acquiredPoints){
State.parentStateID = parentStateID;
State.stateID = stateID;
State.currentBoard = cloneMatrix(board); //here takes place the matrix cloning
State.currentPieces = cloneArray(pieces); //here takes place the array cloning
State.totalPoints = points;
State.acquiredPoints = acquiredPoints;
}
The constructor should instead read like this:
public State(int parentStateID, int stateID, int[][] board, int[] pieces, int points, int acquiredPoints){
this.parentStateID = parentStateID;
this.stateID = stateID;
this.currentBoard = cloneMatrix(board); //here takes place the matrix cloning
this.currentPieces = cloneArray(pieces); //here takes place the array cloning
this.totalPoints = points;
this.acquiredPoints = acquiredPoints;
}
A field which is static exists only once per class. A field which is not static exists once per each object constructed from that class (or any subclass). Because of that, you actually created objects which are empty, and whatever you thought you would store in the object you actually stored in the class, thus sharing the same data among all objects.
As a rule of thumb, you usually do not want any static non-final fields in your classes. Exceptions apply, but they're rare and mostly limited to a few tiny bootstrapping things in frameworks.
Related
I have 2 classes set up in a project where i am creating a primitive chess game. I am trying to access an array from another class but it's private. How would i go about referencing and accessing that array from a different class? Here are the sections of relavent code:
private static final char FREE = '.';
private static final char WHITEROOK = '♖';
private static final char BLACKROOK = '♜';
private static final char WHITEBISHOP = '♗';
private static final char BLACKBISHOP = '♝';
private int boardsize;
private char[][] board;
public Board() {
this.boardsize = DEFAULT_SIZE;
board = new char[boardsize][boardsize];
// Clear all playable fields
for(int x=0; x<boardsize; x++)
for(int y=0; y<boardsize; y++)
board[x][y] = FREE;
// Placing Initial Pieces on the board
board[2][0] = WHITEBISHOP;
board[5][0] = WHITEBISHOP;
board[2][7] = BLACKBISHOP;
board[5][7] = BLACKBISHOP;
board[0][0] = WHITEROOK;
board[7][0] = WHITEROOK;
board[0][7] = BLACKROOK;
board[7][7] = BLACKROOK;
}
It's the board array that I want to access, and use to compare to other arrays within if statements.
Thanks!
The best solution is probably not to allow any other class access the array directly and only let the Board class itself do that.
This could be done by creating public methods for moving a piece, printing the board etc
Here is a very simplified example
public void move(int fromX, int fromY, int toX, int toY {
char piece = board[fromX][fromY];
board[toX][toY] = piece;
}
The usage in another class would then be
Board b = new Board();
b.move(4,1,4,3);
You say you want to compare the array to other arrays but that is also better if it's handled by the Board class
public int compareWith(char[][] otherArray) {
int result = 0;
//compare
return result;
}
or even better, if you are comparing two boards then it would be
public int compareWith(Board otherBoard) {
int result = 0;
//compare
return result;
}
try to create a public method returning an array, or changing its insides
example
public void EditArray(int index1, int index2, char value){ board[index1][index2] = value; }
getting the values of the array directly will not work, you will have to write methods anyway (sorry my English)
welcome to SO!
The traditional solutions to this would be either to make the field public:
public char[][] board;
or, probably safer and more common, create a getter method:
private char[][] board;
public char[][] getBoard() {
return board;
}
Then, in the other class, you can create a Board and access its board using the getter:
Board myBoard = new Board();
char[][] boardArray = myBoard.getBoard();
//use the array:
System.out.println(boardArray[0][2]);
I have created two classes, one called "Bucket", and the other called "Player".
In "Bucket", I have a constructor method that creates a virtual bucket (i.e. small array) that contains three values - 1, 1, and 1. As well, I created a method to get the bucket array.
In the "Player" class, I have created a method that uses a larger array (I have called this larger array "ArrayOfBuckets"), which uses a loop to store a new bucket at each index value, up until a certain point (when i>NumberSticks). However, when I try to set
ArrayofBuckets[i] = bucketInstance.getBucket();
I get an error from Eclipse, saying that "Type mismatch: cannot convert from Bucket to int". I have spent an hour trying to solve this, to no avail. Any help would be really nice. Thanks a lot, and here is all the code that is used:
The Player Class:
import java.util.Scanner;
public class Player {
Scanner scan = new Scanner(System.in);
public String name;
private int pType;
private int[] ArrayOfBuckets;
public Player(String tempName)
{
this.name = tempName; //this. is unneccessary
}
public void ArrayOfBuckets(int NumberSticks) //this is a constructor method and creates the arrays that contains a
{
ArrayOfBuckets = new int[NumberSticks];
int i = 0;
while(i<NumberSticks)
{
Bucket bucketInstance = new Bucket();
ArrayOfBuckets[i] = bucketInstance.getBucket();//new Bucket(); //ADD THIS
i++;
}
}
and the Bucket Class:
import java.util.Random;
public class Bucket {
// private int[][] largeArray = null; //WTF DO I DO HERE
private int AIChoiceStick;
private int[] bucket;
private Random random = new Random();
private int CurrentScore[] = new int[51]; //at max, if 100 sticks are initially chosen, then each player takes at max 50 sticks,
private int h = 0; //^so why not have one more in case
public Bucket()
{
bucket = new int[3];
bucket[0] = 1;
bucket[1] = 1;
bucket[2] = 1;
public int[] getBucket()
{
return bucket;
}
You're speaking about a two-dimensional array.
private int[][] ArrayOfBuckets;
Your ArrayOfBuckets (should be just buckets according to naming conventions) is an array of arrays, so it gets two sets of square brackets.
Then the initialization:
ArrayOfBuckets = new int[NumberSticks][3];
By the way, if you want to have room for 50 elements in an array, then initialize it new int[50] so it will have indexes 0 through 49.
I'm making a program to get the midpoint of a line. However i'm running into a problem.
What i need to be able to do is have as many points as i want, and dimensions. However i have no idea how to do this
So let me give you an idea of what i want to do.
points[point][x]=1; points[point][y]=2; points[point][z]=3;
See what i'm getting at? This is what i currently have
public float[][] points={{}};
And when i want to write to it
for(int i=0; i<parts.length;i++){
points[currentPoint][i]=Float.valueOf(parts[i]);
}
java.lang.ArrayIndexOutOfBoundsException: 0
So how can i do this?
public float[][] points={{}};
This creates an empty two dimensional array. Hence, the ArrayIndexOutOfBoundsException.
If you want to create an array to hold 6 points and 3 dimensions then you have to allocate it:
public float[][] points = new float[6][3];
However, I would reconsider your design. If you would like to go more object oriented way than you would probably like to have a class for line as well as for point. For example:
class Line {
private final Point startPoint;
private final Point endPoint;
Line(Point startPoint, Point endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint;
final int startPointDimensions = startPoint.getDimensions().size();
final int endPointDimensions = endPoint.getDimensions().size();
if (startPointDimensions != endPointDimensions) {
throw new RuntimeException("Points that form a line must have the same dimension! " +
"Start point dimension: " + startPointDimensions +
"End point dimension: " + endPointDimensions);
}
}
public Point midpoint() {
// your code goes here
}
}
class Point {
private final List<Float> dimensions;
Point(List<Float> dimension) {
dimensions = dimension;
}
public List<Float> getDimensions() {
return dimensions;
}
}
You can read more about lists in the oracle's documentation. I would prefer lists to arrays if you do not know up front how many dimensions you want to support or if you want to support different number of dimensions.
Use this to create a 3x3 2-D array and initialize all values to 0:
public float points[][] = new float[3][3];
And this to iterate through the array and set values:
for (int j=0; j<3; j++) {
for (int i=0; i<3; i++) {
points[j][i] = 42; //Or whatever
}
}
I have an array of objects. When the array fills up, I want to make a new array twice as large as the old one, and transfer all the elements over. I'm doing something wrong, I think its something to do with I'm not creating the correct reference to the new array. Here's my code, any help figuring this out would be appreciated.
private int DIRECTORY_SIZE = 6;
Entry [] directory = new Entry[DIRECTORY_SIZE];
private int numberOfElements = 0;
public int getNumOfElements(){
return numberOfElements;
}
public void setDirectorySize(int size){
DIRECTORY_SIZE = size;
}
public int getDirectorySize(){
return DIRECTORY_SIZE;
}
public void addEntry(String surname, String initial, String num) {
// TODO add an entry to an array, also increments numberOfElements variable tracking whats in array
if(getNumOfElements() == getDirectorySize()){ // if array is full
doubleArraySize(); // put temp values into new bigger directory array
}
int i = findFreeLocation();
directory[i] = new Entry(surname, initial, num);
numberOfElements++;
}
private void doubleArraySize(){
Entry[] temp = new Entry[DIRECTORY_SIZE]; //make new temp array same size as old one
for(int i = 0; i < DIRECTORY_SIZE ; i++){
temp[i] = directory[i]; // cycle through array putting all values into temp
// works up to here
}
setDirectorySize(DIRECTORY_SIZE*2); // double size of array
Entry[] directory = new Entry[DIRECTORY_SIZE]; // create new, double size directory array
for(int i = 0; i < temp.length ; i++){
directory[i] = temp[i];
}
}
private int findFreeLocation() {
int i;
for (i = 0; i < DIRECTORY_SIZE; i++)
{
if(directory[i] == null)
{
break;
}
}
return i;
}
In doubleArraySize() function , this is the issue :
Entry[] directory = new Entry[DIRECTORY_SIZE];
// you are not assigning it to the class attribute directory
// instead you are creating a local array directory
Make the following change :
this.directory = new Entry[DIRECTORY_SIZE];
// this will assign the newly created array to the class attribute
Note : I personally prefer to use this pointer to refer to class attributes so that it makes my code more readable, and its clear to everyone that the variable in question is a class attribute rather than local variable.
**SIZE has already double by this point. No need to multiple by 2
I remember doing something exactly like this when I was making a Vector ADT. However, I used instance variables instead of methods in my code for element number and the capacity. I definitely didn't initialize a Vector inside a method for a Vector.
setDirectorySize(DIRECTORY_SIZE*2); // double size of array
Entry[] directory = new Entry[DIRECTORY_SIZE]; // create new, double size directory array
Isn't DIRECTORY_SIZE an instance variable? Because if it is, I don't think you can initialize an object using an instance variable from the object you are overwriting.
Putting my code into your context, it would look something like this:
private void doubleDirectorySize()
{
Entry[] new_array = new Entry[new_directory_size*2];
for (int i = 0; i < directory_size; i++)
{
new_array[i]= directory[i];
}
directory= new_array;
}
This only works if directory was initialized to null, though, moving the pointer directory to the new array.
I have a Path class which I think is immutable. In another class called Test, I have a final reference to an object of Path.
Yet, in between the constructor and the getter method, the Path object changes even though it is immutable and the reference is final. I know this because the length of the int array node in Path changes from the constructor to the getter. It seems as it the object is a completly different one altogether.
My program is multi-threaded but I've tried it with a single thread and that didn't resolve the problem.
Here is the immutable Path class
public class Path implements Iterable<Point> {
private final int[] nodes;
private final double distance;
public Path(Scenario scenario, int gateway, int sensor){
this.scenario = scenario;
nodes = new int[2];
nodes[1] = -gateway - 1;
nodes[0] = sensor;
distance = scenario.DISTANCE_GATEWAY_SENSOR[gateway][sensor];
}
public Path(Path base, int newSensor){
scenario = base.scenario;
//Copy the old path. These are rigid structures so that we do not need to deep copy
nodes = new int[base.nodes.length + 1];
for(int i = 0; i < base.nodes.length; i++)
nodes[i + 1] = base.nodes[i];
nodes[0] = newSensor;
distance = base.distance + scenario.DISTANCE_SENSOR_SENSOR[newSensor][nodes[1]];
}
public Path(Scenario scenario, int[] nodes, boolean isSensor, double distance){
this.scenario = scenario;
this.distance = distance;
this.nodes = Arrays.copyOf(nodes, nodes.length);
if(!isSensor)
for(int i = 0; i < this.nodes.length; i++)
this.nodes[i] = -this.nodes[i] -1;
}
#Override
public Iterator<Point> iterator() {
return new PointIterator();
}
public class PointIterator implements Iterator<Point>{
private int next = -1;
#Override
public boolean hasNext() {
return next + 1 < nodes.length;
}
#Override
public Point next() {
int p = nodes[++next];
if(p >= 0)
return scenario.SENSOR_LOCATION[p];
return scenario.CS_LOCATION[-p - 1];
}
#Override
public void remove() {
throw new IllegalAccessError("This method is not supported");
}
}
}
and here is the Test class (with a final reference to the Path class)
public class Test {
private final Path gatewayTour;
public Test(Scenario scenario, boolean[] chosenGateway){
distanceFitness = 0;
Point current = scenario.SINK_LOCATION;
boolean visited[] = new boolean[scenario.CONFIG.NUM_CS];
int nextGateway;
LinkedList<Integer> order = new LinkedList<>();
do {
double minimumDistance = Double.MAX_VALUE;
nextGateway = -1;
for(int i = 0; i < scenario.CONFIG.NUM_CS; i++)
if(!visited[i] && CHOSEN_GATEWAYS[i] && scenario.CS_LOCATION[i].isCloserThan(minimumDistance, current)) {
nextGateway = i;
minimumDistance = scenario.CS_LOCATION[i].distance(current);
}
if(nextGateway >= 0) {
distanceFitness += minimumDistance;
visited[nextGateway] = true;
order.add(nextGateway);
current = scenario.CS_LOCATION[nextGateway];
}
} while(nextGateway >= 0);
int path[] = new int[order.size()];
Iterator<Integer> it = order.iterator();
for(int i = 0; i < order.size(); i++)
path[i] = it.next().intValue();
gatewayTour = new Path(scenario, path, false, distanceFitness);
}
public Path getGatewayTour(){
//Here, the gatewayTour object has changed and does not have the same content as in the constructor
return gatewayTour;
}
}
Is there anything in my program that permits the object to change? I'll be more precise: is there anything that woud permit the int array "nodes" in Path class to change length? Because this is the real problem.
[EDIT]: My test was flawed, which led me to believe that the value of my 'nodes' array changed. Thanks to all who pointed flaws or possible improvements in my code.
I'll accept the answer of AlexR because he pointed out that one could change individual elements in a final array; something I didn't know and that help resolve the problem.
Word final means that the reference marked with this word cannot be changed. It does not mean that the referenced object cannot be changed.
This means that there is no problem to change the instance of Path by changing its fields. Yes, you are right, your fields are final too. But let's examine them:
private final int[] nodes;
private final double distance;
private final Scenario scenario;
distance is a primitive, so it indeed cannot be changed once assigned during initialization. nodes is an array, i.e. object. The array itself cannot be changed, i.e. the reference refers to the same array. However you can change elements of the array.
scenario is object too. You have not sent the class Scenario here, but again if fields of this class can be changed this object can be changed.
private final int[] nodes;
Is still mutable, assuming your constructor simply copies the array reference.
public Path(int[] nodes, double distance) {
this.node = nodes;
this.distance = distance;
}
This is because Path's nodes is still pointing to the instance that was passed in. If that instance changes, then your Path's state has changed.
One solution is to make a copy of node in the constructor (using System.arraycopy).
To be sure the answer is correct we need to see more code; it's not clear what is being changed where. However, if the idea is to guarantee that nodes is unmodifiable, a primitive array (final or not) will not work. Something more like
private final List<Integer> nodes;
public Path(Integer[] array /* note boxed as Integer */) {
nodes = java.util.Collections.unmodifiableList(
java.util.Arrays.asList(array));
/* etc. */
}
Problem here!
public Path(Scenario scenario, int[] nodes, boolean isSensor, double distance){
this.scenario = scenario;
this.distance = distance;
this.nodes = nodes;
You copy the nodes array reference.
Use:
this.nodes = Arrays.copy(nodes, 0, nodes.length);
If you modify the array, changes will be reflected into Path! Similarly, if you modify the array in the constructor, changes will be reflected to the caller...
As such, your class is NOT immutable at the moment. Also, "real" (to my sense) immutable classes are final themselves.