web-dev-qa-db-ja.com

Javaでコンストラクタを別のコンストラクタから呼び出す方法は?

別のコンストラクタから(サブクラスからではなく、同じクラス内で)コンストラクタを呼び出すことは可能ですか。もしそうならどうですか?そして、他のコンストラクタを呼び出すための最善の方法は何でしょうか(それを行う方法がいくつかある場合)。

2045
ashokgelal

はい、可能です。

public class Foo {
    private int x;

    public Foo() {
        this(1);
    }

    public Foo(int x) {
        this.x = x;
    }
}

同じクラス内のスーパークラスコンストラクタではなく特定のスーパークラスコンストラクタにチェーンするには、superではなくthisを使用します。 1つのコンストラクタ にしか連鎖できないこと、および これはコンストラクタ本体の最初のステートメントでなければならない であることに注意してください。

この関連する質問 も参照してください。これはC#に関するものですが、同じ原則が適用されます。

2733
Jon Skeet

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;
 }
}

最近支持されたvalueOfまたは単に "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(someValue)を使います。 superの呼び出しは、コンストラクター内の最初の呼び出しでなければなりません。そうしないと、コンパイラー・エラーになります。

223
Josh

[ 注:私は他の答えでは見られなかった1つの側面を追加したいだけです:this()が最初の行になければならないという要件の制限を克服する方法) ]

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;

  }

}
191
Christian Fries

最初の行ではなく、コードの内側から別のコンストラクタを呼び出す必要がある場合は、通常、次のようなヘルパーメソッドを使用します。

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);
   }
}
38
Kaamel

コンストラクター内では、thisキーワードを使用して同じクラス内の別のコンストラクターを呼び出すことができます。そうすることは 明示的なコンストラクタ呼び出し と呼ばれます。

これは、Objectsセクションの実装とは異なる実装を持つ、もう1つの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;
    }

}

このクラスには一連のコンストラクタが含まれています。各コンストラクタは、四角形のメンバ変数の一部または全部を初期化します。

26
amila isura

誰もがすでに言ったように、あなたはthis(…)を使います。これは 明示的コンストラクタ呼び出し と呼ばれます。

しかし、以下の点に注意してください。 このような明示的なコンストラクタ呼び出しステートメント内 - 参照してはならない

  • any インスタンス変数 または
  • any インスタンスメソッド または
  • any 内部クラス このクラスまたは任意のスーパークラスで宣言されている、または
  • thisまたは
  • super

JLSに述べられているように(§8.8.7.1)。

14
olovb

はい、あるコンストラクタを別のコンストラクタから呼び出すことは可能です。しかしそれには規則があります。あるコンストラクタから別のコンストラクタへ呼び出しが行われると、

その新しいコンストラクタ呼び出しは、現在のコンストラクタの最初のステートメントでなければなりません

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");
    }
}

したがって、この場合も、他のステートメントの前に別のコンストラクター呼び出しが最初に宣言されます。

11
S R Chaitanya

はい、クラス内には任意の数のコンストラクタを含めることができ、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");
    }
}

これはコンストラクタのオーバーロードとして知られています。
コンストラクタには、オーバーロードの概念のみが適用され、継承やオーバーライドは適用されません。

10
Utsav

簡単な方法を教えます

two /型のコンストラクタがあります。

  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. this()の呼び出しはコンストラクタの最初のステートメントでなければなりません
  2. これはNameよりObjectです。これは自動的にデフォルトのコンストラクタを呼び出します。 3.これは、Parameterizedコンストラクタを呼び出します。

注意: これはコンストラクタの最初のステートメントでなければなりません。

はい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);
   }
7

"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コンストラクタとしての文字列..デフォルトコンストラクタ.. argコンストラクタとしてのint.

7
ABHISHEK RANA

ものすごく単純

public class SomeClass{

    private int number;
    private String someString;

    public SomeClass(){
        number = 0;
        someString = new String();
    }

    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 )
        this.setString(someString);
    }

    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.
}

お役に立てれば。

