ArrayList behavior

E

Edward A Thompson

I am puzzled by the bahavior of ArrayList process, and was hoping some
could explain...


Given the following code:

Book b = new Book();
ArrayList books = new ArrayList();

for (i=1; i <= 5; i++)
{
b.title = i;
books.add(b);
}

at the end of the loop I have 5 items in the list;
5,5,5,5,5 instead of 1,2,3,4,5.

What is books.add doing? Is it storing a reference, and not an actual
copy of the object? I would have thought I coudl reuse b over and
over.
If I put the instantiation of b inthe loop all is well.

Can someone explain?
 
M

Michael Borgwardt

Edward said:
What is books.add doing? Is it storing a reference, and not an actual
copy of the object?

Exactly. Java objects live on the heap, not the stack, and they are *never*
implicitly copied (except when they are serialized and sent over a network).
 
J

Joona I Palaste

Edward A Thompson said:
I am puzzled by the bahavior of ArrayList process, and was hoping some
could explain...
Given the following code:
Book b = new Book();
ArrayList books = new ArrayList();
for (i=1; i <= 5; i++)
{
b.title = i;
books.add(b);
}
at the end of the loop I have 5 items in the list;
5,5,5,5,5 instead of 1,2,3,4,5.
What is books.add doing? Is it storing a reference, and not an actual
copy of the object? I would have thought I coudl reuse b over and
over.
If I put the instantiation of b inthe loop all is well.
Can someone explain?

What you have doing is storing the same object over and over again in
the ArrayList. You only *HAVE* one object, you know - the line "Book b =
new Book();" is the only place in your entire code where you make a
Book object. How do you suppose the ArrayList would store references to
five Book objects when you only have one?
Because the ArrayList stores references to the object, any changes to
the object are visible through the reference. You end up with the object
in the state you last put it in.
If you want an ArrayList that makes a copy of the object being stored,
then write one. Java Collections doesn't come equipped with one.
 
R

Roedy Green

I was trying to confimr this. This is what I suspected.

This is much more generally true. You can't store an object, only a
reference to an object. You never copy an object unless you use clone
or write your own method to do so.
 
H

hiwa

(e-mail address removed) (Edward A Thompson) wrote in message
In your code, b is not assigned with new Book objects since
its initialization. In other words, it's forever the same
single object.
 
T

Tony Morris

You have one instance of Book and one reference referring to it (b).
You set the Book instance title to 1, then 2, then 3, 4 and 5.
You add that same reference (which is copied since Java is strictly pass by
value http://www.xdweb.net/~dibblego/javafaq/javafaq.html#q23) to the
ArrayList five times.
When it comes time to "looking" at what is in the ArrayList, you have 5
references referring to the same instance, which has a title of 5.

Side Note 1: public access to member variables is generally bad practice.
Side Note 2: declaring a reference of a List implementation is generally bad
practice.
Better to use a List reference, and allow the instance type to decide on the
implementation.
This practice is not specific to List types, or any Collection type. To
explain the benefits requires a lot of typing - I'm sure google will help :)

// List reference, not ArrayList reference
List books = new ArrayList();

for (i=1; i <= 5; i++)
{
Book b = new Book();
b.setTitle(i); .// title should be private with a public set method,
google for "data encsapsulation".
books.add(b);
}

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)
 
B

BarryNL

Edward said:
I am puzzled by the bahavior of ArrayList process, and was hoping some
could explain...


Given the following code:

Book b = new Book();
ArrayList books = new ArrayList();

for (i=1; i <= 5; i++)
{
b.title = i;
books.add(b);
}

at the end of the loop I have 5 items in the list;
5,5,5,5,5 instead of 1,2,3,4,5.

What is books.add doing? Is it storing a reference, and not an actual
copy of the object? I would have thought I coudl reuse b over and
over.
If I put the instantiation of b inthe loop all is well.

Can someone explain?

You have only one book object in your array and it's in there five
times. It is, as you suggest, storing a reference. You should do:

ArrayList books = new ArrayList();

for (i=1; i <= 5; i++)
{
Book b = new Book();
b.title = i;
books.add(b);
}
 
E

Ed Thompson

Tony said:
You have one instance of Book and one reference referring to it (b).
You set the Book instance title to 1, then 2, then 3, 4 and 5.
You add that same reference (which is copied since Java is strictly pass by
value http://www.xdweb.net/~dibblego/javafaq/javafaq.html#q23) to the
ArrayList five times.
When it comes time to "looking" at what is in the ArrayList, you have 5
references referring to the same instance, which has a title of 5.

Side Note 1: public access to member variables is generally bad practice.
Side Note 2: declaring a reference of a List implementation is generally bad
practice.
Better to use a List reference, and allow the instance type to decide on the
implementation.
This practice is not specific to List types, or any Collection type. To
explain the benefits requires a lot of typing - I'm sure google will help :)

// List reference, not ArrayList reference
List books = new ArrayList();

for (i=1; i <= 5; i++)
{
Book b = new Book();
b.setTitle(i); .// title should be private with a public set method,
google for "data encsapsulation".
books.add(b);
}
Your feedback is welcome.
I was just giving a code snippet, but in actuality book Title is
declared as a protected variable, so that subclasses in the same package
can access directly. I have MANY fields to populate (its an intense
database app), and performance is an issue, so I opted to 'protect' the
variables, and not use setters/getters to keep my data transfer objects
small.
 
T

Tony Morris

Some people suggest that protected member variables violate encapsulation
just as much as public members. i.e. "They" suggest that a member should be
declared private with protected set/get methods.
I'm not going to offer my opinion on this subject, only to say that it is
very subjective and like most things, a "trade-off" decision to be made by
the developer given the requirements.

In your case, where you have provided direct access to enhance performance,
is a perfect example of this "trade off".

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)
 
