Solved

Referencing Problem in Java (for arraylists)

Posted on 2003-11-19
18
399 Views
Last Modified: 2010-03-31
I am facing a referencing problem.

I have a program that uses 2 arraylists, namely, "neighbors" And  "allNodes"

They get initialized in my program by accessing a static variable "a" of another program. For some strange reason, any modifications made to either of the two arraylists causes the same change in the other. I have checked my code thoroughly for un-intentional assignments of the nature of neighbors = allNodes, THERE ARE NONE.

MY PROGRAM:

public ArrayList neighbors = new ArrayList();
public ArrayList allNodes = new ArrayList();
LaunchContainer L = new LaunchContainer();
  ArrayList temp1 = LaunchContainer.a;
  neighbors = temp1;
   ArrayList temp2 = L.a;
   allNodes =  temp2;

Code Snippet of LaunchContainer which has the static variable "a"
-----------------------------
public class LaunchContainer {
         public static ArrayList a = new ArrayList();
        public static void main(String[] args) {
            for (int i=0;i<args.length;++i)
      {
              a.add(args[i]);
      }
      
        Container.getInstance();      
        while (true) {
            try {
                Thread.sleep(60000);              
            } catch (InterruptedException e) {
            }
        }
       
    }
------------------------

Any ideas of why this happens and HOW i may solve it ?! your help wld be appreciated :)

Regards
N


0
Comment
Question by:nandu2
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 4
  • 3
  • +2
18 Comments
 
LVL 35

Expert Comment

by:TimYates
ID: 9780349
If this is hapening, you have 1 of two situations

1)  You do not infact have 2 ArrayLists, you have one, and a reference to it; ie:

ArrayList a = new ArrayList() ;
ArrayList b = a ;

b.clear() ;
a.add( "Hello" ) ;

both a and b will hold the string "Hello"

2) You have two ArrayLists, but the objects inside them are references of each other...

class MyObject
{
    String val = "Hi" ;
}

ArrayList a = new ArrayList() ;
ArrayList b = new ArrayList() ;

MyObject o = new MyObject() ;
a.add( o ) ;
o.val = "Fish" ;
b.add( o ) ;

Both ArrayLists in this instance will contain a MyObject...both values of "val" will be "Fish" (as it is the same object in both lists)

0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780360
You will notice that you have (1), as removing an element from one list will cause an element to vanish from the other list too

You will notice if you have (2), as changing a member variable of an oject inside one list will change the variable in the other as well...

You could of course have both (1) and (2)...

If you could post more code, we might be able to spot where you are going wrong? :-)

Tim
0
 

Author Comment

by:nandu2
ID: 9780373
So, how do I go around the problem ? Interestingly, I didn't face this problem earlier.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Expert Comment

by:vk33
ID: 9780398
Look, if I'm not mistaken both temp1 and temp2 are initialized with a reference to the static ArrayList a in your LaunchContainer:

  ArrayList temp1 = LaunchContainer.a;
  neighbors = temp1;
   ArrayList temp2 = L.a;
   allNodes =  temp2;

So, both neighbors and allNodes are referencing the same ArrayList object - LaunchContainer.a. So, you have one object and two references (see TimYates suggestion).

Regards!
0
 
LVL 35

Accepted Solution

by:
TimYates earned 500 total points
ID: 9780412
You have made your ArrayList static...

> public static ArrayList a = new ArrayList();

This means that ALL instances of LaunchContainer will share one ArrayList

so:

LaunchContainer L = new LaunchContainer();
  ArrayList temp1 = LaunchContainer.a;
  neighbors = temp1;
   ArrayList temp2 = L.a;
   allNodes =  temp2;

temp1 and temp2 are exactly the same ArrayList...

try doing:

LaunchContainer L = new LaunchContainer();
  ArrayList temp1 = new ArrayList( LaunchContainer.a ) ;
  neighbors = temp1;
   ArrayList temp2 = new ArrayList( L.a ) ;
   allNodes =  temp2;

