I need to know why the following happens, in this code (the last two block) I expect the exact same output yet the local objects (who are mere references to the ones in the list, right?) are in their old state while the list is updated. I have a bug because of a similar copying procedure in my gamecode (tilebased, objects swap positions, so I thought why not just swap their references...)
Example:
package game;
import java.util.ArrayList;
public class Tester {
private String s;
private Foo foo;
public Tester(String s, String f) {
this.s = s;
this.foo = new Foo(f);
}
class Foo {
private String f;
public Foo(String f) {
this.f = f;
}
}
#Override
public String toString() {
return foo.f + ":" + s;
}
public void swap(Tester other) {
String tempS = this.s;
Foo tempFoo = this.foo;
this.s = other.s;
this.foo = other.foo;
other.s = tempS;
other.foo = tempFoo;
}
public static void main(String[] args) {
ArrayList<Tester> test = new ArrayList<Tester>();
test.add(new Tester("First", "1"));
test.add(new Tester("Second", "2"));
System.out.println("After initializing list");
for (Tester t : test) {
System.out.println(t);
}
Tester first = test.get(0);
Tester second = test.get(1);
Tester tmp = first;
first = second;
second = tmp;
System.out.println("\nAfter temps");
System.out.println(first);
System.out.println(second);
System.out.println("\nList changed after temps?");
for (Tester t : test) {
System.out.println(t);
}
System.out.println("\nAfter swap");
first.swap(second);
System.out.println(first);
System.out.println(second);
System.out.println("\nList after swap");
for (Tester t : test) {
System.out.println(t);
}
}
}
And the output:
After initializing list
1:First
2:Second
After temps
2:Second
1:First
List changed after temps?
1:First
2:Second
After swap
1:First
2:Second
List after swap
2:Second
1:First
I think I was a bit unclear, I always print out first then second (the objects) so "After swap" should look exactly like "List after swap", the list has changed after the swapping of the local objects, the local objects (again, mere references to the ones in the list?) have not.
To the comment in the answer: While my confusion is cleared and my problem solved I was asking whether it is possible to get the actual reference of the list to the object so that when I point it to something else the list will also automagically point to that something else. In the example below Foo a points first to object Foo with attribute A, but this reference it got from list.get(). Now if I point it to new Turtles() the list will still point to Foo with A.
I was hoping for a "hard" reference, so that when I point to turtles, the arraylist points to turtles.
This would make swapping easier but I am yet unsure of how to implement a list that can do this (if at all possible), this would suit the specific needs of my game very well.
What you need to bear in mind when working with objects is that the variable which holds the object doesn't actually represent the object. The value of the variable is a pointer in memory to the place where the object exists.
An ArrayList of a certain type of object, by extension, doesn't actually hold objects. It holds object references, or pointers to object locations in memory.
When you say:
Object a = new Object();
Object b = new Object();
a = b;
you're setting a to the value of the pointer to b; in other words, since both a and b point to the same object in memory, changing one changes the other.
Now to answer your question, with this in mind. If you pull two object references out of an ArrayList, and then swap them, you've swapped the references to the objects; however, the references haven't changed location in the ArrayList. This explains the first three outputs.
Once you do an internal swap, however, you've changed the values stored in each object. This means that, though the pointers to the first and second objects are still the same in memory, their internal information has been swapped.
This explains the last two outputs.
(Note, this is also why you have to use System.arraycopy instead of setting int[] a equal to int[] b; if you were to do the latter, then changing a would change b.)
Actually your swap method does not swap the objects themselves but only the values they are containing, the String s is swaped by value, the object foo is swaped by reference.
when you get an element from the list using get(index) you actually get a reference to that object in addition to that internal reference witch the list is holding, so you have there two references pointing to the same object.
to really swap element of a list you should be using the set method of the List with something like that:
Tester tmp = test.get(index);
test.set(index, test.get(index+1));
test.set(index+1, tmp);
this way the elements are swaped in the list so iterating over it will print the result you expect. the swap method you have will be obsolete.
Related
I've learnt that for arrays the clone method is well-behaved and we can use it. But I thought that the type of the elemetns the arrays hold should have implemented Cloneable interface. Let me provide some example:
public class test {
public static void main(String[] args){
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = arr_t.clone();
an_arr[0]= new Test(5);
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //10
}
public static class Test{
public int test;
public Test(int test) {
this.test = test;
}
}
}
DEMO
I thought that 5 should have been printed twice. The reason for that is by clonning arrays we're creating new arrays containing references to the objects the first array holded (Because the type of the elemnts does not implement Cloneable). Couldn't you straighten the things out?
It's not clear if it's neccesary the array element's type implements Cloneable.
It's a simple concept, but seems hard to explain. When you clone the array, you will have two district arrays in memory, but with the same values in their indexes.
In your second array an_arr doing an_array[0] = new Test(5) you will put another reference in the slot 0.
But the index 0 of the clone is in a different place from the cloned array.
Your example is valid if you do
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = arr_t.clone();
an_arr[0].test = 5; // look here, I changed the object
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //5
Now both will print the same value because they hold the same reference to the same object, but the place where this reference is stored, is different.
.clone() makes what's called a "shallow copy". That means it copies as little as possible when running the method; instead of copying the contents of the array, it just creates references to the contents of the original array.
If you change the references by calling:
new Test(5)
Then you've overwritten that reference, and get new data.
The alternative is a deep copy of the array. Those can be expensive to do on bigger objects, so they're not the default.
An array's clone() does the same thing regardless of type of array: it creates a new array of the same type and size and then it assigns (=) each element of array to each element of the new array. That's it.
So if you have a 3-element array pointed to by arr, and arr.clone() returns newArr, then after the creation of the new array it simply does this:
newArr[0] = arr[0];
newArr[1] = arr[1];
newArr[2] = arr[2];
That's it. The type of array is not relevant. There is no "cloning" or anything involved in the elements. It doesn't know (or care) if the element has some kind of method to clone (in fact, there is no general API for cloning in Java, anyway, so this would be impossible).
(And by the way, even if it somehow put cloned objects into the new array, the result in your example would still be the same, because you are assigning a new value into the array, so it doesn't matter what was there before.)
So your question is basically why:
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = new Test[1];
an_arr[0] = arr_t[0];
an_arr[0] = new Test(5);
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //10
and you can figure it out from there.
The "problem" here is that arrays hold references to object, not objects. Further, this has nothing to do with cloning.
When you execute:
an_arr[0] = new Test(5);
You are assigning the new object's reference to the first element.
Also, each array has its own references to Test objects. When you clone the array, only the references are copied (not the objects to which they refer).
Hi I'm new to Java and I just encountered the following problem in a homework. I'm required to write a class that adds a new object to list when a void method is called. As a hint, the structure of an iterator method is given, so the core structure of my code now looks like this:
public class objectList implements Iterable<Obj> {
private ArrayList<Obj> objectList;
attribute_a A;
attribute_b B;
attribute_c C;
public objectList(attribute_a A, attribute_b B, attribute_c C){
objectList = new ArrayList<Obj>;
this.A = A;
this.B = B;
this.C = C;
}
public void extendList(attribute_a A, attribute_b B, attribute_c C){
objectList.add(new Obj(A,B,C));
}
public Iterator<Obj> iterator(){
return objectList.iterator();
}
#Override
public String toString(){
newstr = "";
for(i = 0;i<objectList.size();i++)
{
//Assuming Obj has the method toString()
//It prints out all details of each object, then join into one string
newstr += objectList.get(i).toString();
}
return newstr;
}
}
I'm told to just use java.util.iterator, not a custom iterator - so it saved me from defining HasNext(), next(), remove(), etc.
Edit: my goal is to be able to print objects stored in objectList, after extendList() is called several times i.e. there are many items stored in the list. Now I can only print the latest item in it (only 1 item is in the list).
What do I have to do to make the "cursor" automatically point to next item -> get attribute -> perform tasks on the attribute -> next item, etc. until the list is finished?
Let's see what's going on here...
So, you have a class, and it has a field called objectList. When you create a new objectList instance, the constructor gets called and the field is initialised to an empty list. So far so good. (However, why do you have the fields called A, B and C? They don't seem to be used at all, so it seems confusing to require someone to pass three parameters to your constructor that are effectively ignored.)
Then, whenever extendList is called, a new Obj is added to the instance's list. That looks about right. This means that at any given point, we can say that the size of the objectList is equal to the number of times that extendList has been called on that object.
Equally, calling iterator will just return the standard Java iterator for this list. So that iterator should visit every Obj in that list, which will be a number of items equal to the number of times that extendList was called on the same objectList object.
So - why doesn't it work?
It's not clear from the code you've posted. Your class itself looks OK, so the conclusion is that you must be calling it wrong. My guess is that you're actually constructing multiple instances of the class - every time you call the constructor, you create a new instance with different fields. For example, this won't do what you expect:
new objectList().extendList("A1", "B1", "C1");
new objectList().extendList("A2", "B2", "C2");
new objectList().extendList("A3", "B3", "C3");
return new objectList().iterator();
because a new instance is created each time, effectively throwing the state away from before. You'd want to rewrite that as:
objectList ol = new objectList();
ol.extendList("A1", "B1", "C1");
ol.extendList("A2", "B2", "C2");
ol.extendList("A3", "B3", "C3");
return ol.iterator();
If that doesn't solve it, look at how you're using the class, count how many times you call extendList on the same instance that you get the iterator from. If in doubt - get Java to count for you - add System.out.println("in extendList") calls (and perhaps some in the constructor) to see what gets called when. In fact, if there's a concern that different instances of the class are being used, you can get a unique identifier for the specific instance with System.identityHashcode(), e.g.:
public void extendList(attribute_a A, attribute_b B, attribute_c C){
System.out.println("Extending list for " + System.identityHashcode() + " with " + A + ", " + B + ", " + C);
objectList.add(new Obj(A,B,C));
}
Failing that, it may be worth getting familiar with how to use a debugger, and stepping through your program line by line. This will let you see the state of your program at every step, and hopefully it'll make it clear to you where things start diverging from your expectations.
(I'll also encourage you to use standard Java naming conventions, as your code is surprisingly challenging to read at the moment without them. Class names should start with capitals (and be in UpperCamelCase). Variables and field names should start with lower case letters (and be in lowerCamelCase). At the moment your class name looks like a variable, and your fields look like generic parameters. new objectList() just looks wrong!)
Try initializing this objectList = new ArrayList<Obj>; out side the constructor,
private ArrayList<Obj> objectList=new ArrayList<Obj>();
I'm working on an assignment that deals with array manipulations for Java. Right now I have to delete elements inside the middle of an array. Now I know that arrays, once they're created cannot be changed in length. So I decided to make a new object, and have the former reference point to my new array.
public class A{
public static void main(String[] args){
B test = new B(val);
test.cut(2,4);
test.display();
}
class B{
private Obj[] array;
B(Obj val){
construct something
}
public void cut(int i, int j){
B newObject = new B(val);
...
newObject.array = this.array;
newObject = this;
}
}
The issue is that when I display the test object, it will only show me the original test object contents rather than newObject contents. Since this is a void method, I can't return an object. How do I reference the new object then? The last two lines for my cut method seem to have no effect at all. I know that ArrayList would be preferable for things like this, but this being a homework assignment we are forced to use arrays.
Now I know that arrays, once they're created cannot be changed in length.
This is true.
But the reference pointing to an array inside the B object instance can be changed (as you didn't declare it final):
public void cut(int i, int j){
Object[] newArray = new Object[len];
//... copying array content ...
this.array = newArray;
}
Beware of the thread safety issues such mutability causes. Mutable objects are usually frowned upon...
If the rules of assignment allow the use of class Arrays, this is what you can use instead of your own cut method:
newArray = Arrays.copyOfRange(oldArray, from, to);
In the method cut you create a new object of B then assign the the this reference to it. This has not effect as you have found because the this reference (the actual object) is not changed at all, The newObject is visible only inside this method, once it is terminated, the object is gone.
While you are in the same class B you dont have to create a new Object of it just for the purpose of altering the data it holds. You could just create a new array and copy the original content to it.
For copying the content you could use the method System#arraycopy. If you are not permited to use any jdk helping functionalities, then you could just loop over the original array and copy elements into the new one as you want.
Is there a way to move the entire contents of an ArrayList to another instance of ArrayList in O(1)?
I.e.: only the reference to the backing array is passed from one instance to the other (elements are not copied one by one).
For example:
ArrayList<String> a = new ArrayList<>(Arrays.asList("A", "B", "C"));
ArrayList<String> b = new ArrayList<>();
a.moveContentsTo(b);
// 'a' is now empty, while 'b' contains everything that 'a' did before and 'a != b'
// It is desired that the 'moveContentsTo' method is O(1)
Even better, is there an ArrayList#swapContents(ArrayList) method?
Further explanation and use-case:
Further explanation 1: the references of 'a' and 'b' must not be exchanged. I am not looking for tmp = a; a = b; b = tmp; type of solutions.
Further explanation 2: The operation must be ~O(1) in time.
The use-case: This is useful when an object wants to encapsulate a list constructed outside:
public class A {
private ArrayList<String> items = new ArrayList<>();
/**
* This method takes the sole ownership of the contents. Whoever
* passed the list from the outside will not be able to modify
* contents of 'this.items' from outside the class.
*/
public AnImmutableObject(ArrayList<String> items) {
if (items != null) {
items.moveContentsTo(this.items);
}
}
/**
* Other collections that do not provide the 'move' functionality
* must be copied. If we just stored the reference to 'items' we
* would break encapsulation as whoever called the constructor
* still have write capabilities to the collection.
*/
public A(Collection<String> items) {
if (items != null) {
this.items.addAll(items);
}
}
public List<String> getItems() {
return Collections.unmodifiableList(items);
}
}
Notice that we want to avoid making a copy (to increase speed and decrease memory usage). The crucial bit is that the callee must lose the ability to modify the (now encapsulated) ArrayList.
#Lirik answer is greate +1. However, if you are looking for a real ArrayList#swapContents(ArrayList), here is how you can do it:
public static void swapContents(ArrayList<String> listA, ArrayList<String> listB)
{
List<String> temp = new ArrayList<String>(listA);
listA.clear();
listA.addAll(listB);
listB.clear();
listB.addAll(temp);
}
AFAIK, it's very not Java-like to keep track of "ownership" of references (at least on the programmer's side) which is why I doubt that you'll find the std::move()-like functionality that you want. It just isn't very commonly needed in Java.
I guess C++ needs to keep track of object ownership explicitly because there is no garbage collection.
I think that your best bet is to create a defensive copy in your constructor and save space by relying on copy constructors of immutable objects:
public class AnImmutableObject {
private final List<String> items;
/**
* Creates a new immutable object with the given list of items.
* Always deep copy from an outside source, because we can't know if the
* calling code will modify that collection later.
*/
public AnImmutableObject(Collection<String> items) {
// It's a constructor. We know items needs to be set.
// We are creating a new array list, using its constructor which deep
// copies the collection, and immediately wrapping it to make it truly
// immutable. We are guaranteed that no one will hold a reference to the
// mutable view of the new ArrayList.
this.items = Collections.unmodifiableList(new ArrayList<String>(items));
}
/**
* Creates a new immutable object with the same items as another.
* Copying the reference here is completely safe because we
* enforce the immutability of the items array.
*/
public AnImmutableObject(AnImmutableObject source) {
items = source.items;
}
public List<String> getItems() {
return items;
}
}
At this point, you can "pass the arrays around" (really share them) in O(1) between your own immutable objects:
ImmutableObject a = new ImmutableObject(Arrays.asList("A", "B", "C")); // O(n)
ImmutableObject b = new ImmutableObject(a); // O(1)
Hopefully, something like this can suit your purposes.
Another route you could go is use Guava's ImmutableList. Since these are immutable, you can safely copy the reference to the ImmutableList in a constructor.
The main approach is about making it safe for you to copy references to the lists rather than taking ownership over them.
This should do it:
ArrayList<String> a = new ArrayList<>(Arrays.asList("A", "B", "C"));
ArrayList<String> b = a;
a = new ArrayList<>();
Conceptually speaking, a is now empty and b contains what a contained before. There was a single assignment and no copying of data, which is about the fastest you can do it. Does that satisfy your requirement, or do you actually want a to still reference the same array except that the given array should now be empty?
Update
I don't believe that in C++ the time complexity for the move operation is O(1) either. It's also prudent to point out that "because classes in Java use reference semantics, there are never any implicit copies of objects in those languages. The problem move semantics solve does not and has never existed in Java." (see the answer by FredOverflow: C++ Rvalue references and move semantics)
Is there a way to move the entire contents of an ArrayList to another ArrayList so that only the reference to the backing array is passed from one to the other (i.e., so that elements are not copied one by one).
Given the above statement, then if you copy something from array a to array b in Java, both arrays will reference the same data. All that you do with move semantics in C++ is that you save the temporary object which needs to be created in order to make such a copy:
X foo();
X x;
// perhaps use x in various ways
x = foo();
The last one does:
destructs the resource held by x,
clones the resource from the temporary returned by foo,
destructs the temporary and thereby releases its resource.
Move semantics does:
swap resource pointers (handles) between x and the temporary,
temporary's destructor destruct x's original resource.
You save one destruct, but only in C++... the above problem does not exist in Java! See this article for more details on move semantics: http://thbecker.net/articles/rvalue_references/section_02.html
I am unable to understand how this works
public void addToRule(Rule r) {
if (!getRuleList().contains(r)) {
getRuleList().addElement(r);
}
}
If I run this code:
obj.addToRule(r);
System.out.println(getRuleList().contains(r));
it prints out true how can this happen?
btw ruleList is a vector member of the main class and is not a static variable(don't think this matters but sharing anyway).
import java.util.Vector;
public class RuleEngine{
private Vector ruleList = new Vector();
public Vector getRuleList(){
return ruleList;
}
public void addToRule(Rule r){
if(!getRuleList().contains(r))
getRuleList().addElement(r);
}
public static void main(String args[]){
RuleEngine re = new RuleEngine();
Rule r = new Rule("Rule1");
re.addToRule(r);
System.out.println(re.getRuleList().contains(r));
}
}
class Rule{
public String name = "";
public Rule(String nam){
this.name=nam;
}
}
OK people have told me that this works because of the pass by reference in java. I get it. but what can i do to get a copy of that object instead of its reference?
I'm guessing getRuleList() is returning a reference to a List (or something similar). Think of it as a pointer (or more specifically, a copy of a pointer) if you're familiar with C. You're working on the same underlying instance of the object when you call getRuleList().
For proof, try: System.out.println(getRuleList() == getRuleList()); The == operator will only compare if the two references are pointing to the same object (not a deep equal like .equals). You'll see that until you call setRuleList() with a different object reference that the statement holds true.
These assumptions are of course without seeing your full code.
So, to answer your questions you have to at first know how Java passes Variables.
a Variable has a value:
int i = 1234;
Person p = new Person("Peter");
Now, the Variable i contains exactly 1234, while the Variable p contains the Memory Adress of the created Person.
so i contains 1234 and p contains the adress (let's say a4dfi3).
anyMethodYouLike(p);
System.out.println(p.getName());
public void anyMethodYouLike(Person somePerson) {
somePerson.rename("Homer");
}
so in this example, we give the Method anyMethodYouLike the Variable p... wait! we give the Method the value of the Variable (a4dfi3). The Method then calls rename on this Variable (which still has the same adress as p has, hence it modifies the same Person that p points to).
So, after the Method, the Name of the Person p points to, gets printed, which results in "Homer".
someOtherMethod(p);
System.out.println(p.getName());
public void someOtherMethod(Person somePerson) {
somePerson = new Person("Walter");
}
In THIS example we still give the adress of our Person called "Peter" to the Method. But this time, the Method creates a new Person in somePerson (therefore overriding the adress in somePerson to.. let's say 13n37s.
BUT! the Person at a4dfi3 wasn't changed! The print call still outputs "Peter" and not "Walter".
Now, let's see how this behaves with primitives:
someMethod(i);
System.out.println(i);
public void someMethod(int someInt) {
someInt++;
}
So, the Value of i (1234) gets passed to someInteger. Then someInteger gets incremented to 1235. But i is still 1234.
This is the big difference between Objects and primitives in Java.
Hope I could help,
Ferdi265
From your comments it looks like you have not completely understood what the difference is between a value and a reference in Java. Basically, objects are always passed around as references in Java.
Consider
class Test {
private List list = new ArrayList();
public List getList() {
return list;
}
}
The getList() method will return a reference to the list object. It will not return a copy of the list object. Doing something like
Test test = new Test();
String s = "ABC";
test.getList().add(s);
System.out.println(test.getList().contains(s));
Will return true since the first time getList() is called, a referece to the list is returned, on which add(s) is invoked. The second time getList() is called, it returns a reference to the same list, not a copy of it, not a new list - the same reference. Calling contains(s) will return true since it the same list onto which the object s was added.
Consider this, however.
Test test1 = new Test();
Test test2 = new Test();
String s = "ABC";
test1.add(s);
System.out.println(test2.getList().contains(s));
This will print out "false". Why? test1.getList() returns a reference to the list inside test1 and test2.getList() returns a reference to the list inside test2. Here, s was added to test1:s list, so it will not be contained inside test2:s list.
It should always print true, because you add the rule to the rule list in case it is not there. What happens is:
you tell the object to add add a rule to its rule list
the objects checks if the rule exists, and if it doesn't, adds it
So it is guaranteed to contain the rule after the code is executed.