Different objects in array - java

Good time of the day to anybody reading,
I would like to ask if the following situation is possible to do in Java:
What do I want to do - create a 2D array which can have different objects in it (i.e. in [0][2] I would like to have PreRoom object, in [0][3] - Room object) and would like these object to be accessible (obviously).
How am I doing this?
1) Declare 2D array of Object type:
Object[][] map = new Object[151][151];
2) Create an object:
map[0][2] = new PreRoom(r, true);
3) But after this I'm unable to use any method of PreRoom/get any its property, i.e. unable to do:
map[0][2].x;
//or
map[0][2].getR;
Am I doing this wrong? Or it's impossible to do and therefore the only solution is to create a unified object for current 2?
Thanks in advance.
EDIT: solution found, thanks for the replies.

You declare Object[][] map = new Object[151][151]; So anything you store in it will be an Object (Obviously), so how does it know that your Object in map[0][2] is of PreRoom? You will need to cast it as such so you can use any methods of PreRoom
((PreRoom)map[0][2]).methodName();
Be careful in future if you are storing numerous types in your map. You may find instanceof useful if you ever need to iterate through your map not knowing which values are of what.
For example;
if(map[x][y] instanceof PreRoom) {
//map[x][y] is an instance of your PreRoom class
PreRoom preRoomObj = (PreRoom) map[x][y];
}

You can define an interface or abstract class that will be implemented/inheritedd by both PreRoom and Room class.
Then you array could be something like
<InterfaceName/AbstractClassName>[] = new <InterfaceName/AbstractClassName>[151][151];
You interface or base class should declare the common methods and variable.

Here you need to explicitly type cast to call the methods on that object
((PreRoom)map[0][2]).x

Related

Is there a way to map a string to a method that returns a different type depending on the string?

I want to map a String to a method that builds a certain object, but not necessarily from the same class for every String. Looking around on here a nice solution was to have a Map<String, ObjectBuilder>, ObjectBuilder<T> being an interface with an abstract method T buildObject().
I then have multiple classes, let's say Object1Builder implements ObjectBuilder<Object1>, Object2Builder implements ObjectBuilder<Object2> and so on.
I can then construct my map like so :
stringToBuilder = new HashMap<String, ObjectBuilder>(){{
put(string1, Object1Builder);
put(string2, Object2Builder);
put(string3, Object3Builder);
}};
And I can then do Object1 myObject1 = stringToBuilder.get(string1).buildObject()
Problem is, I get an error
Raw use of parameterized class 'ObjectBuilder'
in IntelliJ when I instanciate and construct stringToBuilder and I understand it has something to do with not specifying the generic of the interface ObjectBuilder when constructing the map, but I don't see how I could circumvent this. Moreover, I'm not very satisfied with the fact that I'm storing these classes in a map, I wish I could access them through the map without having the whole instance in the map.
You've probably noticed I'm quite new to Java and all this but please be sure I'm trying my best. Thank you in advance :)
What you want will never be possible without explicit casts. The reason is that there is no direct relation between the map keys (strings) and values (ObjectBuilders).
If you can switch from strings to use the T values as map keys, this can be done with a little internal casting.
First, declare your map as Map<Class<?>, ObjectBuilder<?>>. Note the two wild-cards; the compiler cannot help us with enforcing that the keys and the values have the same generic type. That's what we need to do ourselves.
Next, initialize it as necessary. I dislike the anonymous class with initializer you use, so I'll use Map.of:
Map<Class<?>, ObjectBuilder<?>> classToBuilder = Map.of(
Object1.class, Object1Builder,
Object2.class, Object2Builder,
Object3.class, Object3Builder,
);
Finally, we need a method to get the builder:
#SuppressWarnings("unchecked")
private <T> getBuilder(Class<T> type) {
// Omitted: presence check
return (ObjectBuilder<T>) classToBuilder.get(type);
}
This can now be used as follows:
Object1 object1 = getBuilder(Object1.class).buildObject();

How do I set and get a Vector<Integer> in two different classes?

I need to set and get a Vector in two different classes but I seem to be losing the size of the Vector in the process. If I do v.size() I get 100 for example. Then I use a setter. Then in another class I use a getter to access this Vector again. If I do v.size() in this new class I get 0. The below code is a rough example of what I have, as I can't copy paste my code exactly, since it's part of a larger private project.
public class Params {
private Vector<Integer> _v = new Vector<Integer>();
public Vector<Integer> get_v(){return _v;}
public void set_v(Vector<Integer> _v){this._v = _v;}
}
public class a {
v.add(10);
System.out.println(v.size()); //returns 1
Params p = new Params();
p.set_v(v);
}
public class b {
Params p = new Params();
v = p.get_v();
System.out.println(v.size()); //Returns 0
}
When you make Params = new Params() on b you create a new object of the class Params, and this new object initializes a new empty Vector on the _v property.
You should pass the object created on a to b so this class can use it.
Your problem is you are re initializing your Params class. In essence, you are creating two Params Objects and both have their own Vector, they are completely separate. You could solve this by making your vector static thus making the different instances have the same vector.
You create two difference instances of Params. Each of them has a different variable named _v.
To solve this problem You need to use only a single copy of Params or define _v as static.
Some tips not directly related to the question
Don't use Vector. The use of Vector is deprecated.
If you are not in a multithreading environment use an ArrayList, if you are in a multithreading environment use a synchronized List created with the synchronizedList method of Collections class.
Name your classes in uppercase.
Give readable names to your classes and variables.
Thanks so much for all the help! Wow I've never used this before and I was very pleased with the results. So I solved my problem, I basically just defined my Params once and pass it on to each class instead of recreating it.

