I am creating a game in java. I am using an array of Armor's for equipment
The issue, is that whenever I change 1 variable in my array, the other objects are also affected. This looks like a pointer issue but, all of the objects have been initialized as separate and called as new.
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
System.out.println(armorDes(0));
System.out.println(armorDes(1));
System.out.println(armorDes(2));
}
All of the print lines output
baggy pants
0 armor
10 evasion bonus
Basic pants woven from rough cloth
instead of their own stats.
This was tested with a debugger and all of the objects are declared to different locations in data. Is this a java issue are am I just stupid?
Code is unclear above
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();// Why creating object using default constructor here? no use
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
// Use toString() method in Armour class to see the values present in variables.
//Also be sure all variables are instance variables
System.out.println(equip[0]);
System.out.println(equip[1]);
System.out.println(equip[2]);
//System.out.println(armorDes(0));
//System.out.println(armorDes(1));
//System.out.println(armorDes(2));
}
Related
The code is :
package classes;
public class Test {
private static double mutationRate = 0.5;
public static void main(String[] args) {
Population pop = new Population();
pop.initialise();
Population po = new Population();
po.getIndividusList().add(pop.getFittest());
po.getIndividusList().add(mutate(pop.getIndividusList().get(1)));
}
private static Chromosom mutate(Chromosom l) { // changer les couples d'interventions des parcs)
// loop through genes
Chromosom ch = new Chromosom();
for (int i = 0; i < l.size(); i++)
ch.put(i, l.get(i));
for (int i = 0; i < ch.size(); i++) {
double alea = Math.random() * 13;
int moisIntervention1 = (int) alea;
Intervention interv1 = new Intervention(1, moisIntervention1);
ch.get(i).modInterventions(ch.get(i).intervention2(interv1));
}
return ch;
}
}
The problem is that I did not change the instance pop but when I change the other instance po, pop changes too.
java pass by value.
when you call this mutate(pop.getIndividusList().get(1))
you are sending pop's instance, so it will get change.
Supose pop.getIndividusList().get(1) return String varibale do this way
String var=pop.getIndividusList().get(1);
then call mutate(var)
I'm unsure about whether I understood the problem, but I think that you mean that when you alter the items in Population po, the items in Population pop mirror those changes.
That is, indeed, the expected behavior of your code: to populate po, you are adding items from pop - (pop.getFittest, pop.getList.get(1) ).
But the individuals are, I believe, instances of objects, so add/remove and similar operations work with references to the objects, and not with copies of them. Therefore, as you have 2 references to the same obj, any change is mirrored.
IF you want to create a copy, you should add to po a new object with the same state, either by creating a constructor that takes another instance as parameter, implementing a copy method, or something similar.
It should be something like this:
Population po = new Population();
Individual fittest = pop.getFittest();
Individual poCopy = new Individual();
//ADD CODE HERE TO COPY ALL THE FIELDS FROM fittest TO poCopy
//....
po.getIndividusList().add(poCopy);
I have this list of objects that includes an array i (want) to use just as reference. So when i create a new object, fill it with an array in the list and start changing that new object i do not want my initial arrays for the object in my list to change.
I basically do this:
//Fill list with my reference objects;
Object newObject = new Object(); //So i do not change the previous newObject in the loop.
newObject = (find)ObjectFromList;
newObject.array = RotateArray(newObject.array);
If i fill another newObject with the same object from the list it already is rotated. I hope i have been clear enough. Below a shortened version of my code, still a bit messy too:
LoadRooms(); //Loads all the objects and arrays from a file into the list.
for(int x=0;x<width;x++)
{
for(int y=0;y<height;y++)
{
Room newRoom = new Room();
//Fill newroom with correct room type, rotate and build tilemap.
//Dead ends
if(!mazeMap[x][y].N && !mazeMap[x][y].E && mazeMap[x][y].S && !mazeMap[x][y].W)
{
newRoom = FindRoom(Room.RoomType.DeadEnd);
newRoom.room = TurnRoomCW(newRoom.room);
newRoom.room = TurnRoomCW(newRoom.room);
newRoom.room = TurnRoomCW(newRoom.room);
}
else if(!mazeMap[x][y].N && mazeMap[x][y].E && !mazeMap[x][y].S && !mazeMap[x][y].W)
{
newRoom = FindRoom(Room.RoomType.DeadEnd);
}
//Etc, etc then i build a map from the newRoom.room array
}
}
This is what TurnRoom() looks like:
private String[][] TurnRoomCW(String[][] room)
{
String[][] rotatedRoom = new String[room[0].length][room.length];
for (int y = 0; y < room[0].length;y++)
{
for (int x = 0;x < room.length;x++)
{
rotatedRoom[y][x] = room[7 - x][y];
}
}
return rotatedRoom;
}
and here is FindRoom
private Room FindRoom(Room.RoomType roomType)
{
Collections.shuffle(rooms, rand);
for (Room r : rooms)
{
if (r.roomType.equals(roomType))
return r;
}
return null;
}
When i want to turn something like a corner type room, say NE into the correct position all other rooms turn with it. So when i want to turn, say SW into position the NE will be position wrong again.
Your FindRoom method is returning a reference to the actual room.
'TurnRoomCW' returns a new object, but you then assign that new object back into the original room
So your problem is right here:
newRoom = FindRoom(Room.RoomType.DeadEnd); // 1) find a DeadEnd room
newRoom.room = TurnRoomCW(newRoom.room); // 2) create rotated room, assign it to the room from step 1)
If you want to work with a new Room object, you will need to create a new one somehow. For example, you might define a constructor for Room that returns a new object initialized from an existing one. For example,
/** copy constructor */
public Room(Room oldRoom) {
this(); // regular constructor
this.room = oldRoom.room.clone(); // new Room gets its own array!
this.roomType = oldRoom.roomType;
// … etc for any other member variables
}
Basically, Java objects are references (pointers if you prefer), so unless you make an explicit copy of an Array (or any other object), it will point to the same object.
If you want to avoid that, you have to do a clone first:
List myList = referenceList.clone();
This is generally a good habit anyway to avoid having your "internal" object being modified by the external world.
Ok so I'm doing an assignment for my java coursets part I'm stuck at is :
"Implement an operation createparliamentMembers which will create the particular Parliament
with 80 members."
So i've already created the constructor with it's methods. This is how I wrote the operation to create the objects using the constructor.:
public static void createparliamentMembers(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
The problem is the arrays and objects only seem to exist in the operation for creating them and when I try running method of the objects created they don't work because the driver class doesn't recognize the arrays. On the other hand when I use this as just a normal part of the Driver for it runs fine and all methods of the objects work normally.
Edit: Ok so I'm still getting the same problem as before even though i initiliased them outside the createparliamentMembers();
The following code is the Driver im using to test the methods: It keeps saying there is a:
Exception in thread "main" java.lang.NullPointerException at Driver.main(Driver.java:11)
which is the code array[1].FlipCoin(); as im trying to use the method flipcoin from the created objects but it's not working.
public static void main(String [] args) {
Commands.createparliamentMembers();
array[1].FlipCoin();
}
Your arrays are only defined locally, which means they live and die with the method. When your method finishes, they get put out of memory.
The solution is to define these arrays as instance variables. By that I mean, you need to define the arrays for your class, and then use them in your method:
class someClass {
int[] myArray = new int[2];
private void someMethod() {
myArray[0] = 3;
myArray[1] = //whatever
}
}
You state in comment:
I do have a parliament class it's on it own and contains the methods and constructor for the members of the parliament. The above method was in a seprate class called Commands. I don't understand completely the "Can you add the members to a Parliament object as you create them?" The parliament isn't an object more se then a class containing a constructor and methods for parliament members i want to create.
Parliament isn't an object yet, but you should in fact create one, and in fact your instructions tell you just that: "which will create the particular Parliament with 80 members...". You will need to tell us more about your program's structure and your specific requirements, but I suggest:
First create a Parliament object in the createParliamentMembers method, and call it parliament.
Then create the members of parliament in that method.
As you create these members, add them to the Parliament object, parliament.
At the end of the method return the parliament variable.
This means that your createParliamentMembers method's signature must change so that rather than return void it should be written to return a Parliament object.
When calling the method in the main method, assign what it returns to a Parliament variable that is in the main method.
It looks like you are writing a factory method. Create a constructor for Parliament like this:
public Parliament(Member[] members, Legislator[] legislators, Leader[] leaders) {
// do whatever with what's passed in
}
Then change your method to return a Parliament object and in the method pass your initialized arrays into the Parliament constructor, like this:
// same code as your except the last line
public static Parliament createParliament(){
Member[] array = new Member[75];
for(int i = 0; i < array.length; i++)
{
if (i < 35) array[i] = new Member(i, "Blue");
else array[i] = new Member(i,"Red");
}
Legislator[] leg = new Legislator[3];
for (int i = 0 ; i < leg.length; i++){
leg[i] = new Legislator(i, "Impartial");
}
Leader[] lead = new Leader[2];
for (int t = 0; t < lead.length; t++){
if (t < 1) lead[t] = new Leader(1, "Red");
else lead[t] = new Leader(2, "Blue");
}
return new Parliament(array, leg, lead);
}
I have a list of longitude and longitude points in an xml file that is used throughout my application. I find my self repeating this code to get points often and think there must be a better way?
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
XML is in the format of:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="stations">
<item>
<name>Station name</name>
<longitude>1111111</longitude>
<latitude>11111</latitude>
<code>1</code>
</item>
And another (possible) problem is that to get just one station I have to get all of them and pull the one I want from the array. Is this going to be considerably slower? Can I make this array consistent throughout the app? (But keeping the separate Intent methodology)
I had the same thought as MilkJug, to use a utility method to create the stations, but I want to offer a slightly different approach: Move as much of the construction logic as possible into the Station class constructor. To keep the example simple, I'm moving the utility method into the Station class as well.
This provides an overall cleaner design, as outside of the Station class itself, your code should never have to deal with a Station object whose construction/initialization steps haven't been fully completed.
(kgiannakakis's suggestion to use a database may be a better way to go if you have a lot of Station objects.)
public class Station {
private static List<Station> sStationArray = null;
/**
* Construct a Station from a specially-encoded String. The String
* must have all the necessary values for the Station, separated by tabs.
*/
public Station(String fieldString) {
String[] fields = fieldString.split("[\t ]");
// For safety, setValuesFromArray() should be declared 'final'.
// Better yet, you could just move its body into this constructor.
setValuesFromArray(fields);
// I'm assuming 'mName' is the name field for the Station
Log.i("Station", this.mName);
}
public static Station getStationArray(Context ctx) {
if (sStationArray == null) {
// (Please don't use the prefix 'm' for non-member variables!)
final String[] tempArray =
ctx.getResources().getStringArray(R.array.stations);
final int len = tempArray.length;
// Passing the length into the ArrayList constructor (if it's
// known, or can be guessed at) can be a very simple yet
// effective optimization. In this case the performance boost
// will almost certainly **not** be meaningful, but it's
// helpful to be aware of it.
sStationArray = new ArrayList<Station>(len);
for (int i = 0; i < len; i++) {
Station s = new Station(tempArray[i]);
sStationArray.add(s);
}
}
return sStationArray;
}
}
Why not create a utility method that takes a context as a parameter and returns the station resources? For example:
public class StatUtil {
private static List<Station> mStationArray = null;
public static Station getStation(Context ctx) {
if (mStationArray == null) {
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
}
return mStationArray;
}
}
and call it from your code with:
stationArray = StatUtil.getStation(this);
Repeatedly fetching the stations will be slower than caching them, but not significantly slower unless you are fetching them in a loop. Doing as above will prevent multiple copies from being fetched.
I could propose two solutions:
You could create a Singleton class that initializes once, reads the data from the XML and stores the stations in a List or a Map. Use a Map if you want to quickly find a station based on its name. The Singleton class will provide methods for retrieving all stations or just one of them.
Create a database table and store the information there. You may need more code, but the advantage will be that you will be able to run more advanced queries.
So lets say I want to make a deep copy of an object, but using its contsructor. So I have:
public class PositionList {
private Position[] data = new Position[0];
private int size = 0;
public PositionList(PositionList other, boolean deepCopy) {
if (deepCopy==true){
size=other.getSize();
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
}
else {
data=other.data;
size = other.size;
And so say I have this being called:
PositionList list = new PositionList();
PositionList acopy = new PositionList(list, true);
What I am doing, however, is incorrect, and Im not sure why..
The problem lies in your deep copy logic:
size=other.getSize();
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
You are setting the size field (which is redundant with the data array) but are not assigning a new array to the data field, which is presumably the whole point of your "deep" copy. You should initialize data to the other's size (or other.data.length):
data = new Position[other.data.length];
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
(And get rid of size all together)