mynameisJEFF
mynameisJEFF

Reputation: 4239

Java: Creating a copy of the reference pointing to the same object

I am trying to create an adjacency list representation of a graph. And each vertex is defined below with four different attributes but I only need to use the node attribute for identification purpose.

class Vertex{
    private long node;
    private String color;
    private long d;
    private long pi;

public Vertex(long node){
    this.node = node;
}
// to String
public String toString(){
    return node+"";
}

 public int hashCode(){
     return (int)(node * 31);
}

public boolean equals(Object o) {
    if (o == this){
        return true;
    }
    if (o == null || getClass() != o.getClass()){
        return false;
    }
    Vertex other = (Vertex)o;
    return node  == other.node;
    }
}

I use the code below to read in the data in a text file and create a HashMap<Vertex, ArrayList<Vertex>> object below. The problem with my code below is that I am always creating a new object, even the the same node value has been seen once already,i.e. I could be creating two Vertex objects and both have node = 5 This is actually quite inefficient. Moreover, when I make changes to the one of Vertex with node = 5 and say I change its color attribute to WHITE. This will not be reflected in the other Vertex object that also has node = 5.

So, I think in this situation, what I really need is to be able to make a copy of the reference to the same object, whenever I read the value 5 twice or more in the text file. But I do not know what is the best way to do this ?

class other_class{
   public HashMap<Vertex, ArrayList<Vertex>> read_file(String file_loc) throws IOException {
    HashMap<Vertex, ArrayList<Vertex>> graph = new HashMap<Vertex, ArrayList<Vertex>>();
    FileInputStream fil = new FileInputStream(file_loc);
    BufferedReader br = new BufferedReader( new InputStreamReader(fil));
    String element = null;

    while( (element = br.readLine()) != null){
        String[] line = element.split("\\s");
        Vertex v_l = new Vertex( Long.parseLong(line[0]) );
        Vertex v_r = new Vertex( Long.parseLong(line[1]) );
        if(graph.containsKey(v_l) == false){
            ArrayList<Vertex> edges_of_this_vertex = new ArrayList<Vertex>();
            edges_of_this_vertex.add(v_r);
            graph.put(v_l, edges_of_this_vertex);
        } else{
            graph.get(v_l).add(v_r);
        }
    }
   }
}

Example data file

1   5    
1   2
5   1     <-- The 5 here creates a new Vertex object, which is not ideal, I want to be a copy of the reference to the Vertex object on line 1 with node equal to 5 .

Upvotes: 1

Views: 107

Answers (3)

Alin Valentin
Alin Valentin

Reputation: 537

You could make a HashMap<Long, Vertex> in which you will use the node as key, and the vertex object as value.

Vertex v_l = graph.get(new Long(line[0]));
Vertex v_r = graph.get(new Long(line[1]));

You now have the references for the previously created vertices in v_l and v_r, or, if any of the vertices with node = line[0] or line[1] doesn't exist yet, you will get a null, so you will know you have to instantiate them for the first time.

This looks like homework so I will not provide the whole method.

Upvotes: 0

leonbloy
leonbloy

Reputation: 75896

Similar to David's answer

private static Vertex getVertex(Map<Long,Vertex> vs,long id) {
    if(! vs.containsKey(id)) vs.put(id,new Vertex(id));
    return vs.get(id);
}

public static void loadGraph() throws Exception {
    HashMap<Vertex, ArrayList<Vertex>> graph = new HashMap<Vertex, ArrayList<Vertex>>();
    FileInputStream fil = new FileInputStream("C:/temp/x.txt");
    BufferedReader br = new BufferedReader( new InputStreamReader(fil));
    String element = null;
    Map<Long,Vertex> verts = new HashMap<Long,Vertex>();
    while( (element = br.readLine()) != null){
        String[] line = element.split("\\s+");
        Vertex v_l = getVertex(verts, Long.parseLong(line[0]) );
        Vertex v_r = getVertex(verts, Long.parseLong(line[1]) );
        if(graph.containsKey(v_l) == false){
            ArrayList<Vertex> edges_of_this_vertex = new ArrayList<Vertex>();
            edges_of_this_vertex.add(v_r);
            graph.put(v_l, edges_of_this_vertex);
        } else{
            graph.get(v_l).add(v_r);
        }
    }
}

Upvotes: 1

David SN
David SN

Reputation: 3519

One possible option is to use a factory method instead of a constructor to create new Vertex objects and reuse the existing instances whenever possible.

class Vertex{
    ...    
    private static Map<Long, Vertex> instances = new HashMap<Long, Vertex>();

    public static synchronized Vertex getInstance(long node) {
        if (instances.containsKey(node)) {
            return instances.get(node);
        } else {
            Vertex vertex = new Vertex(node);
            instances.put(node, vertex);
            return vertex;
        }
    }

    private Vertex(long node){
        this.node = node;
    }
    ...
}

Upvotes: 1

Related Questions