-1

I'm having an issue with some pointers from what I can read about java. It always passes parameters as values rather than references. here

I have a project and employee class that should "share" an object but when I create an instance of activity, add it to the project list and then later add it to the employee list of activities it works. But then when I change the worktime for an employee it's only visible via the project instance where i add the worktime from. It's not visible when i then call the activity worktime from the employee object. Is there a way to "share" an object between classes e.g. pass it by reference like you can in PHP?

When I output the hashcodes of the activity objects in both classes they are also different...

Project class:

public class Project {
    
    private List<Activity> activites = new ArrayList<Activity>();
    
    public List<Activity> getActivities() {
        return activites;
    }

    public void setActivities(Activity activity) {
        this.activites.add(activity);
    } 
    
}

employee class:

public class Employee {
    
    private List<Activity> activities = new ArrayList<Activity>();
    
    public List<Activity> getActivities() {
        return activities;
    }
        
    public void setActivity(Activity activity) {
        activities.add(activity);
    }

}

activity class:

public class Activity {
    private String activityName;
    private HashMap<Employee,Integer> workTime = new HashMap<Employee,Integer>();
    
    public Activity(String activity) {
        this.activityName = activity;
    }
    
    public HashMap<Employee, Integer> getWorkTime() {
        return workTime;
    }
    
    public void setWorkTime(Employee e, Integer t) {
        workTime.put(e, t);
    }



}

An example of the issue:

 public void main(String[] args) {
    Activity a = new Activity('task i');
    Project p = new Project();
    p.setActivities(a);
    
    Employee e = new Employee();
    e.setActivity(a);
    
    p.getActivities().get(0).setWorkTime(e,5);

    System.out.println(p.getActivities().get(0).getWorkTime()); // 5
    System.out.println(e.getActivities().get(0).getWorkTime()); // -> null (would like 5)

}
  • 3
    Just a Tipp: it is never a good idea to just "guess" the code you are adding to your question instead of adding your actual real code that you are running. I know that the code you posted is not what you are actually running because your main method signature is wrong and `'task i'` is not how you define Strings in java and will not compile at all. – OH GOD SPIDERS May 05 '21 at 15:06
  • In the code shown there is a single `Activity` reference that is shared by the `Project` and `Employee`. – Dave Newton May 05 '21 at 15:09
  • 1
    Also, how can getWorkTime() be `5` when it's a map. Another thing, if you want to use `Employee` as a key, implement hashcode and equals – Bart May 05 '21 at 15:09
  • And to proof my point even further: If I copy your code from above and fix the 2 errors I mentioned then I can absolutely not reproduce your problem at all. `p.getActivities().get(0).getWorkTime()` and `e.getActivities().get(0).getWorkTime()` will both return a an identical HashMao. – OH GOD SPIDERS May 05 '21 at 15:11
  • Meta: Java is pass-by-value, but that value can be an object reference. What you're expecting to happen is what would happen. – Dave Newton May 05 '21 at 15:15

1 Answers1

3

The problem is here

public void setWorkTime(Employee e, Integer t) {
        workTime.put(e, t);
}

You are putting the employee instance in a map. But the Employee class does not override equals and hashCode so every instance of Employee will be a new and unique key.

You need to override equals and hashCode using some field(s) of the Employee class that would constitute equal instances (e.g. Employee name and/or Employee ID).

UPDATE

In recognition of the comments regarding only a single instance of Employee is being used, I concur. Although I believe it is important to do as I suggested it was not the specific problem.

I ran the above code and made main a static entry point and fixed the Activity argument to correctly add a String. The OP originally had the following:

System.out.println(p.getActivities().get(0).getWorkTime()); // 5
System.out.println(e.getActivities().get(0).getWorkTime()); // -> null (would like 5)

The above does not print 5 or null. It prints the default toString of the map. The Employee instance must must be supplied as the key via get and it will print 5 in both cases.


System.out.println(p.getActivities().get(0).getWorkTime().get(e)); // 5
System.out.println(e.getActivities().get(0).getWorkTime().get(e)); // 5

WJS
  • 36,363
  • 4
  • 24
  • 39
  • okay so in general in languages that can only pass values and not references it's better to have e.g. a uuid and store that? – Lukas Mittun Alexander Guldstv May 05 '21 at 15:12
  • It should be noted that in the example he's given he only creates one single Employee object, so not having overridden equals and hashcode wouldn't matter in that specific instance. But that just shows again that his example code was never suitable for demonstarting his actual problem. – OH GOD SPIDERS May 05 '21 at 15:13
  • I don't believe the pass by value is an issue. But it is a good idea to ensure your employee class is immutable from an equals and hashCode perspective. If you change those the values use to compute the above of an existing key, you won't find your object. – WJS May 05 '21 at 15:15
  • 1
    This should not be a problem in this code since there is only one Employee object - so its hashCode is the same as its own hashCode, and the default equals method will return true when compared with itself. It's also fine to use a HashMap without overriding equals and hashCode, if comparing by object identity is the behaviour you actually want (i.e. if you won't have two different instances representing the same employee). – kaya3 May 05 '21 at 15:15
  • To all who commented, see my updated answer. And thanks. – WJS May 05 '21 at 17:01