Home arrow Java arrow Page 8 - Java in Review
JAVA

Java in Review


Tired of hearing about the gory syntax details of Java? Keep reading for a more conceptual view of the language, focusing on important issues that deserve more attention than they usually receive. Even an advanced programmer will find useful information in this article. It was excerpted from chapter one of Hardcore Java, edited by Robert Simmons Jr. (O'Reilly, 2004; ISBN: 0596005687).

Author Info:
By: O'Reilly Media
Rating: 4 stars4 stars4 stars4 stars4 stars / 12
June 16, 2005
TABLE OF CONTENTS:
  1. · Java in Review
  2. · Syntax Issues
  3. · Collection iteration with for
  4. · Labels
  5. · Assertions versus exceptions
  6. · Assertions and deployment
  7. · Initialization
  8. · Access Issues
  9. · Common Mistakes

print this article
SEARCH DEVARTICLES

Java in Review - Access Issues
(Page 8 of 9 )

When you look through the many Java books that are available, they all talk about access restrictions. The words private, protected, and public are some of the first keywords that a newbie Java programmer learns. However, most of these books discuss access restrictions only with regards to the impact of restrictions on the code.

By now, you should know what a private method is and the difference between private and protected. Therefore, I won’t bother rehashing this familiar territory. Instead, I would like to take your understanding of access restrictions to another level. Instead of focusing on what they do, I will focus on which to use in various situations.

Preferred Restrictions

While writing Java programs, many programmers fall into a definable pattern. All attributes are private, all interface methods are public, and all helper methods are private. Unfortunately, this causes a ton of problems in the real world. Consider the following common GUI code:

  package oreilly.hcj.review;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import javax.swing.*;
 
public class SomeDialogApp extends JDialog implements ActionListener {
   
private JButton okBtn = null;
    private JButton someBtn = null;
   
// ...etc.
   
public SomeDialogApp() {
      setJMenuBar(buildMenu());
      buildContents();
   
}
   
public void actionPerformed(final ActionEvent event) {
      Object source = event.getSource();
      if (source == this.okBtn) {
        
handleOKBtn();
      } else if (source == this.someBtn) {
        handleSomeBtn();
      }
     
// ...etc.
    }
   
private void buildContents() {
      this.okBtn = new JButton("OK");
      this.okBtn.addActionListener(this);
      this.someBtn = new JButton("Something"); 
      this.someBtn.addActionListener(this);
      // ...etc.
   
}
   
private JMenuBar buildMenu() {
      JMenuBar result = new JMenuBar();
     
// ...add items and menus
      return result;
    }
   
private void handleOKBtn() {
      // handler code
    }
   
private void handleSomeBtn() {
      // handler code
    }
  }

In this code, the attributes are all private. There are also four private helper methods: handleSomeBtn(), handleOKBtn(), buildContents(), and buildMenu(). Everything in this class is okay until someone wants to modify the class. For example, what if I only want to change the functionality of the handleOKbtn() method and reuse the rest of the class -> In this case, I would basically have to reimplement the entire dialog. Accessing the button instance itself is impossible, so I wouldn’t be able to rebuild the actionPerfomed()method. Furthermore, since the helper method is private, I can’t access that either. Time to reinvent the wheel.

On the other hand, if all those helper methods were protected instead of private, I would be able to simply redefine the meaning of the handleOKBtn() helper method and reuse the entire class.

When developing classes that others will use, you can never be sure what they will want to do to the class. But if your goal is to promote reuse, making the helper methods protected allows the users to extend the class. Also, since protected blocks users attempting to use the method directly, you won’t be giving up any security on that front. On the other hand, those inheriting from your class will have access to these helper methods. However, the general assumption you should be making is that people extending the class generally know what they are doing. Even if they don’t, the worst they can do is break their derived class.


I came hard up against this problem recently when trying to extend the Introspector class to perform some functionality. I merely wanted to redefine one method. However, because that method was private, and Introspector is implicitly final (which we will discuss in the next chapter), I couldn’t do it.

In the end, you are better off using private for attributes—public for public methods, and protected for helper methods. This gives your class maximum reusability without breaking encapsulation.

Friends Allow Unrestricted Access

Most access permissions are clearly laid out in the class file. However, many Java programmers don’t understand the access permissions as they are related to instances of the same class. I call these instances friend instances.

In real life, friends don’t allow unrestricted access. You can rarely borrow a friend’s car without asking. Java is much more friendly and trusting. In Java, instances of the same class are friends and give unrestricted access to all of their properties and methods. This unlimited access is a serious hazard that must be carefully avoided while making solid code. The class in Example 1-10 shows how friend instance access works.

Example 1-10. Demonstration of friend instance access

  package oreilly.hcj.review;
  public class FriendAccess {
    private int value;
   
public FriendAccess(final int value){
      setValue(value);
    }
   
public void setValue(final int value) {
      this.value = value;
    }
   
public int getValue() {
      return value;
    }
   
public void someMethod(final FriendAccess obj) {
     
if ((obj.value == 5) && (this.value == 5)){
        obj.value = 25; // <= Ouch, this works and bypasses the setter.
      }
   
}
  }

In someMethod, different instances of the same class have complete access to each other. This can become a problem when you modify the class a little bit. Hack on the class until you end up with this variation, which demonstrates the dangers of friend access:

  package oreilly.hcj.review;
  public class FriendAccess {
    private int value;
   
public FriendAccess(final int value) {
      setValue(value);
    }
    
public void setValue(final int value) {
     
if (value > 10){
        throw new IllegalArgumentException();
      }
     
this.value = value;
    }
   
public int getValue() {
      return value;
    }
    
public void someMethod(final FriendAccess obj) {
      if ((obj.value == 5) && (this.value == 5)) {
        obj.value = 25;
      }
    }
  }

In this variation, the range-checking code that is emphasized in the setValue( ) method was added. Now, if you look back at someMethod( ), you see that the method body sets the property value of the instance passed and completely bypasses the setter. The problem is that you set value to something that the setter would have rejected as illegal. However, since you have access to the variables directly, you can make the change and get away with it. Later, when some other class uses the object, expecting its value to be less than or equal to 10, your code will explode. Fortunately, you can easily block this with another edit to the code:

  package oreilly.hcj.review;
  public class FriendAccess {
    private int value;
   
public FriendAccess(final int value) {
      setValue(value);
    }
   
public void setValue(final int value) {
      if (value > 10) {
        throw new IllegalArgumentException();
      }
      this.value = value;
   
}
   
public int getValue() {
      return value;
    }
   
public void someMethod(final FriendAccess obj) {
      if ((obj.value == 5) && (this.value == 5)) {
       
obj.setValue(25); // <= IllegalArgumentException
     
}
    }
  }

If you write your class this way, you generate a lot of overhead due to the call to the setter. However, you also reap the benefits of having your setters work and your debugging time massively reduced. The bug in the above class should take any competent programmer about 10 seconds to fix once he sees the RuntimeException.

Directly setting member variables of a different instance is a problem waiting to happen and should be avoided. The compiler won’t stop you from doing it—then again, a gun won’t stop you from shooting yourself in the foot either.

In fact, I wouldn’t even advise setting properties directly in the same instance. Properties that use setters and getters are special little creatures with their own needs. Many of the setters perform logic checks or do other tasks that you may miss if you set them directly in other utility methods. (See Example 1-11.)

Example 1-11. A bean that uses friendship to bypass setters

  package oreilly.hcj.review;
  public class FriendBean extends MutableObject {
    private int value;
   
public FriendBean(){
      super();
    }
   
public void setValue(final int value) {
      if (value > 10) {
       
throw new IllegalArgumentException();
      }
      int oldValue = this.value;
      this.value = value;
      propertyChangeSupport.firePropertyChange("value", oldValue, value);
    }
   
public int getValue() {
      return value;
    }
   
public void someMethod() {
      if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) ==
        Calendar.THURSDAY) {
        this.value = 25;
      }
    }
  }

