Best way to handle multiple constructors in Java

后端 未结 9 1439
没有蜡笔的小新
没有蜡笔的小新 2020-12-02 07:00

I\'ve been wondering what the best (i.e. cleanest/safest/most efficient) way of handling multiple constructors in Java is? Especially when in one or more constructors not al

相关标签:
9条回答
  • 2020-12-02 07:44

    I would do the following:

    public class Book
    {
        private final String title;
        private final String isbn;
    
        public Book(final String t, final String i)
        {
            if(t == null)
            {
                throw new IllegalArgumentException("t cannot be null");
            }
    
            if(i == null)
            {
                throw new IllegalArgumentException("i cannot be null");
            }
    
            title = t;
            isbn  = i;
        }
    }
    

    I am making the assumption here that:

    1) the title will never change (hence title is final) 2) the isbn will never change (hence isbn is final) 3) that it is not valid to have a book without both a title and an isbn.

    Consider a Student class:

    public class Student
    {
        private final StudentID id;
        private String firstName;
        private String lastName;
    
        public Student(final StudentID i,
                       final String    first,
                       final String    last)
        {
            if(i == null)
            {
                throw new IllegalArgumentException("i cannot be null"); 
            }
    
            if(first == null)
            {
                throw new IllegalArgumentException("first cannot be null"); 
            }
    
            if(last == null)
            {
                throw new IllegalArgumentException("last cannot be null"); 
            }
    
            id        = i;
            firstName = first;
            lastName  = last;
        }
    }
    

    There a Student must be created with an id, a first name, and a last name. The student ID can never change, but a persons last and first name can change (get married, changes name due to losing a bet, etc...).

    When deciding what constrructors to have you really need to think about what makes sense to have. All to often people add set/get methods because they are taught to - but very often it is a bad idea.

    Immutable classes are much better to have (that is classes with final variables) over mutable ones. This book: http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA97&sig=JgnunNhNb8MYDcx60Kq4IyHUC58#PPP1,M1 (Effective Java) has a good discussion on immutability. Look at items 12 and 13.

    0 讨论(0)
  • 2020-12-02 07:45

    Some general constructor tips:

    • Try to focus all initialization in a single constructor and call it from the other constructors
      • This works well if multiple constructors exist to simulate default parameters
    • Never call a non-final method from a constructor
      • Private methods are final by definition
      • Polymorphism can kill you here; you can end up calling a subclass implementation before the subclass has been initialized
      • If you need "helper" methods, be sure to make them private or final
    • Be explicit in your calls to super()
      • You would be surprised at how many Java programmers don't realize that super() is called even if you don't explicitly write it (assuming you don't have a call to this(...) )
    • Know the order of initialization rules for constructors. It's basically:

      1. this(...) if present (just move to another constructor)
      2. call super(...) [if not explicit, call super() implicitly]
      3. (construct superclass using these rules recursively)
      4. initialize fields via their declarations
      5. run body of current constructor
      6. return to previous constructors (if you had encountered this(...) calls)

    The overall flow ends up being:

    • move all the way up the superclass hierarchy to Object
    • while not done
      • init fields
      • run constructor bodies
      • drop down to subclass

    For a nice example of evil, try figuring out what the following will print, then run it

    package com.javadude.sample;
    
    /** THIS IS REALLY EVIL CODE! BEWARE!!! */
    class A {
        private int x = 10;
        public A() {
            init();
        }
        protected void init() {
            x = 20;
        }
        public int getX() {
            return x;
        }
    }
    
    class B extends A {
        private int y = 42;
        protected void init() {
            y = getX();
        }
        public int getY() {
            return y;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            B b = new B();
            System.out.println("x=" + b.getX());
            System.out.println("y=" + b.getY());
        }
    }
    

    I'll add comments describing why the above works as it does... Some of it may be obvious; some is not...

    0 讨论(0)
  • 2020-12-02 07:59

    You should always construct a valid and legitimate object; and if you can't using constructor parms, you should use a builder object to create one, only releasing the object from the builder when the object is complete.

    On the question of constructor use: I always try to have one base constructor that all others defer to, chaining through with "omitted" parameters to the next logical constructor and ending at the base constructor. So:

    class SomeClass
    {
    SomeClass() {
        this("DefaultA");
        }
    
    SomeClass(String a) {
        this(a,"DefaultB");
        }
    
    SomeClass(String a, String b) {
        myA=a;
        myB=b;
        }
    ...
    }
    

    If this is not possible, then I try to have an private init() method that all constructors defer to.

    And keep the number of constructors and parameters small - a max of 5 of each as a guideline.

    0 讨论(0)
提交回复
热议问题