2010-02-20 2 views
7

У меня есть общий код, который я не могу понять, как законно предотвратить получение предупреждений; Я использую @SuppressWarnings («unchecked») на данный момент, так как кажется, что отличать родовой тип нельзя без предупреждений.Предупреждения в Java при отливке на общий тип

Как я могу избавиться от аннотации?

Что у меня есть:

public MyObject(SharedContext<Object> ctx) { 
    super(ctx); // set protected field 'context' 
    ... 
    context.set("Input Fields" ,Collections.synchronizedMap(new TreeMap<String,Pair<String,Boolean>>(String.CASE_INSENSITIVE_ORDER))); 
    context.set("Output Fields" ,Collections.synchronizedMap(new TreeMap<String,String>    (String.CASE_INSENSITIVE_ORDER))); 
    context.set("Event Registry",new EventRegistry(log)                    ); 
    } 

@SuppressWarnings("unchecked") 
protected void startup() { 
    inputFields  =(Map<String,Pair<String,Boolean>>)context.get("Input Fields" ,null); 
    outputFields =(Map<String,String>    )context.get("Output Fields" ,null); 
    eventRegistry =(EventRegistry     )context.get("Event Registry",null); 
    ... 
    } 

Защищенная переменная контекст типа SharedContext<Object>.

Без аннотаций компилятор дает предупреждение:

...\MyClass.java:94: warning: [unchecked] unchecked cast 
found : java.lang.Object 
required: java.util.Map<java.lang.String,com.mycompany.Pair<java.lang.String,java.lang.Boolean>> 
    inputFields  =(Map<String,Pair<String,Boolean>>)context.get("Input Fields" ,null); 
                   ^
...\MyClass.java:95: warning: [unchecked] unchecked cast 
found : java.lang.Object 
required: java.util.Map<java.lang.String,java.lang.String> 
    outputFields =(Map<String,String>    )context.get("Output Fields" ,null); 

ответ

4

После некоторых дальнейших исследований я считаю, что я нашел разумную альтернативу, которая, по крайней мере ограничивает подавление аннотацию только один глобальный статический метод утилита, чтобы сделать неконтролируемый бросок.

самодостаточными тестовая программа, которая следует должна быть достаточно ясно:

public class Generics 
{ 

static public void main(String[] args) { 
    Generics.test(); 
    } 

static private void test() { 
    Map<String,Object> ctx=new TreeMap<String,Object>(); 
    Map<String,Object> map=new TreeMap<String,Object>(); 
    Map<String,Object> tst; 

    ctx.put("Test",map); 
    tst=uncheckedCast(ctx.get("Test")); 
    } 

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

} 

Другой блог предложил усовершенствование этого метода полезности:

@SuppressWarnings("unchecked") 
public static <T, X extends T> X uncheckedCast(T o) { 
    return (X) o; 
    } 

принуждая, что возвращается, чтобы быть подклассом параметр принят.

Предполагая, что я поставил uncheckedCast в общедоступный класс GenUtil, мой метод запуска в вопросе не будет иметь (бесполезных) предупреждений emi tted и выглядят так:

protected void startup() { 
    inputFields =GenUtil.uncheckedCast(context.get("Input Fields" ,null)); 
    outputFields =GenUtil.uncheckedCast(context.get("Output Fields" ,null)); 
    eventRegistry=GenUtil.uncheckedCast(context.get("Event Registry",null)); 
    ... 
    } 
+3

Лично я считаю, что «GenUtil.uncheckedCast» хуже зла, чем пресекать конкретное предупреждение: нет никакой гарантии, что этот метод утилиты используется ответственно, то есть таким образом, чтобы это не вызывало загрязнение кучи, но программисты больше не запрашивают с предупреждением о попытке более надежной реализации. (Который иногда, хотя и не всегда, возможен ...) – meriton

+1

Я не согласен - любой актер по сути информирует компилятор: «Я знаю, что это за тип, а вы этого не делаете, так что выходите из моего пути и принимаем мои слово для этого ». Предупреждение, испущенное в этом обстоятельстве, просто не должно быть там - это похоже на компилятор, говорящий: «Я знаю, что не знаю, но я не уверен, что вы тоже». –

