12

IntegerFloat、 ... (およびDoubleを除く)などのラッパー型の操作ごとに 1 つのジェネリック メソッドのみを使用して、加算、減算、乗算、除算などの基本的な算術演算を実行したいと考えています。BigDecimalBigInteger

ジェネリッククラスを使用して、次のようなことを(追加で)実行しようとしました。

public final class GenericClass<E extends Number> {

    public E add(E x, E y) {
        return x + y; // Compile-time error
    }
}

コンパイル時エラーを発行し、

演算子 + は E,E には適用できません

そのような汎用バージョンを使用してそのような操作を実現する方法はありますか?

4

11 に答える 11

13

いいえ、これを行う方法はありません。そうしないと、Java に組み込まれてしまいます。型システムは、この種のことを表現するのに十分強力ではありません。

于 2012-12-26T21:00:50.770 に答える
6

いいえ、+ 演算子は Number クラスの一部ではないため、それはできません。できることは、抽象基本クラスを作成し、そこから拡張することです。

static void test() {

    MyInteger my = new MyInteger();
    Integer i = 1, j = 2, k;
    k = my.add(i, j);
    System.out.println(k);
}

static public abstract class GenericClass<E extends Number> {
    public abstract E add(E x, E y);
}

static public class MyInteger extends GenericClass<Integer> {
    @Override
    public Integer add(Integer x, Integer y) {
        return x + y;
    }       
}

(テストを容易にするためにこれらのクラスを静的にしましたが、この修飾子は削除できます。)

Number 型のパラメーターと戻り値を受け取って返す抽象関数を追加し、それとサブクラスをオーバーライドすることもできますが、戻り値に必要なキャストはその有用性を無効にします。

于 2012-12-26T22:31:02.550 に答える
2

私が考えることができるのは、タイプを不明なタイプとして受け取り、インスタンスを使用することだけです。

何かのようなもの:

public class GenericClass<? extends Number>{
    public Integer add(? x, ? y){
        if(x instance of Integer && y instance of Integer){
            //Do your math with Integer class methods help
            //Return here
        }
        return (Interger)null;
    }

} 

しかし、よくわかりません:/

于 2012-12-26T23:27:19.843 に答える
1

Numberはクラス型であるため、プリミティブ型の演算子は適用されません。さらに、Javaのジェネリックはプリミティブ型をサポートしていないため、Eをバインドしてプリミティブ型のみを許可することはできません。

これを回避する1つの方法は、NumberがAddメソッドで個別にサポートする各プリミティブ型を処理することですが、それはあなたが達成しようとしていることを打ち負かすと思います。

于 2012-12-26T21:08:06.270 に答える
1

Louis Wassermanが指摘したように、Java でこれを行う方法はありません。ただし、それほどトリッキーではないプログラミングを使用することで、解決策を提示できます。私が気に入っている解決策から始めましょう:質問に対するSylvainLの回答です。しかし、一歩下がって、あらゆるタイプの を処理できると思いますNumberJava APIを見ると、 のサブクラスはNumberいくつかの抽象メソッドをオーバーライドする必要があることに注意してください。つまり、intValue() (およびその他) です。これらの方法を使用して、ポリモーフィズムを真の可能性に活用できます。SylvainLの回答から取得したクラスを取得すると、次のような新しいクラスを作成できます。

public final class EveryNumberClass<E extends Number>
{
    public static int add(E x, E y)
    {
        return x.intValue() + y.intValue();
    }

    public static int subract(E x, E y)
    {
        return x.intValue() - y.intValue();
    }
}

これらの演算は、乗算と除算に拡張できます。s に限定されませんが、任意Integerの演算を取り込み、与えられた演算の適切な動作を表現するために使用できます。また、メソッドの動作はの整数表現を返さない場合がありますが、間違いなく返されます (アトミックなもの数学のものを含むほとんどの数字のソース コードを調べました)。唯一の問題は、 から予期しない動作が返された場合に発生します。これは、原子番号、ユーザー定義の で発生する可能性があるか、大きな数値が強制的に縮小された場合に発生する可能性があります。それらがあなたのプロジェクト(またはあなたのライブラリ)にとって懸念事項である場合は、使用を検討します NumberintValue()NumberintValue()Numberlong値、またはSylvainLの回答を参照してください。

于 2016-06-23T19:11:18.947 に答える
1

Afonso が提案したように、関数を作成し、必要なすべての可能性を書き留める別の可能性があります。いくつかのバリエーションを次に示します。

      // Examples with static functions:
        Integer i = addNumbers (1, 2); // OK
        Double d = addNumbers (3.0, 4.0); // OK
        String s = addObjects ("a", "b"); // OK
