Hey miguel--
I'm sorry if I was curt in my previous response, but time was a factor. No, just kidding (that joke was for anyone who's seen Pulp Fiction). Actually I just didn't realize it came off as a little brusque.
What I should have said is: when you write a class, it is the union of all data and methods contained in itself and all of its superclasses and superinterfaces. Access modifiers (coderanch, protected, default, and private) may restrict
access to those data members and methods, but they're still part of the class.
So if you look at Rectangle, for instance, when you create a new Rectangle instance:
rect has all of the methods it defines (getHeight(), getWidth()) as well as those defined by AbstractShape, Shape, and java.lang.Object (everything extends java.lang.Object if you don't specify some other class, so the methods and data defined therein are always available on every object).
When I first started using OO it was a little disorienting to see methods and data being accessed in an object that doesn't define them, but once you get used to it it's as natural as breathing. (Plus, javadoc has gotten better since those days so it actually does list all the methods that can legally be called on an object, including the inherited ones.)
Now a
word about getters and setters--it is true they are given special privilege by the JavaBeans specification. IMHO, though, the good people at Sun kind of screwed this one up. I understand why *getters* have special recognition, because those methods can be used to define the exact behavior of a class (if the class is written properly). Setters, on the other hand, in my mind at least, are just methods like any other operation on a class.
Here's why a getter should be special...consider this class:
Now when you go to write the javadoc of this class, how do you write the
doc for the increment method? What is the documentation supposed to say for this method? Most of the time, people will simply write something like: "increments the count". But this is not a very good definition of what the method does because let's say you're a unit tester, and you get this class and its doc. You want to verify that the class does what it says it does.
increment() says it "increments the count", but what does that mean? You might be able to figure it out because it's a fairly simple class, but I'm sure you can imagine working with a more complex class, or even for a company with its own vocabulary. What if, at your company, it is commonly known that "bump" means increment by 1, and the doc said instead "bumps the count". You might not know what that means your first day on the job.
Much better, though, is to write the documentation in terms of the properties of the class itself so that it is completely unambiguous as to what the method does: "Increments by 1 the result returned by getCount()." Now, this method is defined in terms of a property of the class--count--explicitly. If I have a class, and I call getCount(), then increment(), then getCount(), I can expect the second call to getCount() will yield a value one more than the previous call to getCount(). There is no ambiguity or company vocabulary that can impede the reader's understanding. setCount() can also be defined in terms of this property: "Changes the result returned by getCount() to c." (A very useful side benefit of this way of designing classes and writing documentation: it's easy to write unit tests because the assertions a unit test would make about this class almost write themselves.)
The problem with the JavaBeans spec, though, is it doesn't stop at defining a class property by getters. It also says that if a class lists a setXxx()-type method, whether a getter is present or not for Xxx, Xxx is now recognized as a "property". This is not as it should be, though...I can imagine a situation in which I need to use a setter but I do not wish to define a new property.
(I'm using the term "property" with a somewhat ambiguous special-ness attached to it. In OO theory, a property is defined as a special kind of element of a class. The set of properties of a class comprise the essential intrinsic nature of that class. If a class exposes a piece of data because that data is fundamental to the definition of that class, then that bit of data is a "property". This is an off-the-cuff explanation of the term, but I trust you get the point.)
For example, say I write a UserInfo class which contains a username and a password. I need the class to be mutable (the properties can be changed after instantiation), and I need to ensure that the class never enters into an inconsistent state (when one property is null (or empty string) and the other is not--so a user info object containing a username "foo" and null or empty string password is not allowed, and vice versa.)
How do I do this staying in the paradigm of JavaBeans getters and setters? Here's my first try:
Everything looks good--according to my design, I have two properties, and according to the JavaBeans spec, I have two properties: username and password. The only problem is, this class doesn't follow my rule about inconsistency. UserInfo objects should
never be allowed to break my rule of one property being non-null if the other is null...but if you try to use this class, you quickly see that its design actually requires the caller to momentarily put it into an inconsistent state. Consider a scenario where I have a UserInfo instance that I need to put to a null state:
This is unacceptable. Furthermore, you'll see that if I leave the class API as it is, there's no way to fix it! I can't have it throw an exception in the code anywhere to ensure that the caller is settings things into a consistent state, because by writing the class this way I am
requiring the user to momentarily set it to an inconsistent state. I cannot guarantee the consistency of the data...indeed, I *can* guarantee that it will be
inconsistent at some point, which is the exact opposite of what I wanted. As the developer of this class, following the JavaBeans spec to the letter, I have to leave it up to the caller to make sure they keep these UserInfo objects consistent. This is called "quality by gentleman's agreement" and it doesn't work.
Much better if I break the JavaBeans spec and rewrite the class:
This is much better than the previous version. It guarantees that an exception will get thrown if the caller ever tries to put the class into a state where either username or password are empty strings or null. No more ensuring quality by gentleman's agreement.
According to my design, there are still only two properties of this class: username and password. But according to the JavaBeans spec, a third now exists: info. This is unfortunate because info does not really meet the definition of "property" according to OO theory--and there's no way to define info as a property because there's no way to get at the data that info represents. This new "property" is redundant, and therefore not fundamental to this class, because it doesn't exist separately from the other two defined properties on the class. To prove this, I can write the behavior of the setInfo() method completely in terms of the the username and password properties on the class...but what can the info property itself be used to define? Nothing...so in my mind, it's not really a property of the class in the OO sense and shouldn't be recognized as such.
One quick note about the class above--you might be wondering how I expect not to get NullPointerExceptions in my if statement. After all, I say (u==null || u.length()==0)...what if u is null? Then won't the runtime system throw an NPE when I call the length() method on a null reference?
The answer is no--because I put the null test on the
left side of the logical OR "||", the runtime system performs that test first. If that returns true, then the JVM doesn't need to evaluate the other side--if one part of a logical OR is true, then the whole statement is true regardless of what the other side comes out to. This is called "logical short-circuiting" and is built into the language...just make sure you put the test you want performed first on the left side. You can see why this is useful if you examine the code above and consider how to perform these tests any other way and avoid NPEs--you'll quickly see how the code blows up to be somewhat more lengthy.
One final note: in case you haven't encountered it before, the ^ operator is the logical XOR--"eXclusive OR". It is true only if the two boolean operands are different. If the operands are both false or both true, then XOR'ing them yields false.
sev
[ February 27, 2004: Message edited by: sever oon ]