1
golangLover 2022-01-20 11:25:09 +08:00 via Android 1
面向接口编程
|
2
HuPu OP 有人说换成 linkedList 要改的地方少
List list=new ArrayList 只能用 list 的功能 那我 AL=new AL 要改成 linkedList 不也是只改一处吗 |
3
gabon 2022-01-20 11:25:46 +08:00 via iPhone
如果你想替换为 linkedlist 就可能不兼容了
|
4
HuPu OP @golangLover 你好 有没有具体的例子
|
5
chendy 2022-01-20 11:26:12 +08:00
局部变量无意义,成员 /全局变量用 List
new ArrayList<String>().var 自动补全出来就完事了 |
7
micean 2022-01-20 11:27:24 +08:00 3
少写 5 个字母
|
8
johnj 2022-01-20 11:28:28 +08:00 5
Java 讲究面向接口编程。所有依赖的对象,都用接口去引用而非实现类。
作为新手先记住规则,这时候你不理解很正常,缺乏背景和实际经验很难能理解好处。 |
9
chengyiqun 2022-01-20 11:30:41 +08:00 1
通常出现在一个组件的构造函数或者返回参数时注意下就行.
构造函数或者函数形参用接口, 可以传入多种类型, return 就返回具体的类型. |
10
X0ray 2022-01-20 11:31:01 +08:00 1
|
13
Leviathann 2022-01-20 11:32:44 +08:00 via iPhone
我都用 var a = new ArrayList
|
14
chendy 2022-01-20 11:33:31 +08:00 1
面向接口是在参数返回值这样的地方
比如一个方法参数写死了 ArrayList ,然后 Collections.emptyList 或者 signotelList 或者 Arrays.asList 就都进不来了,写 List 就会好很多 返回值也类似,如果声明返回 ArrayList ,那么实现就必须返回 ArrayList 用不了其他的,同样换成接口会好很多 而局部变量本身就是具体的实现环节,不需要进一步抽象,ArrayList 就是 ArrayList ,写 List 并没有啥用 更何况 java 里 99%都是 ArrayList ,换其他实现类明显也是为了其他实现类的特性,所以应该是用具体类型 |
15
liuzhaowei55 2022-01-20 11:33:44 +08:00 via Android 27
其实好多的面向接口编程,有些接口活了一辈子也不见得有第二个实现。
|
17
Bromine0x23 2022-01-20 11:34:44 +08:00
限定只能用 List 的方法。
只用和只能用还是有点区别的,这么写最大好处是防手滑。 |
19
gscsnm 2022-01-20 11:35:20 +08:00
|
20
ic2y 2022-01-20 11:37:57 +08:00
代码防御; 可以让后面调用的人,只能调用接口声明的方法,而不会误调用 具体实现的某些公开方法。
在后续,如果要切换具体的实现,只要替换 new ArrayList 即可,对调用方无感知。 |
21
HuPu OP 是不是这个意思 我从一开始 List=new AL 下面我每次用到 list 的时候都不会碰 AL 专属的方法。 如果我 AL=new AL 了 就可能不小心用了一个 AL 专属方法
以后再改成 linkedList 就不好改了 |
22
Leviathann 2022-01-20 11:39:45 +08:00 via iPhone 5
@HuPu java collection framework 作者的原话
Does anyone actually use LinkedList? I wrote it, and I never use it. |
23
thinkershare 2022-01-20 11:40:18 +08:00 1
如果实在局部方法里面, 这样写完全没啥用, 你想怎么搞都行, 因为你要自己对这个方法负责, 除非你要显示的指明, 此处接口需要收缩, 才需要这么搞, 否则只有在 API 接口上收缩对象的对外接口才有意义!
|
25
yazinnnn 2022-01-20 11:43:23 +08:00
这么写没意义
|
26
HuPu OP @Bromine0x23 是不是这个意思 我从一开始 List=new AL 下面我每次用到 list 的时候都不会碰 AL 专属的方法。 如果我 AL=new AL 了 就可能不小心用了一个 AL 专属方法
|
27
RainyH2O 2022-01-20 11:44:16 +08:00
因为和有序可重复列表同一级别的抽象是:有序不可重复列表、无序不可 /可重复列表以及有序性、重复性组合的集合、关联数组等。
而数组实现、链表实现这些只是上述高级抽象的低一级实现。 用同级别的抽象描述功能可做到关注点分离。 |
28
why1001 2022-01-20 11:45:53 +08:00
可以看看设计模式,有帮助于理解
|
29
yazinnnn 2022-01-20 11:46:41 +08:00
反正现在大家也是偏向 fp 写业务,你返回啥 list 的实现都是 list.stream().巴拉巴拉了,返回值类型也可以不关心了
|
30
nvkou 2022-01-20 11:53:56 +08:00 via iPhone
强类型就是这样的了。
说白了是为了工程,各部之间约定接口而不关心实现。不然你实现类完工前我就不用开工了? 强类型系统有很多限制,用接口,继承,泛型补足一定的灵活性。不然更加啰嗦 |
31
banmuyutian 2022-01-20 11:55:10 +08:00
需要用特定接口的时候再用第二种写法呗,10 楼里的讨论很清楚了
|
32
Cbdy 2022-01-20 11:55:22 +08:00
var list = new ArrayList() > List list = new ArrayList() > ArrayList list = new ArrayList()
节省了键盘寿命 |
33
AoEiuV020CN 2022-01-20 11:59:44 +08:00
我觉得是反过来的,List list=new ArrayList 这就可以的情况,为什么你会想写 ArrayList list=new ArrayList
|
35
zxxufo008 2022-01-20 12:13:16 +08:00
我理解的工作一年的还是 rookie
|
36
johnj 2022-01-20 12:19:04 +08:00 2
如果你的问题只是针对 List 这个类型,那回答就是这是无脑,最佳实践。
放大到所有类(接口),面向接口编程,一个明显的好处是方便依赖注入。注入的时候,可以替换接口的任何实现类。这样你的代码依赖的就是接口而不是具体实现。 |
38
kaedea 2022-01-20 12:57:26 +08:00 via Android
Dependency Reverse
|
39
zhangchongjie 2022-01-20 13:09:28 +08:00
把多态看看吧
|
40
Vegetable 2022-01-20 13:24:30 +08:00
都说的很有道理,建议你用 var
|
41
winterbells 2022-01-20 13:27:29 +08:00
kotlin 的 Arraylist 和 Java 的 Arraylist 是同一个东西,但包不同。导入了 java.util.* 就是 Java 的,没有就是 kotlin.collections 的。
上次看到这个报错惊了.. |
42
Rocketer 2022-01-20 13:35:04 +08:00 via iPhone
可能你还没遇到合适的场景。
一般来讲,定义属性和方法的参数类型时都会尽量选择较高层的类 /接口,以方便调用方。 但如果只是个局部变量,比如创建一个 list 然后作为参数传给上面提到的那种属性或方法,那怎么定义都行。 |
43
SirCarol 2022-01-20 13:44:54 +08:00
|
44
wolfie 2022-01-20 13:50:04 +08:00
多态
|
45
nekoneko 2022-01-20 13:55:23 +08:00
定义时的区别就是一个只能用接口提供的方法,一个可以用独有的方法,看情况使用即可没什么特殊的规定.
主要是用于限定方法参数 public void a(List list) public void b(Arraylist list) |
46
Jwyt 2022-01-20 13:59:11 +08:00
@Leviathann LinkedList 确实好像没用到过,LinkedHashMap 用的比较多
|
47
passerbytiny 2022-01-20 14:05:14 +08:00
List list=new ArrayList ,声明一个 List 类型变量,用它的实现类 ArrayList 的构造器实例一个对象作为变量的值。
ArrayList list=new ArrayList ,你需要的是一个 ArrayList 类型的变量,并直接用它的构造器实例一个对象作为变量的值。 上面的语句一和语句二是两种语句,面向的是两种场景,并不是一种语句的二选一的两种写法。之所以语句一常见而语句二基本见不到的原因是:绝大多数情况下你需要的是一个“列表”,而不是要一个“基于数组实现的列表”。 ArrayList 的人生定义就是“List 的默认实现类”,所以通常情况下不会有声明 ArrayList 类型变量的需求。换成 LinkedList 就不一样了,当你明确的需要一个链表+顺序表时,就必须这样定义:LinkedList linkedList = new LinkedList |
48
passerbytiny 2022-01-20 14:09:13 +08:00
纠正上面的错误,链表本身就是顺序的,不应该描述成链表+顺序表。当你明确的需要一个“经常插队方式插入删除数据”的列表时,就必须用“LinkedList linkedList = new LinkedList”语句。不过好像这样的场景也不多。
|
49
Jooooooooo 2022-01-20 14:23:43 +08:00
确实意义不大, 你第二种写法几乎都不会有问题.
|
50
wangxiaoaer 2022-01-20 14:29:11 +08:00
@HuPu #24 你创建的这个 list 可能作为参数传递给其他函数,其他函数接收的是 list 而不是 arraylist 。这个接收函数现在不一定有,以后可能会有,也或者一辈子都不会有。哈哈哈
|
51
HuPu OP @wangxiaoaer 方法的参数类型是 list ,一样可以传 arraylist 啊
|
52
lianglu 2022-01-20 14:40:15 +08:00
这个问题其实跟开发 Spring 项目的时候要不要写接口一样,绝大部分的业务只有一个 Service 实现类,但是为了规范,为了扩展,最好还是写接口;同理 List 也一样
|
53
menglddd 2022-01-20 14:41:36 +08:00
面向接口编程,引用传递的过程中,可以作为更通用的接口在传递,还可以动态修改具体实现。如果要使用实现类的其他操作,就不需要用这种写法。
|
54
wangxiaoaer 2022-01-20 14:45:57 +08:00 via iPhone
@HuPu 草率了哈。
|
55
micean 2022-01-20 15:04:18 +08:00
没想到这问题也能讨论 50 多个回复? java 患者中毒颇多啊,各位在 java11 用不用 var 呢?
楼主你不要纠结这种问题 |
56
zxjunz 2022-01-20 15:04:58 +08:00
隐藏细节
|
57
Bromine0x23 2022-01-20 15:08:59 +08:00 1
@HuPu 是这个意思。有时候 IDE 一个补全就用上特有方法了。
|
58
ixx 2022-01-20 15:25:58 +08:00
道理你都懂 我就说点使用上的问题
如果你定义 ArrayList al = new ArrayList(); 如果有一个方法你定义的参数是 test(ArrayList list); 调用的时候你写 test(al); 是可以的,如果要换成 LinkedList 要改的地方就多了 如果定义的是 List al = new ArrayList(); 调用的时候 test(al);会报错提示你类型不对, 你只有改 test 参数定义为 test(List list);才行 改完你再想换 LinkedList 就容易了 |
59
SorcererXW 2022-01-20 15:44:22 +08:00
“Accept interfaces, return structs”
|
60
oneisall8955 2022-01-20 15:51:19 +08:00
接口入参定义为 List 有意义,方法内局部变量没意义
|
61
dallaslu 2022-01-20 15:54:25 +08:00
酒保:
XueHua beer = new XueHua(); 一个重构工程师进入了酒吧:来杯扎啤! |
62
h82258652 2022-01-20 16:02:08 +08:00
方法输入输出面向抽象没问题,方法内部没必要,直接 var 就行了
|
63
HuPu OP @ixx 如果已知 test(List list)了 外面的 List al = new ArrayList();或者 ArrayList al = new ArrayList();没影响啊
|
65
ixx 2022-01-20 16:30:41 +08:00
@HuPu #63 已知是没问题 ,如果你新写一个呢,假如你写的时候没注意写了 testNew(ArrayList list); 如果外边定义使用的 ArrayList al = new ArrayList(); 是不会提示你有问题的 只有等你换 LinkedList 时才会发现要跟着改
如果外边是 List al = new ArrayList(); 定义新方法的时候就会提示你类型不对 |
66
passerbytiny 2022-01-20 16:46:16 +08:00
@HuPu #59 “光跑起来的时候能运行还不行,纯看代码也得能逻辑上说得通才行”,这是强类型语言根弱类型语言的显著区别。对于你这一场景,两句语句确实在运行上没区别。但代码逻辑上,一个传的是 List 类型变量,一个传的的 List 的子 /实现类 ArrayList 类型的变量——前者是基类,后者是子类,这个区别是很大的。建议先了解一下“编译时”跟“运行时”,这俩搞明白之后再回头来看就很容易懂了。
|
67
passerbytiny 2022-01-20 16:59:53 +08:00
@HuPu #59 我发现我们都跑题了。前面的回复你想看看,不想看可以拉到,跟你的问题没关系。
List list=new ArrayList 相比于 ArrayList list=new ArrayList 写法的意义是:纯粹从代码逻辑看的话,没意义;在编码风格上,前者比后者简洁,而越简洁的代码越好。 首先,前者比后者少几个字母。不过更重要的是,既然面向对象的多态性要求你将方法参数定义成抽象类型——你应当定义 test(List xxx),而不是 test(ArrayList xxx);那么定义传递给这个方法的变量时,同样定义为抽象类型能保持代码的简洁。 |
68
vance123 2022-01-20 17:10:49 +08:00
这只是一个面向接口的一个示例。如果面向实现编程,假设这个类在上百个地方被调用,下次你想改变实现,就得同时修改这上百个位置;更糟糕的是假如调用的地方你修改不了,像是别人的代码,这个实现就几乎没法改了
|
69
YvesX 2022-01-20 17:13:00 +08:00
什么都追求最佳实践是病
|
70
Nich0la5 2022-01-20 17:25:22 +08:00
在你不需要 arrayList 的特有方法的时候尽量使用上层接口,想象一下协作的时候 对方传给你一个 List 你就不用关心他到底是个 linkedlist 还是 arrayList ,java 就是面向抽象开发的语言,不这么写就不 java 了。
硬要传个 arrayList 行不行 当然行,但有一天你就是想传个 linkedList 了就发现出问题了。linkedList 确实用的少,所以这个场景意义没有那么大 |
71
RudyS 2022-01-20 17:26:18 +08:00
编译和实际运行是两种状态
|
72
pkoukk 2022-01-20 17:59:33 +08:00
public void sth() List{
ArrayList list=new ArrayList; return list } java 是不能这么写么? c#和 golang 我都是这么写的 我觉得在变量声明的时候没有必要面对 interface,只要语言支持里式代换,在出入参处声明就行啊 |
73
Edsie 2022-01-20 18:08:29 +08:00
最烦这种,固执的纠结这种无意义的东西,明明怎么用都可以,没有什么最佳实践 用 var 不就行了 把心思用在其他地方吧
|
74
johnniang 2022-01-20 18:28:42 +08:00 via Android 1
如果你要是用 ArrayList 独有的方法,这样写没问题。
如果你是用的只是 List 接口里面定义的方法,建议赋值给 List 。 试想一下,未来 JDK 中实现了一种更高效的 List ,你只需要修改实现即可,不需要修改变量的类型,以及修改后可能带来的问题。 |
75
uleh 2022-01-20 18:43:26 +08:00
ArrayList al = new ArrayList() 这样写当然也能编译通过,代码执行也不会有太大问题
但是编写代码的时候,并不是代码能 run 就可以的。 首先应该是你对问题的抽象,然后使用代码逻辑来表达这个抽象。 从这个角度上来说,你的思考顺序应该是:我要使用 List 来保存数据。 然后在 Java 的语言系统里,根据需求给 List 找一个实现,比如 ArrayList 或者 LinkedList 。 所以这个并不是“可以不可以”的问题,而是本质上体现了你思考的逻辑和出发点。 |
76
ScepterZ 2022-01-20 18:58:31 +08:00
@HuPu 首先,这是一行,两处。
然后,你“只用 list 的功能”这一点,如果你写 List ,是有代码层面强制你这么做的,如果你写 ArrayList ,就只能靠自觉了 |
77
Jwyt 2022-01-20 19:12:36 +08:00
|
78
imkerberos 2022-01-20 20:12:51 +08:00
等你有机会写 TestUnit 的时候就理解了.
|
79
privatetan 2022-01-20 20:38:00 +08:00
多态,在运行时动态绑定,然后选择具体实现。
|
80
kenvix 2022-01-20 21:29:32 +08:00
如果 `List list=new ArrayList` 就是个局部变量我觉得怎么写都无所谓,我一直都是 val/var 直接类型推导
|
81
kenvix 2022-01-20 21:30:13 +08:00
当然如果是入参、出参那就意义重大了——为了多态
|
82
hingbong 2022-01-20 21:39:49 +08:00 via Android
声明变量没什么意义,在方法上用接口做参数比较有意义
|
83
Narcissu5 2022-01-20 23:21:32 +08:00
首先回楼主,工作一年真的只能叫新手。。。
其次,虽然写 Java 的很多,但是很多人其实并不真的理解 OO ,更不懂得使用设计模式。虽然写 Java 但是一大堆静态方法,我想这也是 Go 这种更加偏向面向过程的语言能够在中国特别流行的原因之一。 |
84
EscYezi 2022-01-20 23:39:05 +08:00 via iPhone
习惯这么写,感觉清爽一点
Map<K,V> m = new HashMap<>() |
85
20150517 2022-01-21 00:01:42 +08:00 via iPad
果然这种简单问题能吸引流量
|
86
ShotaconXD 2022-01-21 09:20:00 +08:00
....封装 继承 多态 都忘光啦
|
87
chocotan 2022-01-21 10:00:49 +08:00
|
88
qiany 2022-01-21 11:34:06 +08:00
这种要配合设计模式用 工作三年应该才能有所体会
|
89
wanguorui123 2022-01-21 11:37:13 +08:00
var a=[]
|
90
byte10 2022-01-21 12:07:36 +08:00
@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 的变量。楼主你明白了吗,这个回答应该是可以完美解开你的疑惑了吧。 |
91
darkengine 2022-01-21 13:01:18 +08:00
其实函数内的局部变量活着类的私有成员变量你随便用,如果是 public 的成员变量或者 publich 方法的参数或返回值的类型,你就得仔细考虑了。
|
92
jameslan 2022-01-21 13:18:52 +08:00
就是教条。从语言设计者到使用者。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),你这让人怎么面向接口编程。。。。 |
93
aguesuka 2022-01-21 15:38:54 +08:00
(暴论) 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. |