This will make temp1 and temp2 NEW ArrayLists that hold the same data as LaunchContainer.a

Tim
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780417
Hehehe, too slow ;-)
0
 
LVL 4

Expert Comment

by:vk33
ID: 9780426
To solve your problem I would suggest cloning arrayLists. E.g. ArrayList.clone() returns "shallow copy", you'll have separate ArrayList objects, but similar content. That's what you need, isn't it?

   ArrayList temp1 = LaunchContainer.a.clone();
   neighbors = temp1;
   ArrayList temp2 = L.a.clone();
   allNodes =  temp2;

Regards!
0
 
LVL 2

Expert Comment

by:SuperKarateMonkey
ID: 9780427
What are you actually adding to the source ArrayList, a?

And how are you modifying the element Objects?  If you're just calling some of their methods, then the underlying elements are changing, which is why both output lists are changing.
0
 
LVL 4

Expert Comment

by:vk33
ID: 9780434
wow, just several seconds time difference! ;)
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780441
Hee hee :-)   Like speeding bullets we are :-)
0
 

Author Comment

by:nandu2
ID: 9780448
********** brief description of what's going on... *******
allNodes contain a list of ALL NODES OF A NETWORK
neighbors, only the neighbors of a node.

The problem arises in the line allNodes.add(msg.get(j)); of the snippet shown here. TimYates, You are right, I have case 1 and 2.
As you can see, I tried deleting the unrequired (automatic) additon that was made to neighbors arraylist, with no success.

