0

I am trying to do the following:

import java.util.ArrayList;


public class One {

    private ArrayList<Integer> list;

    public One() {
        addString(list);
        sysoutList(list);
    }

    public void sysoutList(ArrayList<Integer> list2) {
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }

    private void addString(ArrayList<Integer> list2) {
        list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
    }

}

The problem is, that sysoutList() throws a NullPointerException because list2 is null. It seems, that the initialization of list in addString() has no effects, because the class variable can't be referenced. In C++ I would solve this problem with pointers, but how can I do that in Java?

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
John
  • 795
  • 3
  • 15
  • 38
  • 1
    Remove `list2 = new ArrayList<>();` from the `addString` method, insert it at the beginning of the `One` constructor – BackSlash Sep 10 '14 at 08:46

3 Answers3

2

Always remember that Java is pass by value.

If you reinstantiate a variable inside a method, the passed variable is left untouched. Your example does exactly that.

String myValue = "All your variables belong to us";

setValue(myValue);

System.out.println(myValue); //All your variables belong to us

void setValue(String v){
    v = "Hello World!";
}

You should initialize first your variable:

import java.util.ArrayList;


public class One {

    private ArrayList<Integer> list = new ArrayList<Integer>();

    public One() {
        addString(list);
        sysoutList(list);
    }

    public void sysoutList(ArrayList<Integer> list2) {
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }

    private void addString(ArrayList<Integer> list2) {
        list2.removeAll();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
    }

}

A list is a special case tough. You could think with the add() method I'm pratically modifying the variable, so the modification shouldn't occur. That's not true, why?

That's because you are passing the value of the reference for the list. If you assign a new value to that reference using the new keyword, you "loose" the object attached to it (you don't have its reference anymore).

But if you modify a property of that object (such as with the add() method) the reference for the object is still valid and thus you modify the original object.

We can make a similitude.

Imagine you have a kite attached to a string. Now you attach a new string to it and pass the newly created string to a friend.

If he cuts the string (aka creates a new one), he loses the reference to your kite and he can't reach it. He can attach a new kite and do all the modifications (aka add() something to it) that he wants, but it will never be your kite.

If he instead uses the string you gave to him to reach the kite and modify it, you'll receive a modified kite.

To remain in the similitude in your case you are creating a string with no kite (list) with private ArrayList<Integer> list; and then passing it to your friend creating a new string (list2). Now both you and your friend have a string with nothing attached.

He creates a new kite and attaches it to his string (list2 = new ArrayList<>()) but your string is still attached to nothing. When you try to fly your kite you'll notice that the kite simply doesn't exists (null reference).

First you have to create your own kite and attach your string (private ArrayList<Integer> list = new ArrayList<Integer>();). When you pass it to your friend another string is attached to it (list2). Now your friend can use list2 to modify your kite.

EDIT

Regarding your other question, if is possible to istantiate a variable in a method which is called from the constructor the answer is yes, but such variable MUST be declared as static if you want to use it outside your method.

In the kite similitude is like you attach a kite to a string and you and your friend use the same string to operate on it (yep, holding hands).

For you becomes:

import java.util.ArrayList;


public class One {

    private static ArrayList<Integer> list;

    public One() {
        addString();
        sysoutList();
    }

    public void sysoutList() {
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

    private void addString() {
        list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
    }

}

You don't need to pass the ArrayList around since you are using the same "kite string" everywhere in your program.

NB: If you call sysoutList() before addString() you'll still get a NullPointerException because list isn't initialized yet.

This is a bad practice. I firmly suggest you to change your logic.

Community
  • 1
  • 1
Narmer
  • 1,414
  • 7
  • 16
1

If you really want to instantiate the class variable in the method, called by the constructor you could do it like this:

import java.util.ArrayList;


public class One {

    private ArrayList<Integer> list;

    public One() {

        addString();
    }

    private void addString() {
        list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
    }
}
DeiAndrei
  • 947
  • 6
  • 16
0

Just instantiate your list :

private ArrayList<Integer> list = new ArrayList<>();  //In 4th line

replace above in the place of :

private ArrayList<Integer> list;

Error is occuring because list was not initialized. You can also initialize it in the constructor.
Here is an example

public One() {
    list = new ArrayList<>();
    addString(list);
    sysoutList(list);
}

Above diamond operator i.e. <> doesn't work in jdk prior to 7, you will need to use ` for that.

afzalex
  • 8,598
  • 2
  • 34
  • 61