J

Jon Skeet

Tony Morris said:
Some people suggest that protected member variables violate encapsulation
just as much as public members. i.e. "They" suggest that a member should be
declared private with protected set/get methods.
I'm not going to offer my opinion on this subject, only to say that it is
very subjective and like most things, a "trade-off" decision to be made by
the developer given the requirements.

In your case, where you have provided direct access to enhance performance,
is a perfect example of this "trade off".

Not without benchmarking it isn't - I'd expect any decent JITter to
inline calls to setTitle so that they'd be about as fast as setting the
variable directly.

Weakening encapsulation for performance reasons without testing that
those ideas about performance are actually justified is a really bad
idea, IMO.
 
K

Kaidi

Then how about this code:

String b="";
ArrayList books = new ArrayList();
b="aaa";
books.add(b);
b="bbb";
books.add(b);
b="ccc";
books.add(b);
-----
after it, I think books should contain "aaa", "bbb" and "ccc".
So what is the point as to the difference of String and the Book object?

Thanks.
 
J

Jon Skeet

Kaidi said:
Then how about this code:

String b="";
ArrayList books = new ArrayList();
b="aaa";
books.add(b);
b="bbb";
books.add(b);
b="ccc";
books.add(b);

Yes, it will.
So what is the point as to the difference of String and the Book object?

You're changing the value of b in that case - which is a reference -
rather than the data within the object itself (which you can't do for
strings in the first place).

In your case you weren't changing the value of the variable b - you
were only changing the data within the book itself.
 
B

BarryNL

Kaidi said:
Then how about this code:

String b="";
ArrayList books = new ArrayList();
b="aaa";
books.add(b);
b="bbb";
books.add(b);
b="ccc";
books.add(b);

There is no difference. The crucial point to remember here is that

b = "bbb";

is just another way of saying:

b = new String("bbb");
 
M

Michael Borgwardt

BarryNL said:
There is no difference. The crucial point to remember here is that

b = "bbb";

is just another way of saying:

b = new String("bbb");

No, it is NOT!!

The second creates a new String object which is not identical to the literal,
while the first directly assigns the literal.
 
D

Dario

BarryNL said:
There is no difference. The crucial point to remember here is that

b = "bbb";

is just another way of saying:

b = new String("bbb");

*Completly* *wrong* !

Try:
System.out.println("bbb" == new String("bbb"));
It will print false !

Even if:
System.out.println("bbb".equals(new String("bbb")));
will print true !

Do not confuse reference with strings !

- Dario
 
B

BarryNL

Dario said:
*Completly* *wrong* !

OK, I simplified a bit, but as far as the original context was concerned
they do equivalent things. 'b = "bbb";' does indeed create a new String
object with the content "bbb".
 
T

Tony Morris

right, hence the "subjectiveness" of the debate.

"Weakening encapsulation for performance reasons without testing that
those ideas about performance are actually justified is a really bad
idea, IMO"
This I agree with, without a doubt.

In my time, I have found many justifications for decreasing maintainability
(perhaps just a fraction), for significant performance increases, but I have
never found a justification for providing public access to data members
(unless they are declared final and of an immutable type).

The overcoming of this "performance hit" (loosley speaking) is the job of a
JIT compiler, which (I can only assume), has been thoroughly tested and
benchmarked with effort beyond that which I can personally achieve during
development.

--
Tony Morris
(BInfTech, Cert 3 I.T., SCJP[1.4], SCJD)
Software Engineer
IBM Australia - Tivoli Security Software
(2003 VTR1000F)
 
E

Edward A Thompson

Some people suggest that protected member variables violate encapsulation
just as much as public members. i.e. "They" suggest that a member should be
declared private with protected set/get methods.
I'm not going to offer my opinion on this subject, only to say that it is
very subjective and like most things, a "trade-off" decision to be made by
the developer given the requirements.

In your case, where you have provided direct access to enhance performance,
is a perfect example of this "trade off".

I did find some precedent for my approach in the core J2EE Design
pattern defintion for Transfer Object:

"The TransferObject is an arbitrary serializable Java object referred
to as a Transfer Object. A Transfer Object class may provide a
constructor that accepts all the required attributes to create the
Transfer Object. The constructor may accept all entity bean attribute
values that the Transfer Object is designed to hold. Typically, the
members in the Transfer Object are defined as public, thus eliminating
the need for get and set methods. If some protection is necessary,
then the members could be defined as protected or private, and methods
are provided to get the values. By offering no methods to set the
values, a Transfer Object is protected from modification after its
creation. If only a few members are allowed to be modified to
facilitate updates, then methods to set the values can be provided.
Thus, the Transfer Object creation varies depending on an
application's requirements. It is a design choice as to whether the
Transfer Object's attributes are private and accessed via getters and
setters, or all the attributes are made public."

http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html

At least I am not way off
 
E

Edward A Thompson

See my response to Tony - there is a precedent.

Jon Skeet said:
Not without benchmarking it isn't - I'd expect any decent JITter to
inline calls to setTitle so that they'd be about as fast as setting the
variable directly.

Weakening encapsulation for performance reasons without testing that
those ideas about performance are actually justified is a really bad
idea, IMO.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top