Использовать перегрузку конструктора изнутри конструктора классов [duplicate]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

1840
задан James A. Rosen 12 November 2008 в 21:16
поделиться

17 ответов

Ключевое слово this можно использовать для вызова конструктора из конструктора при написании нескольких конструкторов для класса, есть моменты, когда вы хотите вызвать один конструктор из другого, чтобы избежать дублирования кода .

Bellow - это ссылка, в которой я рассказываю другую тему о конструкторе и getters () и seters (), и я использовал класс с двумя конструкторами. Я надеюсь, что объяснения и примеры помогут вам.

Сеттерные методы или конструкторы

2487
ответ дан Community 25 August 2018 в 07:00
поделиться
  • 1
    Поэтому я предположил, что нельзя назвать супер-конструктор, а другой конструктор того же класса, что и оба, должны быть первой строкой? – gsingh2011 2 November 2012 в 20:02
  • 2
    @ gsingh2011: Действительно. Вы можете привязать только к одному другому конструктору. – Jon Skeet 2 November 2012 в 20:06
  • 3
    Это должно появиться в первой строке, но вы можете делать вычисления в конструкторе до его вызова: вы можете использовать статические методы в аргументах этой () в первой строке и инкапсулировать любые вычисления, которые должны быть выполнены до вызова к другому конструктору в этом статическом методе. (Я добавил это как отдельный ответ). – Christian Fries 11 March 2013 в 22:34
  • 4
    @ gsingh2011 Я знаю, что это поздно, но как способ, вы можете вызвать перегруженный конструктор, используя это (...), а затем в этом перегруженном конструкторе вы можете сделать вызов конструктора базового класса, используя super (...) – Ali 13 May 2013 в 08:23
  • 5
    @JustinTime: Опять же, это зависит от того, что вы подразумеваете под созданием & quot; - объект «создан»; в котором выделена его память, и тип устанавливается до того, как будут выполнены какие-либо тела конструктора. Конструкторы - это инициализация, а не создание. В частности, тип объекта является его «окончательным». введите прямо с самого начала - так что если вы вызовете какие-либо виртуальные методы из конструкторов, вы получите наиболее специфичное переопределение. Я считаю, что это отличается от C ++. – Jon Skeet 9 February 2016 в 20:06

Используя this(args). Предпочтительный шаблон - работать от самого маленького конструктора до самого большого.

public class Cons {

 public Cons() {
  // A no arguments constructor that sends default values to the largest
  this(madeUpArg1Value,madeUpArg2Value,madeUpArg3Value);
 }

 public Cons(int arg1, int arg2) {
  // An example of a partial constructor that uses the passed in arguments
  // and sends a hidden default value to the largest
  this(arg1,arg2, madeUpArg3Value);
 }

 // Largest constructor that does the work
 public Cons(int arg1, int arg2, int arg3) {
  this.arg1 = arg1;
  this.arg2 = arg2;
  this.arg3 = arg3;
 }
}

Вы также можете использовать недавно защищенный подход значенияOf или просто «из»:

public class Cons {
 public static Cons newCons(int arg1,...) {
  // This function is commonly called valueOf, like Integer.valueOf(..)
  // More recently called "of", like EnumSet.of(..)
  Cons c = new Cons(...);
  c.setArg1(....);
  return c;
 }
} 

Чтобы вызвать суперкласс, используйте super(asdf). Вызов супер должен быть первым вызовом в конструкторе или вы получите ошибку компилятора.

