Constructor overloading - best practice in Java

L.Spillner :

Constructors can be overloaded as any other method as well and I am aware of that fact. Due to a task I decided to use an abstract superclass with multiple constructors:

Abstract Superclass:

protected ListSortierer()
{
  this( null, null );
}

protected ListSortierer( List<E> li )
{
  this( li, null );
}

protected ListSortierer( Comparator<E> comp )
{
  this( null, comp );     
}

protected ListSortierer( List<E> li, Comparator<E> com )
{
  this.original = Optional.ofNullable( li );
  this.comp = Optional.ofNullable( com );
}

To access each of these constructors I needed multiple constructors in the subclass as well.

BubbleSort.java:

public ListBubbleSort()
{
  super();
}

public ListBubbleSort( List<E> li )
{
  super( li );
}

public ListBubbleSort( Comparator<E> com )
{
  super( com );
}

public ListBubbleSort( List<E> li, Comparator<E> com )
{
  super( li, com );
}

In this case every constructor of the subclass calls the constructor of the superclass immediately.It came to my mind that I could refer to the own constructor again and pass null values:

public ListBubbleSort()
{
  this( null, null );
}

public ListBubbleSort( List<E> li )
{
   this( li, null );
}

public ListBubbleSort( Comparator<E> com )
{
   this( null, com );
}

public ListBubbleSort( List<E> li, Comparator<E> com )
{
   super( li, com );
}

Doing so would allow me to omit 3 of the overloaded constructors in the abstract superclass but would enforce that every subclass follows the same pattern.

My question is: What is the the better approach in case of consistency?Handle missing values in the abstract superclass or in the subclass? Does it make a difference regarding instantiation or is it just a matter of opinion?

Andrew Tobilko :

What is a better approach in case of consistency?

  1. Make all child constructors private.
  2. Introduce static factory methods.

    ListBubbleSort.withList(List<E> list)
    ListBubbleSort.withComparator(Comparator<E> comparator)
    
  3. Make a call to a proper super constructor. Don't pass any nulls.

    public static <E> ListBubbleSort withList(List<E> list) {
        return new ListBubbleSort(list);
    }
    
    private ListBubbleSort(List<E>) {
        super(list);
    }
    
    protected ListSortierer(List<E>) {
        // initialise only the list field
        this.origin = list;
    }
    
  4. Don't use Optional as a field.

    this.original = Optional.ofNullable(li);

  5. Consider the Builder Pattern if you have 3+ parameters.

Handle missing values in the abstract superclass or in the subclass?

A constructor is supposed to provide initial values. You aren't passing initial values, you are just indicating their absence.

By default, null is the initial value for reference types. So, there is no need to reassign a field if the value for it hasn't been given.

Does it make a difference regarding instantiation or is it just a matter of opinion?

Readability, maintenance.


I would recommend reading Effective Java by Joshua Bloch:

Creating and Destroying Objects

  • Item 1: Consider static factory methods instead of constructors
  • Item 2: Consider a builder when faced with many constructor parameters

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=429845&siteId=1