------------
System.out.println(" LIST OF ALL NODES BEFORE ADDING NODE .. "+allNodes);
                  System.out.println(" LIST OF ALL NEIGHBRS. BEFORE ADDING NODE"+neighbors);
                  allNodes.add(msg.get(j));
                  if (neighbors.contains(msg.get(j)))
                  {
                        System.out.println("Funnily Enough, The neighbors list has the element "+ msg.get(j));


---------------

The above lines are in the following whole code..
------------------------

public void react(MessageEnvelope envelope) {
                  
                  System.out.println(" Message Received from Node "+ envelope.getSender().getName());
                  ArrayList msg = (ArrayList) envelope.getMessage();
                  System.out.println(" This is " + getHandle().getName()+ " Message received ="+ msg.toString());
                  for (int j = 0; j<msg.size(); j++){ // FOR EACH ELEMENT IN ARRAYLIST RECVD.
                        System.out.println(" ELEMENT  "+ j + " = " + msg.get(j));
      if ( !(allNodes.contains(msg.get(j))) ){
                  System.out.println(" Node is not present in my List ");
                  if (!  ((Handle.fromString("handle{"+msg.get(j)+"}")).getName()).equals(myName) )
                  {
                        // if the element is not already present in the List of all-Nodes / is not myself
                        // then add the node to the list of known nodes,
                        // ensure that your neighbors are updated about this new node too.
                  System.out.println(" Node is Not Myself, Hence adding New Node to ALL-NODES LIST " );
                  System.out.println(" LIST OF ALL NODES BEFORE ADDING NODE .. "+allNodes);
                  System.out.println(" LIST OF ALL NEIGHBRS. BEFORE ADDING NODE"+neighbors);
                  allNodes.add(msg.get(j));
                  if (neighbors.contains(msg.get(j)))
                  {
                        System.out.println("Funnily Enough, The neighbors list has the element "+ msg.get(j));
                        System.out.println("So gonna remove... ");
                        neighbors.remove(neighbors.indexOf(msg.get(j)));
                        System.out.println("Removed, Hopefully ! Let's see..");
                  }
                  System.out.println(" LIST OF ALL KNOWN NODES NOW.. " + allNodes);
                  System.out.println(" LIST OF ALL NEIGHBORS NOW ..  " + neighbors);
Integer I = new Integer(Integer.parseInt((Handle.fromString("handle{"+msg.get(j)+"}")).getName().substring(1)));
                  AllNodeID.add(I);
                  h.put(I,msg.get(j));
            }

            }
            }
            String sender = envelope.getSender().getName()+","+ envelope.getSender().getID()+",rmi://localhost:"+ envelope.getSender().getDefaultURLPort();
                                    
                  if (!(neighbors.contains(sender))){
                  System.out.println(" LIST OF ALL NEIGHBORS KNOWN BEFORE : " + neighbors);
                  
                  neighbors.add(sender);
            System.out.println(" " + envelope.getSender().getName()+ " Not Present in Neighbor's List. Adding Sender" );
                  
                  System.out.println(" LIST OF ALL NEIGHBORS KNOWN NOW... "+neighbors);
                  System.out.println(" Printing contents of All Nodes before adding... "+allNodes);
                  h.put(new Integer(Integer.parseInt(envelope.getSender().getName().substring(1))), sender);
                  Enumeration e = h.elements();
                  if (e.hasMoreElements())
                  {
                  System.out.println(" Next element " + e.nextElement());      
                  }
                  if (!(allNodes.contains(sender)))
                  {
                  
                  allNodes.add(sender);
                  System.out.println(" Adding "+ sender + " to List of All Nodes");
                  h.put(new Integer(Integer.parseInt(envelope.getSender().getName().substring(1))), sender); //hashtable for sender NUMBER - sendeR ADDRESS
                  }
                                    
                  int NodeNum = Integer.parseInt(envelope.getSender().getName().substring(1));
                  System.out.println(" Printing the Node Number that was just read ..." + NodeNum );
                  neighborID.add(new Integer(NodeNum));
                  AllNodeID.add(new Integer(Integer.parseInt(envelope.getSender().getName().substring(1))));
                  }else System.out.println(" The Sender already exists in my List of  Neighbors ");
                               
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780450
I remember once, me and cavey79 wanted the Date on here to have milliseconds....just so we could see how close we were to each other's posts ;-)

</off_topic> ;-)
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780469
Just put:

public ArrayList neighbors = new ArrayList( LocationContainer.a );
public ArrayList allNodes = new ArrayList( LocationContainer.a );

and get rid of the :

ArrayList temp1 = LaunchContainer.a;
  neighbors = temp1;
   ArrayList temp2 = L.a;
   allNodes =  temp2;

malarkey
0
 
LVL 2

Expert Comment

by:SuperKarateMonkey
ID: 9780471
To get around this, just clone your objects:


String s1 = "abc";
String s2 = "def";
a.add( s1 );
a.add( s2 );

// This is how you do it right now:

neighbors = new ArrayList( L.a );
allNodes = new ArrayList( L.a );

// This is no good.

// Try this:

for( int i = 0; i < a.size(); i++ )
{
  String temp  = (String)a.get(i);
  neighbors.add( new String( temp ) );
  allNodes.add( new String( temp ) );
}

This forces the creation of new, independent strings.  For other objects, the same principle applies, assuming you have that kind of constructor.
0
 
LVL 35

Expert Comment

by:TimYates
ID: 9780480
> This forces the creation of new, independent strings.

Why would this help?

String is immutable...it doesn't matter if you add the same one all over the shop...

Tim.
0
 
LVL 4

Expert Comment

by:vk33
ID: 9780540
yes, exactly! For immutables there's no difference if you have two references or two separate objects. It's rather a "feature" than a "bug"... :)
0
 
LVL 1

Expert Comment

by:B000GT
ID: 9780555
do what TimYates and vk33 suggested...
cloning is the way around this
and they have examples in their posts...
 
gl

- nc
0
 

Author Comment

by:nandu2
ID: 9780556
Thanks vk33, Yates and others ! Saved me a bunch of time :)

N
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
fibonacci ten numbers 4 54
web project error add remove 1 56
learn programming 8 73
Strange router problem - can't access hotmail.com 14 56
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question