質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • Java

    13465questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Generics

    15questions

    Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

[Java] ジェネリクスとシングルトン

解決済

回答 3

投稿

  • 評価
  • クリップ 3
  • VIEW 493

yama_da

score 65

以下の例ように(疑似コードです)、一種類の型を扱うシングルトンクラスを、ジェネリクスを用いて複数種類分用意したいのですが、どのように実現すれば良いのでしょうか?
代替案でも構いません、回答よろしくお願いします。

    public static void main(String[] args) {
    /**
         *
         * GenericsSingleton<T> はT型のオブジェクトを扱うシングルトンクラス.
         *
         * strSingleton1 と strSingleton2 は同じインスタンス,
         * intSingleton と strSingleton1,2 は違うインスタンス.
         */
        GenericsSingleton<String> strSingleton1 = GenericsSingleton<String>.getInstance();
        GenericsSingleton<String> strSingleton2 = GenericsSingleton<String>.getInstance();
        GenericsSingleton<Integer> intSingleton = GenericsSingleton<Integer>.getInstance();
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+4

Javaのジェネリクスは後付けだったこともあって、コンパイルしたバイトコード上では型情報が消えてしまいます。そのため、コンパイル後にはGenericsSingleton<String>.getInstance()GenericsSingleton<String>.getInstance()の区別がつきません。

ということで、「型ごとに別インスタンスとしたい」のであれば、getInstance(Class<T> clazz)のようにClassを引数にとって、それで振り分けをやるしかないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+3

ご参考までに可変長引数使うと、引数無しでも関数の呼び出し可能です。
やっていることはmaisumakunサンと同じで、
getInstanceでジェネリクスのクラス毎に振り分けです。

public class GenericsSingleton<T> {

    public static <T> GenericsSingleton<T> getInstance(T... dummy) {
        System.out.println(dummy.getClass());
        // ex) class毎にmapからget、なければnewして、put
        return new GenericsSingleton<T>();// map.get(dummy.getClass());
    }

    public static void main(String[] args) {
        GenericsSingleton<String> test = GenericsSingleton.getInstance();
        Integer obj = null;
        GenericsSingleton.getInstance(obj);

        GenericsSingleton.getInstance(null);// nullpo
    }
}


一番最後だけヌルポしますので、ご注意を。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/25 15:36

    dummyは配列になるため、getClassすると配列型のClassを返すことになります。
    getComponentTypeが妥当ですね。

    キャンセル

  • 2017/09/25 16:25

    おっ、勉強になります。
    確かに「dummy.getClass().getComponentType()」のほうがデバッグした時に分かりやすいですね。
    最悪、クラス名でif文も組めますし。

    キャンセル

  • 2017/09/26 14:42

    回答ありがとうございます。
    可変長引数を使うとなぜ引数なしでもTの型が決まるのですか?型推論的なことが起こるのでしょうか?

    キャンセル

  • 2017/09/26 19:49

    可変長引数dummyの実態は配列となるのですが、Javaの配列は共変という性質上、自身の型情報をもっており、getComponentTypeで配列の型情報を取り出してごにょごにょする、という仕組みかと思います。

    キャンセル

  • 2017/09/27 13:32

    参考になるか微妙ですが、っぽい記事を2つほど。
    http://d.hatena.ne.jp/Nagise/20131121/1385046248
    http://d.hatena.ne.jp/ryousanngata/20120607/1339016044

    キャンセル

  • 2017/09/30 08:32

    返信が遅くなってすみません。
    ありがとうございます、参考になりました。

    キャンセル

+2

import java.util.HashMap;
import java.util.Map;

public class Q93782 {

    public static void main(String[] args) {
        GenericsSingleton<String> s1 = GenericsSingleton.getInstance(String.class);
        GenericsSingleton<String> s2 = GenericsSingleton.getInstance(String.class);
        GenericsSingleton<Integer> i1 = GenericsSingleton.getInstance(Integer.class);
        GenericsSingleton<Integer> i2 = GenericsSingleton.getInstance(1);
        System.out.println("s1 == s2 :" + (s1 == s2));
        System.out.println("i1 == i2 :" + (i1 == i2));
        System.out.println(GenericsSingleton.instances);
    }

    static class GenericsSingleton<T> {
        static Map<Class<?>, GenericsSingleton<?>> instances = new HashMap<>();

        @SuppressWarnings("unchecked")
        public static <T> GenericsSingleton<T> getInstance(Class<T> clazz) {
            return (GenericsSingleton<T>) instances.computeIfAbsent(clazz, c -> new GenericsSingleton<>());
        }

        @SuppressWarnings("unchecked")
        public static <T> GenericsSingleton<T> getInstance(T... dummy) {
            return (GenericsSingleton<T>) getInstance(dummy.getClass().getComponentType());
        }
    }

}


面白そうだったので作ってみました。2個目のgetInstanceはszk.さんのを載せてみました。
どうにも不格好さが抜けない。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/26 12:25

    szk.さんの手法ならString.classやInteger.classを引数として渡す必要はないので
    サンプルコードとしてならs2のほうは引数なしで呼び出したほうが適切じゃないでしょうか。
    GenericsSingleton<String> s2 = GenericsSingleton.getInstance();

    キャンセル

  • 2017/09/26 14:49

    可変長引数なのに引数を渡さないこと前提というのが嫌だったもので…。

    キャンセル

  • 2017/09/27 13:37

    意味のない引数がイヤだという気持ちはとてもわかります。
    大~中規模案件でpubicメソッドだったら、間違いなく固定の引数入れさせます。
    ただジェネリクスで指定したクラスをわざわざ引数に入れるのも、
    なんか流行に逆らってる気がして、個人的には気持ち悪いです。
    ダイアモンド演算子みたいにjavaがどーにか拡張してくれればいいんですけど。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    13465questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Generics

    15questions

    Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。