Chapter 8

Using Java Constructors

Constructors are the last major Java class elements you need to cover. They’re a lot like methods in appearance. In fact, I’ll be able to use some of the discussion in Chapter 7, “Using Java Methods to Communicate,” to address what the similarities are and how you can apply them.

Unlike methods, constructors tie into the way objects get made, not just for the class they belong to, but also for classes they inherit from and classes that inherit from them. That subject is a chapter in itself, so here we’ll confine discussion to the way constructors work for the class at hand.

In this chapter, we’ll cover the following topics:

  • Using the default constructor
  • Defining alternate constructors
  • Adding parameters to constructors
  • Overloading constructors

Using the Default Constructor

certobjective.eps

As I mentioned back in Chapter 1, “Introducing the Basics of Java,” the compiler will insert a default constructor into your class if you don’t write one in. If you write one the way the compiler would—public visibility, no parameters, and no code—it’s often called a no-arg constructor. It’s the same code either way, but the terms help to separate the implicit and explicit options.


In Chapter 9, “Inheriting Code and Data in Java,” I’ll explain why the default constructor is a necessity for making objects. You do need it!

Either constructor has the specific role of initializing each field in its class. In Chapter 1, I claimed that Java’s type-safety rules ensure that each field will get a type-appropriate default value—whether it is integral zero, floating-point zero, false, or null—if it receives no explicit assignment. The compiler uses the default constructor to apply these rules.

The rules for the default constructor are simple:

  • Its name is the same as its class.
  • It has no return type.
  • It has no parameters.
  • It is declared public.
  • It has no code in its body.

If a constructor you intended to write fails the first rule, the compiler will complain that you have a bad method declaration, as shown here:

final class RuleOne {
public RuleWon() {}
}

$ javac RuleOne.java
RuleOne.java:2: error: invalid method declaration; 
   return type required
        public RuleWon() {}
               ^
1 error

Thus if you do not observe both the first and second rules, the compiler may not complain—what you have written will look like a method. If it does complain, it will probably have to do with failing to support the return type, as shown here:

final class RuleTwo {
public int RuleTwo() {}
}

$ javac RuleTwo.java
RuleTwo.java:2: error: missing return statement
   public int RuleTwo() {}
                         ^
1 error

Those are the only two things that distinguish a constructor from a method, so far as the compiler is concerned, and they’re often easy to miss.

Constructors also aren’t class members in the same sense that fields and methods are. If you decide to name a method after the class, the compiler sees no problem:

public final class Class {
public Class() {}
public void Class() {}
}
$ javac Class.java
$

It’s a doubly poor choice for a method name because it shadows the class name and a reserved word as well. Nonetheless, this code compiles without error.

If your constructor observes the first two rules but not the remaining three, you still have a constructor, just not a default or no-arg constructor. Like methods, constructors can be overloaded, can have narrower access, and can contain code:

import java.util.Date;
final class MyDate {
private Date date;

   MyDate() {
// Allow package caller an epoch
// January 1, 1970 00:00:00 GMT
date = new Date(0);
   }
public MyDate(Date date) {
if (date == null)
this.date = new Date();
else
this.date = date;
   }
}

If you want to call another constructor in the class, you can’t do it by name. See the section “Overloading Constructors” for details.

In this example, I’ve given the no-arg constructor default access code to construct an “epoch” date, the assigned birthday of the Unix operating system. Callers from other packages have to pass their own Date object. If they supply a null value, they get an object with the current time.

That said, I should mention here that passing an object reference into a constructor has deeper consequences than it does for a method. The usual reason for doing this is to initialize a field, as the example shows. This action implies that the calling method and the new object will share a reference, and it’s worth considering whether you want to maintain a dependency of that sort. I’ll review the reasons for and against this approach later in this chapter.

Defining Alternate Constructors

certobjective.eps

It’s a common inference that constructors are like methods that bear the class name and have no return type. Tread lightly with this comparison. There are useful similarities, but the differences are more important and sometimes subtle. Construction is a key player in the relationship a class has with its parent class(es). I need at least one more chapter of your time to fully define that relationship. That’s Chapter 9. If you’re the impatient sort, hang tight at least until then.

You also know now that a constructor isn’t a class member in the same sense as a field or method. Specifically, it doesn’t have quite the same scope with them. A constructor also works with fewer modifiers, so its general syntax is simpler than a method’s:

access_modifier class_name (parameters) { statements }

You cannot modify a constructor with any of the following keywords:

  • static
  • final
  • synchronized
  • strictfp
  • native

Any access modifier is acceptable. As you’ll see throughout this chapter, each access modifier imparts a special meaning to a constructor.


Beware: Methods and fields can use their class name as a legal identifier without conflicting with a constructor or even with each other.

A quick review: constructors have the following conditions:

  • No return type
  • Access modifiers only
  • A separate namespace
  • Same name as the class