7
GetBackerZ

他のコンストラクタからコンストラクタを呼び出す

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

super() callを使って親コンストラクタを呼び出すこともできます

7
Akshay Gaikwad

キーワードthisはコンストラクタからコンストラクタを呼び出すために使用することができます。あるクラスに対して複数のコンストラクタを書くとき、あるコンストラクタを別のコンストラクタから呼び出すことを避けたい場合があるコードが重複しています。

Bellowは私がコンストラクタとgetters()とsetters()に関する他のトピックを説明するリンクであり、私は2つのコンストラクタでクラスを使いました。説明と例が役に立つことを願っています。

セッターメソッドまたはコンストラクタ

5
S. Mayol

複雑な構成の必要性をカバーする設計パターンがあります - それがうまくできない場合は、ファクトリメソッドまたはファクトリクラスを作成します。

最新のJavaとラムダの追加により、必要な初期化コードをすべて受け入れることができるコンストラクタを簡単に作成できます。

class LambdaInitedClass {

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

と呼んでください...

 new LambdaInitedClass(l -> { // init l any way you want });
5

これは、テレスコープコンストラクタアンチパターンまたはコンストラクタチェーンと呼ばれます。はい、できます。私は上記の多くの例を見ます、そしてあなたがあなたが2つか3つのコンストラクタだけを必要としているのを知っているなら、それは大丈夫かもしれないと言って付け加えたいです。しかし、もっと必要な場合は、Builderパターンのような異なるデザインパターンを使用してみてください。例えば:

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

もっと必要かもしれません。この場合、ビルダーパターンが優れた解決策になります。ここに記事があります、それは役に立つかもしれません https://medium.com/@modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e

4

この質問には非常に多くの例があることを私は知っていますが、私は自分のアイデアを共有するためにここに置いていることを私は見つけました。チェーンコンストラクタには2つの方法があります。同じクラスでこのキーワードを使用できます。継承では、スーパーキーワードを使用する必要があります。

    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");
        }
    }
4
Negi Rox

this(...) キーワード(同じクラスからコンストラクタを呼び出す必要がある場合)または super(...) キーワード(スーパークラスからコンストラクタを呼び出す必要がある場合)を介して別のコンストラクタを呼び出すことができます。

しかしながら、そのような呼び出しはあなたのコンストラクタの 最初の ステートメントでなければなりません。に 克服 この制限を使用してください この答え

4
John McClane

私はこの方法を好む:

    class User {
        private long id;
        private String username;
        private int imageRes;

    public User() {
        init(defaultID,defaultUsername,defaultRes);
    }
    public User(String username) {
        init(defaultID,username, defaultRes());
    }

    public User(String username, int imageRes) {
        init(defaultID,username, imageRes);
    }

    public User(long id, String username, int imageRes) {
        init(id,username, imageRes);

    }

    private void init(long id, String username, int imageRes) {
        this.id=id;
        this.username = username;
        this.imageRes = imageRes;
    }
}
1
ansh sachdeva

もともとMirko Klemmによるanserから

完全を期すために: Instance初期化ブロック は常に実行され、他のコンストラクタが呼び出される前に実行されます。それは単にクラス定義の本体のどこかにあるステートメントのブロック "{...}"で構成されています。あなたも複数持つことができます。それらを呼び出すことはできませんが、メソッドを呼び出すのと同様に、コンストラクタ間でコードを再利用したい場合、それらは「共有コンストラクタ」コードのようになります。

だからあなたの場合

{ 
  System.out.println("this is shared constructor code executed before the constructor");
  field1 = 3;
}

静的メンバーを初期化するためのこれの "静的"バージョンもあります。 "static {...}"

0
rogerdpack

はい、別のコンストラクターからコンストラクターを呼び出すことができます。例えば:

public class Animal {
    private int animalType;

    public Animal() {
        this(1);
    }

    public Animal(String animalType) {
        this.animalType = animalType;
    }
}

Javaのコンストラクターチェーン から詳細を読むこともできます。

0
Soni Vashisht