Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java类型安全映射-是否可以对这两种泛型类型进行类型检查?_Java_Generics_Dto_Typesafe_Nested Generics - Fatal编程技术网

Java类型安全映射-是否可以对这两种泛型类型进行类型检查?

Java类型安全映射-是否可以对这两种泛型类型进行类型检查?,java,generics,dto,typesafe,nested-generics,Java,Generics,Dto,Typesafe,Nested Generics,我正在为从POJO转换到POJO的类型安全映射创建一个库,根据键保存数据,以提供类型安全。键不是任意的,而是像enum一样的固定常量。我已经检查了,但没有检查下面提到的2个条件的解决方案 我有两门课Map和Key。Map有get方法,该方法返回给定键的值。有两个条件: A:键应与映射的泛型类型匹配 B:get应返回匹配键的泛型类型的值 我希望在编译时检查这两个条件。我不想传递多余的类或类型参数 class Map<K extends Key<?>{ <T>

我正在为从POJO转换到POJO的类型安全映射创建一个库,根据键保存数据,以提供类型安全。键不是任意的,而是像enum一样的固定常量。我已经检查了,但没有检查下面提到的2个条件的解决方案

我有两门课
Map
Key
。Map有
get
方法,该方法返回给定键的值。有两个条件:

  • A
    应与
    映射
    的泛型类型匹配
  • B
    get
    应返回匹配
    键的泛型类型的值
我希望在编译时检查这两个条件。我不想传递多余的类或类型参数

class Map<K extends Key<?>{
    <T> T get1(K key) {...} //My first attempt: Solves A(checks key type) but not B(return type T)
    <T> T get2(Key<T> key) {...} //Another attempt: Solves B(checks return type T) but not A(key type)

    // I want to write method get, which checks both conditions something like this:
    <T,K1 extends K & Key<T>> T get(K1 key){...}//Won't compile ofcourse
}
interface/*or abstract class*/ Key<T>{
  //We could use enum instead of subclassing Key, but java enum constants are not generic. See: http://openjdk.java.net/jeps/301
}
迄今为止的解决办法: 我找到了一个解决方案,但它很笨拙,并在客户端生成原始类型警告:让Key有两个类型T和ActualKey

class Map<K extends Key<?,?>>{
    <T> T get(Key<T, K> key) {...}
}
class Key<T,ActualKey extends Key<?,?>> {...}
//Client Code
class PersonKey<T> extends Key<T,PersonKey> {//raw-type warning
    PersonKey<String> name=new PersonKey<>();
    PersonKey<Integer> age=new PersonKey<>();
}
class HouseKey<T> extends Key<T,HouseKey>{//raw-type warning
    HouseKey<String> name=new HouseKey<>();
    HouseKey<String> address=new HouseKey<>();
}
//Usage:
Map<PersonKey> person=new Map<>();//raw-type warning
String name=person.get(PersonKey.name);//Intended use
Integer age=person.get(PersonKey.age);//Intended use
String name=person.get(HouseKey.name);//A: Successfully generates compile error: Arg must be PersonKey, not HouseKey
Integer age=person.get(PersonKey.name);//B: Successfully generates compile error: must return String, not Integer
类映射>{…}
//客户端代码
类PersonKey扩展键{//raw type警告
PersonKey name=新PersonKey();
PersonKey年龄=新PersonKey();
}
类HouseKey扩展键{//原始类型警告
房屋钥匙名称=新房屋钥匙();
房屋钥匙地址=新房屋钥匙();
}
//用法:
Map person=new Map()//原始类型警告
字符串名称=person.get(PersonKey.name)//预期用途
整数age=person.get(PersonKey.age)//预期用途
字符串名称=person.get(HouseKey.name)//A:成功生成编译错误:Arg必须是PersonKey,而不是HouseKey
整数age=person.get(PersonKey.name)//B:成功生成编译错误:必须返回字符串,而不是整数
似乎无法删除客户端代码中的此原始类型警告。

编辑:

我删除了答案之前的内容,因为答案是错误的

我找到了一个可以满足您需求的解决方案,它是完全类型安全的,避免了原始类型,但会生成更复杂的密钥声明。地图的使用将根据您的需要变得简单

首先,定义两个不同的关键接口: 第一个声明接受的泛型类型不是键值的类型,而是键本身的类型

public interface Key<T extends Key<T>> {

}
公共接口密钥{
}
第二个声明定义了一个类型为的键:

public interface TypedKey<T, K extends Key<K>> extends Key<K> {

}
公共接口类型扩展键{
}
现在我们可以这样定义地图:

public class Map<K extends Key<K>> {

    <T, K1 extends TypedKey<T, K>> T get(K1 key) {
        return null; // TODO implementation
    }

}
public class PersonKeyWrapper {

    public static class PersonKey implements Key<PersonKey> {
        private PersonKey() {}
    }

    public static class PersonTypedKey<T> extends PersonKey implements TypedKey<T, PersonTypedKey<T>> {

    }

}

public class HouseKeyWrapper {

    public static class HouseKey implements Key<HouseKey> {
        private HouseKey() {}
    }

    public static class HouseTypedKey<T> extends HouseKey implements TypedKey<T, HouseTypedKey<T>> {

    }

}
公共类映射{
T get(K1键){
返回null;//TODO实现
}
}
这需要在实例化时实现Key的类型,并且每次调用get方法时都需要一个TypedKey,它与第二个泛型类型的Key相同

通过这个简单的测试类,您可以看到结果:

public class Tester {

    static final class PersonKey implements Key<PersonKey> {
        private PersonKey() {}
    }

    static final class HouseKey implements Key<HouseKey> {
        private HouseKey() {}
    }

    static final class WrongKey implements Key<PersonKey> {
        private WrongKey() {}
    }

    static class ExtendableKey implements Key<ExtendableKey> {

    }

    static class ExtensionKey extends ExtendableKey {

    }

    static class PersonTypedKey<T> implements TypedKey<T, PersonKey> {

    }

    static class HouseTypedKey<T> implements TypedKey<T, HouseKey> {

    }

    /*static class ExtensionTypedKey<T> implements TypedKey<T, ExtensionKey> { // wrong type

    }

    static class WrongTypedKey<T> implements TypedKey<T, WrongKey> { // wrong type

    }*/

    public static void main(String[] args) {
        Map<PersonKey> personMap = new Map<>();
        Map<HouseKey> houseMap = new Map<>();
        //Map<WrongKey> wrongMap = new Map<>(); // wrong type
        //Map<ExtensionKey> extMap = new Map<>(); // wrong type
        PersonTypedKey<String> name = new PersonTypedKey<>();
        PersonTypedKey<Integer> age = new PersonTypedKey<>();
        HouseTypedKey<String> houseName = new HouseTypedKey<>();
        String nameString = personMap.get(name);
        Integer ageInt = personMap.get(age);
        //String houseString = personMap.get(houseName); // wrong type
        //ageInt = personMap.get(name); wrong type
        Map<ExtendableKey> extMap = new Map<>();

        whatMayBeWrongWithThis();
    }

    static class OtherPersonTypedKey<T> implements TypedKey<T, PersonKey> {

    }

    static class ExtendedPersonTypedKey<T> extends PersonTypedKey<T> {

    }

    public static void whatMayBeWrongWithThis() {
        Map<PersonKey> map = new Map<>();
        String val1 = map.get(new OtherPersonTypedKey<String>());
        String val2 = map.get(new ExtendedPersonTypedKey<String>());
        /*
         * TypedKey inheritance can be disallowed be declaring the class final, OtherPersonTypedKey can not be disallowed
         * with those declarations
         */
    }

    // if needed you can allow Key inheritance by declaring key, typedKey and map with extends Key<? super K>
}
公共类测试器{
静态最终类PersonKey实现密钥{
私有PersonKey(){}
}
静态最终类HouseKey实现了{
私钥(){}
}
静态最终类错误键实现键{
私钥错误(){}
}
静态类ExtendableKey实现密钥{
}
静态类ExtensionKey扩展了ExtendableKey{
}
静态类PersonTypedKey实现TypedKey{
}
静态类HouseTypedKey实现了TypedKey{
}
/*静态类ExtensionTypedKey实现了TypedKey{//错误的类型
}
静态类ErrorTypedKey实现了TypedKey{//错误类型
}*/
公共静态void main(字符串[]args){
Map personMap=newmap();
Map houseMap=新地图();
//映射错误映射=新映射();//类型错误
//Map extMap=new Map();//类型错误
PersonTypedKey name=新的PersonTypedKey();
PersonTypedKey年龄=新建PersonTypedKey();
HouseTypedKey houseName=新的HouseTypedKey();
字符串nameString=personMap.get(name);
整数ageInt=personMap.get(年龄);
//String houseString=personMap.get(houseName);//类型错误
//ageInt=personMap.get(name);类型错误
Map extMap=newmap();
这有什么不对的吗;
}
静态类OtherPersonTypedKey实现TypedKey{
}
静态类ExtendedPersonTypedKey扩展PersonTypedKey{
}
public static void this()可能有什么问题{
Map Map=newmap();
String val1=map.get(新的OtherPersonTypedKey());
字符串val2=map.get(新的ExtendedPersonTypedKey());
/*
*如果声明类final,则不允许TypedKey继承,否则不允许OtherPersonTypedKey继承
*通过这些声明
*/
}

//如果需要,您可以通过声明Key、typedKey和带有extensedkeydro谢的map来允许密钥继承。但这不会编译:
map map=null;map.get1(PersonKey.name);
Error:
get1方法(KeyGreat research!这需要在客户端使用大量的锅炉板,但我想没有更好的方法了。另一个更简单的方法是使用2个参数,正如我提到的。无论如何,谢谢,我将此标记为可接受的答案。我观察到一件非常奇怪的事情。我的解决方案:
class PersonKey Extendes Key
只需警告即可编译,甚至可以执行成功剪切Eclipse编译器上的所有测试用例。但javac给出错误:
类型参数不在类型变量的范围内
public class Tester {

    static final class PersonKey implements Key<PersonKey> {
        private PersonKey() {}
    }

    static final class HouseKey implements Key<HouseKey> {
        private HouseKey() {}
    }

    static final class WrongKey implements Key<PersonKey> {
        private WrongKey() {}
    }

    static class ExtendableKey implements Key<ExtendableKey> {

    }

    static class ExtensionKey extends ExtendableKey {

    }

    static class PersonTypedKey<T> implements TypedKey<T, PersonKey> {

    }

    static class HouseTypedKey<T> implements TypedKey<T, HouseKey> {

    }

    /*static class ExtensionTypedKey<T> implements TypedKey<T, ExtensionKey> { // wrong type

    }

    static class WrongTypedKey<T> implements TypedKey<T, WrongKey> { // wrong type

    }*/

    public static void main(String[] args) {
        Map<PersonKey> personMap = new Map<>();
        Map<HouseKey> houseMap = new Map<>();
        //Map<WrongKey> wrongMap = new Map<>(); // wrong type
        //Map<ExtensionKey> extMap = new Map<>(); // wrong type
        PersonTypedKey<String> name = new PersonTypedKey<>();
        PersonTypedKey<Integer> age = new PersonTypedKey<>();
        HouseTypedKey<String> houseName = new HouseTypedKey<>();
        String nameString = personMap.get(name);
        Integer ageInt = personMap.get(age);
        //String houseString = personMap.get(houseName); // wrong type
        //ageInt = personMap.get(name); wrong type
        Map<ExtendableKey> extMap = new Map<>();

        whatMayBeWrongWithThis();
    }

    static class OtherPersonTypedKey<T> implements TypedKey<T, PersonKey> {

    }

    static class ExtendedPersonTypedKey<T> extends PersonTypedKey<T> {

    }

    public static void whatMayBeWrongWithThis() {
        Map<PersonKey> map = new Map<>();
        String val1 = map.get(new OtherPersonTypedKey<String>());
        String val2 = map.get(new ExtendedPersonTypedKey<String>());
        /*
         * TypedKey inheritance can be disallowed be declaring the class final, OtherPersonTypedKey can not be disallowed
         * with those declarations
         */
    }

    // if needed you can allow Key inheritance by declaring key, typedKey and map with extends Key<? super K>
}
public interface TypedKey<T, K extends TypedKey<T, K>> {

}

public class Map<K extends Key<K>> {

    <T, K1 extends TypedKey<T, ? extends K>> T get(K1 key) {
        return null; // TODO implementation
    }

}
public class PersonKeyWrapper {

    public static class PersonKey implements Key<PersonKey> {
        private PersonKey() {}
    }

    public static class PersonTypedKey<T> extends PersonKey implements TypedKey<T, PersonTypedKey<T>> {

    }

}

public class HouseKeyWrapper {

    public static class HouseKey implements Key<HouseKey> {
        private HouseKey() {}
    }

    public static class HouseTypedKey<T> extends HouseKey implements TypedKey<T, HouseTypedKey<T>> {

    }

}
public class Tester {

    /*static class PersonTypedKey<T> implements TypedKey<T, PersonKey> { // no more allowed

    }

    static class HouseTypedKey<T> implements TypedKey<T, HouseKey> { // no more allowed

    }*/

    public static void main(String[] args) {
        Map<PersonKey> personMap = new Map<>();
        Map<HouseKey> houseMap = new Map<>();
        PersonTypedKey<String> name = new PersonTypedKey<>();
        PersonTypedKey<Integer> age = new PersonTypedKey<>();
        HouseTypedKey<String> houseName = new HouseTypedKey<>();
        String nameString = personMap.get(name);
        Integer ageInt = personMap.get(age);
        //String houseString = personMap.get(houseName); // wrong type
        //ageInt = personMap.get(name); wrong type

        whatMayBeWrongWithThis();
    }

    /*static class OtherPersonTypedKey<T> implements TypedKey<T, PersonKey> { no more allowed

    }*/

    static class ExtendedPersonTypedKey<T> extends PersonTypedKey<T> { // allowed, you can declare PersonTypedKey final if you don't wont't to allow this

    }

    static class OtherPersonTypedKey<T> implements TypedKey<T, PersonTypedKey<T>> {

    }

    public static void whatMayBeWrongWithThis() {
        Map<PersonKey> map = new Map<>();
        String val1 = map.get(new OtherPersonTypedKey<String>());
        String val2 = map.get(new ExtendedPersonTypedKey<String>());
        /*
         * OtherPersonTypedKey can not be disallowed with this declaration of PersonTypedKey
         */
    }
}
public class PersonKeyWrapper {

    public static class PersonKey implements Key<PersonKey> {
        private PersonKey() {
        }
    }

    private static class PersonTypedKey<T> extends PersonKey implements TypedKey<T, PersonTypedKey<T>> {

    }

    public static <T> TypedKey<T, ? extends PersonKey> get() {
        return new PersonTypedKey<T>();
    }

}

public class HouseKeyWrapper {

    public static class HouseKey implements Key<HouseKey> {
        private HouseKey() {}
    }

    private static class HouseTypedKey<T> extends HouseKey implements TypedKey<T, HouseTypedKey<T>> {

    }

    public static <T> TypedKey<T, ? extends HouseKey> get() {
        return new HouseTypedKey<T>();
    }

}
public class Tester {

    public static void main(String[] args) {
        Map<PersonKey> personMap = new Map<>();
        Map<HouseKey> houseMap = new Map<>();
        TypedKey<String, ? extends PersonKey> name = PersonKeyWrapper.get();
        TypedKey<Integer, ? extends PersonKey> age = PersonKeyWrapper.get();
        TypedKey<String, ? extends HouseKey> houseName = HouseKeyWrapper.get();
        String nameString = personMap.get(name);
        Integer ageInt = personMap.get(age);
        //String houseString = personMap.get(houseName); // wrong type
        //ageInt = personMap.get(name); wrong type
    }

    /*static class ExtendedPersonTypedKey<T> extends PersonTypedKey<T> { // no more allowed

    }

    static class OtherPersonTypedKey<T> implements TypedKey<T, PersonTypedKey<T>> { // no more allowed

    }*/
}