이 경고 이해 : 직렬화 가능한 클래스는 정적 최종 SerialversionUid를 선언하지 않습니다.

StackOverflow https://stackoverflow.com/questions/1514881

문제

정적 이니셜 라이저 코드가 있습니다.

someMethodThatTakesAHashMap(new HashMap<K, V>() {
{
  put("a","value-a"); 
  put("c","value-c");}
});

어떤 이유로 든 Eclipse로부터 경고를 받고 있습니다. Serializable 클래스는 정적 최종 SerialversionUid를 선언하지 않습니다.

이것이 익명의 클래스에 대해 불평하고 있습니까? 그것에 대해 무엇을 할 수 있습니까?

도움이 되었습니까?

해결책

사용중인 구문이 호출됩니다 이중 브레이스 초기화 - 실제로 ""인스턴스 초기화 블록 그것은 An의 일부입니다 익명의 내부 수업"(확실히 해킹이 아님). 따라서이 표기법을 사용할 때 실제로 새로운 클래스 (!)를 정의하고 있습니다.

당신의 경우 "문제"는 그 것입니다 HashMap 구현 Serializable. 이 인터페이스에는 방법이 없습니다 직렬화 가능성의 의미를 식별하는 데만 사용됩니다. 다시 말해, 마커 인터페이스이며 구체적으로 아무것도 구현할 필요가 없습니다. 하지만, Deserialization 동안 Java는 a라는 버전 번호를 사용합니다. serialVersionUID 직렬화 된 버전이 대상과 호환되는지 확인합니다. 당신이 이것을 제공하지 않는다면 serialVersionUID, 그것은 계산됩니다. 그리고, Javadoc에서 문서화 된 바와 같이 Serializable, 계산 된 값은 매우 민감하므로 사막화 문제를 피하기 위해 명시 적으로 선언하는 것이 좋습니다. 그리고 이것은 Eclipse가 "불평"하는 것입니다 (이것은 단지 경고 일뿐입니다).

따라서이 경고를 피하기 위해 serialVersionUID 당신의 다명 내부 수업에 :

someMethodThatTakesAHashMap(new HashMap<String, String>() {
    private static final long serialVersionUID = -1113582265865921787L;

    {
        put("a", "value-a");
        put("c", "value-c");
    }
});

그러나 당신은 구문의 간결함을 느슨하게합니다 (그리고 당신은 그것을 필요로하지 않을 수도 있습니다).

따라서 또 다른 옵션은 다음을 추가하여 경고를 무시하는 것입니다. @SuppressWarnings("serial") 당신이 전화하는 방법에 someMethodThatTakesAHashMap(Map). 이것은 귀하의 경우에 더 적합한 것 같습니다.

이 구문은 간결하지만 몇 가지 단점이 있습니다. 먼저, 이중 브레이스 초기화를 사용하여 초기화 된 개체에 대한 참조를 보유하면 쓰레기 수집에 적합하지 않은 외부 객체에 대한 참조를 암시 적으로 사용합니다. 그러니 조심해. 두 번째 (이것은 마이크로 최적화와 같은 것 같습니다), 이중 브레이스 초기화는 다음과 같습니다. 아주 약간의 오버 헤드. 셋째,이 기술은 실제로 우리가 본 것처럼 익명의 내부 클래스를 사용하므로 약간의 Permgen 공간을 먹습니다 (그러나 당신이 아니라면 이것이 실제로 문제가되는 것을 의심합니다. 진짜 학대). 마지막으로 - 이것은 아마도 가장 중요한 지점 일 것입니다 - 나는 그것이 코드를 더 읽기 쉽게 만드는지 확실하지 않습니다 (잘 알려진 구문이 아닙니다).

따라서 테스트 (간결함)에서 사용하는 것을 좋아하지만 "일반"코드에서 사용하지 않는 경향이 있습니다.

다른 팁

예, 경고를 억제 할 수 있지만 다음과 같이 다시 작성합니다.

HashMap<String, String> map  = new HashMap<String, String>();
map.put("a","value-a"); 
map.put("c","value-c");
someMethodThatTakesAHashMap(map);

