代码之家  ›  专栏  ›  技术社区  ›  Atmocreations

泛型:类型作为变量?

  •  3
  • Atmocreations  · 技术社区  · 16 年前

    为了能够替换特定的实现,通常需要编写

    List<AnyType> myList = new ArrayList<AnyType>();
    

    而不是

    ArrayList<AnyType> myList = new ArrayList<AnyType>();
    

    这很容易理解,通过这种方式,您可以轻松地将实现从ArrayList更改为LinkedList或任何其他类型的列表。

    public List<AnyType> getSpecificList()
    {
        return new ArrayList<AnyType>();
    }
    

    这使得之前的模式变得毫无意义。如果我现在想用LinkedList而不是ArrayList替换实现,该怎么办?需要在两个位置上进行更改。

    有可能有这样的东西吗(我知道语法是绝对不正确的)?

    public class MyClass<T>
    {
        Type myListImplementation = ArrayList;
    
        List<T> myList = new myListImplementation<T>();
    
        public List<T> getSpecificList()
        {
            return new myListImplementation<T>();
        }
    }
    

    这将允许我简单地将单词“ArrayList”更改为“LinkedList”,一切都很好。我知道这两个列表可能有不同的构造函数,这不会“按原样”工作。我并不想添加第二个类型参数来指定正在使用的列表实现。

    有没有什么干净的机制来解决这个问题^

    阿特莫创造

    9 回复  |  直到 16 年前
        1
  •  14
  •   Juha Syrjälä    16 年前

    factory pattern 而不是直接实例化特定的列表实现。然后,您只需要在工厂方法内部的一个地方更改列表实现。

    例如,您可以从以下内容开始:

     List<T> createList() {
         return new ArrayList<T>();
     } 
    
     List<T> myList1 = createList();
     List<T> myList2 = createList();
    

    List<T> createList() {
        return new LinkedList<T>();
    }
    
        2
  •  8
  •   Andrzej Doyle    16 年前

    就我理解你的问题而言,你想做的已经是可能的了(与泛型无关)。

    总是 在实际进行构造函数调用时,需要给出列表(或任何类)的确切类型,这是不可避免的。同样,您可以在其他任何地方避免细节(将其存储在变量中、从方法返回、将其作为方法参数传递等)。在您的情况下,您已经这样做了-通过声明 myList

    我想你的问题可能是因为你在同一个类中创建了两个不同的列表(但都是同一类型的),你想把它抽象出来。使用工厂类型模式可以很容易地做到这一点;或者是一个单独的工厂,或者在您的情况下,只是更换 迈利斯特 声明

    List<T> myList = getSpecificList();
    

    编辑-出于兴趣,最接近您最初建议的修复方法是使用反射:

    public class MyClass<T>
    {
        Class<? extends List<T>> myListClass = ArrayList.class;
    
        List<T> myList = myListClass.newInstance();
    
        public List<T> getSpecificList()
        {
            return myListClass.newInstance();
        }
    }
    

    双重编辑:哦,你必须处理一大堆基于反射的检查异常,我把它们作为练习留给读者,以防你受到诱惑。;-)

        3
  •  5
  •   Keith Randall    16 年前

    如果我现在想替换 而不是ArrayList?是的 需要在两点钟换 位置。

        4
  •  3
  •   Daniel Pryden    16 年前

    这实际上与泛型无关,而是与 polymorphism

    使用的意义 List (或 List<T> ArrayList (或 ArrayList<T> )是吗 是一个 界面 虽然 这是一个具体的实施。接口很好,您应该使用它们,但它们实际上与泛型没有直接关系。

    在您的示例中,为什么需要将 列表 变量?如果你真的想抽象出对象的创建,你应该使用工厂方法,就像你现在做的那样。

    一般来说,多态性的一般目的和接口的具体目的是 客户 数据对象的(“使用者”)不需要知道实现细节。然而,代码 创造 (“products”)您的对象应该能够知道实现细节(因为它正在填充对象)。因此,让对象创建代码知道它正在创建 ArrayList 或者 LinkedList 或者别的什么。

        5
  •  0
  •   Brad Cupit Regan    16 年前

    实例化“参数化”列表实现的唯一方法是通过反射,但您肯定迈出了正确的第一步,返回列表接口而不是复杂的类。一些可行的想法:

    1. 编写一个私有方法,比如newList(),它只返回一个空列表实现。在整个类中使用此方法,然后如果要将其从ArrayList更改为LinkedList,只需更改newList()方法的实现即可。这类似于getSpecificList()方法
    2. 公共MyClass(Class<?扩展列表<T>){…}

    然而,Idea#2需要反射来实例化列表实现,这可能不是您想要的。

        6
  •  0
  •   Alex Feinman    16 年前

    如果列表中的“数组”或“链接”部分对您的实现很重要,那么就公开它。如果它不重要,那就不要。

    能够 具有如下界面:

     ArrayList<T> createArrayList();
    

    如果出于某种原因,清单的实施非常重要。返回“List”是一种很好的做法,因为您需要的只是List本身,在这种情况下,实现就不那么重要了。

        7
  •  0
  •   Konrad Rudolph    16 年前

    他们走这条路 理解您的问题(尽管我可能弄错了;您的问题不是很清楚),您只是在搜索一个泛型方法的正确语法,该方法如下所示:

    public <T> List<T> getSpecificList()
    {
        return new ArrayList<T>();
    }
    

    注意前面的 <T> . 现在,如果要更改列表的类型,则此更改仅限于一个位置。

        8
  •  0
  •   CJS    16 年前

    如果不初始化myList,则只需在一个位置进行更改。当然,除非您需要使用ArrayList特有的任何方法。。。

    List<AnyType> myList = getSpecicList();
    
    public List<AnyType> getSpecificList()
    {
        return new ArrayList<AnyType>();
    }
    
        9
  •  0
  •   recursive    16 年前

    public class MyClass<T>
    {
        List<T> myList = this.getSpecificList();
    
        public List<T> getSpecificList()
        {
            return new ArrayList<T>();
        }
    }
    

    现在您只需在一个位置更改类型。