简体   繁体   中英

How can a Java class have no no-arg constructor?

The Oracle Java tutorial site has this paragraph that is confusing me:

All classes have at least one constructor. If a class does not explicitly declare any, the Java compiler automatically provides a no-argument constructor, called the default constructor. This default constructor calls the class parent's no-argument constructor, or the Object constructor if the class has no other parent. If the parent has no constructor (Object does have one), the compiler will reject the program.

If all objects directly or indirectly inherit from Object how is it possible to elicit the compiler rejection spoken of? Does it have to do with the constructor being private?

If all objects directly or indirectly inherit from Object how is it possible to elicit the compiler rejection spoken of?

I think the basis is of your misunderstanding is that you are thinking that constructors are inherited. In fact, constructors are NOT inherited in Java. So consider the following example:

public class A {
    public A(int i) { super(); ... }
}

public class B extends A {
    public B() { super(); ... }
}

The class A :

  • does not inherit any constructors from Object ,
  • does not explicitly declare a no-args constructor (ie public A() {...} ), and
  • does not have a default constructor (since it does declare another constructor).

Hence, it has one and only one constructor: public A(int) .

The call to super() in the B class tries to use a non-existent no-args constructor in A and gives a compilation error. To fix this, you either need to change the B constructor to use the A(int) constructor, or declare an explicit no-args constructor in A .

(Incidentally, it is not necessary for a constructor to explicitly call a superclass constructor ... as I've done. But a lot of people think it is good style to include an explicit call. If you leave it out, the Java compiler inserts an implicit call to the superclasses no-args constructor ... and that results in a compilation error if the no-args constructor does not exist or is not visible to the subclass.)

Does it have to do with the constructor being private?

Not directly. However, declaring a constructor private will prevent that constructor being called from a child class.

The key thing to understand is that the no-arg constructor will only be automatically generated if the class doesn't already have a constructor.

It's thus easy to create a class that doesn't have a no-arg constructor.

The simplest way to think of this problem is as follows:

  1. The non-args constructor is provided as the default constructor by Java for any class you create.

  2. The moment you create a custom constructor with arguments, Java says “ hey, this class has got a custom constructor, so I am not going to bother creating/supplying the default non-args constructor!

  3. As a result now your class does NOT has the default non-args constructor.

  4. This means when you create a subclass, based on your class, you need explicitly call the arguments based custom constructor that you created.

If you have a sub-class of a sub-class

class A 
{
    A(int i) {..}
}

class B extends A 
{
}

Here the default constructor inserted into B will try to invoke A's no-argument constructor (which doesn't exist) as it only has a constructor taking one argument

The immediate superclass of the object must have a protected or public constructor (or no constructor at all, in which case one will be created). So, if I create a class that extends Object, with a private constructor only, then nothing will be able to extend my class.

Yes. A private contructor is a special instance constructor. It is commonly used in classes that contain static members only. If a class has one or more private constructors and no public constructors, then other classes (except nested classes) are not allowed to create instances of this class.

The declaration of a private constructor prevents the automatic generation of a default constructor.

EDIT:

A class defined within another class is called a nested class. Like other members of a class, a nested class can be declared static or not. A nonstatic nested class is called an inner class. An instance of an inner class can exist only within an instance of its enclosing class and has access to its enclosing class's members even if they are declared private .

What this means is that if you inherit from a line of class(es) that make the default no-arg constructor private (or it does not exist, for example), your sub-classes must declare a constructor in line with its parent's alternative constructor.

For example, the following declaration of Bar is not allowed:

public class Foo {
  private Foo() {  } // or this doesn't even exist
  public Foo(int i) {
  }
}
public class Bar extends Foo {
}

Let me append to all aforementioned one more interesting case where the default/no-arg constructor is infeasible, in the sense that unless it is explicitly declared, the compiler cannot assume it and yet it has nothing to do with subclassing. This is the case of having a class with a final field which expects a constructor to initialize it. For example:

class Foo extends Object {
    private final Object o;

    public Foo(Object o){
       this.o = o;
    }
}

Here it's easy to see that an instantiation of a Foo-object requires the initialization of the final field o so any invocation of Foo() - directly or not - is doomed to failure... Let me underline that the no-arg constructor in the super class ( Object ) exists and is publicly accessible but it is the presence of the final field ( o ) that deactivates it in Foo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM