2014-10-16 140 views
1

我希望能夠在運行時設置我想實例化哪種類型的項目。下面是我想要做的一個簡單的例子,因爲這個功能並不是我的問題中最相關的部分(如果你輸入Administrable的子類,它已經可以正常工作)。下面Java泛型:明確檢查原始類型

public class Role { 
    private Class<? extends Administrable> admin; 

    public Class<? extends Administrable> getAdmin() { 
     return admin; 
    } 

    public void setAdmin(Class<? extends Administrable> admin) { 
     this.admin = admin; 
    } 

    public Administrable getAdministrable() throws InstantiationException, IllegalAccessException { 
     return admin.newInstance(); 
    } 
} 

我試圖讓測試失敗,並ClassCastException(或任何其他Exception,真的),但我是雙重驚訝的是,我的測試代碼編譯,並沒有拋出任何RuntimeException運行。

public class RoleTest { 

    // this works already 
    @Test 
    public void testAdmin() { 
     // Site is a subclass of Administrable 
     Class<? extends Administrable> clazz = Site.class; 
     role.setAdmin(clazz); 
     assertEquals(clazz, role.getAdmin()); 
    } 

    // this works already 
    @Test 
    public void testAdminNull() { 
     role.setAdmin(null); 
     assertNull(role.getAdmin()); 
    } 

    // this test succeeds, i.e. it does not throw any exception 
    @Test(expectedExceptions = RuntimeException.class) // using TestNG 
    public void testAdminIllegal() { 
     Class clazz = String.class; 
     // I thought that this wouldn't even compile 
     role.setAdmin(clazz); 
     // But the strangest thing is that it seems to work at runtime, too ! 
     assertEquals(clazz, role.getAdmin()); 
    } 
} 

這意味着我沒有明確檢查一個原始類型的setter,我真的很想在那裏。有沒有可能實施這項檢查,如果是的話,如何?我已經嘗試了一些反射技術,以查看clazz是否爲ParameterizedType,並進行了投射等,但似乎沒有任何工作能夠滿足。

+1

您正在使用原始類型。它不會用'class clazz = String.class;'進行編譯。您的編譯器應該發出警告,雖然... – assylias 2014-10-16 21:32:09

+1

泛型提供*編譯*時間類型安全。在運行時,所有類型都是有效的。 – Bohemian 2014-10-16 21:58:44

回答

2

傳遞原始類型Class

Class clazz = String.class; 
// I thought that this wouldn't even compile 
role.setAdmin(clazz); 

慣於拋出任何異常,但您使用的是未經檢查的類型你的編譯器會發出警告。如果你真的給了一個泛型類Class<?>,它不會編譯。

要檢查作爲參數傳遞的類型,改變你的方法如下:

public void setAdmin(Class<? extends Administrable> admin) { 
    if (admin != null && !Administrable.class.isAssignableFrom(admin)) { 
     throw new IllegalArgumentException("The parameter " + admin.getName() + " should be administrable."); 
    } 
    this.admin = admin; 
} 

或者,如果你想使你的測試失敗(無校驗),從Administrable上的管理實例調用一個方法:

class Administrable { 
    public void test(){} 
} 

public void testAdminIllegal() throws IllegalAccessException, InstantiationException { 
    Class clazz = String.class; 
    // I thought that this wouldn't even compile 
    role.setAdmin(clazz); 

    role.getAdministrable().test(); 
} 
+1

優秀的,改編的setAdmin()做到了。 – blagae 2014-10-17 00:11:47