IMO가 필요하지 않으며 읽는 것이 훨씬 좋습니다.

나는 일반적으로 Bart K.에 동의하지만 정보 제공 목적 :
필드를 추가하여 경고를 제거 할 수도 있으며 CTRL+1을 누르면 자동으로 생성 할 수 있습니다.
정의 전에 @SuppressWarnings ( "Serial") 주석을 추가하여 경고를 억제 할 수 있습니다.
익명 클래스는 직렬화 가능성을 구현하며 직렬화 가능에는이 정적 필드가 필요하므로 직렬화 및 탈시 할 때 버전을 구별 할 수 있습니다. 자세한 내용 :
http://www.javablogging.com/what-is-serialversionuid/

그만큼 ImmutableMap Google Collections 라이브러리의 클래스는이 상황에 유용합니다. 예를 들어

someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());

또는

someMethodThatTakesAHashMap(ImmutableMap.of("a","value-a","c","value-c"));

질문의 나머지 절반을 다루기 위해 "내가 억제해야합니까?" -

예. 제 생각에는 이것은 끔찍한 경고입니다. SerialVersionUid는 기본적으로해야합니다 ~ 아니다 다른 방법이 아니라 사용됩니다.

SerialversionUid를 추가하지 않으면 최악의 상황은 실제로 직렬화 호환되는 두 가지 버전의 객체가 호환되지 않는 것으로 간주된다는 것입니다. SerialversionUid는 직렬화 호환성이 변경되지 않았다고 선언하여 Java의 기본 평가를 무시하는 방법입니다.

SerialversionUid를 사용하면 클래스의 직렬화 된 양식이 호환되지 않는 방식으로 변경 될 때 실수로 ID를 업데이트하지 못한다는 것입니다. 기껏해야 런타임 오류도 얻습니다. 최악의 경우 더 나쁜 일이 발생합니다. 그리고 업데이트에 실패하는 것이 얼마나 쉬운 지 상상해보십시오.

당신의 의도는 익명의 해시 맵 인스턴스를 초기화하는 것이 었습니다. 경고는 코드가 의도 한 것보다 더 많은 일을하고 있다는 단서입니다.

우리가 찾고있는 것은 익명 해시 맵 인스턴스를 초기화하는 방법입니다. 위에서 가지고있는 것은 해시 맵의 익명 서브 클래스를 만들어 그 익명 클래스의 익명 인스턴스를 만듭니다.

코드는 의도 한 것보다 더 많은 일을하기 때문에 해킹이라고 부릅니다.

우리가 정말로 원하는 것은 다음과 같습니다.

foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));

그러나 아아 이것은 유효한 자바가 아닙니다. 키/값 쌍의 배열을 사용하여 유형 안전 방식 으로이 작업을 수행 할 수있는 방법은 없습니다. Java Simple에는 표현력이 없습니다.

정적 메소드의 Google Collection의 EmpableMap.는 가깝지만 다양한 숫자의 키/값 쌍에 대한 공장 메소드 버전을 만드는 것을 의미합니다. (Finnw의 답변을 참조하십시오.)

그러니 물건을 단순하게 유지하십시오. 이 초기화로 코드가 흩어져 있지 않으면 Bart K의 솔루션으로 이동하십시오. 그렇다면 EmpableMap을 사용하십시오. 또는 "스타일의"공장 방법으로 자신의 해시 맵 서브 클래스를 굴립니다. 또는 유틸리티 클래스에서 이러한 "스타일 공장 방법을 작성하십시오. 다음은 두 가지 키/값 쌍에 대한 것입니다.

public final MapUtil {
    public static <K,V> Map<K,V> makeMap(K k1, V v1, K k2, V v2) {
        Map<K,V> m = new HashMap<K,V>();
        m.put(k1, v1);
        m.put(k2, v2);
        return m;
    }
}

기업 동료들이 당신과 같은 족쇄를 착용하고 있다는 지식에 대한 진실성을 받아들이고 위안을 얻으십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top