199
ответ дан 4 revs, 2 users 97% 25 August 2018 в 07:00
поделиться
  • 1
    Если используется множество параметров конструктора, рассмотрите построитель. См. Пункт 2 «Эффективная Java». Джошуа Блох. – koppor 13 November 2012 в 22:16
  • 2
    Проблема с реализацией последнего подхода с использованием фабричного метода newCons заключается в том, что вы пытаетесь изменить состояние объекта, используя setArg1(...), который, скорее всего, должен установить свои поля как final. Поскольку мы стараемся как можно больше сохранить неизменяемый объект, если не полностью, шаблон построителя будет исправлять эту проблему более корректно. – YoYo 30 January 2016 в 07:46
  • 3
    Не могли бы вы сделать: public cons () {this (madeUpArg1Value, madeUpArg2Value); } – LordHieros 16 April 2018 в 13:31
  • 4
    Инициализация должна начинаться от наименьшего до наибольшего - у меня никогда не было бы конструктора по умолчанию, вызывающего цепочку к многопараметрическому конструктору. Что должно произойти, так это то, что все конструкторы называют либо по умолчанию, либо конструктором с меньшим количеством параметров. – Rodney P. Barbati 23 April 2018 в 18:17
  • 5
    @ RodneyP.Barbati Это довольно распространено в Java для конструкторов с более низкой конструкцией, чтобы вызывать конструкторы большей arity , а затем ничего не делать . если класс K имеет, например, два конечных поля a, b, то "общий конструктор" будет K(A a, B b) { this.a = a; this.b = b; }. Тогда, если b имеет разумное значение по умолчанию, может быть конструктор с одним аргументом K(A a) { this(a, DEFAULT_B); }, и если есть значение по умолчанию a, у нас есть конструктор по умолчанию: K() { this(DEFAULT_A); }. Это довольно распространенное соглашение в Java. – Joshua Taylor 17 May 2018 в 13:12

Вы можете создать конструктор из другого конструктора того же класса, используя ключевое слово this. Пример -

class This1
{
    This1()
    {
        this("Hello");
        System.out.println("Default constructor..");
    }
    This1(int a)
    {
        this();
        System.out.println("int as arg constructor.."); 
    }
    This1(String s)
    {
        System.out.println("string as arg constructor..");  
    }

    public static void main(String args[])
    {
        new This1(100);
    }
}

Выход - строка как конструктор arg .. Конструктор по умолчанию .. int как конструктор arg ..

5
ответ дан ABHISHEK RANA 25 August 2018 в 07:00
поделиться

Внутри конструктора вы можете использовать ключевое слово this для вызова другого конструктора в том же классе. Это называется явным вызовом конструктора.