With those conditions in mind, I think calling a constructor a kind of method isn’t completely wrong, but it’s a limited comparison with more qualifications to observe than similarities to exploit.

The changes you can make with constructors—access visibility, parameter list, and code body—nonetheless allow for some interesting effects. It makes more sense to talk about the effects you want, and how to achieve them with access modifiers, than the other way around. The following sections adopt that focus.

Hiding (Replacing) the Default Constructor

A default constructor is a fine thing as long as default initialization of your fields is what you want. Remember, once you create a no-arg constructor, the default constructor goes away. So long as there is one valid, explicit constructor in a class, the compiler is satisfied and does not intervene. Replacing the default constructor is therefore synonymous with hiding the compiler’s version.

The compiler will still specify default values for all member fields you don’t initialize, so it’s still okay to do as little work as you need to in this area. You can initialize some fields and leave others alone, as this example shows:

public final class MyDefault {
    private String name;
    private String location;
    public MyDefault() {
        name = "Riley Ibex";
    }
}

The name variable gets set to the literal String value given in the constructor. You could instead assign this value as part of the field declaration. If you do both, the constructor version wins. The location variable will be assigned the null value.

Incidentally, the short and focused nature of my examples leads me to declare fields at the top of the class structure. You don’t have to do this in Java. In fact, don’t. Declaring your variables close to where they are used, particularly in code that doesn’t fit on a single screen, makes it easier for another programmer to refer to the type, as this example shows:

public final class Relates
{
private String name;
public String getName() { return name; }
private String location;
private String getLocation() { return location; }
}

I mention this because it’s tempting to keep declarations next to an explicit constructor when you’re first writing a class. It’s an easy way to track types as you put the constructor together. But once a class is tested and ready for use, it’s not much help to anyone who isn’t debugging the constructor itself.

An explicit constructor is often self-documenting in this regard. If you’re calling other constructors inside your constructor (or using literals), the type information is front and center:

public Relates() {
name  = "Riley Ibex";
location = new String("San Francisco");
}

It’s hard to make a persuasive case in a dozen lines or fewer, but once you come across a Java class that runs hundreds of lines, or even more, you’ll appreciate every means you can get of organizing the code for readability.

Limiting Constructor Access

In a Java package (or a single source file), non-public classes often participate as subordinates to the public-facing class. As I showed in a previous example, a default access constructor might initialize one or more fields to values that makes sense for the type. If the caller using the public constructor passes in nonsense or a null value, a behind-the-scenes constructor can document how the class tries to ignore those efforts and keep the program running. A constructor can also throw exceptions in response to bad input. I’ll cover this technique in Chapter 11, “Throwing and Catching Exceptions in Java.”

Another motivation for hiding data, encapsulating it, and even limiting access to the encapsulating methods themselves is to create an internal context for the class. You establish a private context in your class when you guard its fields against any mutation at all, on the premise that a caller could violate the boundaries you prescribe for an object’s state.

A Java array does this by fixing its length upon construction. The String class does this by using an array and fixing its contents upon construction, creating an immutable object. While you don’t always need a class to operate under constraints that are as tight, you always want to consider which methods you must expose to callers for the class to do its intended job and expose only that.


If there’s one thing programmers should be taught to dislike, it is code behavior that is surprising.

It’s no different for constructors. Anyone can call a public constructor in a public class. That call will always allocate memory resources and will always return a new referent. Those are big consequences in an object-oriented world. If you don’t plan for it a class at a time, you aren’t planning at all. Start by asking when it’s appropriate to make objects and how you’re going to manage them.

In particular, side effects in a constructor—operations that silently alter the object’s state—can be far more confusing than it is with methods. Mixing state change with initialization is an unfair puzzle, and a programmer shouldn’t have to guess if (or why) a class does it. Consider a constructor that takes an object parameter and changes it, as Listing 8-1 shows.

Listing 8-1: Public constructor with side effects

package essentials.ch08;
final class YourBuffer {
private static int counter = 1;
private StringBuffer buffer;
public YourBuffer(StringBuffer buf) {
buffer = buf;
      buf.append(counter++);
      System.out.println("YourBuffer() field: " + buffer);
   }
}
final class MyBuffer {
private StringBuffer buffer;
public MyBuffer() {
buffer = new StringBuffer("starter");
    }
public StringBuffer getBuf() {
return buffer;
    }
}
final class TestBuffers {
public static void main(String args[]) {
        MyBuffer mb = new MyBuffer();
        System.out.println("mb buffer: " + mb.getBuf());
        YourBuffer yb = new YourBuffer(mb.getBuf());
        System.out.println("mb buffer: " + mb.getBuf());
        yb = new YourBuffer(mb.getBuf());
        System.out.println("mb buffer: " + mb.getBuf());
   }
}
$ java -cp . essentials.ch08.TestBuffers
mb buffer: starter
YourBuffer() field: starter1
mb buffer: starter1
YourBuffer() field: starter12
mb buffer: starter12