One problem with this code is that someMethod( ) sets the property value directly while bypassing the setter and the property change event. If any GUI objects are registered as property change listeners, they won’t know about the change and will display stale data. To fix this, you could potentially alter the method so that the method fires the property change event.

This will work, but, of course, you will have to replicate all of the other logic in the setter method whenever you set the value in a utility method. To make matters worse, whenever you add new logic to the setter, you must also remember to add the same logic to someMethod( ). This would be extremely bad practice in object-oriented, or even procedural, software engineering. If you use the setter for the property, as the variation below shows, your life will be much easier:

  package oreilly.hcj.review;
  public class FriendBean extends MutableObject {
    private int value;
   
public FriendBean() {
      super();
    }
   
public void setValue(final int value) {
     
if (value > 10) {
       
throw new IllegalArgumentException();
     
}
     
int oldValue = this.value;
     
this.value = value;
     
propertyChangeSupport.firePropertyChange("value", oldValue, value);
    }
   
public int getValue() {
      return value;
    }
   
public void someBetterMethod() {
      if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) ==
         Calendar.THURSDAY) {
        this.setValue(25);
      }
    }
  }

In this variation of your class, you reuse the functionality of the setter by calling the setter whenever you want to change the property’s value. This approach is far easier to maintain and to change if the need arises; you have to change only the setter and not any other code. Overall, you should not be setting the value of properties, even in the same instance, without using the setters in the class. In fact, if a property has a setter, that setter should be the only thing that ever alters that property. In addition to preventing possible bugs, this technique implements proper encapsulation.


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials