Editor's note: Sometimes, the most interesting discussions begin when someone says, "This may be a stupid question, but ..." If the person asking the question has taken the time to think about the problem before asking, the question is often not stupid at all. Uncertainty points out an ambiguity in the specs, holes in the docs, or a search for how more experienced programmers might address a particular problem. From time to time, we will publish one of the "(Not So) Stupid Questions" we receive and invite our readers to answer the question in the feedback section. This one began in a different form as a suggestion from Vladimir V. Ostromensky. He sent us some sample code, somewhat like the code we present below, with a question about String equality. We have adapted and extended his initial question.
Remember that new people are joining the Java community all the time and may be looking for help from those with more experience. Also, those who began with Java as their first language can benefit from those coming to the community with experience in other languages. As always, answer the questions with kindness. You are also welcome to submit your questions to
.
This may be a stupid question, but ... "Some uses of the private keyword don't make sense."
First thoughts:
To encapsulate a class, we are told to make all instance variables private. Even setters can violate encapsulation, so consider this example of an encapsulated class.
class Fraction {
private int numerator;
private int denominator;
public Fraction(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public int getNumerator(){
return numerator;
}
public int getDenominator(){
return denominator;
}
public Fraction multiply( Fraction x ){
return new Fraction ( numerator * x.numerator,
denominator * x.denominator);
}
public Fraction divide( Fraction x) {
return new Fraction ( numerator * x.denominator,
denominator * x.numerator);
}
}
The public interface is a constructor and methods to multiply and divide Fractions. We can exercise the code like this:
class Exercisor {
public static void main( String[] args) {
Fraction f = new Fraction( 1, 3 );
Fraction g = new Fraction( 2, 5 );
Fraction quotient = f.divide(g);
Fraction product = f.multiply(g);
System.out.println("1/3 * 2/5 = " +
product.getNumerator() + "/" +
product.getDenominator());
System.out.println("1/3 / 2/5 = " +
quotient.getNumerator() + "/" +
quotient.getDenominator());
}
}
In J2SE 5.0, you can easily change the type of numerator and denominator from ints to Integers and the code will still compile and run. This is the mark of a well encapsulated class - isn't it? Note that we need to use getNumerator() and getDenominator() from Exercisor, but that we can directly access the numerator and denominator from within Fraction.
In other words: objects can see the private variables and methods of an object of the same type. The private keyword is class-private, not object-private.
Note that to divide fractions, we invert the second fraction and multiply. If we change the implementation of Fraction, we can introduce a side effect that can introduce mistakes for client classes.
class Fraction {
private int numerator;
private int denominator;
Fraction(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public int getNumerator(){
return numerator;
}
public int getDenominator(){
return denominator;
}
public Fraction multiply( Fraction x ){
return new Fraction ( numerator * x.numerator,
denominator * x.denominator);
}
public Fraction divide( Fraction x) {
int temp = x.numerator;
x.numerator = x.denominator;
x.denominator = temp;
return multiply(x);
}
}
Now Exercisor returns 5/6 for both the product and the quotient, because the divide() method is permitted to swap the argument's numerator and denominator fields, even though these have private access. The result is that the second fraction is replaced with its reciprocal.
This brings me to three questions:
1. When do I want to use private?
2. What are the recommendations for using the other keywords? and
3. Is there be a way of enforcing object privacy? Should I even be worrying about this?
(Not So) Stupid Questions is where we feature the questions you want to ask, but aren't sure how.
This is a bit offtopic, but I just want to mention, that you can always break field-protection by using reflection.
The privacy of fields is only enforced in the compilation step, on the virtual machine layer it isn't strictly enforced.
/**
* Retrieves the specified field of the given object.
*
* @param object the object that holds the field
* @param fieldName the name of the field
* @return the field
* @throws NoSuchFieldException when the field does not exist
*/
public static Field getField( Object object, String fieldName )
throws NoSuchFieldException
{
try {
Field field = null;
Class instanceClass = object.getClass();
while (field == null) {
try {
field = instanceClass.getDeclaredField( fieldName );
} catch (NoSuchFieldException e) {
instanceClass = instanceClass.getSuperclass();
if (instanceClass == null) {
throw e;
}
//System.out.println("trying parent class [" + instanceClass.getName() + "]");
}
}
field.setAccessible(true);
return field;
} catch (SecurityException e) {
e.printStackTrace();
throw new NoSuchFieldException( "Unable to access field [" + fieldName + "]: " + e.toString() );
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw new NoSuchFieldException( "Unable to access field [" + fieldName + "]: " + e.toString() );
}
}
The above code is taken from the GPL'd J2ME Polish project.
This is a bit offtopic, but I just want to mention, that you can always break field-protection by using reflection.
Only when there is no security manager! The field.setAccessible(true) will check whether there is a security manager installed, and if so, ask it whether the operation is allowed.
By default there is no security manager, but application servers for instance, when running in production mode, will install a security manager which will not allow shenanigans like these, because they are responsible for protecting applications from each other.
Java would be badly broken if you really could not rely on private being private in production code...
Im only just starting out in java, learning it at university.
Ive always thought encapsulation to stop direct access to fields within other classes, get and set methods should be used to modify them.
This to me means that, any get and set methods would check that the data is within parameters, for example if you have a field that need between 1-10 for a ranking system or something, its no good changing it to 11.
You cannot stop direct access, as even using get and set methods are accessing the variable, and by some path its accessing the field.
In the example you are relying on the same class to make sure the fields that are to be divided or multiplied are able to. Really you should check the numbers arnt 0 within the constructor before it sets them, there are some other values that are out of range of ints etc that might need ot be checked. The example is quite simple, and the problem is with the class not the objects.
Encapsulation should stop other classes from directly accessing data, not the same class but a different instance of the object, the code should be setup so that every object will have good fields to prevent crashes.
I garentee you much of this may not make sense, but there you are im welsh!
I can't think of any way to strictly enforce object privacy, but as this example shows, object privacy is important.
As a rule of thumb, objects should access their own data members via the same accessors other classes would use.
So, rather than just accessing numerator and denominator members directly, correct code would use getNumerator and getDenominator accessors in the multiply method. When divide was implemented, the same rule applies, and the implementor could either
return new Fraction(x.getDenominator(), x.getNumerator).multiply(this) ;
which is a bit wasteful, or
int n = getNumerator()*x.getDenominator();
int d = getDenominator()*x.getNumerator();
return new Fraction(n, d);
The point is, swapping x's numerator and denominator isn't an option, because Fraction doesn't allow anyone to modify it, even itself. It's up to the programmer to use apply this discipline however, since there's no formal way to declare it.
Acquiring this discipline saves a lot of headaches when accessors are changed or overridden. Everything keeps working because nothing has circumvented the accessor logic with direct references.
If you find this cumbersome, the alternative is to use the final keyword a lot -- which is not a bad thing. If your class depends on things being implemented in a certain way, it should enforce that with the "final" keyword. This allows you to inline your getter's code by hand without fear of finding it broken by future changes. In the old days, this was also a nice optimization hint, but lately, I find Hotspot getting along just fine without the gratuitous hints.
My answer...
2004-12-19 11:15:30 tackline
[Reply | View]
As general comments on the code:
Values such as Fraction should supply hashCode, equals and toString.
You may want to consider ensuring that the denominator is strictly positive and reducing to the simplest terms. It doesn't take many operations for a fraction expression to build up large denominators and numerators. Perhaps use long or better BigInteger.
I tend to avoid variable names as non-descriptive as "x" or "temp". In this case 'other' and either 'otherNumeratorOrig' or 'otherNumeratorOriginal' are better alternatives.
1. When do I want to use private?
Pretty much always on member variables and inner classes. Whenever you can, usually not very often, on methods. You do not want to have to worry about code outside of your class playing with your privates. That applies equally to access through get and set methods.
For immutable objects you may want to consider making the constructor(s) private and adding a static creator method. You can then, for instance, cache common values. Perhaps subclass for special cases, such as integer fractions, decimals, fraction expressible as long/long and fractions that require BigIntegers.
2. What are the recommendations for using the other keywords?
Modifiers?
final - On member variables whenever you can, and occasionally on local variables to make things clearer (or for anonymous and local inner class access). Apply to classes to overcome issues with equals and other binary operations.
abstract - You should aim to not write concrete (non-abstract) methods that are overriden. Concrete should sink to the bottom of the class hierarchy. If you find most of the methods of a class are abstract, consider using an interface. Use on utility classes together with a private constructor that throws an error (although utility classes are an indicator of poor design, allegedly).
static - Never on a variable (unless final and either private or unmodifiable). Do not force the creation of an object solely to execute a single method on it.
transient - Don't serialise anything not absolutely necessary for the representation. No duplication of data (not that that is a good thing anyway). Also back edges. For instance Component has parent transient so serialising does take the whole ancestral window and contents with it.
volatile - Very rare. Usually used incorrectly. Prior to Java 1.5 only really useful for primitives. For instance to signal to a long calculation to cancel. From 1.5 can be used for double checked locking. In general something to be avoided by the general public.
@Override - Not strictly a modifier or a keyword, but always use it in 1.5+ code when overriding.
public - Constants and most methods.
protected - Rare. Usually defined as abstract in an abstract base class. C++ equivalent would be a private, pure virtual function. Sometimes used on member variables if being a bit lazy.
(the default, package private access) - I would tend not to bother using this, other than on classes and interfaces. Unless doing some nasty optimisation.
As a matter of clarity I prefer not to explicitly have public abstract on interface methods, and public static final on interface constants.
In summary, prefer to use transient (if owner Serializable), private, abstract, final and not volatile.
3. Is there be a way of enforcing object privacy? Should I even be worrying about this?
Kind of possible, but it is a hack and I do not recommend it. Make your class final (for class privacy) and create a super class in its own package with the "private" members as protected. More conveniently, if you reference other objects through an interface, then you can't accidentally poke their privates.
But no, you don't want to bother about it. In Java the class is in a sense the fundamental unit of code. It is not a useful concept to protect a unit of code from itself.
The divide shortcut demonstrated isn't particularly useful. It doesn't improve clarity or improve performance. If you wanted to reduce repetition, introduce a private multiply(otherNumerator, otherDenominator) method. In general it's a good idea not to call public methods on 'this'. Implementing divide as multiply(other.reciprocal()) would actually give reasonable performance, particularly if you had already switched to BigInteger.
In the example provided, a reverseDivide could use the same technique of "temporarily" modifying its own members. Having instance privacy would not help.
Never use member variables as if they were locals. In some circumstances, when extending a library class, it is necessary to modify instance state for the duration of a method. Often you need to check for recursion. In this case, add a try/finally to ensure the values are set back to their correct values. There is always the chance you have over missed a possible exception, for instance divide by zero, or an error such as out of memory or stack overflow. Consider using a ThreadLocal if it may be accessed concurrently. Don't look to the Java libraries for good example code...
It dawned on me at dawn that my protected hack is complete nonsense. It would only work if you referred to the other object through the introduced base class, which makes it pointless. Probably thinking about protected as relates to inner classes, which I can't remember either.
Worrying about object-privacy
2004-12-17 09:34:20 heaththegreat
[Reply | View]
Privacy is used to hide implementation from the user of a class.
You needn't worry about Object-level privacy because you (the Object's author) are the only one that has access to the internals of the Object.
It does, of course, mean that you can shoot yourself in the foot (as you did with the second divide implementation). But, assuming you write the class correctly, no one can programmatically change the implementation.
Worrying about object-privacy
2005-01-04 05:57:35 jimburnell
[Reply | View]
I'm surprised that this is the only response so far that gets it right. In fact, I'm sort of surprised that this topic was even posted here.
The one and only reason for information hiding is to protect external users of a class from future changes in implementation. Internal users by definition MUST have access to the private members of an object, because they're the ones that make the object do what it has to do. The only good reason for the implementor of a class to use the class' public interface functions is to avoid code duplication (assuming those functions do something non-trivial).
The concept of "enforcing object-level privacy" is an excellent example of taking a good software concept to ridiculous extremes.
Encapsulation problem
2004-12-17 07:15:00 jt2190
[Reply | View]
Yes, you can easily change the type of numerator and denominator from ints to Integers and the code will still compile and run, however, this is not the mark of a well encapsulated class. You've actually broken encapsulation! This is a classic problem.
If Fraction returns a reference to an Integer, the object receiving that reference may use it to work directly with the "private" object, without going through Fraction. The instance of Fraction can even cease to exist, and the Integer can stick around.
To solve this, return a copy of the private Integer.
The same works in reverse... if you set one of Fraction's Integer references to a reference provided by an external object, you have no guarantee that there aren't other references to that Integer object. Have Fraction create or update its own instance of Integer.
Encapsulation problem
2004-12-17 07:36:31 dasouk
[Reply | View]
actually there is no need to return a copy of the Integer, Integer objects are immutable so they don't break the encapsulation even though the reference to the Integer can be passed around
:D
Encapsulation problem
2004-12-17 15:22:13 jt2190
[Reply | View]
Yes, this is correct. If only all objects were like this, we could avoid the whole problem.
Placing final in front of the immutable object only stops you from changing your variable to referance another object. It does nothing to protect your class. In the case of an immutable object you don't have to do any extra work to protect it. In the case of normal objects you need to make a copy of them in order to protect your class from a user modifying the internal objects. Here making something final does nothing also as they reference is final, but the object can still be modified.