59

In C++, you can use an initializer list to initialize the class's fields before the constructor begins running. For example:

Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
    // Empty; already handled!
}

I am curious why Java does not have a similar feature. According to Core Java: Volume 1:

C++ uses this special syntax to call field constructors. In Java, there is no need for it because objects have no subobjects, only pointers to other objects.

Here are my questions:

  1. What do they mean by "because objects have no subobjects?" I don't understand what a subobject is (I tried looking it up); do they mean an instantiation of a subclass which extends a superclass?

  2. As for why Java does not have initializer lists like C++, I would assume that the reason is because all fields are already initialized by default in Java and also because Java uses the super keyword to call the super(or base in C++ lingo)-class constructor. Is this correct?

jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
Jesse Good
  • 50,901
  • 14
  • 124
  • 166

3 Answers3

107

In C++, initializer lists are necessary because of a few language features that are either not present in Java or work differently in Java:

  1. const: In C++, you can define a fields that are marked const that cannot be assigned to and must be initialized in the initializer list. Java does have final fields, but you can assign to final fields in the body of a constructor. In C++, assigning to a const field in the constructor is illegal.

  2. References: In C++, references (as opposed to pointers) must be initialized to bind to some object. It is illegal to create a reference without an initializer. In C++, the way that you specify this is with the initializer list, since if you were to refer to the reference in the body of the constructor without first initializing it you would be using an uninitialized reference. In Java, object references behave like C++ pointers and can be assigned to after created. They just default to null otherwise.

  3. Direct subobjects. In C++, an object can contain object directly as fields, whereas in Java objects can only hold references to those objects. That is, in C++, if you declare an object that has a string as a member, the storage space for that string is built directly into the space for the object itself, while in Java you just get space for a reference to some other String object stored elsewhere. Consequently, C++ needs to provide a way for you to give those subobjects initial values, since otherwise they'd just stay uninitialized. By default it uses the default constructor for those types, but if you want to use a different constructor or no default constructor is available the initializer list gives you a way to bypass this. In Java, you don't need to worry about this because the references will default to null, and you can then assign them to refer to the objects you actually want them to refer to. If you want to use a non-default constructor, then you don't need any special syntax for it; just set the reference to a new object initialized via the appropriate constructor.

In the few cases where Java might want initializer lists (for example, to call superclass constructors or give default values to its fields), this is handled through two other language features: the super keyword to invoke superclass constructors, and the fact that Java objects can give their fields default values at the point at which they're declared. Since C++ has multiple inheritance, just having a single super keyword wouldn't unambiguously refer to a single base class, and prior to C++11 C++ didn't support default initializers in a class and had to rely on initializer lists.

starball
  • 20,030
  • 7
  • 43
  • 238
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • Excellent answer. I was very suprised at the response time for my question. I'll upvote you after I register. Also, a link about the change in C++0x would be appreciated. – Jesse Good Aug 22 '11 at 23:48
  • @Jesse- Glad to help! Don't forget to accept the answer as well if you think it answers the question. :-) And I've included a link for the C++0x change in the question. – templatetypedef Aug 22 '11 at 23:50
  • 3
    @templatetypedef : `In C++, references (as opposed to pointers) must be initialized to bind to some object.` . I think, its not *"must be initialized"*. You can have uninitialized references in a valid program; just that you must not use it, to avoid undefined behavior. :-). +1 for a good post. – Nawaz Aug 23 '11 at 06:32
10

C++

There is a difference between

ClassType t(initialization arguments);

and

ClassType * pt;

The latter doesn't need to be initialized (set to NULL). The former does. Think of it as an integer. You can't have an int without a value, BUT you can have an int pointer without a value.

So when you have:

class ClassType
{
    OtherClass value;
    OtherClass * reference;
};

Then the declaration:

ClassType object;

automatically creates an instance of OtherClass in value. Therefore, if OtherClass has initialization, it must be done in the ClassType constructor. However, reference is just a pointer (address in memory) and can remain uninitialized. If you want an instance of OtherClass you must use

object.reference = new OtherClass(initialization arguments);

Java

There is only

class ClassType
{
    OtherClass reference;
}

This is equivalent to a pointer in C++. In this case when you do:

ClassType object = new ClassType();

You don't automatically create an instance of OtherClass. Therefore, you don't have to initialize anything in the constructor unless you want to. When you want an object of OtherClass you can use

object.reference = new OtherClass();
George
  • 1,457
  • 11
  • 26
1

Because Java does not need them to allow initialization of fields whose type has no zero-value.

In C++

class C {
  D d;
}

without a member initializer for d, D::D() will be called which makes it impossible to initialize the field if there is no zero-type for D. This can happen when D::D() is explicitly declared private.

In Java, there is a known zero-value for all reference types, null, so a field can always be initialized.

Java also does a bunch of work to make sure* that all final fields are initialized before first use and before the constructor ends, so while Java has a requirement like C++'s const field initialization requirement, it just overloads this.fieldName = <expression> in the constructor body to mean field initialization.

  • : modulo exceptions thrown in the ctor, overridden method calls from the base class, etc.
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • Thanks for the answer. However, I was a little weary of the term "zero value", as it sounds like it is talking about the integer 0, whereas in C++Ox (nullptr) and the Java null I dont consider to be equivalent. – Jesse Good Aug 22 '11 at 23:52
  • @Jesse, I didn't invent the term "zero-value." It is a common term in programming language specification documents and the like. E.g. ["Effective Go"](http://golang.org/doc/effective_go.html) says of return parameters, "When named, they are initialized to the zero values for their types when the function begins" and the [language spec](http://golang.org/doc/go_spec.html#The_zero_value) defines `nil` as the zero value for pointer types. – Mike Samuel Aug 23 '11 at 00:05
  • Thanks for the links regarding "zero-value". As you may know, different languages use different terminology regarding similar concepts, like [here](http://stackoverflow.com/questions/1350819/c-free-store-vs-heap). So, I would recommend differentiating the two. – Jesse Good Aug 23 '11 at 02:10
  • @Jesse, Yeah. I think languages where the specifiers expect that `bzero`ing an objects memory sets all its fields to the `zero-value` as in Go, tend to prefer that term, whereas the Java language spec uses "default value" since Java doesn't specify a module named "unsafe" that requires specifying anything about object layout. Perhaps "default value" or "initial value" would be better, especially since "zero value" w.r.t. IEEE 754 values prompts the question "Which zero?" – Mike Samuel Aug 23 '11 at 02:53