i am copying object tt to ttt and i want to make change to ttt only but when i update ttt dunno why it update my tt along???? it's my makechange() function got problem?
this is main class:
package test;
public class Test {
public static void main(String[] args) {
Solution sol;
sol= new Solution();
sol.add();
sol.copy();
//this makechange function only update ttt only!!
sol.makechange();
sol.disOld();
System.out.println("===============");
sol.disNew();
}
}
this is new class:
package test;
import java.util.ArrayList;
import java.util.List;
public class Solution {
Object[][] tt=new Object[2][2];
Object[][] ttt=new Object[2][2];
List l = new ArrayList<>();
public void add(){
l.add(100);
tt[0][0]=l;
l = new ArrayList<>();
l.add(123);
tt[0][1]=l;
l = new ArrayList<>();
}
public void disOld(){
for(int i=0; i<tt.length; i++){
for(int j=0; j<tt[i].length; j++){
System.out.println(tt[i][j]);
}
}
}
public void copy(){
ttt=tt;
}
public void makechange(){
l.add(99);
ttt[1][0]=l;
}
public void disNew(){
for(int i=0; i<ttt.length; i++){
for(int j=0; j<ttt[i].length; j++){
System.out.println(ttt[i][j]);
}
}
}
}
this is my output:
[100]
[123]
[99]
null
===============
[100]
[123]
[99]
null
this is my expected output should be like this:
[100]
[123]
null
null
===============
[100]
[123]
[99]
null
Because = just copies the reference (pointer), not the object, so the real object you're referencing is the same. I suggest you use a copy constructor as explained here.
You can read a more extended explanation here (it's about ArrayList, but you can extrapolate to any other object).
Extract from that answer:
b = a
Keep in mind this lines DOES NOT copy the whole list a to b, but only
copies the reference to the list. Now both a and b reference (point)
to the same List. So it doesn't matter if you use a.add() or b.add(),
you'll be modifying the same List.
To help you understand the above, check the following diagram
The left diagram corresponds to when you do Object[][] tt=new Object[2][2];. You can see that you create an Object[2][2] instance in memory, which is the circle, and you assign a pointer (reference) to it called tt, which is the rectangle.
The right diagram corresponds to when you do ttt = tt. This means: "make ttt point to same object as tt". It does not copy anything for you. So now both tt and ttt point (reference) the same object instance in memory. So if you use tt or ttt, you will be modifying the same object instance.
I hope this clarifies what you're doing. As for fixing it, you should copy each element of the array one by one as explained in Duncan's answer. More generically, you should use a copy constructor to copy objects as I linked above.
The = just makes both references point to the same object. If you want to make a copy(in general), then have a look at Cloninng(Not Recommended) in Java or consider a Copy-Constructor.
To solve your problem, change your copy method to the following:
public void copy(){
for(int i=0; i<tt.length; i++)
for(int j=0; j<tt[i].length; j++)
ttt[i][j]= tt[i][j];
}
This is not how you copy an array:
public void copy(){
ttt=tt; // booo, hisss, etc.
}
After this method executes, ttt points at exactly the same array as tt. Changes made to that array are visible through both variables.
You need to properly copy the array, e.g. using a technique from How do I copy a 2 Dimensional array in Java?.
Related
I want to know how do you access an attribute in a class inside an array like an example below:
import java.util.*;
public class DogTest{
public class Dog {
int Quantity;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
Dog dogs[] = new Dog[15];
for ( int i = 1; i <=15; i++){
System.out.println("Enter number of Dogs ");
dogs[i].Quantity = scan.nextInt();
}
}
}
The code above does not seem to work. dogs[i].Quantity is derived from my C++ knowledge by the way.
Error msg:
Exception in thread "main" java.lang.NullPointerException
Is my structure wrong? Or there is another way to do it?
Arrays start at position 0. So at end of your loop you try to access dogs[15] which does not exist. Essentially an array of size 15 is accessed by numbers 0-14. This may be the problem.
Try starting loop like this
for(int i=0;i<15;i++)
{
}
First of all declare a class for itself, not as an inner class like you did.Never give fields first uppercase letter, that is naming convention.
public class Dog{
int quantity;
}
And, your actual problem is that when you declare an array of dogs, you declared an array of size, in your case, 15 but it doesn't contain any objects. You just initialised and array which holds 15 nulls and can be filled with Dog objects. And because that you get a null pointer exception.So, first you should fill your array with the dog objects, something like this:
for (int i = 0; i < dogs.length; i++){
dogs[i] = new Dog(); // calls a constructor for Dog object
}
And, after that, you can access your objects trough for loop to change a field quantity
for(int i = 0; i < dogs.length; i++){
dogs[i].quantity = i;
}
Also, I would recommend to make your fields private and make getter and setter methods for accessing and changing their value.
Edit: And yes, mikekane was right about the array size, you would get an ArrayIndexOutOfBoundsException just after you fix this problem with the code you've tried to solve it...
[Background note: I am a new Java programmer with a C++ background, so is a little confused about how arguments are passed around in Java.]
While reading and writing some code, I came to the following case
public class B{
int[] intArr;
Vector<String> strVec;
void mutator(){
// modifies intArr and strVec
}
}
public class A{
B bOfA;
A(B b){
bOfA = b;
}
void foo(){
bofA.mutator();
}
}
foo() in A definitely modifies bOfA, but what about b, the object that is passed in? Will its fields/data members be modified as well?
Are the fields shallow or deep copied?
Are strVec and intArr treated differently, because strVec is a container and inArr is an array, which might be implemented as some kind of pointers, therefore behave quite differently depending on if it is shallow or deep copied.
Thank you.
A (late) update with real code and somewhat surprising (I was assuming the pass-by-value mechanism interpreted in the C/C++ way) results:
import java.util.Vector;
public class B{
int[] intArr = null;
Vector<String> strVec = null;
int x = 0;
String s = null;
B(int sz){
x = 0;
s = new String("ini");
intArr = new int[sz];
strVec = new Vector<String>(sz);
for (int i=0; i<sz; i++){
intArr[i] = 0;
strVec.add( new String("xx") );
}
}
void mutator(){
x = -1;
s = new String("mute");
int sz = intArr.length;
strVec = new Vector<String>(sz);
for (int i=0; i<sz; i++){
intArr[i] = -1;
strVec.add( new String("aa") );
}
}
}
import java.util.Vector;
public class A{
B bOfA=null;
A(B b){
bOfA = b;
}
void foo(){
bOfA.mutator();
}
}
import java.util.Vector;
public class C{
public static void main(String[] args){
B b = new B(3);
A a = new A(b);
System.out.println("Contents of B before:");
System.out.println(b.x);
System.out.println(b.s);
for(int i=0; i<3; i++){
System.out.println(b.intArr[i]);
System.out.println(b.strVec.elementAt(i));
}
a.foo();
System.out.println("\n\nContents of A:");
System.out.println(a.bOfA.x);
System.out.println(a.bOfA.s);
for(int i=0; i<3; i++){
System.out.println(a.bOfA.intArr[i]);
System.out.println(a.bOfA.strVec.elementAt(i));
}
System.out.println("\n\nContents of B after:");
System.out.println(b.x);
System.out.println(b.s);
for(int i=0; i<3; i++){
System.out.println(b.intArr[i]);
System.out.println(b.strVec.elementAt(i));
}
}
}
And the results by cygwin:
Contents of B before:
0
ini
0
xx
0
xx
0
xx
Contents of A:
-1
mute
-1
aa
-1
aa
-1
aa
Contents of B after:
-1
mute
-1
aa
-1
aa
-1
aa
Java passes everything by value. But, the value of Object(s) are references.
Both the array and the Vector are shallow copies.
Arrays are reference objects. When you assign them, they are not copied at all - what happens there is similar to assigning an array to a pointer in C++.
When you copy an array using System.arraycopy, a shallow copy is performed. Constructing a collection from another collection creates a shallow copy as well.
Note: Unlike C++ libraries, Java class libraries uses immutable classes a lot. For example, String is immutable; so are the wrappers for numbers, such as Integer. Immutability makes the shallow vs. deep copying a lot less relevant.
Another note: Vector<T> should be used when you need a synchronized container; if you do not want synchronization, use ArrayList<T> instead.
what about b, the object that is passed in?
Will its fields/data members be modified as well?
Since java by default is pass-by-value, object that is passed in the contructor is pass-by-value but its internally its fields within that object will have reference, therefore when you call bofA.mutator() the B b field will change as well.
To have deep copy you need to copy each of the field in the b object that was passed and use Arrays.copyOf().
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
Consider following case.
List<Integer> listOne = new ArrayList<>();
List<Integer> listTwo = new ArrayList<>();
listOne.add(1);I think this happens due to
listOne.add(2);
listOne.add(3);
Collections.reverse(listOne);
listTwo = listOne; //listTwo has same reference
Collections.reverse(listOne);
System.out.println(listOne); //out put [1, 2, 3]
System.out.println(listTwo); // same out put
Java is pass by value, where values (for non primitive types) happen to be references. I think this provide survival for java for this kind of scenario. To be honest why java try to avoid pass by reference and try to be different from some of other languages? while java still suffering from pass by reference behaviors?
Edit: additionally please some one explain what happen in above code
Java does not suffer from pass by reference behaviors, it enjois them :)
when you write
List listOne = new ArrayList<>();
you have three things to consider:
1) a variable, which is a chunk of memory, and is named listOne
2) an object on the heap, with is an instance of ArrayList, which is a larger chunk of memory, and has no name
3) value of the listOne variable, which is not a memory chunk, but is a set of 0s and 1s placed in the memory of the variable listOne, and that value also has no name.
Now when we talk if listOne is passed by value or by reference, we use imprecise jargon which leads to misunderstanding. listOne (thing 1) is not passed at all, neither by value nor by reference. The value of listOne (thing 3) is passed, and this gives access to the ArrayList object (thing 2). So if we use name "listOne" but mean thing 3, it is passed by value, and if we mean thing 2, it is passed by reference. In both cases, name "listOne" is not correct name for thing 2 or thing 3, but it is used because it is short and convenient.
Java is pass by value.A copy of actual argument is passed to parameters.It is evident in case of primitive data types where changes in formal parameters is not shown in actual arguments.
static void incre(int a)
{
a++;
}
public static void main (String a[])
{
int c=3;
incre(c);
System.out.println(c); //still prints 3
}
Exact thing happens in case of references, but making a copy of reference does not create a new object, they both point to same object now.Hence changes made by references is reflected here.
class Demo {
int c =2;
Demo(int c)
{
this.c=c;
}
void incObject (Demo x)
{
(x.c)++;
}
int show()
{
return c;
}
public static void main (String []args)
{
Demo o = new Demo(1);
o.incObject(o);
System.out.print(o.show()); //prints 2
}
}
Collections.reverse();
modifies the backing array. This is clear from the implementation:
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
Now, listOne and listTwo have the same reference which points to the same backing array. So, no matter which handle(listOne or listTwo) modifies the backing array, the other will reflect the same changes. In your case:
Collections.reverse(listOne); // backing array has [3,2,1]
listTwo = listOne; //listTwo has same reference
Collections.reverse(listOne); // backing array has [1,2,3]
System.out.println(listOne); //out put [1, 2, 3]
System.out.println(listTwo); // same out put
As far as pass by value/reference is concerned. You said it yourself:
Java is pass by value, where values happen to be references.
why java try to avoid pass by reference and try to be different from
some of other languages?
One of the main reasons would be that Java(JVM) manages its own memory.
Collections.reverse(listOne); passes the reference to listOne(the object) by value, which is how one defines "pass by reference". Everything other than primitives is passed this way: by reference. It does not try to avoid it, it is only different from C++ in that it doesn't explicitly use pointers.
EDIT: Okay, I think I see where you're coming from.
private static void changelist(List<Integer> list) {
list.add(4);//This modifies the list object
list = new ArrayList<Integer>();//This modifies the local copy of the reference to the list object
list.add(5);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);//output is [1,2,3]
//This copies the value of the reference.
//If you modify the object in the underlying
//function, changes will be preserved when you return
//However if you modify what the reference points to,
//the function will only modify the local copy
changelist(list);
System.out.println(list);//output is [1,2,3,4]
}
To make my question understandable, I'm using the following example code. The output of this code is 5, while I wanted it to be 3. I'm guessing that B is working as a pointer for A, but I want A to be copied in B initially, and subsequent changes in A should not affect B.
import java.io.*;
public class fg
{
public static void main(String args[]) throws Exception
{
int[] A = new int[3];
A[0]=1;
A[1]=3;
A[3]=7;
check(A);
}
public static void check(int[] A)
{
int[] B = A;
A[1] = 5;
System.out.println(B[1]);
}
}
You need to explicitly create a copy,
int[] B = Arrays.copyOf(A, A.length);
since int[] is a reference type, so an assignment just copies the reference (basically, pointer).
If the array elements themselves are not primitive types, you probably will need a deep-copy, so
type B[] = new type[A.length];
for(int i = 0; i < A.length; ++i) {
B[i] = makeCopyOf(A[i]);
}
where makeCopyOf() should create a sensible copy of a type instance. If you don't find anything better, type makeCopyOf(type orig) { return orig.clone(); } could serve as a fallback.
B is a reference, and as such is analogous to a pointer (with various differences - you can't do arithmetic and it's not a direct memory pointer).
As such, you'll have to create a copy of the structure (the array) that you're referring to. Note that if you're copying objects, you may need a deep copy. You would likely have to do this in a copy constructor (see this article as to why clone() is considered broken)
I have the following function.
func(ArrayList `<String>`[] name) { ........ }
The function fills the ArrayList[]. (I don't want to return the ArrayList[])
However, in the caller function the ArrayList[] obtained has all ArrayLists as null.
For eg.
name = new ArrayList[num];
func(name);
System.out.println(name[0]);
I get NullPointerException at line 3. Is this because of line 1, i.e. I am not parametrizing? If yes, is there another way this can be done? Because java does not allow creating a generic array of parametrized ArrayList.
That is obviously not your real code, but you're creating an array of ArrayLists, which probably isn't what you want. You can probably just do:
ArrayList<String> name = new ArrayList(num);
func(name);
System.out.println(name.get(0));
Note that when you create the ArrayList, you're only specifying the initial capacity, not the size (number of initial items). It will have an initial size of 0. Your func can just call add to add items.
Even better (no typing errors):
ArrayList<String> name = new ArrayList<String>();
I recommend not bothering with the initial capacity argument (num) - just leave it blank and it will work perfectly. But do bother with the generic type of String in the constructor, or the compiler will complain.
If you want to know how to use the ArrayList (for example, why to use the get() function), you should look at the documentation.
For arrays in Java when you create it all of the elements are either 0, false, or null depending in their type.
So:
final List<String>[] foo;
foo = new ArrayList<String>[10];
foo[0].add("hello"); // crash
that crashes because foo = new ArrayList<String>[10]; allocates enough room to hold 10 ArrayList<String> but it sets all of the values to null. So you need one additional step:
for(int i = 0; i < foo.length; i++)
{
foo[i] = new ArrayList<String>();
}
I haven't compiled the code, but pretty sure it is all correct. You would do that between step 1 and 2 of your program.
I am guessing a bit because your code isn't quite accurate (it would not generate a null pointer as written as near as I can tell).
EDIT:
You would do the new in the method and the for loop with the assignments could be done inside of the method. I prefer to allocate and initialize in the same place (less confusing) but you can split it up if you needed to.
The problem you are encountering is due to the fact that in Java, parameters to methods are passed by value. What this means, is that every parameter is effectively "copied" into the method, meaning that any assignments you make to the parameters are only visible within the method, and cannot be seen by the caller.
Going by your example, you're passing in a null reference to an array of List<String>'s. This reference is then "copied" into the func() method, and when func then assigns something to this variable, it is only the local variable that is being updated, and not the reference held by your calling code.
Here's some compilable code (based on your example) that demonstrates the problem:
public class Main {
public static void main(String[] args) {
List<String>[] array = null;
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
The println in fill prints the correct value, because the array variable has been assigned to something within the fill method, however the println in the main method throws an NPE because only the "copy" of the array variable was changed by func, and not the "real" variable.
There are two ways to get around this: either instantiate the array within your calling code, or change the fill() method to return a reference to the array is has created.
Below is the first approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = (List<String>[])new List[10];
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
You may be wondering why this works, because you're still assigning ArrayList's to the elements of the array, however these objects are visible outside of the calling method. The reason for this is that although the fill method is getting a "copy" of the reference to the array, the reference itself is still referencing the same array object. This means that you can modify the internal state of the array object, and any changes you make will be seen by the caller because it referencing that same object.
Below is the second approach:
public class Main {
public static void main(String[] args) {
List<String>[] array = fill();
System.out.println("In main(): " + array[0].get(0));
}
public static List<String>[] fill() {
List<String>[] array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
return array;
}
}
(As an aside, you should generally try to avoid creating arrays of generic collections, a better idea would be to use a list to store the lists themselves. E.g:
List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.get(0).add("test");
new ArrayList<?>[10] give me incompatible type. However, new ArrayList[10] works for me.