Solved

Referencing Problem in Java (for arraylists)

Posted on 2003-11-19
18
382 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
  • 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
 
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
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

747 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now