2

ジェネリック型で静的フィールドを作成しようとしてもコンパイルされません:

class MyClass {

    public static Function<Z, Z> blargh = new Function<Z, Z>() {
        public Z apply(Z a) {
            return a;
        }
    };
}

エクリプス 言います:

Multiple markers at this line
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - The type new Function<Z,Z>(){} must implement the inherited 
     abstract method Function<Z,Z>.apply(Z)

ただし、すべての s を具象型に置き換えるZと問題なく動作します。

static Function<Integer, Integer> blargh = new Function<Integer, Integer>() {
    public Integer apply(Integer a) {
        return a;
    }
};

何が起きてる?


環境:

  1. 私はもともと、このコードがフィールドではなくメソッドを使用している理由を理解しようとしていました。

    public static <T extends Throwable> F<T, String> eMessage() {
      return new F<T, String>() {
        public String f(final Throwable t) {
          return t.getMessage();
        }
      };
    }
    

    多分それはこの制限を克服するためですか?

  2. Functionタイプは Google の guava ライブラリからのものです。

4

3 に答える 3

3

メンバー フィールドでは、クラス レベルのジェネリックのみを使用できます。例えば:

public class MyClass<Z> {
    private Function<Z, Z> function;
    // ...
}

正しい。代わりにこれを宣言staticすると壊れます。なんで?

について考えてみてくださいArrayList。そのクラス宣言は次のようなものです。

public class ArrayList<E> extends AbstractList<E> implements List<E>, ... {
    // ...
}

E静的変数は のすべてのインスタンスに属しますが、インスタンスごとに異なる可能性があるため、静的な意味でのコンテキストはありArrayListませんEArrayList

// Here's one ArrayList with E as String
List<String> strs = new ArrayList<String>();
// And another with E as Boolean
List<Boolean> bools = new ArrayList<Boolean>();

したがってE、インスタンスごとに変化する可能性があるため、レベルEで変数を持つことは意味がありません。static

ジェネリックを使用してメソッドを宣言できるようになりましstaticたが、その方法はまったく異なります。たとえば、Collections.sort次のような宣言を行うことができます。

public static <T> void sort(List<? extends T> list, Comparator<T> comparator)

T戻り値の型の前にメソッドの一部として宣言されていることに注意してください。Tこれはメソッド内のコンテキストを定義しておりT、呼び出しごとに異なる場合があります。

編集後のコメント:あなたの場合、Zどこにも宣言していないので、とにかくそれを使用することはできません。については、上記の私の宣言を参照してくださいMyClass<Z>クラスで直接使用した方法に注意してください。つまりZ、任意の型になります。

あなたが理解しようとしていたことの場合Function、変換を表す一般的な方法として見る必要があります。投稿されたメソッドを分析しましょう。

public static <T extends Throwable> F<T, String> eMessage() {
    return new F<T, String>() {
        public String f(final Throwable t) {
            return t.getMessage();
        }
    };
}

まず、これはメソッドであり、OP のような静的フィールドではないことに注意してください。したがって、ここにジェネリックを含めることは合法です。また、それstaticは であるため、ジェネリックは戻り値の型の前に宣言する必要があります。ここでは、 を宣言し<T extends Throwable>ているので、Tを拡張する何らかのエラーまたは例外である必要がありますThrowable。戻り値の型は です。これは(a )F<T, String>を取り、 を返す関数です。実際のオブジェクトは、 を呼び出すことによってそれを行うメソッドを宣言します。プロジェクトは機能的なJavaであるため、すべてがクラスに基づいているため、ジェネリックはどこにでもあります。TThrowableStringfThrowable.getMessageF

覚えとけ:

  1. クラス レベルで宣言されたジェネリックは、非静的メンバーおよびメソッドでのみ使用できます。
  2. メソッド レベルで宣言されたジェネリックは許容されますが、クラス レベルの型を参照せず、代わりに戻り値の型の前に宣言された型を参照します。
  3. 静的フィールド レベルで宣言されたジェネリックは、具体的な型のコンテキストを持たないため、単純に許可されません。
于 2012-09-17T17:28:15.393 に答える
3

編集:問題がよくわかりました。

まず、型をクラス パラメーターとして宣言する必要があると思います。

class MyClass<Z> {

可視性を得るためですが、そのように使用できない理由は、クラスのすべてのインスタンス間で静的メンバーを共有する必要があるためです。ただし、異なる型パラメーターを持つインスタンスを作成できるため、特定の型に依存する静的メンバーは意味がありません。

于 2012-09-17T17:00:14.953 に答える
1

I think the simplest answer might be that: although the JDK compiler is flexible in how it interprets generics, it is impossible to modify or specify the "Z" class given the semantics of your code.

In all use of generics, you must define a syntax which specifies the identity of the generic class that is being operated upon. For example (As in the examples above).

1) Use a generic, parameterized utility function. In this case, its obvious to the compiler because the specified class is sent as input the function.

2) Define the class itself as being generic, and non static. This would then require that the user of the class declare it with the proper specified class parameter.

Specifically, for Function classes, you are clearly defining a constrained class : one which takes "Z" as input, and returns "Z" as output. If you want to generify this, you might create a FunctionFactory class, which takes in, for example, a single instance of Z, and returns a type-specified function of type :

public static <Z> Function<Z,Z> functionFactory(final Z default){
                    return new Function<Z,Z>(){
                        @Override
                        public Z apply(Z input) {
                        // TODO Auto-generated method stub
                        if(input==null)
                                         return default;
                                    else 
                                         return input;
                        }
                    };
            }
于 2012-09-18T16:17:19.420 に答える