Imagine that the MyBuffer and YourBuffer classes represent different storage, one of which is used to seed the other’s content. In the TestBuffers class, I construct a MyBuffer object and pass its string to the YourBuffer constructor. That constructor modifies the parameter. The MyBuffer object gets its data changed each time the TestBuffers program uses it to construct a YourBuffer object.

You could expect a method to do this, in particular a functional one. In a constructor, it is unseemly behavior at best and one of the reasons you want to think carefully about passing your object data to a constructor. If there is any silent effect permitted by calling a public constructor, it’s a matter of time before someone makes it hurt. Until you’re sure your constructor doesn’t induce such effects, don’t make it part of the class’s public interface.

Using Packages to Encapsulate Constructors

That said, there are positive reasons for using non-public constructors.

Use one class to construct another class. If you have a class that shouldn’t be instantiated directly—let’s say it has a context that a public caller could not piece together—then delegate the responsibility to another class in the same package.

To understand why this is important, let’s review an example in detail. I need at least two public classes, one with a constructor declared public, the other with a default-access constructor. That is, I have two classes I can see but only one I can construct. The classes must share a package, but because they are all declared public, they can’t share a file. That constraint implies you’ll need to review multiple files at one time to understand what’s going on.

This is, by the way, another (unavoidable) outcome of class dependencies: You have to learn to read two more files at the same time to piece it all together. A diagram would come in especially handy here, so let’s have one. Figure 8-1 shows all the relationships I propose for the upcoming code sample using Unified Modeling Language (UML) signifiers.

Figure 8-1: Using one class to construct others

c08f001.eps

The lines ending in a filled diamond signify a composition of elements. That is, the Program class is composed of an A object, along with whatever else, and the A class is composed of a B object, along with whatever else. The open arrowheads signify navigability: The TestProgram class can get to the Program class and the A class can get to the C class. (The TestA class says it gets to the A class, but that remains to be seen.)

Compilation can get tricky without a little help, so I’m keeping things simple by compiling the classes in reverse order of dependencies. Here are classes C and B:

package essentials.ch08;
public final class C {
   C() {
      System.out.println("C object made");
   }
}
$ javac -d . C.java
$
package essentials.ch08;
public final class B {
   B() {
      System.out.println("B object made");
   }
}

$ javac -d . B.java
$

Each class is declared public and has a default-access constructor that prints to the command line when an object is made. You can see them from outside the package, which is necessary to declare variables of those types.

The A class has a default-access constructor too and maintains a field of type B that it initializes in its constructor:

package essentials.ch08;
public final class A {
private B b;

   A() {
      System.out.println("A object made");
b  = new B();
   }
}
$ javac -d . A.java
$

The last thing I’ll add to this package is a Program class with a public constructor. When called, it will construct a C object, just to demonstrate access. It also supports a makeA() method to return an A object back to any caller:

package essentials.ch08;
public final class Program {
public Program() {
      System.out.println("Program object made");
// just to show C is accessible
      C c = new C();
   }
public A makeA() {
return new A();
   }
}
$ javac -d . Program.java
$

A bug that is added to working code is called a regression. Testing one class at a time is called unit testing.

Adding test code inside the package, by the way, is a good idea. Testing in increments and after each (substantive) change to code ensures that you’re making progress and not introducing bugs to tested code. I am again streamlining that process here to stay on point. Each class you write, however, would not suffer from a main() method that tests the class elements. It takes longer, but the exercise also teaches you that the compiler covers only so much territory. It’s fine for testing correct language use. It is inadequate for testing correct program operation.

Nonetheless, I’ll skip directly to the external test. I need a program in another package to construct a Program object and get an A object from it. I should also do something to prove I’m getting a live A object and not a null value.

Just before looking at code, however, I want to make sure I understand the sequence of events. It’s hard and error prone to form a mental picture over several files of source code. A UML sequence diagram gives you a way to map the expected action. Vertical bars show the lifetime of each instance; arrows show who’s calling who and who is returning what to whom. The timeline flows from top to bottom.

Figure 8-2 is a sequence diagram that specifies how a TestProgram class should interact with the objects in the essentials.ch08 package.

Figure 8-2: UML sequence diagram with the TestProgram class

c08f002.eps

Take a moment to see if this diagram squares with your impression of the source code shown so far. Now all that remains is to write the TestProgram class and see if it all works out! The TestProgram code is shown in Listing 8-2.

Listing 8-2: TestProgram class code, compilation, and execution

