1

I have a Model class defined in my project. and as usual it has some private variables and public getters and setters

public class Person{

 private ArrayList<String> mark;

 public void setMark(ArrayList<String> mark){
  this.mark = mark;
 }

 public void getMark(){
  return this.mark;
 }
}

Suppose in some other class I am using this Model like

Person person = new Person();
ArrayList<String> mark = new ArrayList();
mark.add("10");
mark.add("15");
mark.add("18");
person.setMark();

then the private variable of person holds the value "my name", the I am accessing the variable using public getter of the class like

ArrayList<String> localMark = person.getMark()

so as per my knowledge person.getMark() returns the reference of private variable name, so if I modify the local variable 'localMark', then it will effect the private variable of Person class, so there it breaks the private property of the variable

ex:

 ArrayList<String> localMark = person.getMark();
 System.out.println(localMark.get(0)); // will be "10"
 localMark.set(0,"25") // person.mark will be changed
 System.out.println(person.getMark().get(0)); //will be printing "25"

most of the developers following the same design pattern I guess, but what is the correct way to create Models

EDIT

As per the comment of vinod I checked, and Strings it passes value but not reference but for ArrayList... it returns reference.

droidev
  • 7,352
  • 11
  • 62
  • 94
  • 2
    *System.out.println(person.getName()); //will be printing "new Name"* ==> Did you check?. I think you should check what is printed :) – TheLostMind Nov 27 '15 at 09:53
  • How do you modify the localName? What about Immutability? – Raf Nov 27 '15 at 09:53
  • I din't but if it returns the reference it should be the value isn't it ? – droidev Nov 27 '15 at 09:54
  • @Raf locaName is a local variable of another class, I can modify it with any value there – droidev Nov 27 '15 at 09:56
  • 2
    I down-voted your question because you posted something which won't happen to Strings. *re-assigning* the reference won't change a thing because java is *pass-by-value*. Next, the changes you do on the instance in a different class will affect the actual instance if you have *mutable* instances returned by your getter (which you shouldn't, you should return defensive copies of mutable instances) – TheLostMind Nov 27 '15 at 09:56
  • @VinodMadyalkar I don't think, it requires a down vote. Adding an answer expalining what's wring will be the nice approach afaik :) – Suresh Atta Nov 27 '15 at 09:57
  • 2
    @sᴜʀᴇsʜᴀᴛᴛᴀ - But he should try his code before posting. :). Don't you think my comment gives him enough info / hints? :) – TheLostMind Nov 27 '15 at 09:59
  • @VinodMadyalkar That is what my point. You can guide him with an answer. – Suresh Atta Nov 27 '15 at 10:00
  • @sᴜʀᴇsʜᴀᴛᴛᴀ - Okie dokie :P – TheLostMind Nov 27 '15 at 10:00
  • @Raf - Well, *Reflection* could be used to break *immutability*. But the OP is merely re-assigning references – TheLostMind Nov 27 '15 at 10:10
  • @VinodMadyalkar interesting. I am yet to learn Reflections. Thanks. – Raf Nov 27 '15 at 10:15
  • @Raf - No problemo. Check [this](http://stackoverflow.com/questions/20945049/is-a-java-string-really-immutable) if you are interested :) – TheLostMind Nov 27 '15 at 10:17
  • please reload the question, I have tried and checked,for strings there is no issues, it returns the value, not reference. – droidev Nov 27 '15 at 10:21
  • @VinodMadyalkar I think its the time to remove the down vote :) – droidev Nov 27 '15 at 10:32
  • @VividVervet - Done. Check my answer as to why the value is reflected in case `List` is used – TheLostMind Nov 27 '15 at 10:36

2 Answers2

3

You have a reference (name) to an object instance (the value of name). As the reference is private, you're in full control of it.

When you return a reference, you in fact return it 'by value', meaning that a copy of the reference is returned. Both references point to the same value (the String instance)).

An outside caller obtaining the reference can assign a new value, but your model's own reference is unaffected by that and still points to the value.

It's like a dog (object) on a leash (reference).

  • When you return a reference you're returning a new leash onto the same dog.
  • The owner of the new reference can modify your dog (pet it, shave it, whatever) when the dog is mutable (which Strings are not, so it cannot be modified)
  • ...or he can attach a new dog to his leash
  • ...but he can never (reflection aside) attach YOUR leach to another dog.
Peter Walser
  • 15,208
  • 4
  • 51
  • 78
1

If the instance being exposed by call to get() is mutable, then whatever changes you make in some other place will be reflected in the instance everywhere it is used.

Example :

methodX classA - 
 List<String> locaNamesList = person.getNamesList();
 locaNamesList.clear();

Somewhere else
methodY classB -
List<String> locaNamesList = person.getNamesList(); // note the same person instance should be used.
//locaNamesList will be empty here

Just re-assigning the reference won' change anything.

List<String> locaNamesList = person.getNamesList();
locaNamesList = null; // won't change the actual list. You are setting local field locaNamesList to null and not the actual instance.

You have to use defensive-copies of mutable instances and pass them around if you don't want the original instance to be changed by external players (provided you can't make the instance itself immutable)

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • then how do I redesign my model class ? what you mean by defencive copies ? – droidev Nov 27 '15 at 11:23
  • @VividVervet - Defensive copy means - *creating a new Object which is exactly same as the original. This is usually done via a copy constructor . You can use a factory or other method*. Thus you will return a copy of your instance and not the actual instance itself – TheLostMind Nov 27 '15 at 11:59