Solved

General visiblity question

Posted on 2004-09-15
11
236 Views
Last Modified: 2010-03-31
Could somebody please clarify each of the following questions (?? … ??) for me - i'll use some code as an example! :)

private void addTimeSpan(Element from, Element to)
    {
      int type = -1, period = -1, day = -1, less = -1;
      Date date = null;
      long dateEpoch = -1; // form date has been saved in XML file
      MomentInTime fromMoment, toMoment;
     
      /** FROM **/
      // get all these variable values as strings
      String typeStr = from.getAttributeValue("type"),
      periodStr = from.getAttributeValue("period"),
      dayStr = from.getAttributeValue("day"),
      lessStr = from.getAttributeValue("less"),
      dateStr = from.getAttributeValue("date");
     
      if(typeStr != null)
        type = Integer.parseInt(typeStr.trim());
      if(periodStr != null)
        period = Integer.parseInt(periodStr.trim());
      if(dayStr != null)
        day = Integer.parseInt(dayStr.trim());
      if(lessStr != null)
        less = Integer.parseInt(lessStr.trim());
      if(dateStr != null)
        date = new Date(Long.parseLong(dateStr.trim()));
     
      fromMoment = new MomentInTime(type, period, day, less, date);
    }

So now I have to repeat for:
/** TO **/

suppose I made a method:
private void setAttributes(Element e, String period, String day …)

for /** FROM **/
call   setAttributes(from, periodStr, dayStr …)
?? will these strings now be set correctly in the addTimeSpan method ??
then   fromMoment = new MomentInTime(type, period, day, less, date);

for /** TO **/
call   setAttributes(to, periodStr, dayStr …)
?? will the fromMoment object now be altered (because using same String objects) ??

Also am I correct in saying if my method was:
private void setAttributes(Element e, int period, int day …)
?? then the values will NOT be set in addTimeSpan because types are primitive ??

And does the date object pose any similar problems.

I suppose an excellent and much appreciated answer to this wordy question would be the code re-written as efficiently as possible with an explanation of why things will or will not work a certain way!

Kindest regards,
Cathal.
0
Comment
Question by:cathalmchale
  • 7
  • 2
  • 2
11 Comments
 
LVL 16

Accepted Solution

by:
imladris earned 50 total points
ID: 12065242
The variable typeStr is declared in the addTimeSpan method. This means that typeStr is a reference to a String object. The call to getAttributeValue returns a reference to a String object which is then assigned to typeStr and all is well.

However, if you were to use a setAttributes call you would be facing a difficulty. The difficulty lies with the way that arguments are passed to methods. In Java (and most modern languages) arguments are passed "by value". This means that a *copy* of the argument is put on the stack, and the method uses this copy as the argument. The advantage of this tactic is that the callers variables are "safe" from sideeffects caused by the method. When you're reading the code, and you see a method being called, you cannot see what might be happening in the method. Calling by value helps the reader by encouraging that indeed, usually, nothing *does* happen.
So, since a copy goes to the method, assigning some value to that copy inside the method will not change the value of the variable you passed in.