+2

Компилятор не принимает ваше слово, он испускает проверку времени выполнения. Приведение может быть (и иногда используется) как утверждение о типе объекта. Предупреждение сообщает вам, что эта проверка неполна и, следовательно, нельзя полагаться. – meriton

0

Как это context переменное существо присвоенного? Это от параметра ctx, который имеет тип:

SharedContext<Object> 

?

Если это так, то это ваша проблема, потому что, когда вы делаете это, вы не набрали то, что получаете.

+0

Да это. Я не могу ввести то, что я получаю за Object, потому что каждая запись в контексте обязательно имеет другой тип. –

+0

Есть ли общий общий тип для всех из них? –

+0

Если нет, попробуйте пройти в SharedContext ctx –

0

Какую версию компилятора вы используете? С Java-компилятором (окна Sun JDK) я не видел подробного предупреждения. Я получаю предупреждающую информацию только тогда, когда я использую флаг «-Xlint: unchecked».

Try -Xlint: -ссмотрел и сообщите нам, если он разрешит вашу проблему. Более подробной информации о флагах,

http://java.sun.com/javase/6/docs/technotes/tools/windows/javac.html

+0

Да, я использую -Xlint: unchecked - Я хочу видеть такие предупреждения. То, что я хочу здесь, заключается не только в том, чтобы отключить его, отключив (я могу сделать это с помощью аннотации), а чтобы убрать его, правильно указав мое намерение компилятору. –

1

Это объект SharedContext, который вы написали? Если да, возможно ли заменить общее сопоставление String-> Object на определенные поля?

например.

context.setInputFields(...) 
context.setOutputFields(...) 
context.setEventRegistry(...) 
context.getInputFields() 
etc. 

Общий объект контекстного объекта всегда кажется мне менее совершенным. Особенно это касается дженериков и непроверенных литых сообщений.

В качестве альтернативы вы можете создать объект-оболочку с именем SoftwareMonkeyContext, который имеет определенные методы setter/getter, как указано выше, и внутренне использует ваш метод GenUtil.uncheckedCast. Это помешает вам использовать GenUtil.uncheckedCast в нескольких местах вашего кода.

1

Первый бесконтрольно литой может быть устранен путем определения, не универсальный класса, который расширяет общий Map<String, Pair<String, Boolean>> и хранение, что в SharedContext вместо родовой TreeMap, например, (С использованием ForwardingMap из Guava):

class InputFieldMap extends ForwardingMap<String,Pair<String,Boolean>> { 

    private final Map<String,Pair<String,Boolean>> delegate = 
     Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); 
    protected Map<String,Pair<String,Boolean>> delegate() { return delegate; } 

} 

// ... 

context.set("Input Fields" ,Collections.synchronizedMap(new InputFieldMap())); 

// ... 

inputFields  =(InputFieldMap)context.get("Input Fields" ,null); 
outputFields =(Map<?,?> )context.get("Output Fields" ,null); 

Вы могли бы сделать второй бросок безопасным таким же образом, или (если вы только чтение карты не изменяющее ее) использовать карту как (с параметрами подстановки) и преобразовать значение в строку с каждым поиска:

String bar = String.valueOf(outputFields.get("foo")); 

или завернуть карту:

Map<?, String> wrappedOutputFields = 
    Maps.transformValues(outputFields, Functions.toStringFunction()); 

// ... 

String bar = wrappedOutputFields.get("foo"); 
+0

Хороший ответ, и интересный. Однако, разве вы не думаете, что это несколько поражает всю цель дженериков, если мне нужно определить не общий подкласс? В конце концов, преимущество «Map » заключается в том, что я * не * должен создавать 'MapStringString extends TreeMap', чтобы создать карту String -> String. –

+1

Не совсем. Если вы хотите определить класс «MapStringString», вы все равно получите выгоду от дженериков. Попробуйте написать «MapStringString» в Java 1.4, и вы поймете, что я имею в виду. – finnw

Смежные вопросы