//
      // Example with a raw type for a class with both method
      // (or member function) and static functions:
GenericClass gc = new GenericClass();  // Raw type
//
      // Note the error if we don't add a cast:
// i = gc.add(1, 2); // Error: Cannot convert from Number to Integer
//
      // Now OK with a cast but with a Type safety warning:
        i = (Integer) gc.add (1, 2); // Type safety warning.
        i = GenericClass.add2 (1, 2); // OK
        i = GenericClass.add3 (1, 2); // OK
//    
      // Example with an instanciated type for the same class:
        GenericClass<Integer> gc1 = new GenericClass<Integer>();
//
      // Note that we don't need a cast anymore:
        i = gc1.add(1, 2); // Now OK even without casting.
//
        i = GenericClass2.add2 (1, 2); // OK
        s = GenericClass2.add2 ("a", "b"); // OK
        i = GenericClass2.<Integer>add2 (1, 2); // OK.
        d = GenericClass2.<Double>add2 (1.0, 2.0); // OK
        s = GenericClass2.<String>add2 ("a", "b"); // OK
//  
    public static<T extends Number> T addNumbers(T x, T y) {

        if (x instanceof Integer && y instanceof Integer){
            return (T) (Integer) ((Integer)x + (Integer)y);
        } else if (x instanceof Double && y instanceof Double){
            return (T) (Double) ((Double)x + (Double)y);
        } else
            return (T)null;
    }
//    
    public static<T> T addObjects(T x, T y) {

        if (x instanceof Integer && y instanceof Integer) {
      //
      // We must add an (Integer) cast because the type of the operation
      // "((Integer)x + (Integer)y))" is "int" and not "Integer" and we
      // cannot directly convert from "int" to "T".  Same thing for Double
      // but not for the type String:
      //
            return (T) (Integer) ((Integer)x + (Integer)y);
        } else if (x instanceof Double && y instanceof Double) {
            return (T) (Double) ((Double)x + (Double)y);
      } else if (x instanceof String && y instanceof String) {
            return (T) ((String)x + (String)y);            
      } else
            return (T)null;
    }
 //  
    static class GenericClass<T extends Number> {

        public T add(T x, T y) {
            if (x instanceof Integer && y instanceof Integer) {
                return (T) (Integer) ((Integer)x + (Integer)y);
            } else if (x instanceof Double && y instanceof Double) {
                return (T) (Double) ((Double)x + (Double)y);
            } else
                return (T)null;
        }
 //   
        // The type <T> here is NOT the same as the one for the class.
        // We should rename it in order to make this clearer. See add3() 
        // for an example of this.
        public static<T> T add2(T x, T y) {
            if (x instanceof Integer && y instanceof Integer) {
                return (T) (Integer) ((Integer)x + (Integer)y);
            } else if (x instanceof Double && y instanceof Double) {
                return (T) (Double) ((Double)x + (Double)y);
            } else if (x instanceof String && y instanceof String) {
                return (T) ((String)x + (String)y);
            } else
                return (T)null;
        }
 //   
        // The type here is not the same as the one for the class
        // so we have renamed it from <T> to <N> to make it clearer.
        public static<N extends Number> N add3(N x, N y) {
            if (x instanceof Integer && y instanceof Integer) {
                return (N) (Integer) ((Integer)x + (Integer)y);
            } else if (x instanceof Double && y instanceof Double) {
                return (N) (Double) ((Double)x + (Double)y);
            } else
                return (N)null;
        }
    }
于 2012-12-27T15:26:31.990 に答える
1

double や BigDecimal など、任意の型の任意の値を表すことができる「スーパー」型を使用する方が簡単で効率的であるため、通常、これは必要ありません。

注: aは、それへの参照doubleで an の半分未満のスペースを使用します。Integer

于 2012-12-26T21:05:52.550 に答える
0

これが、ジェネリックを使用した算術演算に取り組むことに興味がある人の助けになることを願っています

  public < T > T add( T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) + Integer.parseInt(b.toString()))));
  }
  public < T > T sub(T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) - Integer.parseInt(b.toString()))));
  }
  public < T> T mul(T a,T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) * Integer.parseInt(b.toString()))));
  }
  public < T  >  T  div (T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) / Integer.parseInt(b.toString()))));
  }
  public < T  > T mod(T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) % Integer.parseInt(b.toString()))));
  }
  public < T  > T leftShift(T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) <<  Integer.parseInt(b.toString()))));
  }
  public < T  > T rightShift(T a, T b)
  {
      return (T) (String.valueOf((Integer.parseInt(a.toString()) >> Integer.parseInt(b.toString()))));
  }
于 2017-01-10T04:47:09.590 に答える