Is there a way to create an Immutable object in java, when the object have mutators?

This code is familiar.
List<Character> list = new ArrayList<Character>();
// populate the list
list.add('X');
list.add('Y');
// make the list unmodifiable
List<Character> immutablelist = Collections.unmodifiableList(list);
Now i have a typical Model Class with variables, getters and setters. Can i make that Object immutable,after i have invoked the setters i want? Something like this is my dream...
Person person = new Person();
person.setFirstName("firsName");
person.setLastname("lastName");
// i have a lot to set!!- Person is pretty large
// some way to do this
Person stubborn = Object.immutableObject(person);
I know there is no Object.immutableObject()..But is it possible to achieve something like this??
There's no general way to get this behavior.
You can create an ImmutablePerson class with a constructor that would accept a Person and construct an immutable version of that Person .
There is no way to do it without doing some work.
You need to either get a compile time check by creating a new immutable object from the mutable one as Eran suggests, add some code for a runtime check, or get a weaker compiler time check by using a split interface
e.g
interface ReadOnlyPerson {
int getX();
}
interface ModifiablePerson extends ReadOnlyPerson{
void setX();
}
class Person implements ModifiablePerson {
}
You can then pass out the immutable reference after construction.
However this pattern does not give a strong guarantee that the object will not be modified as the ReadOnlyPerson reference can be cast etc.
Sure, just have a boolean flag in the Person object which says if the object is locked for modifications. If it is locked just have all setters do nothing or have them throw exceptions.
When invoking immutableObject(person) just set the flag to true. Setting the flag will also lock/deny the ability to set/change the flag later.

java naming an object from an aspect of another object

I am trying to create an object named after an aspect of another object. I assumed that I would need to change count.counts value into a string in order for this to work but I cannot work out how to reference this in creating the new object.
This is the code i have;
String no=Integer.toString(count.count);
BattleCruiser =new BattleCruiser();
EList.add(battle);
count.count++;
An object does not have a name. We give names to variables so that we know what they point to, what they represent.
Dynamically name a variable does not seem very useful, since you need to reference it afterwards. If the reference is dynamic too, then why not use a data structure instead? For instance:
If you're trying to give numbers to your variables, for instance ship0, ship1... then you can use an array ships instead, and access ships[0], ships[1].
If you want more general names that reference objects, you can use a Map<String,Object> instead.

Creating a deep copy method, Java

I want to make a deep copy method. I seeked help here the other day with this issue, but that was for a copy constructor. Now I need a regular method. I have the code created (nonworking), but I'm just not understanding it completely.
public GhostList deepCopy(){
int length=this.getLength();
GhostList jadeed=new GhostList();
Ghost[] data = new Ghost[length];
for (int i=0;i<this.getLength();i++){
data[i] = new Ghost();
data[i].setX(this.ghosts[i].getX());
data[i].setY(this.ghosts[i].getY());
data[i].setColor(this.ghosts[i].getColor());
data[i].setDirection(this.ghosts[i].getDirection());
}
return jadeed;
}
Now when I create a new GhostList named jadeed, and then under that I create a new data array of ghosts, does it know that data belongs to the jadeed GhostList? I dont see how the two can be associated, even though they should be.
Also, I'm not getting the lengths to match up for the copy and this.object. What is my problem?
You created a new GhostList and a new Ghost array.
You fill in the Ghost array and return the GhostList but the returned GhostList has nothing to do with the Ghost array.
You should add all the new ghosts to the GhostList
First, you mentioned a copy constructor. If you already have that working, then all you need to do in your deepCopy method is:
return new GhostList(this);
Let's forget that for now and get back to the code you posted. You are creating an array named data but you never used it anywhere. Aren't you supposed to assign this array to jadeed? Something like:
jadeed.ghosts = data;
And finally, instead of calling the method deepCopy, it would be better to call it clone and implement the Cloneable interface. Doing this allows everyone to know how to get a copy of your object using a standard interface.
Your GhostList class will have as its data member a reference to the array of Ghost. You've not shown us the class definition, so lets say that member is named foo. Now all you need to do is make the foo reference of the newly created jadeed object refer to the array of Ghost which you've created and populated. You can do it as:
jadeed.foo = data;
before you return jadeed.
If GhostList and everything it's composed of is Serializable, you can serialize the GhostList instance into a byte array and re-read it. It's a few lines of code, unless you use `Jakarta Commons Lang - one line of code:
http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/SerializationUtils.html#clone%28java.io.Serializable%29

Categories

Resources