Java FAQ and Advice

Created April 20, 2006. Last Updated: April 22, 2006

This FAQ will be extended from time to time, and the author will accept requests for additions, corrections, and modifications.It was created on request (long ago) of Fran Trees as a service to the Advanced Placement Computer Science teachers: a wonderful bunch of incredibly dedicated educators. Some questions seem to recur periodically on the AP list and this tries to capture the answers provided there.

Explain Java visibility: public, protected, private, and default

If you are familiar with C++ note that the Java meaning of protected is different.

Java provides five (now) kinds of visibility. Most people say 4, so stay tuned.

Public: the feature is visible everywhere.

Default (no marker) the feature is visible within its package

Private: the feature is visible within its own class only.

Protected: The feature is visible within its package AND within subclasses of its class in other packages

NESTED classes. The features of nested classes are mutually visible (to nester and nestee) regardless of visiblity markers -- which only means anything for private.

The intent of visibility is to protect code from misuse by other programmers, NOT to separate code from other code. Restricted visiblity lets you maintain invariants, in particular.

Protected is really only useful in (a) multi package projects and (b) library code where the user of the library is expected to extend the library, not just use it. In particular, it is unlikely to ever be very useful in the kind of code written within an AP course. This author never uses protected fields any more (ah, my sinful past), but occasionally provides a protected accessor for a private field. Protected mutators (setters) for private fields are a really bad idea, however. Package visiblity is preferred in the extremely rare situation in which you might need this. Read the entry on Immutable Objects for some hints.

In C++ protected closes visibility. In Java, it OPENS visibility.

 

Explain Immutable Objects and why they are a good idea

An object is Immutable if its state cannot be changed once it is created.

To create an immutable, do the following

It's class should have private final fields. (Fields should always be private anyway.)

It's constructors must completely initialize the object to a usable state. (You should always do this anyway.)

Note that since the fields are final you cannot provide mutators (setters) for them.

Immutable objects are a good idea since they are like constants. A program with a high proportion of immutable objects is easier to reason about than otherwise. The state of any object is the state in which it was created.

Note that there is a higher degree of immutable than we have described here. If a class defines a field that is a collection, then that collection could have elements added to it or deleted from it without breaking the rules we have set here. Sometimes it is possible to preload such collections and enforce this higher level of immutability: no modifications are permitted and no modifier methods are provided.

Note that any class that has a lot of setter methods probably isn't very well designed. If the setters just set fields, the user of the class is probably thinking about those fields rather than at an abstract and conceptual level about what the object represents. The fields should be the last thing you add to a class definition, not the first. The public methods define the capabilities of the objects of the class and they should have a consistent easy to use design, based on a metaphor about the objects. So, even if a class isn't immutable, then think about how many of the fields can be final.

When I run my program I get an exception, perhaps Null Pointer Exception. What does this mean and how do I deal with it?

Java reference variables are like pointers. All Java objects are created dynamically with the new operator. If you have a reference variable and don't initialize it correctly you will get a Null Pointer Exception.

All exceptions in Java produce volumes of information, including a trace of all outstanding method invocations. Here is an example. The earliest call is at the bottom (it is a stack, actually) and the current method at the top. The numbers are line numbers in the source code of the program, when available. (This example came from a program written in a compiler course.)

java.lang.NullPointerException
at micro.Codegen.extractExpr(Second.java:835)
at micro.Codegen.generate_2(Second.java:861)
at micro.Codegen.loadreg(Second.java:808)
at micro.Semantic.genInfix(Second.java:711)
at micro.Parser.expression(Second.java, Compiled Code)
at micro.Parser.statement(Second.java:484)
at micro.Parser.statementList(Second.java, Compiled Code)
at micro.Parser.program(Second.java:446)
at micro.Parser.parse(Second.java:434)
at micro.Second.main(Second.java:968)
Exception in thread "main" Process Exit...

Therefore, look on line 835 of your program (in file Second.java ) in method micro.Codegen.extractExpr. Somewhere on that line is a reference variable that was not properly initialized, giving the Null Pointer Exception. Other exceptions may not involve reference variables, but the line numbers are accurate. Look there for the error. You can trace back to see how the program got to the final function by going down the stack. extractExpr was called from generate_2 at line 861, which was called from loadreg line 808, etc.