programing

체크되지 않은 캐스팅 경고에 대처하려면 어떻게 해야 합니까?

prostudy 2022. 6. 4. 08:09
반응형

체크되지 않은 캐스팅 경고에 대처하려면 어떻게 해야 합니까?

이클립스는 다음과 같은 형태로 경고합니다.

형식 안전:개체에서 HashMap으로 선택 취소된 캐스트

이것은 가 오브젝트를 반환하는 제어가 불가능한 API 호출입니다.

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}

이클립스 경고는 이론적으로 최소한 코드 문제가 있음을 나타내므로 가능하면 피하고 싶습니다.하지만 아직 이걸 없앨 좋은 방법을 찾지 못했어요.하여 메서드에 추가할 수 .@SuppressWarnings("unchecked")따라서 경고를 무시한 코드 블록의 영향을 제한할 수 있습니다.더더 방법 ?? ???이클립스에서 이 경고들을 끄고 싶지 않아

코드에 접근하기 전에는 더 간단했지만 여전히 경고를 불러일으켰습니다.

HashMap getItems(javax.servlet.http.HttpSession session) {
  HashMap theHash = (HashMap)session.getAttribute("attributeKey");
  return theHash;
}

해시를 사용하려고 하면 다른 곳에 문제가 발생하여 경고가 표시되었습니다.

HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap.  References to generic type HashMap<K,V> should be parameterized.

물론 확실한 답은 체크되지 않은 캐스팅을 하지 않는 것이다.

'의 ', '의 범위'를.@SuppressWarnings주석입니다.Javadocs에 따르면 로컬 변수를 사용할 수 있습니다. 이렇게 하면 전체 메서드에 영향을 주지 않습니다.

예:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

이 문제가 발생할지 여부를 판단할 방법은 없습니다.Map 합니다.<String, String> 있어야 않으면 어떤 파라미터가 알 수 ClassCastException이 때문에, 이 코드는 경고를 생성합니다.이는 컴파일러가 가 안전한지 여부를 알 수 없기 때문입니다.

안타깝게도 여기에는 좋은 선택지가 없습니다.이 모든 것의 목적은 타입의 안전을 유지하는 것입니다."Java Generics"는 일반화되지 않은 레거시 라이브러리를 처리하기 위한 솔루션을 제공하며, 특히 섹션 8.2에 "empty loop technology"라고 불리는 솔루션이 있습니다.기본적으로 안전하지 않은 캐스팅을 하고 경고를 억제합니다.그런 다음 다음과 같이 맵을 루프합니다.

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

치 않은 " 됩니다."ClassCastException하지만 적어도 문제의 근원 근처에서는 발생할 수 있습니다.

와, 내 질문에 대한 답을 찾은 것 같아.그럴 가치가 있는지 모르겠어! :)

문제는 출연진이 체크되지 않았다는 것이다.그래서 직접 확인해야 합니다.매개 변수화된 유형 정보는 컴파일 시 지워져 런타임에 사용할 수 없기 때문에 instance of를 사용하여 매개 변수화된 유형만 확인할 수 없습니다.

단, 해시 내의 각 항목과 인스턴스를 체크하여 안전한 새로운 해시를 작성할 수 있습니다.그리고 당신은 어떠한 경고도 유발하지 않을 것이다.

myers와 Esko Luontola 덕분에 원래 여기에 썼던 코드를 파라미터화했습니다.그래서 어딘가에 있는 유틸리티 클래스로 정리하여 파라미터화된 해시맵에 사용할 수 있습니다.제네릭스에 대해 잘 모르기 때문에 더 잘 알고 싶다면 이 답변의 편집 내역을 보는 것이 좋습니다.

public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

일이 많군요, 아마 아주 적은 보수를 받고...쓸지 안 쓸지 모르겠어요.사람들이 그것이 가치가 있다고 생각하는지 아닌지 어떤 의견이라도 주시면 감사하겠습니다.또한 개선안을 제안해 주시면 감사하겠습니다.AssertionErrors를 던지는 것 외에 제가 할 수 있는 더 좋은 방법이 있을까요?내가 더 잘 던질 수 있는 게 있을까?[예외(Exception)]체크박스를 켜야 하나요?

Preferences에서 -> ->/-> 하여 Eclipse Preferences 서서 - Java -> Compiler -> Errors / Warnings -> Generic Type을 합니다.Ignore unavoidable generic type problems체크 박스