This is true for Objects (String's in this case) as well as primitives.
0
 
LVL 16

Assisted Solution

by:imladris
imladris earned 50 total points
ID: 12065298
The main dodge to this (there's always a dodge) is as follows.

If you pass a reference to an object into a method, and the method changes the *object*, then the caller will see the changed object as well.

Why?

Well, if you have an object Foo, and pass a reference to it, a *copy* of the reference is passed into the method on the stack. But that copied reference is pointing to the *same* object. So if the method changes the object (calls some method of the object that changes its internal state, or, perhaps, directly changes one of its member variables), then the caller (still having a reference to that same object) will see that object in its new state.

On the other hand, remember that this does *not* work for Strings. Strings are immutable. A String object can't be changed; by anybody. You can only create new ones.
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12065436
>> am I correct in saying if my method was:
>> private void setAttributes(Element e, int period, int day …)
>> ?? then the values will NOT be set in addTimeSpan because types are primitive ??
Yes.

>> for /** FROM **/
>> call   setAttributes(from, periodStr, dayStr …)
>> ?? will these strings now be set correctly in the addTimeSpan method ?
No, since String is an immutable object


>> And does the date object pose any similar problems
No. You can alter a Date or any other object (cf. MyData in what follows)


Run this little demo app:

/*
 * RefDemo.java
 *
 */

/**
 *
 * @author  zzynx
 */

public class RefDemo {
   
    public RefDemo() {
    }
   
    public void setString(MyData inputData, String key) {
        key = inputData.getKey();
    }

    public void setKeyOfMyData(MyData inputData, String key) {
        inputData.setKey(key);
    }

   
    public static void main(String arg[]) {
        RefDemo d = new RefDemo();
       
        String key = "First content";
        System.out.println("Key = " + key);
        d.setString( new MyData("2nd Key", "value 2"), key);
        System.out.println("Key = " + key);
       
        MyData data = new MyData("Key", "value");
        System.out.println("Data = " + data.toString());
        d.setKeyOfMyData(data, "new Key");
        System.out.println("Data = " + data.toString());
    }
   
    public static class MyData {
        private String key;
        private String value;
        public MyData(String key, String value) {
            this.key = key;
            this.value = value;
        }
        public String getKey() { return key; }
        public String getValue() { return value; }
        public void setKey(String key) {
            this.key = key;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public String toString() {
            return "key =" + key + " - value = " + value;
        }
    }
}

Output:

Key = First content
Key = First content                                // <<< the String is not altered
Data = key =Key - value = value
Data = key =new Key - value = value   // <<< the MyData object IS altered
0
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 
LVL 37

Assisted Solution

by:zzynx
zzynx earned 75 total points
ID: 12065578
So, what could you do?

Make a

public class MyData {

      private int type = -1;
      private int period = -1;
      private int day = -1;
      private int less = -1;
      private Date date = null;

      // constructor(s)
      ...

      // setters
      ...

      // getters
      ...
}

private void addTimeSpan(Element from, Element to) {

    MyData data = new MyData();

    /** FROM **/
    setAttributes(from, data);  // This alters the fields of the MyData object 'data'
    fromMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

    /** TO **/
    setAttributes(to, data);  // This alters the fields of the MyData object 'data' again
    toMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());
}
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12065665
Even better
(since more object oriented; it's the MyData object that "imports" the data from an Element object)
is this:


public class MyData {

      private int type = -1;
      private int period = -1;
      private int day = -1;
      private int less = -1;
      private Date date = null;

      // constructor(s)
      ...

      // setters
      ...

      // getters
      ...

     public void importData(Element e) {
           String typeStr = from.getAttributeValue("type"),
           String periodStr = from.getAttributeValue("period"),
           String dayStr = from.getAttributeValue("day"),
           String lessStr = from.getAttributeValue("less"),
           String dateStr = from.getAttributeValue("date");
     
           if(typeStr != null)
               type = Integer.parseInt(typeStr.trim());
           if(periodStr != null)
              period = Integer.parseInt(periodStr.trim());
          if(dayStr != null)
              day = Integer.parseInt(dayStr.trim());
          if(lessStr != null)
              less = Integer.parseInt(lessStr.trim());
          if(dateStr != null)
             date = new Date(Long.parseLong(dateStr.trim()));
     }
}

private void addTimeSpan(Element from, Element to) {

    MyData data = new MyData();

    /** FROM **/
    data.importData(from);  // This alters the fields of the MyData object 'data'
    fromMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

    /** TO **/
    data.import(to);  // This alters the fields of the MyData object 'data' again
    toMoment = new MomentInTime(data.getType(), data.getPeriod(), data.getDay(), data.getLess(), data.getDate());

}
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12065693
Typo: in the importData() function replace all occurrences of 'from' into 'e'


      public void importData(Element e) {
           String typeStr = e.getAttributeValue("type"),
           String periodStr = e.getAttributeValue("period"),
           String dayStr = e.getAttributeValue("day"),
           String lessStr = e.getAttributeValue("less"),
           String dateStr = e.getAttributeValue("date");
     
           if(typeStr != null)
               type = Integer.parseInt(typeStr.trim());
           if(periodStr != null)
              period = Integer.parseInt(periodStr.trim());
          if(dayStr != null)
              day = Integer.parseInt(dayStr.trim());
          if(lessStr != null)
              less = Integer.parseInt(lessStr.trim());
          if(dateStr != null)
             date = new Date(Long.parseLong(dateStr.trim()));
     }
0
 

Author Comment

by:cathalmchale
ID: 12066155
Thanks for the info guys, its good to know exactly whats going on so I hopefully wont make the same mistakes again and again ... and again.
I guess the only problem with such a solution zzynx is that it adds to the lines of code greatly - and if your class is already quite full...!
Perhaps here is an alternative:  (again thanks, ill accept now)

/**
     * @param from Element to be converted to MomentInTime
     * @param to Element to be converted to MomentInTime
     */
    private void addTimeSpan(Element from, Element to)
    {
      MomentInTime fromMoment = createMoment(from);
      MomentInTime toMoment = createMoment(to);
     
      timeSpans.add(new TimeSpan(fromMoment, toMoment));
    }


    /** Helper method for addTimeSpan
     * @param e Element to be converted to MomentInTime
     * @return the initialised MomentInTime object
     */
    private MomentInTime createMoment(Element e)
    {
      MomentInTime moment = new MomentInTime();
      int type = -1, period = -1, day = -1, less = -1;
      Date date = null;
     
      // get all these variable values as strings
      String typeStr = e.getAttributeValue("type"),
      periodStr = e.getAttributeValue("period"),
      dayStr = e.getAttributeValue("day"),
      lessStr = e.getAttributeValue("less"),
      dateStr = e.getAttributeValue("date");
      // initialise variables with these values
      if(typeStr != null)
        type = Integer.parseInt(typeStr.trim());
      if(periodStr != null)
        period = Integer.parseInt(periodStr.trim());
      if(dayStr != null)
        day = Integer.parseInt(dayStr.trim());
      if(lessStr != null)
        less = Integer.parseInt(lessStr.trim());
      if(dateStr != null)
        date = new Date(Long.parseLong(dateStr.trim()));
       
      // return the MomentInTime object
      moment.setMoment(type, period, day, less, date);
      return moment;
    }
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12066247
Thanks for accepting

>> the only problem with such a solution zzynx is that it adds to the lines of code greatly
I definitely disagree on that!
Java is all about lots of small classes. What's the problem with one extra MyData class?

>> and if your class is already quite full...!
...then it's time to rethink the design and split it up in smaller parts
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12066282
>> Perhaps here is an alternative
Mmmm.
Only wonder why you don't make a MomentInTime constructor that accepts Element as parameter.
A function that is called createXXXX() begs for being replaced by a constructor, no?
0
 

Author Comment

by:cathalmchale
ID: 12066323
>> and if your class is already quite full...!
...then it's time to rethink the design and split it up in smaller parts


yea sometimes but when your working on a complex swing gui - panels, models etc. can grow rapidly - its nice to use inner classes so that belonging units are contained but this can sometimes reduce readability greatly etc. bla bla...
0
 
LVL 37

Expert Comment

by:zzynx
ID: 12066372
>> yea sometimes but when your working on a complex swing gui
I do
>> its nice to use inner classes
I don't ;°)
>> so that belonging units are contained
I try to use sub packages with clear names: models, renderers, decorators, ...
0

Featured Post

Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

Question has a verified solution.

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

Suggested Solutions

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
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.
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

773 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