V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
HuPu
V2EX  ›  Java

List list=new ArrayList 写法的意义是什么

  •  1
     
  •   HuPu · 118 天前 · 7093 次点击
    这是一个创建于 118 天前的主题,其中的信息可能已经有所发展或是发生改变。
    List list=new ArrayList 相比于 ArrayList list=new ArrayList 写法的意义是什么
    94 条回复    2022-04-02 14:58:39 +08:00
    golangLover
        1
    golangLover  
       118 天前 via Android   ❤️ 1
    面向接口编程
    HuPu
        2
    HuPu  
    OP
       118 天前
    有人说换成 linkedList 要改的地方少
    List list=new ArrayList 只能用 list 的功能 那我 AL=new AL 要改成 linkedList 不也是只改一处吗
    gabon
        3
    gabon  
       118 天前 via iPhone
    如果你想替换为 linkedlist 就可能不兼容了
    HuPu
        4
    HuPu  
    OP
       118 天前
    @golangLover 你好 有没有具体的例子
    chendy
        5
    chendy  
       118 天前
    局部变量无意义,成员 /全局变量用 List
    new ArrayList<String>().var 自动补全出来就完事了
    HuPu
        6
    HuPu  
    OP
       118 天前
    @gabon 只用 List 的方法 用不到 AL 的方法 为啥会不兼容
    micean
        7
    micean  
       118 天前   ❤️ 3
    少写 5 个字母
    johnj
        8
    johnj  
       118 天前   ❤️ 5
    Java 讲究面向接口编程。所有依赖的对象,都用接口去引用而非实现类。

    作为新手先记住规则,这时候你不理解很正常,缺乏背景和实际经验很难能理解好处。
    chengyiqun
        9
    chengyiqun  
       118 天前   ❤️ 1
    通常出现在一个组件的构造函数或者返回参数时注意下就行.
    构造函数或者函数形参用接口, 可以传入多种类型, return 就返回具体的类型.
    X0ray
        10
    X0ray  
       118 天前   ❤️ 1
    HuPu
        11
    HuPu  
    OP
       118 天前
    @johnj 我也不算完全新手了。。。 我大一时候就不理解 现在工作一年了还是不理解。。。
    HuPu
        12
    HuPu  
    OP
       118 天前
    @X0ray 这说的是定义返回值类型的问题 和我问的不一样啊
    Leviathann
        13
    Leviathann  
       118 天前 via iPhone
    我都用 var a = new ArrayList
    chendy
        14
    chendy  
       118 天前   ❤️ 1
    面向接口是在参数返回值这样的地方
    比如一个方法参数写死了 ArrayList ,然后 Collections.emptyList 或者 signotelList 或者 Arrays.asList 就都进不来了,写 List 就会好很多
    返回值也类似,如果声明返回 ArrayList ,那么实现就必须返回 ArrayList 用不了其他的,同样换成接口会好很多

    而局部变量本身就是具体的实现环节,不需要进一步抽象,ArrayList 就是 ArrayList ,写 List 并没有啥用
    更何况 java 里 99%都是 ArrayList ,换其他实现类明显也是为了其他实现类的特性,所以应该是用具体类型
    liuzhaowei55
        15
    liuzhaowei55  
       118 天前 via Android   ❤️ 27
    其实好多的面向接口编程,有些接口活了一辈子也不见得有第二个实现。
    X0ray
        16
    X0ray  
       118 天前
    @HuPu 是一个意思。getXXX() -----> = new xxx;
    Bromine0x23
        17
    Bromine0x23  
       118 天前
    限定只能用 List 的方法。
    只用和只能用还是有点区别的,这么写最大好处是防手滑。
    gabon
        18
    gabon  
       118 天前 via iPhone
    @HuPu 但是如果用 arraylist 没办法保证不用除 list 接口定义的方法以外的方法。
    ic2y
        20
    ic2y  
       118 天前
    代码防御; 可以让后面调用的人,只能调用接口声明的方法,而不会误调用 具体实现的某些公开方法。

    在后续,如果要切换具体的实现,只要替换 new ArrayList 即可,对调用方无感知。
    HuPu
        21
    HuPu  
    OP
       118 天前
    是不是这个意思 我从一开始 List=new AL 下面我每次用到 list 的时候都不会碰 AL 专属的方法。 如果我 AL=new AL 了 就可能不小心用了一个 AL 专属方法

    以后再改成 linkedList 就不好改了
    Leviathann
        22
    Leviathann  
       118 天前 via iPhone   ❤️ 5
    @HuPu java collection framework 作者的原话

    Does anyone actually use LinkedList? I wrote it, and I never use it.
    thinkershare
        23
    thinkershare  
       118 天前
    如果实在局部方法里面, 这样写完全没啥用, 你想怎么搞都行, 因为你要自己对这个方法负责, 除非你要显示的指明, 此处接口需要收缩, 才需要这么搞, 否则只有在 API 接口上收缩对象的对外接口才有意义!
    HuPu
        24
    HuPu  
    OP
       118 天前
    @chendy 对 参数返回值这种用 List 我可以理解 但是这种新建变量的一直不太理解
    yazinnnn
        25
    yazinnnn  
       118 天前
    这么写没意义
    HuPu
        26
    HuPu  
    OP
       118 天前
    @Bromine0x23 是不是这个意思 我从一开始 List=new AL 下面我每次用到 list 的时候都不会碰 AL 专属的方法。 如果我 AL=new AL 了 就可能不小心用了一个 AL 专属方法
    RainyH2O
        27
    RainyH2O  
       118 天前
    因为和有序可重复列表同一级别的抽象是:有序不可重复列表、无序不可 /可重复列表以及有序性、重复性组合的集合、关联数组等。
    而数组实现、链表实现这些只是上述高级抽象的低一级实现。
    用同级别的抽象描述功能可做到关注点分离。
    why1001
        28
    why1001  
       118 天前
    可以看看设计模式,有帮助于理解
    yazinnnn
        29
    yazinnnn  
       118 天前
    反正现在大家也是偏向 fp 写业务,你返回啥 list 的实现都是 list.stream().巴拉巴拉了,返回值类型也可以不关心了
    nvkou
        30
    nvkou  
       118 天前 via iPhone
    强类型就是这样的了。
    说白了是为了工程,各部之间约定接口而不关心实现。不然你实现类完工前我就不用开工了?
    强类型系统有很多限制,用接口,继承,泛型补足一定的灵活性。不然更加啰嗦
    banmuyutian
        31
    banmuyutian  
       118 天前
    需要用特定接口的时候再用第二种写法呗,10 楼里的讨论很清楚了
    Cbdy
        32
    Cbdy  
       118 天前
    var list = new ArrayList() > List list = new ArrayList() > ArrayList list = new ArrayList()

    节省了键盘寿命
    AoEiuV020CN
        33
    AoEiuV020CN  
       118 天前
    我觉得是反过来的,List list=new ArrayList 这就可以的情况,为什么你会想写 ArrayList list=new ArrayList
    whenov
        34
    whenov  
       118 天前
    @HuPu 用 List 之后,"不用 ArrayList 的方法"是由编译器保证的而不是由程序员保证的
    zxxufo008
        35
    zxxufo008  
       118 天前
    我理解的工作一年的还是 rookie
    johnj
        36
    johnj  
       118 天前   ❤️ 2
    如果你的问题只是针对 List 这个类型,那回答就是这是无脑,最佳实践。

    放大到所有类(接口),面向接口编程,一个明显的好处是方便依赖注入。注入的时候,可以替换接口的任何实现类。这样你的代码依赖的就是接口而不是具体实现。
    leonme
        37
    leonme  
       118 天前 via iPhone
    @HuPu 先工作 10 年再说🐶
    kaedea
        38
    kaedea  
       118 天前 via Android
    Dependency Reverse
    zhangchongjie
        39
    zhangchongjie  
       118 天前
    把多态看看吧
    Vegetable
        40
    Vegetable  
       118 天前
    都说的很有道理,建议你用 var
    winterbells
        41
    winterbells  
       118 天前
    kotlin 的 Arraylist 和 Java 的 Arraylist 是同一个东西,但包不同。导入了 java.util.* 就是 Java 的,没有就是 kotlin.collections 的。
    上次看到这个报错惊了..
    Rocketer
        42
    Rocketer  
       118 天前 via iPhone
    可能你还没遇到合适的场景。

    一般来讲,定义属性和方法的参数类型时都会尽量选择较高层的类 /接口,以方便调用方。

    但如果只是个局部变量,比如创建一个 list 然后作为参数传给上面提到的那种属性或方法,那怎么定义都行。
    wolfie
        44
    wolfie  
       118 天前
    多态
    nekoneko
        45
    nekoneko  
       118 天前
    定义时的区别就是一个只能用接口提供的方法,一个可以用独有的方法,看情况使用即可没什么特殊的规定.

    主要是用于限定方法参数 public void a(List list) public void b(Arraylist list)
    Jwyt
        46
    Jwyt  
       118 天前
    @Leviathann LinkedList 确实好像没用到过,LinkedHashMap 用的比较多
    passerbytiny
        47
    passerbytiny  
       118 天前
    List list=new ArrayList ,声明一个 List 类型变量,用它的实现类 ArrayList 的构造器实例一个对象作为变量的值。
    ArrayList list=new ArrayList ,你需要的是一个 ArrayList 类型的变量,并直接用它的构造器实例一个对象作为变量的值。

    上面的语句一和语句二是两种语句,面向的是两种场景,并不是一种语句的二选一的两种写法。之所以语句一常见而语句二基本见不到的原因是:绝大多数情况下你需要的是一个“列表”,而不是要一个“基于数组实现的列表”。

    ArrayList 的人生定义就是“List 的默认实现类”,所以通常情况下不会有声明 ArrayList 类型变量的需求。换成 LinkedList 就不一样了,当你明确的需要一个链表+顺序表时,就必须这样定义:LinkedList linkedList = new LinkedList
    passerbytiny
        48
    passerbytiny  
       118 天前
    纠正上面的错误,链表本身就是顺序的,不应该描述成链表+顺序表。当你明确的需要一个“经常插队方式插入删除数据”的列表时,就必须用“LinkedList linkedList = new LinkedList”语句。不过好像这样的场景也不多。
    Jooooooooo
        49
    Jooooooooo  
       118 天前
    确实意义不大, 你第二种写法几乎都不会有问题.
    wangxiaoaer
        50
    wangxiaoaer  
       118 天前
    @HuPu #24 你创建的这个 list 可能作为参数传递给其他函数,其他函数接收的是 list 而不是 arraylist 。这个接收函数现在不一定有,以后可能会有,也或者一辈子都不会有。哈哈哈
    HuPu
        51
    HuPu  
    OP
       118 天前
    @wangxiaoaer 方法的参数类型是 list ,一样可以传 arraylist 啊
    lianglu
        52
    lianglu  
       118 天前
    这个问题其实跟开发 Spring 项目的时候要不要写接口一样,绝大部分的业务只有一个 Service 实现类,但是为了规范,为了扩展,最好还是写接口;同理 List 也一样
    menglddd
        53
    menglddd  
       118 天前
    面向接口编程,引用传递的过程中,可以作为更通用的接口在传递,还可以动态修改具体实现。如果要使用实现类的其他操作,就不需要用这种写法。
    wangxiaoaer
        54
    wangxiaoaer  
       118 天前 via iPhone
    @HuPu 草率了哈。
    micean
        55
    micean  
       118 天前
    没想到这问题也能讨论 50 多个回复? java 患者中毒颇多啊,各位在 java11 用不用 var 呢?
    楼主你不要纠结这种问题
    zxjunz
        56
    zxjunz  
       118 天前
    隐藏细节
    Bromine0x23
        57
    Bromine0x23  
       118 天前   ❤️ 1
    @HuPu 是这个意思。有时候 IDE 一个补全就用上特有方法了。
    ixx
        58
    ixx  
       118 天前
    道理你都懂 我就说点使用上的问题

    如果你定义 ArrayList al = new ArrayList();

    如果有一个方法你定义的参数是 test(ArrayList list);

    调用的时候你写 test(al); 是可以的,如果要换成 LinkedList 要改的地方就多了

    如果定义的是 List al = new ArrayList();

    调用的时候 test(al);会报错提示你类型不对, 你只有改 test 参数定义为 test(List list);才行

    改完你再想换 LinkedList 就容易了
    SorcererXW
        59
    SorcererXW  
       118 天前
    “Accept interfaces, return structs”
    oneisall8955
        60
    oneisall8955  
       118 天前
    接口入参定义为 List 有意义,方法内局部变量没意义
    dallaslu
        61
    dallaslu  
       118 天前
    酒保:
    XueHua beer = new XueHua();

    一个重构工程师进入了酒吧:来杯扎啤!
    h82258652
        62
    h82258652  
       118 天前
    方法输入输出面向抽象没问题,方法内部没必要,直接 var 就行了
    HuPu
        63
    HuPu  
    OP
       118 天前
    @ixx 如果已知 test(List list)了 外面的 List al = new ArrayList();或者 ArrayList al = new ArrayList();没影响啊
    sampeng
        64
    sampeng  
       118 天前
    @HuPu 才工作一年不理解正常。再过 4-5 年回来再看
    ixx
        65
    ixx  
       118 天前
    @HuPu #63 已知是没问题 ,如果你新写一个呢,假如你写的时候没注意写了 testNew(ArrayList list); 如果外边定义使用的 ArrayList al = new ArrayList(); 是不会提示你有问题的 只有等你换 LinkedList 时才会发现要跟着改

    如果外边是 List al = new ArrayList(); 定义新方法的时候就会提示你类型不对
    passerbytiny
        66
    passerbytiny  
       118 天前
    @HuPu #59 “光跑起来的时候能运行还不行,纯看代码也得能逻辑上说得通才行”,这是强类型语言根弱类型语言的显著区别。对于你这一场景,两句语句确实在运行上没区别。但代码逻辑上,一个传的是 List 类型变量,一个传的的 List 的子 /实现类 ArrayList 类型的变量——前者是基类,后者是子类,这个区别是很大的。建议先了解一下“编译时”跟“运行时”,这俩搞明白之后再回头来看就很容易懂了。
    passerbytiny
        67
    passerbytiny  
       118 天前
    @HuPu #59 我发现我们都跑题了。前面的回复你想看看,不想看可以拉到,跟你的问题没关系。

    List list=new ArrayList 相比于 ArrayList list=new ArrayList 写法的意义是:纯粹从代码逻辑看的话,没意义;在编码风格上,前者比后者简洁,而越简洁的代码越好。

    首先,前者比后者少几个字母。不过更重要的是,既然面向对象的多态性要求你将方法参数定义成抽象类型——你应当定义 test(List xxx),而不是 test(ArrayList xxx);那么定义传递给这个方法的变量时,同样定义为抽象类型能保持代码的简洁。
    vance123
        68
    vance123  
       118 天前
    这只是一个面向接口的一个示例。如果面向实现编程,假设这个类在上百个地方被调用,下次你想改变实现,就得同时修改这上百个位置;更糟糕的是假如调用的地方你修改不了,像是别人的代码,这个实现就几乎没法改了
    YvesX
        69
    YvesX  
       118 天前
    什么都追求最佳实践是病
    Nich0la5
        70
    Nich0la5  
       118 天前
    在你不需要 arrayList 的特有方法的时候尽量使用上层接口,想象一下协作的时候 对方传给你一个 List 你就不用关心他到底是个 linkedlist 还是 arrayList ,java 就是面向抽象开发的语言,不这么写就不 java 了。
    硬要传个 arrayList 行不行 当然行,但有一天你就是想传个 linkedList 了就发现出问题了。linkedList 确实用的少,所以这个场景意义没有那么大
    RudyS
        71
    RudyS  
       118 天前
    编译和实际运行是两种状态
    pkoukk
        72
    pkoukk  
       118 天前
    public void sth() List{
    ArrayList list=new ArrayList;
    return list
    }
    java 是不能这么写么? c#和 golang 我都是这么写的
    我觉得在变量声明的时候没有必要面对 interface,只要语言支持里式代换,在出入参处声明就行啊
    Edsie
        73
    Edsie  
       118 天前
    最烦这种,固执的纠结这种无意义的东西,明明怎么用都可以,没有什么最佳实践 用 var 不就行了 把心思用在其他地方吧
    johnniang
        74
    johnniang  
       117 天前 via Android   ❤️ 1
    如果你要是用 ArrayList 独有的方法,这样写没问题。

    如果你是用的只是 List 接口里面定义的方法,建议赋值给 List 。

    试想一下,未来 JDK 中实现了一种更高效的 List ,你只需要修改实现即可,不需要修改变量的类型,以及修改后可能带来的问题。
    uleh
        75
    uleh  
       117 天前
    ArrayList al = new ArrayList() 这样写当然也能编译通过,代码执行也不会有太大问题
    但是编写代码的时候,并不是代码能 run 就可以的。
    首先应该是你对问题的抽象,然后使用代码逻辑来表达这个抽象。
    从这个角度上来说,你的思考顺序应该是:我要使用 List 来保存数据。
    然后在 Java 的语言系统里,根据需求给 List 找一个实现,比如 ArrayList 或者 LinkedList 。

    所以这个并不是“可以不可以”的问题,而是本质上体现了你思考的逻辑和出发点。
    ScepterZ
        76
    ScepterZ  
       117 天前
    @HuPu 首先,这是一行,两处。
    然后,你“只用 list 的功能”这一点,如果你写 List ,是有代码层面强制你这么做的,如果你写 ArrayList ,就只能靠自觉了
    Jwyt
        77
    Jwyt  
       117 天前
    @passerbytiny
    啥乱七八糟的,都是 List list = new LinkedList() 啊,怎么会直接声明 LinkedList
    LinkedList 工作中几乎没用到过
    imkerberos
        78
    imkerberos  
       117 天前
    等你有机会写 TestUnit 的时候就理解了.
    privatetan
        79
    privatetan  
       117 天前
    多态,在运行时动态绑定,然后选择具体实现。
    kenvix
        80
    kenvix  
       117 天前
    如果 `List list=new ArrayList` 就是个局部变量我觉得怎么写都无所谓,我一直都是 val/var 直接类型推导
    kenvix
        81
    kenvix  
       117 天前
    当然如果是入参、出参那就意义重大了——为了多态
    hingbong
        82
    hingbong  
       117 天前 via Android
    声明变量没什么意义,在方法上用接口做参数比较有意义
    Narcissu5
        83
    Narcissu5  
       117 天前
    首先回楼主,工作一年真的只能叫新手。。。

    其次,虽然写 Java 的很多,但是很多人其实并不真的理解 OO ,更不懂得使用设计模式。虽然写 Java 但是一大堆静态方法,我想这也是 Go 这种更加偏向面向过程的语言能够在中国特别流行的原因之一。
    EscYezi
        84
    EscYezi  
       117 天前 via iPhone
    习惯这么写,感觉清爽一点
    Map<K,V> m = new HashMap<>()
    20150517
        85
    20150517  
       117 天前 via iPad
    果然这种简单问题能吸引流量
    ShotaconXD
        86
    ShotaconXD  
       117 天前
    ....封装 继承 多态 都忘光啦
    qiany
        88
    qiany  
       117 天前
    这种要配合设计模式用 工作三年应该才能有所体会
    wanguorui123
        89
    wanguorui123  
       117 天前
    var a=[]
    byte10
        90
    byte10  
       117 天前
    @HuPu 🤣 笑死我了。别说一年,整个 3-5 年,你去面试那些家伙,有几个能回答上面向对象编程的哈。还有那个抽象类都说不明白的。一年不理解很正常,少年,你应该看看我的视频,看完你就知道你的差距是多少了。地址: https://www.bilibili.com/video/BV1FS4y1o7QB#reply99287502976
    @vance123 你理解的不到位。楼主是说定义变量,而不是定义接口 变量。

    我来讲一个核心的问题吧,ArrayList list=new ArrayList<>() ,没有问题,但是你要是写 MyArrayList list=new MyArrayList<>() 。这个就有问题,因为我不认识 MyArrayList ,我只认识 ArrayList 或者 List 。我甚至不认识 linkedList 。你要我去翻 API 文档吗?

    所以你以后把 ArrayList list=new ArrayList<>();改成 MyArrayList list=new MyArrayList<>() 是不行的,只能是 yList list=new MyArrayList<>() 。那还不如一开始就是 List list 的变量。楼主你明白了吗,这个回答应该是可以完美解开你的疑惑了吧。
    darkengine
        91
    darkengine  
       117 天前
    其实函数内的局部变量活着类的私有成员变量你随便用,如果是 public 的成员变量或者 publich 方法的参数或返回值的类型,你就得仔细考虑了。
    jameslan
        92
    jameslan  
       117 天前
    就是教条。从语言设计者到使用者。Java 里面类似的蠢东西一抓一大把。

    面向接口编程本身是很好的,但是你得搞清为什么:其目的是为了封装时的解耦合。也就是说,参数类型为接口时,调用者有最大的自由,选择传入什么对象。当外部需要改变时,无需改动封装好的代码( open - close 原则)。

    但是其实还有另外一个问题 - 过度优化:完全没有多态需求的地方,比如一个非常 local 的 class ,也非要弄一个接口,说是以防将来变化。其实接口根本不稳定,每次都要改接口定义,还额外加了很多行代码。

    说回这个局部变量。一个 scope 只在 method 内部的对象,create 之后,要立刻“忘掉”对象的类,只“记得”接口,这真没太大意义,毕竟一个 method 也没多大(理论上)。而且因为其局部性,对多态完全无影响。对大家熟知的类和接口,像 List 和 ArrayList 也就罢了,其他类和对象也这么搞,实在是脱裤子放屁。

    至于说修改的时候方便一些,的确是的。但是 1.都怪这狗屎语法(我记得 Java7 加 diamond operator 的时候有过讨论,但是就是决定弄成现在这个样子,而不是抄 C#加一个 var 。目的是让程序员肉眼检查类型,这 design taste 也是没谁了。现在加上 var 了,啪啪啪,脸疼不?) 2.不用 IDE 的吗? 3.修改这玩意的概率有多大?所以 1.善用 var ,2. List ArrayList 的不用想的,这样写也就罢了,别的真没必要。

    PS: List ArrayList, LinkedList 完全就是 Library 设计的问题了。List 接口给了 random access ,结果一个类 O(1), 一个类 O(n),你这让人怎么面向接口编程。。。。
    aguesuka
        93
    aguesuka  
       117 天前
    (暴论) 99% 的场景里, new ArrayList 都可以用 List.of, new ArrayDeque, Stream.toList 代替; 非得在集合里保存 null, 或一定要用 Mutable 集合且一定要 RandomAccess 时, 应该使用 var list = new ArrayList.

    实际作为 LocalVariable 使用时, List 和 ArrayList 的唯一区别就是在 IDEA 里想调用 list.equals 可以放心大胆的 e+TAB 而不用担心补全的是 list.ensureCapacity.
    hanqy228
        94
    hanqy228  
       46 天前
    @HuPu 看你写的地方了 很多人都说了 如果是私有的作用域那你随意写 ok 。但是如果是公共部分且调用繁多的话还是前者好。不然短时间内可能没事问题。一旦调用越来越多的话,需求一旦有变动。这个技术债会很高很可怕的。牵一发而动全身。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3208 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 10:25 · PVG 18:25 · LAX 03:25 · JFK 06:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.