Вот еще один класс Rectangle с другой реализацией от той, что находится в разделе «Объекты».

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(1, 1);
    }
    public Rectangle(int width, int height) {
        this( 0,0,width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

}

Этот класс содержит набор конструкторов. Каждый конструктор инициализирует некоторые или все переменные-члены прямоугольника.

23
ответ дан amila isura 25 August 2018 в 07:00
поделиться
  • 1
    почему бы вам не назвать второй конструктор, который Rectangle(int width, int height) в Rectangle() вместо Rectangle(int x, int y, int width, int height)? – ANjaNA 18 July 2015 в 02:58
  • 2
    Конструктор по умолчанию не должен иметь знаний о конструкторах более высокого уровня - он по умолчанию. После этого шаблона вам придется изменить один или несколько существующих конструкторов при добавлении нового. Например, добавьте значение lineWidth и посмотрите, что я имею в виду. Но по умолчанию инициализируйте все значения и отмените цепочку конструкторов, вы увидите каждое здание конструктора на предыдущем и инициализируете только те значения, которые он поддерживает, - вы можете добавить новый, не изменяя существующие. В java есть много общих шаблонов, которые не являются хорошими шаблонами. – Rodney P. Barbati 29 May 2018 в 16:21

Довольно простой

public class SomeClass{

    int number;
    String someString;

    public SomeClass(){
        number = 0;
    }

    public SomeClass(int number){
        this(); //set the class to 0
        this.setNumber(number); 
    }

    public SomeClass(int number, String someString){
        this(number); //call public SomeClass( int number )
    }

    public void setNumber(int number){
        this.number = number;
    }
    public void setString(String someString){
        this.someString = someString;
    }
    //.... add some accessors
}

теперь вот небольшой небольшой кредит:

public SomeOtherClass extends SomeClass {
    public SomeOtherClass(int number, String someString){
         super(number, someString); //calls public SomeClass(int number, String someString)
    }
    //.... Some other code.
}

Надеюсь, что это поможет.

2
ответ дан GetBackerZ 25 August 2018 в 07:00
поделиться

Да, можно вызвать один конструктор из другого с помощью this()

class Example{
   private int a = 1;
   Example(){
        this(5); //here another constructor called based on constructor argument
        System.out.println("number a is "+a);   
   }
   Example(int b){
        System.out.println("number b is "+b);
   }
5
ответ дан Ichiro 25 August 2018 в 07:00
поделиться
  • 1
    Это не работает. Этот вызов (5) должен быть первой строкой в ​​конструкторе. – chandsie 20 October 2016 в 19:11

Вызов конструктора из другого конструктора

class MyConstructorDemo extends ConstructorDemo
{
    MyConstructorDemo()
    {
        this("calling another constructor");
    }
    MyConstructorDemo(String arg)
    {
        System.out.print("This is passed String by another constructor :"+arg);
    }
}

Также вы можете вызвать родительский конструктор с помощью super() вызова

5
ответ дан J. Chomel 25 August 2018 в 07:00
поделиться

Вы можете вызвать другой конструктор с помощью ключевого слова this(...) (когда вам нужно вызвать конструктор из того же класса) или ключевое слово super(...) (когда вы нужно вызвать конструктор из суперкласса).

Однако такой вызов должен быть первым утверждением вашего конструктора. Чтобы преодолеть это ограничение, используйте этот ответ .

1
ответ дан John McClane 25 August 2018 в 07:00
поделиться

Когда мне нужно вызвать другой конструктор изнутри кода (не в первой строке), я обычно использую вспомогательный метод, подобный этому:

class MyClass {
   int field;


   MyClass() {
      init(0);
   } 
   MyClass(int value) {
      if (value<0) {
          init(0);
      } 
      else { 
          init(value);
      }
   }
   void init(int x) {
      field = x;
   }
}

Но чаще всего я пытаюсь сделать это другими способами, вызывая, насколько это возможно, более сложные конструкторы из простых в первой строке. Для приведенного выше примера

class MyClass {
   int field;

   MyClass(int value) {
      if (value<0)
         field = 0;
      else
         field = value;
   }
   MyClass() {
      this(0);
   }
}
36
ответ дан Kaamel 25 August 2018 в 07:00
поделиться

Как уже говорили все, вы используете this(…), который называется вызовом явного конструктора .

Однако имейте в виду, что в таком явном выражении вызова конструктора вы можете не ссылаться на

  • на любые переменные экземпляра или
  • любые методы экземпляра или
  • любые внутренние классы , объявленные в этом классе или любом суперклассе, или
  • this или
  • super.

Как указано в JLS (§8.8.7.1).

12
ответ дан olovb 25 August 2018 в 07:00
поделиться

Он называется привязкой к троекрату или цепочке конструкторов Teleescoping Constructor. Да, вы можете это сделать. Я вижу много примеров выше, и я хочу добавить, сказав, что если вы знаете, что вам нужен только два или три конструктора, возможно, все в порядке. Но если вам нужно больше, попробуйте использовать другой шаблон дизайна, такой как шаблон Builder. Например:

 public Omar(){};
 public Omar(a){};
 public Omar(a,b){};
 public Omar(a,b,c){};
 public Omar(a,b,c,d){};
 ...

Вам может потребоваться больше. В этом случае лучшим вариантом будет шаблон Builder. Вот статья, может быть полезно https://medium.com/@modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e

0
ответ дан Omar Faroque Anik 25 August 2018 в 07:00
поделиться

Я знаю, что есть так много примеров этого вопроса, но то, что я нашел, я помещаю здесь, чтобы поделиться своей идеей. существует два способа построения конструктора. В том же классе вы можете использовать это ключевое слово. в Inheritance вам нужно использовать ключевое слово super.

    import java.util.*;
    import java.lang.*;

    class Test
    {  
        public static void main(String args[])
        {
            Dog d = new Dog(); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.
            Dog cs = new Dog("Bite"); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.

            // You need to Explicitly tell the java compiler to use Argument constructor so you need to use "super" key word
            System.out.println("------------------------------");
            Cat c = new Cat();
            Cat caty = new Cat("10");

            System.out.println("------------------------------");
            // Self s = new Self();
            Self ss = new Self("self");
        }
    }

    class Animal
    {
        String i;

        public Animal()
        {
            i = "10";
            System.out.println("Animal Constructor :" +i);
        }
        public Animal(String h)
        {
            i = "20";
            System.out.println("Animal Constructor Habit :"+ i);
        }
    }

    class Dog extends Animal
    {
        public Dog()
        {
            System.out.println("Dog Constructor");
        }
        public Dog(String h)
        {
            System.out.println("Dog Constructor with habit");
        }
    }

    class Cat extends Animal
    {
        public Cat()
        {
            System.out.println("Cat Constructor");
        }
        public Cat(String i)
        {
            super(i); // Calling Super Class Paremetrize Constructor.
            System.out.println("Cat Constructor with habit");
        }
    }

    class Self
    {
        public Self()
        {
            System.out.println("Self Constructor");
        }
        public Self(String h)
        {
            this(); // Explicitly calling 0 args constructor. 
            System.out.println("Slef Constructor with value");
        }
    }
1
ответ дан Paul Chu 25 August 2018 в 07:00
поделиться

Я расскажу вам простой способ

Существует два типа конструкторов:

  1. Конструктор по умолчанию
  2. Параметрированный конструктор

Я объясню в одном примере

class ConstructorDemo 
{
      ConstructorDemo()//Default Constructor
      {
         System.out.println("D.constructor ");
      }

      ConstructorDemo(int k)//Parameterized constructor
      {
         this();//-------------(1)
         System.out.println("P.Constructor ="+k);       
      }

      public static void main(String[] args) 
      {
         //this(); error because "must be first statement in constructor
         new ConstructorDemo();//-------(2)
         ConstructorDemo g=new ConstructorDemo(3);---(3)    
       }
   }                  

В приведенном выше примере я показал 3 типа вызова

  1. , что этот () вызов должен быть первый оператор в конструкторе
  2. Это имя меньше объекта. это автоматически вызывает конструктор по умолчанию. 3.This вызывает конструктор с параметрами.

Примечание: это должно быть первое утверждение в конструкторе.

7
ответ дан psychsane 25 August 2018 в 07:00
поделиться
  • 1
    В основном методе есть следующее: // this (); потому что & quot; должен быть первым оператором в конструкторе . Это утверждение не имеет большого смысла. Если вы пытаетесь сказать, что этот () не может быть вызван из метода main , то да, это не может быть потому, что main является статическим и не будет ссылаться на это () – S R Chaitanya 7 January 2017 в 14:31
  • 2
    это то, что я передаю. Что нового в вашем комментарии @SRChaitanya? – Shivanandam Sirmarigari 26 January 2017 в 02:50
  • 3
    что вы плохо его передаете – Kevin Van Dyck 12 February 2018 в 13:26

Существуют шаблоны проектирования, которые покрывают потребность в сложной конструкции - если это невозможно сделать лаконично, создайте фабричный метод или фабричный класс.

С последней версией java и добавлением lambdas, легко создать конструктор, который может принять любой желаемый код инициализации.

class LambdaInitedClass {

   public LamdaInitedClass(Consumer<LambdaInitedClass> init) {
       init.accept(this);
   }
}

Вызовите его с помощью ...

 new LambdaInitedClass(l -> { // init l any way you want });
3
ответ дан Rodney P. Barbati 25 August 2018 в 07:00
поделиться

Да, можно вызвать один конструктор из другого. Но есть правило. Если вызов выполняется из одного конструктора в другой, то

, что новый вызов конструктора должен быть первым утверждением в текущем конструкторе

public class Product {
     private int productId;
     private String productName;
     private double productPrice;
     private String category;

    public Product(int id, String name) {
        this(id,name,1.0);
    }

    public Product(int id, String name, double price) {
        this(id,name,price,"DEFAULT");
    }

    public Product(int id,String name,double price, String category){
        this.productId=id;
        this.productName=name;
        this.productPrice=price;
        this.category=category;
    }
}

Итак, что-то вроде ниже не будет работать.

public Product(int id, String name, double price) {
    System.out.println("Calling constructor with price");
    this(id,name,price,"DEFAULT");
}

Также, в случае наследования, когда объект подкласса создается, сначала вызывается конструктор суперкласса.

public class SuperClass {
    public SuperClass() {
       System.out.println("Inside super class constructor");
    }
}
public class SubClass extends SuperClass {
    public SubClass () {
       //Even if we do not add, Java adds the call to super class's constructor like 
       // super();
       System.out.println("Inside sub class constructor");
    }
}

Таким образом, в этом случае другой вызов конструктора сначала объявляется перед любыми другими операторами.

4
ответ дан S R Chaitanya 25 August 2018 в 07:00
поделиться

Да, любое число конструкторов может присутствовать в классе, и их можно вызвать другим конструктором с помощью this() [Пожалуйста, не путайте конструкторский вызов this() с ключевым словом this]. this() или this(args) должны быть первой строкой в ​​конструкторе.

Пример:

Class Test {
    Test() {
        this(10); // calls the constructor with integer args, Test(int a)
    }
    Test(int a) {
        this(10.5); // call the constructor with double arg, Test(double a)
    }
    Test(double a) {
        System.out.println("I am a double arg constructor");
    }
}

Это называется перегрузкой конструктора. Обратите внимание, что для конструктора применима только концепция перегрузки, а не наследование или переопределение.

6
ответ дан Utsav 25 August 2018 в 07:00
поделиться

[ Примечание. Я просто хочу добавить один аспект, который я не видел в других ответах: как преодолеть ограничения требования о том, что это () должно быть в первой строке). ]

В Java другой конструктор того же класса можно вызвать из конструктора через this(). Обратите внимание, что this должен находиться в первой строке.

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, 0.0);
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }
}

