LoginSignup
8
4

More than 5 years have passed since last update.

JavaのInterfaceではGetter・Setterの自動生成はできないの?

Last updated at Posted at 2018-09-16

はじめに

結論から言うと、インターフェースではGetter・Setterの自動生成はでません。インターフェースの性質を理解していれば、当たり前なのですが、個人的に混乱したので、まとめます。

開発環境は以下の通りです。

  • jdk 1.8.0_172
  • Lombok 1.18.2

getter, setterのコピペはバグの温床

Javaのコーディングではクラスを頻繁に作ると思います。その度に毎回、以下のようなgetter, setter を定義している人は多いのではないでしょうか?(少なくとも私はそうでした)

// 普通のクラス
public class SampleClass {
    // メンバ変数
    private String foo;

    // Getter
    public String getFoo() {
        return this.foo;
    }

    // Setter
    public void setFoo(String foo) {
        this.foo = foo;
    }
}
// 呼び出し元
public void SampleMethod {
    // 普通のクラス
    SampleClass sample1 = new SampleClass();
    sample1.setFoo("hoge");
    System.out.println("sample1.getFoo(): " + sample1.getFoo());
}

例えば、クラスやメンバ変数(フィールド)が大量にあるとかで、こういうgetterみたいな単純なメソッドを大量にコーディングしなければならない場合、多くの人がコピペすると思います。

こういうコピペって、ミスしても気づきにくいので、バグの温床になりやすいと思います。

クラスに@Dataをつけると?

それを解決してくれるのが、Lombokです。以下のように書くだけで、getterやsetterを自動生成してくれます。(C#のプロパティみたいなもの)

import lombok.Data;

// クラスに@Dataをつける
@Data
public class SampleClassWithLombok {
    // メンバ変数
    private String foo;
}
// 呼び出し元
public void SampleMethod {
    // @Dataのついたクラス
    SampleClassWithLombok sample2 = new SampleClassWithLombok();
    sample2.setFoo("hoge");
    System.out.println("sample2.getFoo(): " + sample2.getFoo());
}

これで、コード量を減らせて、バグの温床もつぶすことができました。

Lombokの導入方法は、以前、こちらにまとめましたので、ご参照ください。

インターフェースに@Dataをつけると?

ここで、疑問に思ったのが、インターフェースに@Dataを付けるとどうなるのか?ということです。

インターフェースのメンバ変数にはprivateを指定することができないので、publicなメンバ変数にgetter, setterをつけてみたいと思います。(意味はないですが)

こんな感じのインターフェースに@Dataをつけてみます。

// インターフェースに@Dataをつける
@Data
public interface SampleInterface {
    // メンバ変数
    public String bar = "bar";
}

つけた途端にEclipseが@Data is only supported on a class.というエラーを吐きました。

そもそもインターフェースのメンバ変数は定数なので、setterというものを定義できないのが原因だと思います。

実装クラスに@Dataをつけると?

実装クラスではどうなのでしょうか?こんなインターフェースと実装クラスがあるとします。

// インターフェース
public interface SampleInterface {
}
import lombok.Data;

// 実装Classに@Dataをつける
@Data
public class SampleImpl implements SampleInterface {
    // メンバ変数
    private String foo;
}
// 呼び出し元
public void SampleMethod {
    // @Dataのついた実装Class
    SampleInterface sample3 = new SampleImpl();
    sample3.setFoo("hoge");
    System.out.println("sample3.getFoo(): " + sample3.getFoo());
}

こんな感じのコードを書いてみたところ、インターフェース・実装クラスでエラーは発生しませんでしたが、呼び出し元でメソッド setFoo(String) は型 SampleInterface で未定義ですというエラーが発生しました。

実装クラスにgetter, setterは定義されているようですが、インターフェースにその定義がないため、エラーになったようです。

ここで、インターフェースにgetter, setterを追加してみました。

// インターフェースにgetter, setterを定義する
public interface SampleInterface {
    // Getter
    public String getFoo();

    // Setter
    public void setFoo(String foo);
}

これでエラーは出なくなりました。しかし、インターフェースにgetter, setterを定義する羽目になりました。これでは、コピペミスを抑制することができませんね。

抽象クラスに@Dataをつけると?

抽象クラスではどうなのでしょうか?こんな抽象クラスと継承クラスがあるとします。

import lombok.Data;

// 抽象Classに@Dataをつける
@Data
public abstract class SampleAbstract {
    // メンバ変数
    private String foo;
}
//継承Class
public class SampleExtends extends SampleAbstract {
}
// 呼び出し元
public void SampleMethod {
    // @Dataのついた抽象Class
    SampleAbstract sample4 = new SampleExtends();
    sample4.setFoo("hoge");
    System.out.println("sample4.getFoo(): " + sample4.getFoo());
}

こんな感じのコードを書いてみたところ、エラーは発生しませんでした。インターフェースと違って、抽象クラスはprivateなメンバ変数を持つことができるので、getter, setterも自動定義できるのかもしれませんね。

さいごに

通常のクラス・実装クラス・抽象クラスは、@Dataをつけることで、メンバ変数のgetter, setterを自動定義することができます。

しかし、インターフェースは、手動でgetter, setterを定義する必要があることがわかりました。

抽象クラスに切り替えれば、お手軽に回避できると思いますが、そもそもインターフェースにgetter, setterが必要になった時点で、一旦、そのインターフェースの設計を見直した方がよいのかもしれません。

8
4
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4