2011-08-09 3 views
0

이것은 1000 번이나 부탁되었지만, 내가 본 모든 대답은 전달 된 객체에서 작동하지 않으며, 항상 에 하드 코딩 된 Object 및 필드입니다. 문자열 필드를 기반으로 List/Vector를 정렬하는 방법을 찾고 있습니다. 리플렉션이나 부두 마법을 사용하면 괜찮습니다.개체 목록/벡터를 구성원의 필드로 정렬 할 수 있습니까?

작성한 방법은 입니다. 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의 모든 필드가 문자열은 아닙니다. 그것의 문자열, 더블 및 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)); 

을 예외에 대한 수용 (필드를 찾을 수 없습니다, 널 포인터, ...).

+0

The Field .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"접근 메소드를 구현해야한다는 것입니다. 이는 필드에서 public 접근을 사용해서는 안되기 때문에 모든 bean의 좋은 디자인입니다. – camickr

관련 문제