То, что this должно появиться в первой строке, выглядит большим ограничением, но вы можете построить аргументы других конструкторов через статические методы. Например:

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, getDefaultArg3(argument1, argument2));
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }

  private static double getDefaultArg3(double argument1, double argument2) {
    double argument3 = 0;

    // Calculate argument3 here if you like.

    return argument3;

  }

}
178
ответ дан Zizouz212 25 August 2018 в 07:00
поделиться
  • 1
    Это правда, что вы можете вызвать статические методы таким образом, чтобы выполнять сложные вычисления для значений аргументов, что хорошо. Однако, если вы считаете, что код необходим перед делегацией конструктора (this(...)), тогда было бы разумно предположить, что где-то была сделана ужасная ошибка, и что дизайн, возможно, нуждается в переосмыслении. – Engineer Dollery 8 June 2016 в 23:00
  • 2
    Я бы согласился с тем, что сложная трансформация very , вероятно, указывает на проблему дизайна. Но 1) есть некоторые простые преобразования, для которых это может быть полезно - не все конструкторы являются только линейной проекцией на другие, а 2) может возникнуть другая ситуация, когда эта информация может стать рукой, например, поддерживать старый код. (Хотя я согласен с вашим заключением, я не понимаю, почему это оправдывало бы пониженное голосование). – Christian Fries 16 June 2016 в 17:36
  • 3
    Это полностью противоположно тому, что я хотел бы предложить - конструктор no parameter должен инициализировать все значения по умолчанию. Конструктор параметров 2 должен вызывать конструктор no param, а затем инициализировать 2 значения, которые он получает. Конструктор 3-х параметров должен вызывать конструктор 2-го параметра, а затем инициализировать третье значение до получаемого значения. Выполнение этого, как показано, означает, что вам нужно сделать гораздо больше работы, чтобы добавить еще один параметр. – Rodney P. Barbati 23 April 2018 в 18:22
  • 4
    @ RodneyP.Barbati: Я вижу несколько проблем в этом, так, как вы его описываете: a) Выполняя это, невозможно проиллюстрировать использование статического метода в конструкторе (и это намерение примера); -) и b) если вы делаете это по-своему, поля не могут быть final (окончательные поля могут быть инициализированы только один раз). – Christian Fries 13 June 2018 в 06:06
  • 5
    @ RodneyP.Barbati: Два других аспекта: c) Я считаю, что вы всегда должны инициализировать объект в одной точке, который должен быть самым общим конструктором. Если для инициализации объекта требуется сложная задача (объект init не ленив) или проверка или получение некоторых ресурсов (например, файла), вам нравится делать это только один раз. И d) добавление другого аргумента (например, аргумент4), для которого инициализация зависит от значения аргумента 1 к аргументу 3, вам нужно было бы изменить все конструкторы в вашем случае, тогда как здесь вам нужно только добавить один, и пусть 3-arg вызовет 4 -arg конструктор. – Christian Fries 13 June 2018 в 08:13
Другие вопросы по тегам:

Похожие вопросы: