2014-10-16 138 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