2011-08-09 15 views
0

これは何千回も要請されていますが、私が見た答えはすべて、渡されたオブジェクトでは機能しません。常にがObjectおよびフィールドにハードコードされています。私は文字列フィールドに基づいてリスト/ベクトルをソートする方法を探しています。 ReflectionやVoodooの魔法を使っても構わない。任意のオブジェクトのリスト/ベクトルを任意のメンバのフィールドでソートできますか?

私が書いた方法は、StackOverFlowErrorになりました。

StandardComparator.sort("distance",Vector<?>)StaticItems.LocationList,Item.SingleLocation.class); 

StandardComparatorクラスは、次のように定義されます:

public class StandardComparator { 
    public static void sort(final String field, Vector<?> locationList, final Class typeOfObject){ 
     Collections.sort(locationList, new Comparator<Object>() { 
      @Override 
      public int compare(Object object1, Object object2) { 
       try { 
        return this.compare(typeOfObject.getField(field),typeOfObject.getField(field)); 
       } catch (SecurityException e) { 
        e.printStackTrace(); 
       } catch (NoSuchFieldException e) { 
        e.printStackTrace(); 
       } 
       return 0; 
      } 
     }); 
    } 
} 

エラー:

E/AndroidRuntime(22828): FATAL EXCEPTION: Thread-10 
E/AndroidRuntime(22828): java.lang.StackOverflowError 
E/AndroidRuntime(22828):  at java.lang.reflect.Field.<init>(Field.java:89) 
E/AndroidRuntime(22828):  at java.lang.reflect.Field.<init>(Field.java:81) 
E/AndroidRuntime(22828):  at java.lang.reflect.ReflectionAccessImpl.clone(ReflectionAccessImpl.java:42) 
E/AndroidRuntime(22828):  at java.lang.Class.getField(Class.java:870) 
E/AndroidRuntime(22828):  at com.AtClass.Extras.StandardComparator$1.compare(StandardComparator.java:24) 

SingleLocationオブジェクト:

次のように

は、私は私のメソッドを呼び出します210

+0

あなたが必要な方法で動作させたい場合、compare()メソッドでいくつかのものを追加する必要があります。スーパークラスメソッドを呼び出すだけでは動作しません(デフォルト動作以来)。 – ngesh

答えて

1

どのようなComparableフィールドでも動作する例です。あなたは、プリミティブ型と非比較対象のための特別な処理を追加する必要があると思います:

import java.lang.reflect.Field; 
import java.util.*; 

public class ReflectionBasedComparator { 
    public static void main(String[] args) { 
     List<Foo> foos = Arrays.asList(new Foo("a", "z"), new Foo("z", "a"), new Foo("n", "n")); 
     Collections.sort(foos, new ReflectiveComparator("s")); 
     System.out.println(foos); 
     Collections.sort(foos, new ReflectiveComparator("t")); 
     System.out.println(foos); 
    } 

    static class Foo { 
     private String s; 
     private String t; 

     public Foo(String s, String t) { 
      this.s = s; 
      this.t = t; 
     } 

     @Override 
     public String toString() { 
      return "Foo{" + 
          "s='" + s + '\'' + 
          ", t='" + t + '\'' + 
          '}'; 
     } 
    } 

    private static class ReflectiveComparator implements Comparator<Object> { 
     private String fieldName; 

     public ReflectiveComparator(String fieldName) { 
      this.fieldName = fieldName; 
     } 

     @Override 
     public int compare(Object o1, Object o2) { 
      try { 
       Field field = o1.getClass().getDeclaredField(fieldName); 
       if (!Comparable.class.isAssignableFrom(field.getType())) { 
        System.out.println(field.getType()); 
        throw new IllegalStateException("Field not Comparable: " + field); 
       } 
       field.setAccessible(true); 
       Comparable o1FieldValue = (Comparable) field.get(o1); 
       Comparable o2FieldValue = (Comparable) field.get(o2); 
       return o1FieldValue.compareTo(o2FieldValue); 
      } catch (NoSuchFieldException e) { 
       throw new IllegalStateException("Field doesn't exist", e); 
      } catch (IllegalAccessException e) { 
       throw new IllegalStateException("Field inaccessible", e); 
      } 
     } 
    } 
} 
+0

トーンライアンに感謝します。コードは動作しますが、二重でソートすると誤ってIllegalStateExceptionがスローされます。 –

+0

それは偶然ではありません。これは、サポートを追加する必要がある原始的な価値です。 –

1

あなた自身のメソッドを呼び出しているだけで、スタックオーバーフローが発生しています。フィールドがStringであることを知っているので、Stringにキャストし、そのcompareTo()メソッドを使用してください。

+0

Item.SingleLocationのすべてのフィールドが文字列であるとは限りません。 String、double、intが混在しています。 –

+0

この場合、これを行う簡単な方法はありません。 doubleとintはプリミティブなので、型を判別してそれに応じて比較するロジックが必要です。より一般的な解決策が必要な場合は、Apache Commons LangのCompareToBuilderをご覧ください。http://commons.apache.org/lang/api-3.0/org/apache/commons/lang3/builder/CompareToBuilder.html –

0

あなたはこれであなたの比較方法を置き換えることができます。

return typeOfObject.getField(field).get(object1).compareTo(typeOfObject.getField(field).get(object2)); 

と例外(フィールドが見つからない、NULLポインタ、...)に応じます。

+0

フィールド.get(Object object)メソッドは、このオブジェクトが表すフィールドの値を返します。詳細はこちら[こちら](http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Field.html#get%28java.lang.Object%29)。 – n0rm1e

+0

クイックレスポンスのおかげで、コンパイルされていないので、このメソッドは目的の結果を得られません。 ObjectオブジェクトのcompareTo(Object)メソッドは未定義です –

+0

はい、そうです。あなたが比較しているものが分かっているなら、あなたはキャストできます。または、渡すオブジェクトの値を比較するために別のメソッドを書くこともできます。 – n0rm1e

0

Bean Comparatorは動作するはずです。

+0

はい、それを実装する方法は?それはリストを受け入れるようには思われません。 –

+0

@ケビン、それはあなたがリストを受け入れていないという意味ですか?コレクションを使用してソートを行う理由は同じです。sort(List、theBeanComparator)また、プリミティブでも動作します。コードはより多くの機能を提供するため、少し複雑に見えます。違いは、このComparatorでは比較したいフィールドに「get」アクセサメソッドを実装する必要があります。これはフィールドにパブリックアクセサを使用しないでください。 – camickr

関連する問題