为什么不能全部用 static
1
chengyiqun 2022-07-21 11:03:49 +08:00
快进到全民面向过程编程(误
因为 java 是面向对象的, 比如我有个猫类, 里面有个喵喵叫方法. 你要写成全局静态的, 然后给狗狗调用嘛? |
2
paradoxs 2022-07-21 11:05:34 +08:00 2
内存
|
3
xhldtc 2022-07-21 11:05:35 +08:00
因为如果每个方法都是静态的,java 就不会是面向对象的。
您需要在不同的对象上调用方法,因为它们具有不同的状态。 PS:这个问题太基础了,多写点代码就会发现 static 和非 static 方法的区别了 |
4
pannanxu 2022-07-21 11:06:17 +08:00 1
jvm:听我说谢谢你,感谢有你,温暖了四季
|
5
Kimen 2022-07-21 11:09:22 +08:00
jvm:听我说谢谢你,感谢有你,温暖了四季
|
6
xiaofan305 2022-07-21 11:12:11 +08:00 via Android
个人认为,对于单例对象,是可以全部 static 的。但是 java 的程序多数都需要搞什么依赖注入,方便解耦,统一生命周期管理和一些事件的处理,这时候就不能全部 static 了。如果是自己写的一些小东西,想怎么写都行,不纠结
|
7
lmshl 2022-07-21 11:12:55 +08:00
这不就是 Rust/Haskell 嘛
当然 Scala 里也可以很轻松实现仅用 static (object method) ,typeclass 风格 理论上在 Java 中只用 static 方法也是可行的,相当于你手动展开 typeclass 调用而已,自己一个人的项目随便怎么玩都行 |
8
murmur 2022-07-21 11:13:19 +08:00 6
这个东西其实就是个编程习惯的问题
比如 Person p1 = new Person(xxx); Person p2 = new Person(xxxx) p1.fuck(Person2) //类方法 和 PersonUtil.fuck(p1, p2) //静态方法 用好了其实没什么高下之分 |
10
kop1989smurf 2022-07-21 11:16:27 +08:00
可不可以全部用静态修饰词?当然可以。
好不好?在 java 中这么用不好。 类与对象( class/object ),公共与私有(public/private),静态(static),继承(extends),接口(interface),实现(implements),这是面向对象的核心理念。 这也是你使用 java 这个“面向对象原教旨主义”语言的最大理由之一。 |
11
kop1989smurf 2022-07-21 11:17:54 +08:00 6
这就像是,你手里又把突击步枪,你说这枪托很硬,我们为什么还要浪费子弹射击呢?用枪托砸人不行么?
当然行,但砸人你为何不用甩棍? |
12
seth19960929 2022-07-21 11:20:28 +08:00
感觉楼上都没说到带你, 我给你说一个实际的.
每个一个对象都有自己的内存地址, 静态的共享内存. 所以本质就是这样. 比如一个 Person 对象要说出自己的名字, 我只用实例化的时候传入名字, say 方法不用管这么多. 直接输出 this.name, 但是静态的话, 你就得考虑怎么实现了. |
13
seth19960929 2022-07-21 11:20:51 +08:00
没说到带你 -> 没说到点
|
14
qiqiqi7001 OP @paradoxs 内存这个问题我知道
1.静态方法在程序开始时生成内存,实例方法在程序运行中生成内存, 所以静态方法可以直接调用,实例方法要先成生实例,通过实例调用方法,静态速度很快,但是多了会占内存。 静态内存是连续的,因为是在程序开始时就生成了,而实例申请的是离散的空间,所以当然没有静态方法快, 而且静态内存是有限制的,太多了程序会启动不了。 但是我还看到另一个结论 2.静态方法和实例方法其实在性能上没有区别,加载时机,和内存占用都一样,调用速度也没有区别。 我想问这两个那个是正确的 |
15
murmur 2022-07-21 11:22:37 +08:00
|
16
murmur 2022-07-21 11:23:51 +08:00
我大概明白什么意思了,getName 也不是 static
那 Person 全 static ,数据就得用 Map<String, Object>了 |
17
wolfie 2022-07-21 11:24:13 +08:00
了解什么是面向对象吗。
|
18
Leviathann 2022-07-21 11:28:33 +08:00
听说是因为早期不让 import static
|
19
thinkershare 2022-07-21 11:29:40 +08:00
人力是有限的, 状态管理是困难的, 所以我们有了方法执行的上下文, 并限制了在上下文上可执行的操作, 因此有了对象. 你当然可以彻底抛弃对象, 然后将 class 作为 namespace. 那我什么不选择 C 语言呢?
|
20
retrocode 2022-07-21 11:30:28 +08:00
@murmur #8 其实还是有区别的, 假设 fuck 方法内部有一个 doll 参数, 那 p1/p2.fuck 的 doll, 大概率只是同一厂家不同批次生产的同一型号, 而 PersonUtil.fuck 里的 doll 则从头到尾就是同一个(战术后仰)!
|
21
caroline1022 2022-07-21 11:31:31 +08:00
我能想到的一个点是,面向对象的使用方式抽象度更高
比如同样一个让动物叫的功能,你在具体编码的时候无需知道具体场景下过来的是个什么动物,你只需要调用动物.叫()这个方法就行了。每一个不同的动物类别自己去实现叫()这个方法就可以 但如果是静态方法的话,你需要在具体场景中判断如果是个猫得调用 猫.叫(),如果是个狗得调用 狗.叫(),这个耦合度会高得多,更难维护也更容易出问题 比如以后如果来个新的动物,面向对象的话只需要让这个新动物实现叫这个方法就可以,不需要修改业务代码;但如果是静态方法则需要在所有调用叫方法的地方里增加新的判断。 |
22
Achieve7 2022-07-21 11:32:55 +08:00
所有的静态方法共享一个内存块儿, 全静态了内存没法管理, 线程一开直接 GG
|
23
dqzcwxb 2022-07-21 11:34:28 +08:00 5
对对对,就是要把 jvm 这个小娘们直接塞满
|
24
ScepterZ 2022-07-21 11:45:47 +08:00
如果你是单例的场景,全 static 也不是不行。否则我是真不知道你要咋写代码……
|
25
Chinsung 2022-07-21 11:45:53 +08:00 2
面向对象本身就是为了这个目的去设计的
一个接口,有一个方法是发出叫声 猫实现了这个接口,是喵 狗实现了这个接口,是汪 如果用静态类,那只能 Util.dog 叫(狗) Util.cat 叫(猫) 这样既要类型检查,能有多少种动物叫就得有多少个方法从名字上区分。 更别说,你如果想要知道这个猫到底能做哪些事,你得找一遍所有静态类,才能知道这个猫被哪些类支持 |
26
icyalala 2022-07-21 11:46:08 +08:00
static 变量才会在 load class 时分配内存,static 方法在这方面和一般方法可以认为没什么区别。
你大可以全用 static 方法 + 实例变量,把 Java 变成 C 函数 + struct 。 |
27
newmlp 2022-07-21 11:48:06 +08:00
@qiqiqi7001 所有方法肯定是程序加载的时候就都分配好空间了啊,怎么会有动态生成方法的做法,不管是不是静态方法,方法都是所有实例共享的,但是调用时传的 this 不一样而已
|
28
unco020511 2022-07-21 11:48:07 +08:00
那你咋面向对象,你都没对象了,咋管理数据和状态?
|
29
0x2CA 2022-07-21 11:52:23 +08:00
其实也可以的,你可以使用 ecs 编程方式,实体-组件-系统的方式,这样你方法都是依赖组件的,不关乎什么对象,只要有这个组件的对象都有这个行为,面向数据编程
|
30
qiqiqi7001 OP @newmlp 我啥时候说动态生成方法的做法了,,,,
|
31
cpstar 2022-07-21 11:57:09 +08:00
有啥不能的,能编译过去,能运行那就是能。
为啥不能的,因为人为设置了条条框框,比如告诉你这个是 OO ,full static method 不叫 OO ,那甭管是 singleton 还是 Util 方式的,叫不叫 OO ? 不要在意这些细节,怎么用的爽怎么来,哪来那么多优雅。 |
32
seth19960929 2022-07-21 11:59:53 +08:00
@murmur 是, 设计问题. 你用 map 还得多考虑一次并发问题
|
33
xfriday 2022-07-21 12:02:11 +08:00
非 static 方法只是把 this 作为隐式参数传递进函数而已
|
34
xuboying 2022-07-21 12:02:19 +08:00
不懂 Java ,从语言的角度应该没有什么限制吧。
感觉更多的是一个设计模式的问题。(如果是 solo ,那么设计模式其实也没什么纠结的必要了) 举一个 C++新版本里有一个 adhoc 的多态的例子。你说到的问题有一点点相似。有人做了 subtype 多态和 adhoc 的多态的区别比较。认为 subtype 的多态对新派生类更友好,adhoc 的多态对新 method 更友好。所以如果你的使用场景符合维护时会添加更多的 method ,可能写 static 方法会更适合。 |
35
qiqiqi7001 OP @xhldtc 对象不是静态,调用之间都是掉静态方法
|
36
oneisall8955 2022-07-21 12:16:06 +08:00 via Android
多态,接口问题,思考下
|
37
siweipancc 2022-07-21 12:19:53 +08:00 via iPhone
啊这……
|
38
gouflv 2022-07-21 12:25:16 +08:00 via iPhone
OOP 说了:我要抽象一切
ps:多少静态方法能把 jvm 塞满? |
39
cedoo22 2022-07-21 12:36:29 +08:00
jvm:听我说谢谢你,感谢有你,温暖了四季
全静态,直接变面向过程 /函数编程。 |
40
DamonLin 2022-07-21 12:37:48 +08:00
我和你有过这样的疑问哈哈
|
41
zhuweiyou 2022-07-21 12:41:49 +08:00
可以,操作对象从参数传进去就行了.内存不是问题,加钱就行.
建议你换语言吧 |
42
DOLLOR 2022-07-21 12:47:33 +08:00
object.action()和 action(object)没啥区别,也没有谁比谁更好。
但是因为是 java ,java 主打 OOP ,肯定是能 OOP 的地方就 OOP 呀。 |
43
sadfQED2 2022-07-21 12:48:25 +08:00 via Android
能全部用静态方法啊,我前前前司,一个 java 项目里面,90%都是静态方法。没出任何毛病
|
44
darkengine 2022-07-21 12:51:10 +08:00 1
这个方法里需要访问成员变量怎么办?哦,也都声明成静态成员变量是吧。谁家猫狗全都名字一样年龄一样啊。
|
46
FYFX 2022-07-21 13:01:13 +08:00 1
正如 34 楼所说,最近在看 https://craftinginterpreters.com/representing-code.html#the-expression-problem ,里面提到因为 java 是面向对象的,假定的是你的操作都是基于相似类型的,增加一个新的派生类类会很方便。如果你要全部 static 相当于放弃了 java 的这个特性,但是 java(除了特别新的版本)又没有函数式编程那种好用的模式匹配,你这么做的话会导致不管是加类还是加方法都很麻烦。
|
47
min 2022-07-21 13:36:43 +08:00
C++里面为什么需要有 new ?
|
48
sun1991 2022-07-21 13:38:59 +08:00
可以全部 static, 没问题.
面向对象编程 vs 面向数据编程. |
49
tabris17 2022-07-21 13:39:51 +08:00
大家冷静听我说:只要我们在 JAVA 中加入动态创建类型的 feature 不就可以了吗 /doge
|
50
fox0001 2022-07-21 13:45:20 +08:00 via Android
我觉得,如果全静态,解耦不好做。或者像 go 那样再弄个 wire ?
|
51
tairan2006 2022-07-21 13:55:19 +08:00
全静态你还 OOP 个啥
|
52
2696284032 2022-07-21 14:06:57 +08:00
jvm:听我说谢谢你,感谢有你,温暖了四季
|
53
Jooooooooo 2022-07-21 14:10:25 +08:00
其实是个好问题, 大多数方法根本没有多态的场景.
|
54
luozic 2022-07-21 14:10:27 +08:00
全静态,那为啥不用汇编 c/c++ 或者 rust ?觉得魔法不够,,,, 那请用 haskell
|
56
EHemingway 2022-07-21 14:40:09 +08:00
打个比方,你喜欢的妹子是前凸后翘,一米七,天黑了人家本来都专门开好房等你的了。你说不 我要用 static !好嘛房间里瞬间涌入像什么 400 斤的人妖,一米五的肌♂肉猛男,这下你高兴了?
|
57
qiqiqi7001 OP 为什么都在说 jvm ,静态方法和实例方法其实在性能上没有区别,加载时机,和内存占用都一样,调用速度也没有区别。
|
58
w950888 2022-07-21 15:22:00 +08:00
因为第一门语言是 C, 初学 Java 时这么玩过, 当时搞不明白面向对象, 所有的方法都加 static, 哈哈哈哈
|
59
wellerman 2022-07-21 15:42:22 +08:00 1
哈哈哈,居然有人收藏了。 方法 static 了,那成员变量不就 static 了。那一个类只能处理一种信息,要处理多种就只能复制多个类文件。
|
60
guyuesh3 2022-07-21 15:43:32 +08:00
@qiqiqi7001
2.静态方法和实例方法其实在性能上没有区别,加载时机,和内存占用都一样,调用速度也没有区别。 我想问这两个那个是正确的 这个正确,方法是所有对象共享的,不存在一个对象一个方法。类的实例占用的空间,可以大致任务等同于类内部字段所占用的空间。调用速度有差别,但是不会巨大( invokestatic invokevirtual invokeinterface invokespecial 的区别) |
61
guyuesh3 2022-07-21 15:50:09 +08:00
@qiqiqi7001
本质上要分析对象和 static 就是要深入 JVM 才能明白啊,因为是 JVM 帮你管理你的 class ,你的对象的啊。 语言语法的特性需要虚拟机帮助实现啊。 参考:jvm specification / java launguage specificatiion https://docs.oracle.com/javase/specs/ |
62
aguesuka 2022-07-21 15:56:48 +08:00
因为 Java 里的 Object 相当于 FP 里面的 Context, Java 全用 static 相当于 FP 不用闭包
|
63
qiqiqi7001 OP @guyuesh3 我主要不是关注 static 这个关键字本身的原理,我看到“java 万物皆对象”感觉说的不太对,我觉得对象不是必须的,大部分用对象的地方都可以用 static 替换,所以我才问为什么不能全部用 static ,但我现在了解到 static 是和 oop 冲突的,这个可以说是一个不能全部 static 的一个原因。
|
64
qiqiqi7001 OP @guyuesh3 早期的,几乎所有的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建 c++,java,c# 这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。
我复制别人的一句话,这个就是我要找的答案。 |
65
luozic 2022-07-21 16:13:34 +08:00
benchmark 一下,什么时候运行得时候创建对象 和启动得时候就创建对象 性能一样了? 多 benchmark debug jvm ,少 yy 和虚空打靶。
|
66
lux182 2022-07-21 16:14:13 +08:00
这是一个好问题。
第一从设计理念上看,静态方法是不需要实例化对象就能调用。使用要分场景,要不就不规范,让人迷惑 第二从 jvm 类加载上看,静态方法是内存不节约的 |
67
qiqiqi7001 OP |
68
lancelock 2022-07-21 17:13:58 +08:00
你可以这样写啊,没人拦着
|
69
NeoZephyr 2022-07-21 17:37:46 +08:00
如果全部是单例,也不是不可以
|
70
nekoneko 2022-07-21 18:06:52 +08:00
java 面向对象里重要的一点是集成和实现, 全 static 就和这点相悖了
|
72
cmdOptionKana 2022-07-21 18:24:01 +08:00 1
@qiqiqi7001
面向对象是 Java 被发明时的编程界的一个思潮,因此 Java 被设计为更容易采用面向对象的编程模式,Java 程序员也更喜欢采用面向对象方式。 但现在最新的思潮,也有认为面向对象不一定好,比如声名大噪的 Rust 和 Go 语言就不支持标准的(完整的) OOP ,照样得到很多关注和使用。 因此你说尽量多用 static 行不行,当然行,只是 Java 在设计上和生态上不便于采用这种方式。如果你问 Java 为什么不全部使用 static, 那很简单,Java 的设计者与使用者选择了 OOP ,在当时的历史背景下是一个很好的选择,而现在则是有历史包袱。 如果你问不采用 OOP 行不行,当然行,Emacs Lisp 和 Erlang 还活着呢,JavaScript 里也有大量代码不用 class 。 |
73
Suddoo 2022-07-21 18:24:47 +08:00 via iPhone
可以,Spring 不就是这么干的,所有东西放内存里,想用谁用谁,跟 import static 有什么本质上的区别吗?
|
74
ToBeHacker 2022-07-21 18:46:17 +08:00
成员方法不就是把 this 作为第一个参数的 static 方法么,这就是语法糖的差异吧
|
75
pkoukk 2022-07-21 18:50:24 +08:00
没怎么写过 java ,上学的时候听老师说不用的 static 函数也会被加载进内存里
是现在 jvm 升级了么,动态编译时会省略不用的 static 函数嘛 |
76
luozic 2022-07-21 19:26:55 +08:00
@qiqiqi7001 这个是触发了 jvm 得 hotspot 编译了,一般得大部分代码会连续跑 10w 次?
|
77
janus77 2022-07-21 19:32:52 +08:00
所以你反对的只是“面向对象”这个原则而已?那你别用 java 啊,编程有各自的流派,你强行要求一个本来就是为面向对象而设计的语言去写成面向过程的东西,图什么呢?
|
78
stephenyin 2022-07-21 20:02:04 +08:00
讨论的越长的帖子,讨论的内容越没什么技术高度。😂
|
79
undeflife 2022-07-21 21:51:26 +08:00
内存分配上是有区别的,static method 和其他类元信息都保存在 permanent generation ,这个是固定尺寸的,具体细节参考 gc turning 手册,jdk 8 之后移除了,改成了使用非 Java heap 内存且会自增的 Metaspace ,但细节取决于 jvm 实现,另外印象中 static method 是不会有 jit 优化的,我怀疑优化后的普通 method 会比未优化的 static method 快。
|
80
ychost 2022-07-21 21:57:27 +08:00
起始是语言的设计问题,像 Node 就不用关心是否 static ,反正 function 一把梭,Java 更多的是为大工程服务的,比如实现 SPI 等能力都是靠多态来解决的
|
81
iold 2022-07-21 22:01:29 +08:00
你这个问题,让我想起来,毕业的第一份工作,接手别人的项目,状态就是一个静态类,里面八百多个静态变量。当时看的我就不会了,一个注释没有。需求是,国际象棋加个简单的机器人,可以人机对战。改的自己怀疑人生,从那以后我的命就不好,老接手插屁股的活儿...
|
82
aristotll 2022-07-21 23:19:07 +08:00
当成 c 写 就可以全是静态方法
|
83
tenstone 2022-07-21 23:28:58 +08:00
那样就失去了面向对象的意义
|
84
qua 2022-07-21 23:42:08 +08:00 via Android
因为 Spring 没法动态代理
|
85
Kaiv2 2022-07-21 23:48:01 +08:00
static 方法 非 static 方法 JVM 内存占用大小没啥区别,都是存放的字节码。
主要是面向对象,方便扩展。 |
86
zrc 2022-07-22 00:16:28 +08:00
static 的方法好做单元测试不?
多线程环境下 static 持有的数据要考虑并发问题吧 |
87
kaneg 2022-07-22 00:17:21 +08:00 via iPhone
那就退化到 c 语言了
|
88
realpg 2022-07-22 04:11:32 +08:00
@janus77 #77
世界上总有很多人非得把一个东西改造成另一个的样子,并以此为乐 比如 php 的消亡, 跟两个好东西,laravel 和 swoole 有直接关系.一个想把 php 改成 java 那样,一个想把 php 改造成 golang 那样. 这两个是不是好东西?是. 但是直接导致了 php 没落的超级加速 |
89
Aloento 2022-07-22 05:45:14 +08:00
面向对象跟面向过程的区别
php 已经不行了 |
90
realpg 2022-07-22 05:53:25 +08:00
|
91
realpg 2022-07-22 05:54:58 +08:00
|
92
makelove 2022-07-22 08:34:42 +08:00
Java 出生那年代是面向对象火热的年代,所以就搞成了函数不是一等公民的硬伤,现在的语言就不会干函数必需要从属于一个类这种傻事,毕竟不是只有面向对象一种编程模式,甚至是罕见的
|
93
xuyang2 2022-07-22 09:10:09 +08:00
因为 static 让代码本身(而不是实例)变成有状态的了
|
94
summerLast 2022-07-22 09:22:03 +08:00
这个问题需要从两方面看,
首先 能不能全部用 static 方法? 答:能, 与实例方法区别是什么?答:1.有无 this 或 self 的语法糖,2.内聚性的强弱,3idea 等工具的友好型,等等 然后 好处和坏处是什么? 答:参考区别 最后就是有无必要全部用 static 方法 ?答:无必要 |
95
summerLast 2022-07-22 09:25:59 +08:00
@summerLast
这个问题需要从两方面看, 首先 能不能全部用 static 方法? 答:能, 那为什么不全部用 static 方法 ,换种问法 与实例方法区别是什么?答:1.有无 this 或 self 的语法糖,2.内聚性的强弱,3.idea 等工具的友好性,等等 然后 好处和坏处是什么? 答:参考区别 最后就是有无必要全部用 static 方法 ?答:无必要 |
96
xiqishow 2022-07-22 09:33:21 +08:00
因为这个世界就是这样的[doge]
static 表示了可共享,弱隔离,可是现实世界就是部分共享,绝对隔离,人和人之间如此,物和物也是如此,static 表示弱化了隔离行,能访问便能操作,改变状态。其实和是否面向对象没绝对的关系,因为 static 本身也是可以是一个对象变量。但如果赋予了 static 表示了其状态随着世界生命周期的持续,和访问的不可控制。当然可以说用 protect private 来修饰,但只要是能访问的便可使用,便可操控。所以大家的实现都是可分享的就 static ,需要隔离的就实例化,和现实一样。 私下认为,计算机语言也是对现实生活的抽象和建模,所以其实现思想也是受制于现实世界。 |
97
ming159 2022-07-22 10:27:57 +08:00
首先,你可以这么写程序,java 并没有限制你不能这么干.
不过,你要明白 new Object() 等于开辟了一块内存区域,而方法调用的时候,方法中的上下文(this) 可以等同于 这块内存(不严谨). 举例: `` public class MyObject{ private String name ; public MyObject(String n){ this.name=n; } public void getName(){ return this.name; } } MyObject obj_1 = new MyObject("张三"); // 开辟了 内存 A MyObject obj_2 = new MyObject("李四"); // 开辟了 内存 B obj_1.getName(); // 张三 obj_2.getName(); // 李四 `` 那么,如果全部是 static 方法,可以自行查阅一下 static 方法内存怎么管理的. 然后上述功能如何体现.自己写一下可能就能理解这么干的优点了. |
98
shijingshijing 2022-07-22 10:32:03 +08:00
@murmur 8# 你这个抽象明显有问题,且不说人寿,连塑料娃娃都没办法处理,而且即使是 Person ,同性异性也不一样。应该抽象成接口,然后各自实现。这样基本上都能包住。
|
99
mosliu 2022-07-22 10:43:45 +08:00
|
100
THESDZ 2022-07-22 10:44:55 +08:00
大型工程中降低心智成本
|