이는 질문의 의도를 충족시킵니다.

이클립스 경고는 피하고 싶은데...

그 정신은 아니더라도.

다음과 같은 유틸리티 클래스를 만들고 이를 사용하여 선택 취소된 경고를 억제할 수 있습니다.

public class Objects {

    /**
     * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }
}

다음과 같이 사용할 수 있습니다.

import static Objects.uncheckedCast;
...

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
      return uncheckedCast(session.getAttribute("attributeKey"));
}

자세한 내용은 http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html 를 참조해 주세요.

어려운 일이지만, 제 현재 생각은 다음과 같습니다.

API가 오브젝트를 반환하면 할 수 있는 일이 없습니다.무슨 일이 있어도 오브젝트를 무작정 캐스팅합니다.Java가 ClassCast Exceptions를 슬로우하도록 하거나 각 요소를 직접 체크하여 Assertions 또는 Inlogal Argument를 슬로우할 수 있습니다.예외 또는 그와 유사한 일부이지만 이러한 런타임 검사는 모두 동일합니다.실행 시 어떤 작업을 하든 컴파일 시간을 선택하지 않은 상태로 유지해야 합니다.

API가 무엇을 반환해야 하는지 알고 있고 API가 작동한다고 가정할 용의가 있기 때문에 블라인드 캐스트를 통해 JVM이 런타임 체크를 수행하도록 하고 싶습니다.필요하다면 깁스 위 어디에나 제네릭스를 사용하세요.아직 단일 블라인드 캐스트를 가지고 있기 때문에 실제로 구입하지 않아도 되지만, JVM이 코드의 다른 부분에서 블라인드 캐스트를 피할 수 있도록 적어도 그 이후부터는 제네릭스를 사용할 수 있습니다.

이 경우 SetAttribute에 대한 콜과 타입이 착신하고 있는 것을 확인할 수 있기 때문에, 발신시에 타입을 같은 타입에 블라인드 캐스팅 하는 것만으로 부도덕한 것은 아닙니다.SetAttribute를 참조하는 코멘트를 추가하고, 그것을 실시합니다.

다음은 다른 답변에서 언급된 두 가지 전략을 사용하여 "체크되지 않은 캐스팅" 경고를 방지하는 간략한 예입니다.

  1. 시 를 전달합니다.Class<T> inputElementClazz 다음과 같이 수 inputElementClazz.cast(anyObject);

  2. 하여 레거시코드 「」 「T」 「T」)로부터 알 수 없는 합니다.Collection<?> unknownTypeCollection은 "되지 않은 캐스팅" 싶은 입니다. "는 우리가 unchecked cast"라는 것을 확실히 알 수 없습니다. "우리는 unchecked cast"라는 것을 알 수 .Collection<T> 솔직히 '콘나'를 Collection<?>한 경우 을 계속할 수 있습니다.Collection<T> knownTypeCollection를 참조해 주세요.

아래 예에서 인터페이스된 레거시 코드는 StructuredViewer에 "input" 속성이 있습니다(StructuredViewer는 트리 또는 테이블 위젯이며 "input"은 그 배후에 있는 데이터 모델입니다).이 "입력"은 모든 종류의 Java 컬렉션일 수 있습니다.

public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
    IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
    // legacy code returns an Object from getFirstElement,
    // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
    T firstElement = inputElementClazz.cast(selection.getFirstElement());

    // legacy code returns an object from getInput, so we deal with it as a Collection<?>
    Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();

    // for some operations we do not even need a collection with known types
    unknownTypeCollection.remove(firstElement);

    // nothing prevents us from building a Collection of a known type, should we really need one
    Collection<T> knownTypeCollection = new ArrayList<T>();
    for (Object object : unknownTypeCollection) {
        T aT = inputElementClazz.cast(object);
        knownTypeCollection.add(aT);
        System.out.println(aT.getClass());
    }

    structuredViewer.refresh();
}

당연히 위의 코드는 잘못된 데이터 타입으로 레거시 코드를 사용하는 경우(예를 들어 어레이를 Java 컬렉션이 아닌 Structured Viewer의 "입력"으로 설정한 경우) 런타임 오류를 발생시킬 수 있습니다.

메서드를 호출하는 예:

dragFinishedStrategy.dragFinished(viewer, Product.class);

캐스트를수 는 이 되어 있기 입니다(HTTP Session API만 ).Object를 참조해 주세요.

약간의 작업만 하면 쉽게 체크되지 않는 배역을 피할 수 있다.은 그것이 합니다.ClassCastException되지 않은 체크되지 않은 예외있습니다.CCE(「」 「」 「」)

HashMap을 전용 클래스로 바꿉니다.

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Attributes extends AbstractMap<String, String> {
    final Map<String, String> content = new HashMap<String, String>();

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
        return content.entrySet();
    }

    @Override
    public Set<String> keySet() {
        return content.keySet();
    }

    @Override
    public Collection<String> values() {
        return content.values();
    }

    @Override
    public String put(final String key, final String value) {
        return content.put(key, value);
    }
}

그 .Map<String,String>코드를 작성한 장소에서 모든 것이 확인됩니다.치 않은 「」는 없습니다.ClassCastExceptions★★★★★★★★★★★★★★★★★★.

Android Studio에서 검사를 비활성화하려면 다음을 사용할 수 있습니다.

//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();

이 경우 맵을 HttpSession에 직접 저장하는 것이 아니라 내 클래스의 인스턴스(클래스의 구현 상세)를 포함합니다.그러면 지도의 요소가 올바른 유형인지 확인할 수 있습니다.

그러나 지도의 내용이 올바른 유형인지 확인하려면 다음과 같은 코드를 사용할 수 있습니다.

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.put("b", 2);
    Object obj = map;

    Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
    Map<String, String> error = safeCastMap(obj, String.class, String.class);
}

@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
    checkMap(map);
    checkMapContents(keyType, valueType, (Map<?, ?>) map);
    return (Map<K, V>) map;
}

private static void checkMap(Object map) {
    checkType(Map.class, map);
}

private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
    for (Map.Entry<?, ?> entry : map.entrySet()) {
        checkType(keyType, entry.getKey());
        checkType(valueType, entry.getValue());
    }
}

private static <K> void checkType(Class<K> expectedType, Object obj) {
    if (!expectedType.isInstance(obj)) {
        throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
    }
}

오브젝트위의 답변에서 Esko Luontola의 체크되지 않은 유틸리티 기능은 프로그램의 혼란을 피하는 좋은 방법입니다.

전체 메서드에서 Suppress Warnings를 사용하지 않을 경우 Java는 강제로 로컬에 배치합니다.멤버에 대한 깁스가 필요한 경우 다음과 같은 코드로 이어질 수 있습니다.

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

유틸리티를 사용하는 것이 훨씬 깔끔하고, 무엇을 하고 있는지 알 수 있습니다.

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

메모: 경고는 다음과 같은 잘못된 행동을 하고 있음을 의미할 수 있습니다.

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

컴파일러가 말하는 것은 이 캐스트는 실행 시 체크되지 않기 때문에 범용 컨테이너의 데이터에 액세스 할 때까지 런타임 에러는 발생하지 않는다는 것입니다.

경고 억제는 해결책이 아닙니다.한 문장에 두 가지 수준의 캐스팅을 하면 안 됩니다.

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

코드를 투고했을 경우는, 간단하게 추측할 수 있습니다만, 다음과 같은 조작을 했을 가능성이 있습니다.

HashMap<String, Object> test = new HashMap();

필요한 경우 경고 메시지를 생성합니다.

HashMap<String, Object> test = new HashMap<String, Object>();

볼 만한 가치가 있을지도 모른다

Java 프로그래밍 언어에서의 범용

해야 할 일에 익숙하지 않다면요.

질문을 잘못 이해했을지도 모르지만(예시와 몇 줄의 주변이 좋을지도 모릅니다만, 항상 적절한 인터페이스(및 Java5+)를 사용하는 것은 어떻습니까? 신신 a a 하고 싶어할 해.HashMapMap<KeyType,ValueType>사실 변수 유형을 다음과 같이 설정해야 할 이유를 짐작할 수 없습니다.HashMapMap.

왜 소스는 "" " " " " 입니다.Object 거시컬컬컬 렉개?? ?????이 경우 제네릭스를 사용하여 원하는 유형을 지정합니다.

Generics를 지원하지 않는 API를 사용해야 하는 경우..가능한 한 적은 회선의 래퍼 루틴으로 콜을 분리하려고 합니다.그런 다음 SuppressWarnings 주석을 사용하고 동시에 유형 안전 캐스트를 추가합니다.

이것은 가능한 한 깔끔하게 하는 개인적인 취향일 뿐입니다.

이것은 새로운 HashMap을 작성하는 것보다 훨씬 빠릅니다(이미 HashMap을 작성하는 경우). 그러나 각 요소가 해당 유형과 비교하여 확인되므로 안전합니다.

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

캐스팅하기 전에 타이프 체크만 하세요.

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  

또, 그 타입을 모르는 물건을 받는 것은 매우 일반적인 일입니다.많은 레거시 "SOA" 구현이 항상 신뢰할 수는 없는 다양한 개체를 전달합니다.(무서운!)

편집 포스터의 업데이트와 일치하도록 예제 코드를 한 번 변경했는데, 몇 가지 코멘트를 보면 해당 인스턴스가 제네릭스와 잘 어울리지 않는 것을 알 수 있습니다.그러나 외부 객체를 검증하기 위해 체크를 변경하는 것은 명령줄 컴파일러와 잘 작동하는 것 같습니다.수정된 예가 게시되었습니다.

컴퓨터 사이언스의 거의 모든 문제는 간접적인 수준*을 추가하는 것으로 해결할 수 있습니다.

이지 않은 중 하겠습니다.Map문맥이 없으면 별로 설득력이 없어 보이지만, 어쨌든:

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*간접적인 수준이 너무 많은 경우를 제외합니다.

제가 이 를 덮어쓸 때 한 이 있습니다.equals()★★★★★★ 。

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

8(「Java 8」로 된 것까지)로하는 것 .-Xlint:unchecked)

session.getAttribute()에 의해 반환된 유형이 HashMap임을 확신하는 경우 해당 유형으로 typecast할 수 없으며 일반적인 HashMap 확인에만 의존합니다.

HashMap<?,?> getItems(javax.servlet.http.HttpSession session) {  
    HashMap<?,?> theHash = (HashMap<?,?>)session.getAttribute("attributeKey");
    return theHash;
} 

그러면 Eclipse는 경고를 놀라게 하지만, 이는 디버깅하기 어려운 런타임 오류를 초래할 수 있습니다.이 접근방식을 사용하는 것은 동작 크리티컬하지 않은 컨텍스트뿐입니다.

두 가지 방법, 하나는 태그를 완전히 피하는 방법이고, 다른 하나는 장난스럽지만 좋은 사용 방법을 사용하는 방법입니다.
이치노
경험의 법칙은, 「객체를 한번에 1개씩 캐스트 한다」입니다.일반화된 세계에서 raw 클래스를 사용하려고 하면, 이 맵에 무엇이 있는지 알 수 없기 때문입니다.<?, ?>(그리고 JVM에서는 맵이 아닌 것도 알 수 있습니다!)라고 생각하면, 캐스트 할 수 없습니다.Map <String, ?> map2가 있는 경우 HashSet <String> 키= (HashSet <String>) map2.keySet()은 경고하지 않습니다.이것은 컴파일러에 대한 "신뢰의 행동"이지만 (트리셋으로 판명될 가능성이 있기 때문에)하지만 그건 단 한 의 믿음일 뿐이야

PS는 첫 번째 방법에서처럼 반복하는 것은 지루하고 시간이 걸린다라는 반대 의견에 대해 "고통 없음"으로 대답합니다.지도<String, String> 이외없없 없없다 。당신은 이 보증에 대한 비용을 지불해야 합니다.제네릭스를 체계적으로 사용할 경우, 이 지불은 기계 시간이 아닌 코딩 컴플라이언스의 형태를 취합니다!
어떤 학파에서는 경고보다는 이러한 선택되지 않은 캐스팅 오류가 발생하도록 이클립스의 설정을 설정해야 한다고 주장할 수 있습니다.그렇다면 당신은 나의 첫 번째 방법을 사용해야 할 것이다.

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }


    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }


    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }


}

이렇게 하면 경고가 사라집니다.

 static Map<String, String> getItems(HttpSession session) {
        HashMap<?, ?> theHash1 = (HashMap<String,String>)session.getAttribute("attributeKey");
        HashMap<String,String> theHash = (HashMap<String,String>)theHash1;
    return theHash;
}

솔루션:이클립스에서 이 경고를 비활성화합니다.@Suppress Warning하지 말고 완전히 비활성화하세요.

위에 제시된 몇 가지 "해결책"은 잘못된 것이며, 어리석은 경고를 억제하기 위해 코드를 읽을 수 없게 만듭니다.

언급URL : https://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings

반응형