initializing ArrayList<>() in methods or constr

2019-02-28 16:22发布

问题:

import java.util.ArrayList;
public class Team {  

    private String name;
    private ArrayList<Player> team;

    public Team(String name)    {
        this.name = name;
        //how come i have to initialize it here in the constructor to see the full list?          
        this.team = new ArrayList<Player>();
    }

    public void addPlayer(Player player)    {
        //why can't i initialize it here in the method, this gives me a list of only recent add?
        //this.team = new ArrayList<Player>(); 
        this.team.add(player);
    }

    public void printPlayers()  {            
        for(Player players : this.team) {
            System.out.println(players);
        }
    }
    public String getName() { return this.name; }
}
  • I'm trying to figure out why this.team = new ArrayList<Player>() have to be in the constructor?
  • Why can't I have this.team = new ArrayList<Player>() initialized in the method?
  • I know that when I run it with the code in the constructor it works as intended (it gives me the full list when things are added)
  • BUT when it's initialized in the method it only list the last given addition to the list. Is it wrong to have it initialized in the method?
  • Also what's the difference of having it initialized as private ArrayList<Player> team = new ArrayList<Player>(); before the constructor?

回答1:

Answering just the question:

Also what's the difference of having it initialized as private ArrayList<Player> team = new ArrayList<Player>(); before the constructor?

Nothing, aside from the fact that team would be initialized before name.

Field initializers are syntactic sugar for instance initializers. So this:

private ArrayList<Player> team = new ArrayList<Player>();

is identical to this:

private ArrayList<Player> team;

{
  // This is an instance initializer.
  team = new ArrayList<Player>();
}

and instance initializers are gathered together and inserted into every constructor which invokes (implicitly or explicily) super, in between the call to super and the rest of the constructor body. So this:

public class Team {  

    private ArrayList<Player> team = new ArrayList<>();

    public Team(String name)    {
      this.name = name;
    }
}

is identical to:

public class Team {  

    private ArrayList<Player> team;

    public Team(String name)    {
      super();

      this.team = new ArrayList<>();

      this.name = name;
    }
}


回答2:

Because of the fact that each constructor invocation will result in a new distinct object the line this.team = new ArrayList<Player>(); within the constructor will only be called once per instance so thus you'll only ever have one ArrayList instance per object in this specific case.

On the other hand, the addPlayer method can be called as many times as you want on a given object thus this.team = new ArrayList<Player>(); within the addPlayer method will replace (overwrite) the previous list on each method call.



回答3:

You can do this in that way (to prevent recreation of ArrayList on every addPlayer method call):

    public void addPlayer(Player player)  {
        if (this.team == null) {
            this.team = new ArrayList<Player>();
        }
        this.team.add(player);
    }

but it will be VERY weird code... Better practice is to initialize 'team' list inside constructor or inline in field declaration. Both of them do the same thing. I prefer to initialize fields inside constructor, but this is only my habit. Other programmers may prefer inline version and this is nothing wrong/bad.



回答4:

Why can't I have this.team = new ArrayList() initialized in the method?

You're creating a new ArrayList each time and assigning it to this.team. So each time you call addPlayer, you're replacing this.team with a new empty ArrayList and then adding a player with this.team.add(player), so only the last added player is in the ArrayList at all times.

What you could do if you really don't want to create the ArrayList in the constructor is check if this.team is null every time you add a player and if the ArrayList is not created or empty, simply create one.

public void addPlayer(Player player)    {
    if (this.team == null) {
        this.team = new ArrayList<Player>();
    }
    this.team.add(player);
}

Also what's the difference of having it initialized as private ArrayList team = new ArrayList(); before the constructor?

If you're wondering whether the private keyword changes anything, you should read the Java docs on access modifiers: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

Other than that, initializing before the constructor changes nothing in this case.



回答5:

I'm trying to figure out why this.team = new ArrayList() have to be in the constructor?

It doesn't, it has to be initialized before it is used. You can initialize it anywhere you want as long as you don't call printPlayer() or addPlayer() before.

Why can't I have this.team = new ArrayList() initialized in the method?

You actually can. See this example:

public void addPlayer(Player player) {
    if (team == null) {
        team = new ArrayList();
    }

    team.add(player);
}

public void printPlayers() {
    if (team != null) {
        for (Player p : team) {
            System.out.println(p);
        }
    }
}

BUT when it's initialized in the method it only list the last given addition to the list. Is it wrong to have it initialized in the method?

No, it's not wrong. It's typically referred to as "lazy initialization" or "on demand" if you do it in the way of the example above.

Also what's the difference of having it initialized as private ArrayList team = new ArrayList(); before the constructor?

Not much, the difference lies in when it is initialized.

public class Example {
    public static List<T> myList = new ArrayList<T>(); // this is done first
    public static List<T> aList;
    public List<T> someList;
    static {
        // this is also done first (on class load)
        aList = new ArrayList<T>();
    }

    { 
        // this is done right before the constructor (I believe)
        // it is called an 'initialization block'
        someList = new ArrayList<T>();
    }

    public Example() {
        // this one you already know...
    }
}