package essentials.ch08.test;
import essentials.ch08.Program;
import essentials.ch08.A;
public final class TestProgram {
public static void main(String args[]) {
      System.out.println("Testing essentials.ch08.Program
");
      Program prog = new Program();
      A aObj = prog.makeA();
// Prove it’s an actual object
      System.out.println("A object: " + aObj);
   }
}

$ javac -d . TestProgram.java
$ java -cp . essentials.ch08.test.TestProgram
Testing essentials.ch08.Program

Program object made
C object made
A object made
B object made
A object: essentials.ch08.A@1715510

This program confirms our expectations. The output shows objects made from the classes C, A, and B, in respective order, and the TestProgram class receives an A object it can operate on. Now I need to show that the TestA program, specified in Figure 8-1, doesn’t work. If it does, it means package access doesn’t work as advertised. Or it means my code didn’t implement it properly, which is more plausible:

package essentials.ch08.test;
import essentials.ch08.A;
public final class TestA {
public static void main(String args[]) {
// can I construct A myself?
      A a = new A();
   }
}
$ javac -d . TestA.java
TestA.java:8: error: A() is not public in A; 
   cannot be accessed from outside package
      A a = new A();
            ^
1 error

Whew! I’ve successfully constructed an arrangement of classes whereby the Program class can construct default-access classes in its package and return them to a class outside the package. If you have followed along, you have taken your first step in package-level encapsulation: You’ve seen how it works and reviewed a minimal testing process to prove it does something useful.

Refer back to Figure 8-2 for a moment. The order in which I invoked these classes amounts to special knowledge, that is, some information that matters to the way the code runs but isn’t apparent from the method interface. A programmer who deduces a simple solution to a problem, particularly after a bit of trial and error, can fool themselves into thinking the solution was evident all along, and decide it’s redundant to document it. Much worse, they can imagine it doesn’t or shouldn’t matter. That thinking is an unsurprising consequence of spending a long time getting the code to work. When you have to maintain that code or track down a bug in it, existing tests and diagrams can save you lots of time and frustration sorting through the whole.

Writing a Proxy Construction Class

Let’s say you have a package in which special knowledge is both more convoluted than our last example and not known to you. All you can see from documentation is that the classes exist. How do you convey this special knowledge to a caller from another package?

If you have a complex construction or other interactions inside a package, you can delegate that task to a specific class, which I’ll call a proxy, and do the work on behalf of out-of-package callers.

Consider the following Helper class in a run package:

package essentials.ch08.run;
public final class Helper {
    Helper() {
        System.out.println("Hello there!");
    }
}
$ javac -d . Helper.java

As before, if you try to construct a Helper object from a class outside the package, like essentials.ch08.test.HelperTest, you’ll get an error:

package essentials.ch08.test;
import essentials.ch08.run.Helper;
public final class HelperTest {
   public static void main(String args[]) {
      Helper help = new Helper();
   }
}
$ javac -d . HelperTest.java
HelperTest.java:7: error: Helper() is not public in Helper; 
  cannot be accessed from outside package
         Helper help = new Helper();
                       ^
1 error

You can see the Helper class; you just can’t access its constructor.

If you can add a class to the package that contains the Helper class, you’re back in business. I’ll write a Proxy class to create its own Helper referent and return its reference to any caller outside the package:

package essentials.ch08.run;
public final class Proxy {
private Helper export = new Helper();
public Helper getHelper() {
return export;
   }
}

You can now write a ProxyTest program to create a Proxy object that can return a Helper reference. To demonstrate that it works, you need code similar to this:

package essentials.ch08.test;
import essentials.ch08.run.Proxy;
import essentials.ch08.run.Helper;
public final class ProxyTest {
public static void main(String args[]) {
      Proxy proxy = new Proxy();
      Helper help = proxy.getHelper();
   }
}
$ javac -d . Proxy.java
$ javac -d . ProxyTest.java
$ java -cp . essentials.ch08.test.ProxyTest
Hello there!

A class inside the package can create multiple Helper objects with the default constructor.

The System.out.println() call in the Helper class just helps confirm that the constructor was called. You now have a technique for making one class a gatekeeper for access to another and distributing a single reference to all external callers.

A class like Proxy may also be used to manage a more complex object assembly process. It can encode so-called special knowledge into explicit program code. There are two benefits to realize. One, any callers to Proxy remain oblivious to any complexity. Two, and even better, you can document that special knowledge with code that makes such a process explicit. Hiding internal complexity by hiding constructors is a valuable service any package can perform.

You can use the class itself to limit its own construction. It may sound silly, but when you declare the available constructors private, you bar other classes from using them. The ClosedToYall program shows what you can (and can’t) do with a private constructor:

package essentials.ch08.run;
public final class ClosedToYall {
   private ClosedToYall() {
      System.out.println("New object!");
   }
   public ClosedToYall tryMe() {
      return new ClosedToYou();
   }
   public static void main(String args[]) {
      ClosedToYall cty = new ClosedToYall();
   }
}

This main() method can construct a ClosedToYou object because it’s a class member. Any method in the same class shares this access, but if it isn’t also declared static, you’d need an object reference to call it. If you remove a constructor from view like this, you need some way to get to the class at all. I used the main() method here simply because I have been using it for test code throughout the book.

You can write a separate method to invoke the constructor, return an existing object reference, or return null if that’s appropriate:

public static ClosedToYall tryMe() {
if ( /* the condition is right */) {
return new ClosedToYall();
return (ClosedToYall)null;
}

Requiring Parameters

Restricting access to a constructor is a useful way to manage object construction before it takes place. A constructor gives you only two options: It can return a reference to a new object, or it can throw an exception. If you want to validate the request—which seems likely if you’re allowing parameters—you can either accept the incoming value or respond in a way that might terminate the program.

But let’s say direct object construction is appropriate to your needs and you only want to refine its use for all callers. You could think of parameters as potential for trouble from callers that pass in values on a hit-or-miss basis. But if everyone’s playing nice, or you have default values you can fall back on, using parameter lists is one way to communicate requirements to the caller.

Adding Parameters to Constructors

I covered the guidelines for parameter lists in the previous chapter. Here I’ll outline particular uses for them with constructors.

Overriding Default Initialization

If you have a meaningful no-arg constructor, you can add constructors that accept parameters, and use them to set different initial states for a new object. Use the no-arg constructor for the default initial state, and use parameters to override that state.

The ArrayList class in the java.util package follows this model. It has three constructors:

ArrayList()
ArrayList(Collection <? extends E> c)
ArrayList(int initialCapacity)

To learn more about generics, you can start with the tutorial at http://docs.oracle.com/javase/tutorial/java/generics/.

The first example is its no-arg constructor. The second constructor takes a parameter that uses a Java facility called generics. In short, generic type definitions let the programmer constrain the type of objects used to populate the ArrayList without specifying the exact type. Generics definitions fall outside the scope of this book, but you’ll see them often as you browse more Java APIs.

The third constructor lets the caller override the initialCapacity value of a default ArrayList object. You learned in Chapter 4, “Using Java Arrays,” that an ArrayList object uses an array internally for its storage. If you need more room, the class will use the System.arraycopy() method to transfer its contents to a bigger array. The class itself encapsulates the resizing process so the caller doesn’t have to manage it directly.

By letting the caller set initialCapacity, the ArrayList class gives a programmer the means to establish size on their own terms, potentially avoiding any behind-the-scenes array transfers.

Disallowing Default Construction

When the no-arg constructor is present, using parameters as overrides makes sense. If you remove the no-arg constructor, however, it implies that there is no meaningful default object state.

The wrapper classes—Boolean, Byte, Character, Double, Float, Integer, Long, and Short—all require parameters for their constructors. The Integer class has two:

public Integer(int value)
public Integer(String s)

The second constructor accepts a String object directly. You could pass an args value in a main() method directly to this constructor, assuming the String value is recognizable as a number. That way you don’t have to perform the conversion yourself. For all these classes, a no-arg constructor isn’t supplied; that defeats the purpose of wrapping a primitive value.

Or let’s say you have a Contact class you use to track various people. For something like contact information, any combination of filled and empty fields might make sense, except all empty. It doesn’t have to be a complicated class, as this example shows:

package essentials.ch08;
final class Contact {
private String name;
private String street;
private String cityState;
private String phone;
private int ID;
private String deptCode;
// "disable" default constructor for now
private Contact() {}
// accessor methods ...
}

For a Contact object to make any sense, you need at least a name:

public Contact(String name)

But what if you had a more specific context you had to implement, like employee-appropriate contact information? If you’re not careful, you might take the straightforward approach and modify the constructor to let a caller add more details, including department code and ID number:

public Contact(String name, String department, int ID)

Even programmers with good intentions will test your constructors’ tolerance for bad input. Embrace spurious tests and defend against them.

This practice can go on ad nauseam. Requiring too many parameters can be just as bad as letting callers make objects they can’t use. You also then have to guard each parameter against a null value or, worse, an empty object like the literal String "". You can anticipate type-appropriate garbage values, such as

Contact ctc = new Contact("", null, 0);

That means there’s a lot of weeding out to do in the constructor.

A constructor must return a referent. A helper method, on the other hand, can weed out junk values and construct the object only when the caller passes in a useful value, as in this example:

public static Contact makeContact(String name, String dept, int ID) {
   //if the parameters are bad, return null, else...
   return new Contact(name, dept, ID);
}

Remember that such a method has to be declared static if you’re going to declare the constructor private. Otherwise you’ll have the chicken-and-egg problem I described earlier (that is, how to return an instance through a method when the class has a private constructor). You don’t have to hide the constructor, but you probably don’t want the caller to choose between these options.

With that in mind, you should design constructors that require parameters essential to constructing the object. Avoid constructors that implicitly accept null or empty objects. For the sake of illustration, here’s one of the constructors for the GridBagConstraints class in the java.awt package:

public GridBagConstraints(int gridx, int gridy, int gridwidth, 
   int gridheight, double weightx, double weighty, int anchor,
    int fill, Insets insets, int ipadx, int ipady)

Maybe once, sometime back in the 1990s, I used that constructor. Imagine if you had to read that line in a program and all the values were literals? You’d have to refer to the API and match each value to its meaning. It’s not hard, but it’s tedious and error prone. As a CircleMUD developer myself, even more years ago now, I occasionally saw functions written in C with more than a dozen parameters. Not fun.

The designer in this case could have reduced this list using some types, such as Grid, Weight and Pad classes. It might have looked like this:

public GridBagConstraints(Grid grid, Weight weight, 
   int anchor, int fill, Insets insets, Pad pad)

Still, that doesn’t remove the tedium. At best, this approach mitigates it. At worst, it replaces one kind of brain-dead work for another. If the parameter list forces callers to make two or more objects they can’t use for anything else, it should be advertised as something like “expert mode”—that is, a constructor only someone with fine-grained control would use.

For the sake of comparison, here is the original constructor and my proposed remedy side by side:

GridBagConstraints gbc;
gbc = new GridBagContraints(0, 0, 0, 0, 0.0, 0.0, 0, 0, null, 0, 0);
Grid grid = new Grid(…);
Weight weight = new Weight(…);
Pad pad = new Pad(…);
Inset inset = new Inset(…);
gbc = new GridBagContraints(grid, weight, 0, 0, inset, pad);

Unless you find a way to avoid this interface altogether, you’re stuck. To be fair, it was probably a consequence of prior design decisions made with the GridBag class that forced the developer’s hand here.

Using Other Objects for Initialization

As you learn more about programming with objects, you will hear that classes should be loosely coupled. Each class should have as minimal a dependency on other classes as it can manage.

But tight coupling, so called, isn’t a bad thing. In fact, it’s unavoidable. The tightest possible coupling you can produce in Java is a subclass. You need subclasses. Without them, you can’t create a type system, such as the Collections classes in the java.util package.

Looser coupling promotes easier reuse of individual classes. That’s not always the goal, but it’s good policy to prefer that in the absence of specific requirements. When you know you don’t want that, don’t worry about it. Just make sure you’re consciously choosing against reusability.

Let’s say you wanted to create an Employee class. Rather than define a Contact constructor to include employee details, which would introduce new fields into the type’s state, you decide it’s better to compose an Employee type to include Contact information. Your Employee constructor could look like this:

public Employee(Contact info, String department, int ID)

You’re still telling the caller to create a Contact object in order to construct an Employee object, and some caller will try to get away with a null value. Still, if your Employee constructor requires a Contact object, enforce that rule.

You can be kind and make sure the object parameters you require aren’t themselves difficult to create. If a caller can construct them on the fly, such as a literal String, then it’s possible to streamline the call like this:

Employee emp = new Employee(new Contact("Michael E"), "Books", 28);

This technique is smarter than it looks. The calling class doesn’t assign this String to a reference. Once we assign emp to null or another Employee referent, the String silently goes away with it.

Overloading Constructors

certobjective.eps

You can also use overloaded constructors to support what I call partial initialization. With this technique, you provide a list of constructors that lets the caller provide as few (or as many) parameters as it has. It goes something like this:

public Employee(Contact ctc)
public Employee(Contact ctc, Department dept)
public Employee(Contact ctc, Department dept, Badge badge)

It’s just like the form for overloaded methods I covered in the preceding chapter. The same rules apply: Varying the type, number, and order of parameters will give you distinct versions of the constructor. It is still a poor choice to change the parameters’ order alone. Changing the type and number of parameters is a better way to communicate.

You can also use the varargs syntax to allow an indefinite number of parameters of one type:

public Employee(Contact ctc, Department dept, Overlord … bosses)

For a complete view of the varargs syntax, see the discussion in Chapter 7, “Using Java Methods to Communicate.”

You can have one varargs element in a parameter list, and it must appear last. The compiler simply converts these arguments into an array, so you can apply a for or for-each statement directly to the parameter in the code body. The compiler will produce an empty array, not a null reference, if the caller supplies nothing.

With this approach, you allow the caller to provide the information it has. The caller should expect that one constructor choice is as good as another and that any parameters not addressed in the constructor of choice are managed underneath the covers.

Partial initialization isn’t very different from the technique for overriding defaults. The appearance of multiple, telescoping constructors will simply suggest to callers that they have as much control over the process as they’d like.

Chaining Overloaded Constructors

As with overloaded methods, it’s also good to centralize common code among overloaded constructors. Modifying and testing the code later is much easier to do when you know it’s kept in one place.

There’s one twist. Methods have their own namespace and, as it turns out, operate on a slightly different set of rules for overloading than constructors do. You can call one overloaded method from another:

public final class Overloaded {
public void myMethod(int x) {
      myMethod();
   }
public void myMethod() { }
}
$ javac Overloaded.java
$

You cannot do the same with constructors:

public final class Overloaded {
public Overloaded(int ... values) {
      Overloaded();
   }
public Overloaded() { }

}
$ javac Overloaded.java
Overloaded.java:7: error: cannot find symbol
           Overloaded();
           ^
  symbol:   method Overloaded()
  location: class Overloaded
1 error

Notice that the compiler complains that it cannot find the Overloaded() method. Without a new keyword to signify construction, the compiler assumes a method is the target. Adding the new keyword will call the constructor, but the compiler assumes that I mean to create a second Overloaded object. See the following example:

public final class Overloaded {
public int [] stuff = { 4, 5, 6, 7 };
public Overloaded(int ... values) {
stuff = values;
      System.out.println("" + stuff[0]);
......// Won’t work; calls for a new object
new Overloaded();
   }
public Overloaded() {
      System.out.println("" + stuff[0]);
   }
public static void main(String args[]) {
      Overloaded ovl1 = new Overloaded(1,2,3);
      System.out.println("" + ovl1.stuff[0]);
   }
}
$ java Overloaded
1
4
1

In this version of the Overloaded class, I call the parameterized constructor from the main() method. That constructor assigns its parameter to the stuff array and calls the no-arg constructor with new. The no-arg constructor prints out the array’s first element. I then print the same element in main() using the object reference.

The output makes it clear there are two objects. When the no-arg constructor is called with new, it reads the stuff array defined in the class, ignoring the caller-supplied parameters. Once the parameterized constructor returns, that object’s state is lost. That’s not the chaining effect I want.

The language provides a facility for chaining constructor calls using the invocation this(). Unlike a new call, which can occur anywhere in a method or constructor body, a this() call has to be the first statement of a constructor. Here’s the same code, using this() to replace the new call:

public final class Overloaded {
public int [] stuff = { 4, 5, 6, 7 };
public Overloaded(int ... values) {
this();
stuff = values;
      System.out.println("" + stuff[0]);
//new Overloaded();
   }
public Overloaded() {
      System.out.println("" + stuff[0]);
   }
public static void main(String args[]) {
      Overloaded ovl1 = new Overloaded(1,2,3);
      System.out.println("" + ovl1.stuff[0]);
   }
}
$ java Overloaded
4
1
1

The caller sees no difference—the value accessed through the object reference is still 1. Internally, however, the this() call will chain the constructors. Instead of sandwiching the no-arg constructor, I’m allowing it to execute first. Then I can override or complement that action as I see fit.

If you try to use a this() call anywhere but in the first statement of any constructor, the compiler complains.

Returning now to the Employee example that I showed earlier:

public Employee(Contact ctc)
public Employee(Contact ctc, Department dept)
public Employee(Contact ctc, Department dept, Badge badge)

I can use the this() call to chain them together so the constructor with the most parameters contains the logic:

this(ctc);
this(ctc, dept);

The constructor with the longest parameter list could chain to the second longest, passing along parameters the latter knows how to initialize, and then initialize the one parameter left. The code might look something like this:

public final class Employee {
private Contact contact;
private Department dept;
private Badge badge;
public Employee(Contact contact) {
this.contact = contact;
   }
public Employee(Contact ctc, Department dept) {
this(ctc);
this.dept = dept;
   }
public Employee(Contact ctc, Department dept, Badge badge) {
this(ctc, dept);
this.badge = badge;
   }
}

It’s a technique you don’t want to take too far. When you have complex logic you don’t want to cut and paste into multiple code bodies; however, it’s a useful technique.

Coupling Objects with Constructors

If you must join two classes at the hip in your code, make the most of that relationship. If it makes sense to use one object as a parameter to another class’s constructor, use the this keyword to do it.

Let’s say your program creates a Contact object for the express purpose of making Employee, Manager, or Contractor objects. Instead of devising a Contact constructor to accept Employee details, you could provide a method that lets a Contact object pass itself to an Employee constructor:

public final class Contact {
private Employee emp;
private String name;
private Contact(String name) {
this.name = name;
// Use current object as a parameter
emp = new Employee(this, "Unassigned", 63);
   }
public static Contact makeContact(String name) {

      // 
if (name == null || name.equals(""))
         // Better to throw an exception but we don’t
         // know how yet.
         return (Contact)null;
return new Contact(name);
   }
public boolean isEmployee() {
return (emp != null);
   }
}

This version of the Contact class puts into play a number of the techniques I’ve described so far.


You can return an empty Contact object from the makeContact() method, but that seems hostile.

First, I provide a static method called makeContact() to return a null value if the String parameter I receive is a null or empty reference. Otherwise, the method calls the constructor and returns the new object to the caller.


In some Java frameworks you’ll encounter, object construction is discouraged in favor of factory methods or similar techniques.

The private constructor gets called only if the parameter information is good. Construction is a relatively expensive process, so catching spurious calls through a factory method like makeContact() helps ensure the process will return something useful.

The Contact constructor calls the Employee constructor and assigns the returned reference to the object’s emp field. Once the Contact object itself is returned, the caller can use the isEmployee() method to verify its status.

I’m illustrating a complex topic here, with both a small bit of code and a contrived case. In doing this, I have two goals in mind. One, I want to prepare you for questions on the Java Oracle Certified Associate (OCA) exam, which only requires that you know how constructors work. It does not require you to know how to work around their limits, as we’ve shown here.

My second goal is to prepare you beyond a mere recall knowledge of Java’s features. Hiding constructors is a big deal in everyday practice. You need to know how to read Java code for meaning as well as validity, and you will encounter code that seems to push constructors out of sight whenever possible. You don’t want to be the interviewee who says you’ve never seen such a thing. It’s a sign that while you may know your basic Java, you aren’t aware of a standard practice that has been in vogue for several years.

Creating a Singleton Object

When you encapsulate the constructor, you can decide when to call it and when to return a reference, either to a new object or to one you’ve already made. Say, for example, you wanted all callers to get a reference to the same object, like this:

package essentials.c08;
public final class Singleton {
private static Singleton ston;
private Singleton() {
   }
public synchronized static Singleton getInstance() {
if (ston == null )
ston = new Singleton();
return ston;
   }
}

You could modify this code slightly to allow for a pool of referents too.

In any singleton class, a getInstance() method is usually the only visible member. When it’s called, it will construct its object if and only if one hasn’t been made already. Everyone who calls this method will share that referent in memory.

If there are a lot of callers, you also have to be more careful with these referents, particularly if they are mutable. I’ve added the synchronized keyword here to acknowledge one potential problem.

If there are two simultaneous callers to this constructor, it’s possible that one of them gets partway through a method, then gets held up by the JVM. Then the JVM lets the other caller go all the way through. When the first caller is allowed to resume, if it’s already past the ston == null check, it will then make another object, and you’ll make another object. The synchronized keyword will keep that from happening.

If that’s too much information for now, don’t worry about it. It’s beyond the scope of this book and the OCA exam. But I’d be remiss if I showed you an incomplete singleton technique.


The Essentials and Beyond
In this chapter, you learned the basics of Java class constructors—and quite a bit more. I described what a default constructor is and the compiler’s rules for defining it. I also described reasons and use cases for adding alternate constructors to a class and how a caller can interpret your intentions based on the ones you supply. I also covered some common defensive strategies that are used with constructors, including proxy, factory, and singleton techniques, which mitigate some of the consequences of keeping your constructors public.
Additional Exercises
1. Write two classes, Push and Pull. Give each one a main() method that prints out the name of the containing class. Call the main() method in one class from the other class’s main() method.
2. Write a ThreeParts class that creates three instances of itself. Supply the methods first(), second(), and third() and declare them static. Make each method return one of the three instances.
3. Test a parameterized constructor from the classes ArrayList, StringBuilder, and Date. Use negative numbers, null references, or empty objects, as appropriate, and observe the response you get from each.
4. The Integer.valueOf() method is a factory method: You give it a primitive integer, it returns an Integer object containing that value. Give it the number 7 as a parameter, but make two Integer objects with it. Make a third Integer object with the value -20. Will the objects be equal? What kind of equality do you get, if any? How can you demonstrate it?
Review Questions
1. Which statement applies exclusively to the default constructor?
A. It has no return type.
B. It has the same name as its class.
C. It is public.
D. It is written by the compiler.
2. Which modifier(s) may not be applied to a constructor? (Choose all that apply.)
A. static
B. synchronized
C. protected
D. native
3. True or false: You must include a default constructor in the code if the compiler does not include one.
4. What does the keyword this refer to?
A. The current class
B. The current object
C. The current method
D. The current constructor
5. True or false: You can call the default constructor written by the compiler using this().
6. What can a constructor do that a method can’t do?
A. Return an object reference
B. Call a constructor using this()
C. Allocate memory
D. Use overloading
7. Which statement correctly describes a property or limitation of object construction?
A. You can use the new keyword in any method or constructor.
B. You can use this() as the first statement in any method or constructor.
C. You cannot use the new keyword with a private constructor unless there is at least one method declared static.
D. All you need to construct an object from another package is a constructor declared public.
8. True or false: You can access a private constructor with a main() method.
9. Declaring a constructor private but allowing it to be accessed through a static method is an example of which of the following?
A. Coupling
B. Encapsulation
C. Factoring
D. Proxying
10. Who can call a default-access constructor? (Choose all that apply.)
A. Any class that resides in the same package
B. Any class that imports the same packages
C. Any class that resides in the same file
D. Any main() method that constructs the class

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.131.47