souki-paranoiastのブログ

地方都市でプログラマーをやっている人のブログ。技術ネタ以外も少し書く。メインの言語はJava。https://paranoiastudio-japan.jimdo.com/ に所属

【Java】「InterfaceのAとBを実装する型」という書き方がローカル変数で実現できない

何を言っているかという話だが、こういうこと↓

public class Main {

    public static void main(String[] args) throws Exception {
        Ccc c = new Ccc();
        System.out.println(c.concatB(c.concatA("hoge"))); // hogeAB
        System.out.println(concatHelper(c, "hogehoge")); // hogehogeAB
        // このcに当たるような存在をclassじゃなくてInterface名で指定したい。。
        // 欲しいのはAaaとBbbを実装しているやつだからね。Cccクラスじゃないからね(´・ω・`)
    }

    static <T extends Aaa & Bbb> String concatHelper(T t, String str) {
        return t.concatB(t.concatA(str));
    }

    interface Aaa {
        default String concatA(String str) {
            return str.concat("A");
        }
    }

    interface Bbb {
        default String concatB(String str) {
            return str.concat("B");
        }
    }

    static class Ccc implements Aaa, Bbb {
    }
}

設計が悪いと言われればそれまでなんだろうけど、リフレクションなんかを使用している時に、「複数のInterfaceを実装しているクラス」という型を宣言したい時がある。

もちろん、上記でいえばconcatHelper()のような形で宣言できるのは知っているのだけど、これを普通のローカル変数の型として定義したい(何というか、スコープがメソッドなのが気に食わない…)。

※これを試しているのはjava version "1.8.0_192" です。10以降(?)で導入されたvarで解決できるかは不明。

あとこれ書いてて思い出したのは、Interfaceを無名関数で複数実装ができないのもちょっと悲しいなぁと思う。

今はできるんだろうか。 Scalaならできるんだろうなぁ…とか思って試したら両方ともできた。やっぱり柔軟な書き方ができるのは羨ましいなー;;

object ScalaMain {
  def main(args: Array[String]): Unit = {
    val sccc: Sccc = new Sccc()
    println(sccc.concatB(sccc.concatA("hoge"))) // hogeAB
    println(concatHelper(sccc, "hogehoge")) // hogehogeAB
    val x: Saaa with Sbbb = new Saaa with Sbbb
    println(x.concatB(x.concatA("foo"))) // fooAB
    val y: Saaa with Sbbb = sccc
    println(y.concatB(y.concatA("foofoo"))) // foofooAB
  }

  private def concatHelper[T <: Saaa with Sbbb](t: T, str: String): String = {
    t.concatB(t.concatA(str))
  }

  trait Saaa {
    def concatA(str: String): String = str.concat("A")
  }

  trait Sbbb {
    def concatB(str: String): String = str.concat("B")
  }

  class Sccc extends Saaa with Sbbb {
  }
}