java关于接口的一般问题

java关于接口的一般问题,java,interface,Java,Interface,考虑到我有一个将列表作为参数传递的方法。在这个方法中,我想在该列表中使用一个特定于ArrayList的函数(比如trimToSize())。处理这种问题的一般方法是什么? 这里有两个例子: 第一种方法(我认为这不好) private void doSomething(最终列表){ //…做点什么 ((ArrayList)list).trimToSize(); //…做点什么 } 第二种方法(我认为这一种更好) private void doSomething2(最终列表){ 最终列表myLis

考虑到我有一个将列表作为参数传递的方法。在这个方法中,我想在该列表中使用一个特定于ArrayList的函数(比如trimToSize())。处理这种问题的一般方法是什么? 这里有两个例子:
第一种方法(我认为这不好)

private void doSomething(最终列表){
//…做点什么
((ArrayList)list).trimToSize();
//…做点什么
}
第二种方法(我认为这一种更好)

private void doSomething2(最终列表){
最终列表myList=新的ArrayList();
//收藏。复制(myList,list);或
myList.addAll(列表);
((ArrayList)myList).trimToSize();
//做点什么
}

我很好奇,对于这样的问题,什么是最好的解决方案。

为什么不将方法声明为
私有void doSomething(最终ArrayList列表)
,如果您只想将ArrayList作为参数?

好吧,首选的方法是首先编写方法以获取
ArrayList
。如果您需要
ArrayList
特定的功能,则该方法不需要获取
列表
。将确保参数是正确类型的责任转移给调用者,不要在方法中随意处理它。

第二,我们在大列表中有巨大的开销,但更安全。我会选择第一个,但要检查提供的列表是否为ArrayList,然后进行一次转换


但是,您应该有充分的理由不将ArrayList作为参数。

如果您接受实现列表接口的任何对象,那么您的函数应该只调用从接口实现的方法


若要从ArrayList类调用函数,则将ArrayList作为参数。比您的任何一个选项都安全。

您显示的第一个选项仅适用于
阵列列表
,因此如果您想支持任何类型的
列表
,它都不是一个选项。如果要支持任何类型的
列表
,必须将其转换(而不是强制转换)为
数组列表

我认为可能会有一些混淆,因为
列表
数组列表
是如此紧密地联系在一起(通过继承)。这只是巧合,参数类型和我们需要调用函数的类是以这种方式关联的

如果我们稍微抽象一下需求:

  • 我们需要根据一系列的价值观采取行动
  • 我们需要在上使用trimToSize() 一系列的值
  • 如果值是以数组形式出现的,那么毫无疑问,只能使用数组中的值创建一个新的
    ArrayList
    ,然后使用trimToSize(),因为强制转换不是一个选项。不幸的是,我们需要的trimToSize()方法恰好位于
    List
    的子类上,而作者希望将值作为
    列表进行传递

    private void doSomething(final List<T> list) {
        final ArrayList<T> arrayList;
        if (list instanceof ArrayList) {
            arrayList = (ArrayList<T>) list;
        } else {
            arrayList = new ArrayList<T>(list);
        }
                ...
        arrayList.trimToSize();
    }
    
    private void doSomething(最终列表){
    最终ArrayList ArrayList;
    if(列出ArrayList的实例){
    arrayList=(arrayList)列表;
    }否则{
    arrayList=新的arrayList(列表);
    }
    ...
    arrayList.trimToSize();
    }
    

    当然,我同意Chinmay Kanchi的观点:对于私有方法来说,接受比必要的更通用的类型是没有意义的。我的方法只有在修改给定列表没有问题的情况下才可行。

    您的第一个方法更改传递给该方法的
    列表,而另一个方法不更改。这两种方法不具有可比性

    因为它是一个私有方法,所以使用列表接口的约定并不太重要。没有受影响的公共API,因此请在类中使用最方便的方法


    例如,如果其他5个方法使用可能不同的列表类型调用此方法,则使用第二个选项并将转换集中在1个方法中(如果愿意,甚至可以检查类型而不转换)。如果您的类只在内部处理ArrayList,并且您知道它在被调用时会是什么样子,那么请将其声明为ArrayList,让您的生活变得轻松。

    为什么要将其作为最终类传递?这应该会导致错误。将参数标记为final只意味着您不能重复使用该变量,即为其指定一个新值。您仍然可以使用和修改(通过方法调用等)该值。@MadMurf不客气。我得到这条信息的方式和你刚才得到的一样:你为什么要叫trimToSize?如果传入的对象没有trimToSize方法怎么办?对于C开发人员来说,最好将final在这里看作是“int*const foo”,而不是“int*const*foo”。您不能更改指针指向的对象,但可以修改指针的目标。请看,他希望能够接受
    列表
    作为参数,但出于不同的原因(特定于实现)@David,他需要方法体中的
    ArrayList
    ,那么,如果该方法需要
    数组列表
    ,那么它接受
    列表
    是没有意义的。mattb:我的意思是,在API级别,他希望该方法能够接受任何
    列表
    。在当前的实现中,他选择了使用
    ArrayList
    的逻辑。API不应该与实现绑定,因为实现应该可以自由更改。一种类型继承另一种类型只是一种巧合,这造成了混乱。从逻辑上讲,这两个列表(
    List
    ArrayList
    )是分开的,恰好包含相同的条目。如果他希望它接受任何列表,那么他应该在传入对象的函数中内部调用的唯一方法是那些在列表接口中定义的方法。否则,当一个非ArrayList对象被传递时,他就容易出错。它甚至做了一个演员。你只是在制造一场灾难
    private void doSomething2(final List<T> list) {
    final List<T> myList = new ArrayList<T>();
    // Collections.copy(myList, list); or
    myList.addAll(list);
    ((ArrayList<T>) myList).trimToSize();
    //..do something
    }
    
    private void doSomething(final List<T> list) {
        final ArrayList<T> arrayList;
        if (list instanceof ArrayList) {
            arrayList = (ArrayList<T>) list;
        } else {
            arrayList = new ArrayList<T>(list);
        }
                ...
        arrayList.trimToSize();
    }