This is a little confusing question for me to express, but I'll do my best.
So:
ArrayList<Object> fieldList = new ArrayList<Object>();
I then dump a lot of different variables to this array:
fieldList.add(objectsURL); //string
fieldList.add(X); //int
fieldList.add(Y); //int
...
If I change the variable, the values in the array change
too-confirming the array stores a reference to the memory, rather
then value itself.
However, if I then retrieve data from the array then set that...
Object object = ((String)this.fieldList.get(0));
Then set object
object = "meeep!"
objectsURL is not set to "meep!" but rather it retains its original
value.
I assume this is because the "object" is not referencing the original
variable anymore, that instead its pointing to a new immutable string
in the memory.
All expected Java behavior I think....but then, how would I go about
setting the actual original variable? is this possible in java?.
So, in other words. Given only access to "fieldList" is it possible to change the value of
"objectsURL"?
So, if:
String objectsURL = "www.google.com"
fieldList.add(objectsURL);
Is there a way to set objectsURL to "www.stackoverflow.com" using only a reference from fieldList?
I dont want to change the fact that fieldList contains "objectsURL", I want to change what string the variable "objectsURL" actualy contains.
If not, is there an alternative method to achieve the same thing?
I hope my question explains the problem well enough.
My use-case is trying to make a serialization/
deserialization system for a bunch of my objects. I was hoping to put
all the fields into a arraylist I could retrieve for both reading and
writing....thus avoiding having to hard-code long lists of
field[0]=blah and blah=field[0] and then going though constant pains
of needing to renumber them each time I add a new field before
another.
(I cant use Javas inbuilt serialization, as I am using GWT and this is client side only.)
Thanks,
I assume this is because the "object" is not referencing the original variable anymore, that instead its pointing to a new immutable string in the memory.
Correct, each time you use the assignment operator = on an object you change the object it refers to, not the object itself.
To change the values in the List, you use the .set method of an ArrayList
this.fieldList.set(0, newValue);
Since your variable is a String, there is no way you can change the String-variable through the list
Your alternatives:
using a char-array
List myList = new ArrayList();
char[] charArray = "My String".toCharArray();
myList.add(charArray);
charArray[0] = 'A';
String theString = new String(myList.get(0)); // "Ay String"
If you use a char-array, make sure that the length of the array is enough to contain the number of characters you want to have in the future, because to change the length of the array you will need to create a new array (array lists can be expanded dynamically, arrays can not)
Embed the String inside your own class (I have ignored getters and setters here)
class MyString {
public String value;
public MyString(String value) {
this.value = value;
}
}
MyString myStr = new MyString("some value");
list.add(myStr);
((MyString) list.get(0)).value = "a new value";
System.out.println(myStr.value); // will print "a new value"
Strings are immutable, so it is impossible to change the contents of a String object. Also, you cannot use the list to change what object the reference variable objectsURL points to. To achieve what you want, you will need to create a custom class that has a String member. You can then store instances of this class in a List and change the String references to via the references in the list. The changes will then be reflected in any other reference variables which refer to the objects in the list.
First, you declare a variable 'object' and assign some Object out of the ArrayList. Later you assign some other object "meeep!" to this variable. There is no reason that your 'object' variable is related to the ArrayList.
Related
While designing a small API, i was about to write a static value that references to an array of String:
public static final String[] KEYS={"a","b","c"}
I have found this to be marked as a 'security hole' in Joshua Bloch's 'Effective Java' item 14, where he proposes as an alternative, declaring te array 'private' and provide a public getter that returns an unmodifiable list:
return Collections.unmodifiableList(Arrays.asList(KEYS))
I just cant see why would this be necessary, the array in the initial statement is declared final even though its public, and its elements are immutable, how could that be modified from an external piece of code?
The array is not immutable.
You can still write:
KEYS[0] = "d";
without any issues.
final just means you cannot write:
KEYS = new String[]{"d"};
I.e. you cannot assign a new value to the variable KEYS.
final means
You can't change the Basket. Still you can change the fruits inside.
Basket is your Array instance. Fruits are your keys inside.
In first case, from somewhere else in the code, I can do
ClassName.KEYS[2] ="MyOwnValue";
But you can't modify when it is unmodifiable list.
Give a shot to read : Why final instance class variable in Java?
While the array reference itself is immutable (you cannot replace it with a reference to another array) and the Strings themselves are immutable too it is still possible to write
KEYS[0] = "new Key";
A composite object ( array , Set , List etc ) being final doesn't mean that its constituent objects will not be changed - you can still change constituent objects . final for a composite object simply means that its reference can't be changed.
For your case, value of KEYS can't be changed but KEYS[0] etc can be changed.
I'm turning crazy on this one.
What I want to do is to get an object from an ArrayList, and add it in 3 others after modifying it.
The problem is that the object I get from my ArrayList is modified aswell when I modify the others... Can't figure out why, is this normal?
Code below:
final Product tmpRef = productsRef.get(i);
Product tmp = tmpRef;
tmp.setPos(products1.size());
Log.d("test2","tmpRef:"+tmpRef.getPos()+";tmp:"+tmp.getPos());
Product tmp2 = tmpRef;
tmp2.setPos(products2.size());
Log.d("test2","tmpRef:"+tmpRef.getPos()+";tmp:"+tmp.getPos()+";tmp2:"+tmp2.getPos());
Product tmp3 = tmpRef;
tmp3.setPos(products3.size());
Log.d("test2","tmpRef:"+tmpRef.getPos()+";tmp:"+tmp.getPos()+";tmp2:"+tmp2.getPos()+";tmp3:"+tmp3.getPos());
tmp.setPos(products1.size());
"pos" is just a simple int, with a getter/setter.
LogCat output:
03-21 09:56:14.926: D/test2(6200): tmpRef:9;tmp:9
03-21 09:56:14.926: D/test2(6200): tmpRef:7;tmp:7;tmp2:7
03-21 09:56:14.926: D/test2(6200): tmpRef:0;tmp:0;tmp2:0;tmp3:0
With #FD_, #blackbelt and #Guidobaldo da Montefelt's explainations, I ended creating a simple new Porduct's constructor to be able to copy the object, and not only the reference. Thanks guys.
Essentially, you just store references in your ArrayList, so it does not matter whether you use something like Product tmp = tmpRef;. tmp still points to the same object, thus changes are applied to both.
In this case, final just means that a pointer cannot be changed once it has been set.
Just search for deep copy java for possible solutions.
final Product tmpRef
means that the Object's reference of tmpRef can not be change. Meaning that you can not do
tmpRef = null;
or
tmpRef = anotherProdocut;
after
final Product tmpRef = productsRef.get(i);,
but the content of the object could change if its member are not final.
Adding to what #blackbelt said, you are getting confused between
"final" and "immutable" concepts. If you don't want the "object's
value" to change, then you have to make it immutable (java doesn't
provide any built-in mechanism for this). final merely prevents you
from reassigning the reference to another object.
EDIT:
1. final - if a "reference" is made final, then you cannot reassign it to point to something else. if a primitive is made final, then it's value cannot change.
eg:
final int i=5;
i=10; // error
final List<String> l = new ArrayList<String>();
l.add("one"); // works
l =new ArrayList<String>() // fails
2. Immutable - you cannot change the values of attributes of the object.
if list l were immutable, then
List<String> l = new ArrayList<String>();
l.add("one"); // fails, depending on your definition/implementation of immutablility
l =new ArrayList<String>() // l is not final, so it works fine
Before doing such a thing, you should really try to understand the difference between references and objects, and more deeply, the difference between copying a reference vs copying an object.
Product is an object stored in a memory zone called Heap. "tmpRef" is a reference that contains the address that points to that object.
This code:
Product tmp = tmpRef;
does not copy any "Product" objects but it simply assign the tmpReference in a new reference variable called tmp. So, you´ll have 1 Object pointed by 2 references. Passing a reference (4 bytes in a 32bit system) is very cheap. That´s why you can pass objects in your methods as parameters. It´s what it is called "copy by reference".
The final keyword means that the reference is immutable, not the Product object.
Probably you have confusion because these logic is not applied to primitive objects, where reference copy does not exist, but primitives are always copied by value, and never by reference.
So if you want to do not change the original object, you do need to create new Product objects in the heap.
Hope this helps.
I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy
Having this method
void doSomething(String input)
{
//trick for create new object instead of reference assignment
String workStr= "" + input;
//work with workStr
}
Which is the java way for doing that?
Edit
if I use input variable as input=something then Netbeans warns about assigning a value
to a method parameter
If I create it with new String(input) it warns about using String constructor
Perhaps the solution is not to assign nothing to input, or just ignore the warning..
String copy = new String(original);
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#String(java.lang.String)
Strings in java are immutable, which means you cannot change the object itself (any operation returning a string (e.g. substring) will return a new one).
This means there is no need to create a new object for Strings, as there is no way for you to modify the original. Any attempt to do so will just result in wasted memory.
Assigning references is only a problem when the objects in question are mutable, because changes in one object will reflect in all other copies of the same reference.
hey people,
I have created a class which extends application to share certain variables. Within each activity I then use an object of that class (globalstate) as so:
gs = (GlobalState) getApplication();
I then declare local variable which reference the shared ones such as:
boolean localStr = gs.str;
Now I am under the impression this would be passed a a reference and therefore any change to localStr would be reflected in str within globalstate. However this does not seem to be the case.
Some variables created in this manor such as an array of object seem to be passed as reference and therefore any changes are reflected within globalstate however for almost every other variables (booleans, strings & ints) it seems the changes aren't reflected and therefore are being copied rather than referenced.
Have I done something wrong or is this how android works, if so how can i pass by reference? Thanks.
boolean is a value type, Java doesn't use a reference to store it. It's the same for all Java primitive types (int, long, ...). Strings are different, they are reference types but are immutable as explained by Johan Sjöberg.
That's why when using an ArrayList (for example) you will get an error if you try to use a value type like new ArrayList<boolean>(). But new ArrayList<Boolean>() will work because Boolean is a reference type, not a value type.
To avoid your problem you should use your reference everywhere (use gs.str instead of creating a local variable, localStr). I can explain it better if you don't really understand what I'm saying.
That's not only how android works, that's how java works. Strings are immutable, meaning they cannot be changed. Every time you try and modify a string a new string is created; hence the following code will leave the string named first unchanged:
String first = "first"; // First points to mem address e.g., 0x1
String second = first; // Second also does
second = "something else"; // Second now points to 0x2, first still to 0x1
It's exactly the same behaviour for all primitive types (int, boolean etc).
However, when you pass a List of objects, alterations of the list contents will be changed everywhere. This is since your objects share the same list reference (which itself doesn't change, only it's contents).