2017-05-30 92 views
2

我有幾個unchecked警告,我想壓制,但上來看,我仍然看到這條消息:爲什麼選中警告

Note: Some input files use unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 

我使用的是以下類型的註釋,並確實的警告信息在IDE源代碼中消失。

@Override @SuppressWarnings("unchecked") 
public GroundBase<J> getGround() { 
    return ground; 
} 

我將代碼作爲公共API分發,我想知道用戶在使用過程中是否也會看到該消息。

我正在測試我的代碼junit。 我正在使用Java 8和intelliJ 2016.3.6。

我已閱讀-Xlint:unchecked建議的詳細信息。代碼中沒有更多未註釋的部分,但編譯器建議仍不會消失(或減少)。

編輯

更好地情境我收到警告,在這裏的簡化,但仍然相關,部分代碼之一:

abstract public class MORBase<J extends OWLObject> 
    implements Descriptor<OWLReferences,J>, MORGround<J> 

    @Override @SuppressWarnings("unchecked") 
    public GroundBase<J> getGround() { 
     return ground; 
    } 
} 

interface Ground<O,J>{ 
    Ground<J> getGround(); 
} 

interface Descriptor<O,J> { 
    <I extends Ground<O,J>> I getGround(); 
} 

這裏關於它的完整信息:

warning: [unchecked] getGround() in MORBase implements <I>getGround() in Descriptor 
public GroundBase<J> getGround() { 
        ^
return type requires unchecked conversion from GroundBase<J#1> to I 
where J#1,I,O,J#2 are type-variables: 
    J#1 extends OWLObject declared in class MORBase 
    I extends Ground<O,J#2> declared in method <I>getGround() 
    O extends Object declared in interface Descriptor 
    J#2 extends Object declared in interface Descriptor 

我很欣賞界面設計的建議,但我的問題是關於爲什麼警告沒有得到suppres SED。

+4

您是否嘗試使用'-Xlint:unchecked'編譯?也許導致警告的代碼與您壓制的代碼不同。 – Radiodef

+7

爲什麼要壓制這些警告而不是修復它們?您是否在評論這些抑制因素,以及爲什麼他們被認爲是安全的強制轉換,正如在_Effective Java_一書中推薦的那樣?他們實際上是否被認爲是安全的演員?你的例子沒有顯示任何未經檢查的強制轉換,更不用說回答這些問題。 –

+0

我發佈的代碼只是一個例子。我的實際方法使用泛型並且更復雜,但這不是我的問題的主要觀點。 – user2497897

回答

1

你的問題實際上在於getGround()Descriptor的定義。類型變量IgetGround()的聲明中是免費的,這意味着您的方法有希望返回無論什麼類型的調用者選擇!返回I類型值的唯一方法是以某種方式顛覆類型系統(例如通過拋出異常或返回null)。

編譯器能夠正確檢測I呼叫者的使用getGround()可能是不同的類型中的getGround()MORBase實施J,但是編譯器不能發出任何字節碼檢查類型(因爲你'正在編譯MORBase,但字節碼需要插入到調用者getGround())。由於它無法檢查類型,也無法插入代碼來檢查類型,所以它會正確地發出未經檢查的警告。

通過將@SuppressWarnings註釋附加到Descriptor界面的getGround()聲明中,可能實際上可能會抑制此警告,但您確實不應這樣做。相反,修復你的代碼。

我推薦的解決將是簡單地丟棄在getGround()聲明的類型變量I,並依靠亞型多態性,讓你簡單地聲明getGround()爲返回Ground<O, J>

interface Descriptor<O,J> { 
    Ground<O,J> getGround(); 
} 

如果這是不可能的,並且您需要能夠返回子類型爲Descriptor的子類型Ground,則需要將類型參數添加到Descriptor以確保類型被正確傳播給呼叫者:

interface Descriptor<O, J, G extends Ground<O, J>> { 
    G getGround(); 
} 

需要注意的是,即使指定了Descriptor接口上的getGround()方法只是返回Ground<O, J>,它仍然可能的Descriptor亞型專門返回一個更具體亞型的方法。例如,這是完全合法的(安全):

interface Descriptor<O, J> { 
    Ground<O, J> getGround(); 
} 

public final class FooDescriptor<O, J> implements Descriptor<O, J> { 
    @Override 
    public FooGround<O, J> getGround() { 
     ... 
    } 
} 

如果要強制執行FooDescriptorFooGround之間的一些關係的問題只出現。這將需要系統,Java沒有的系統或Java類型系統不支持的更高類型的約束。因此,如果您確實需要FooDescriptorFooGround之間的關係,則需要添加其他類型參數以將其關聯。但是,如果你不嚴格需要它們之間的關係,不要通過嘗試對其進行編碼來使你的類型複雜化。

請注意,此問題通常被稱爲「並行繼承層次結構」問題,並且在SoftwareEngineering.SE上存在大量關於它的現有問題,如this one

+0

當你說要修復代碼時,你是否打算讓開發人員不設計'Ground',它不會與特定的'Description'一起工作?這是不可能的,因爲相同的泛型參數被其他方法咀嚼。我知道該參數應該傳播,但認爲這是一個非常簡化的我的代碼外推,如果我傳播所有參數變得不可讀。除此之外,這是外部用戶永遠不會看到的API中非常隱蔽的部分。 – user2497897

+0

順便說一句,在'Description'接口中''getGround()'方法添加註釋不會抑制警告。 – user2497897

+0

@ user2497897:查看我更新的答案。您可以使用並行的'FooDescriptor'和'FooGround'類,而不需要錯誤的類型參數。如你所示,你的Descriptor接口上的類型參數肯定是不正確的,因爲它不受任何限制。 –