欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

為什么Java不支持運算符重載?

錢多多2年前27瀏覽0評論

Java不支持運算符重載 = 小白也能學編程

Java之所以不支持運算符重載,并不是如下原因:

  1. 會使JVM變得復雜、性能下降:君不見C++內置運算符重載的能力?C++的性能在任何時代秒殺Java相信沒有爭議。
  2. 便于靜態分析、工具化等:一葉障目、不見泰山。運算符重載只是一種動態特性,動態語言的形式化靜態分析方法已經有成熟的方法論。
  3. Java是面向對象語言:Ruby是比Java更徹底的面向對象的語言,然而它對運算符重載的支持非常優秀,在Ruby中一切都是對象,幾乎一切都可以override。

不支持運算符重載的根本原因,是源自James Gosling設計Java的初衷:那就是要讓Java的學習門檻足夠低,這樣才能讓這個編程語言被更多的人使用,從而擁有最大的市場占有率。

Java誕生之前, 基本上是C/C++的天下。光C語言的一個指針,就嚇退了多少莘莘學子?C++引入更多的動態特性:多態、多重繼承、函數重載、函數重寫、運算符重載、泛型……這更不知道讓多少人望而卻步!

正是在那樣的大環境下,James Gosling才萌生了“開發一個小白都能上手”的編程語言的念頭。

運算符重載的底層思想并不是面向對象

運算符重載的底層邏輯來自函數式編程。它的祖師爺是Lisp,一個“從來被模仿、從未被超越”的神級語言。

可以負責任地講,如今流行的Python、Javascript、Typescript、Go、Ruby、Haskell、Scala、Groovy等,在動態高級特性上都是在不斷模仿60多年前的Lisp。包括Java從誕生起就在鼓吹的垃圾回收等優點,全部都是“偷師”Lisp。有興趣的小伙伴可以自行下載Lisp的發明者——John McCarthy老爺爺1960年發表的GC論文。

函數式語言的核心思想其實是數學。

說得更白話一點:通過數學表達式描述問題,而不是人肉模擬解答過程。問題描述完了,也就解決了——運行時處理執行細節。

說得更學院派一點:通過無狀態的函數加以其他優化特性,將這些函數組件進行拼接。

看到這里,估計有不少人要來拍磚:運算符重載看起來那么復雜,明明可以定義方法或者函數來解決,除了裝逼格,沒有實用價值。

筆者這里回應一下:數學本來就不是普通大眾擅長的,數學的目的就是用最簡潔的方式來解決最復雜的問題。所以函數式語言從誕生之初,就沒有想過要蕓蕓眾生。它追求的是大道至簡。

這里來看一個例子:計算一組數據(假設放在一個一維數組中)的標準差。

如果不采用函數式編程,采用通常的面向過程或者面向對象的編程范式,那么只能:

第一步,先通過循環體(for/foreach/while等),挨個遍歷求出平均值mean;

第二步,再來一次循環,挨個求與mean的差值并平方,然后逐個累加得到平方合sumOfSquares;

第三步,對sumOfSquares調用平方根函數,求出最終值standardDeviation。

下面我們來進化一點:

有基本函數式編程概念的小伙伴可能會寫出如下的簡化范式(這里以Ruby為例):

mean = a.inject {|x,y| x+y } / a.size

sumOfSquares = a.map{|x| (x-mean)**2 }.inject{|x,y| x+y }

standardDeviation = Math.sqrt(sumOfSquares/(a.size-1))

但是真正的函數式編程高手是會這樣寫的:

第一步:寫一個通用的數學意義上的復合函數(f(g(x)) = f*g(x))的表達:

module Functional

def apply(enum)

enum.map &self

end

alias | apply

def reduce(enum)

enum.inject &self

end

alias <= reduce

def compose(f)

if self.respond_to?(:arity) && self.arity == 1

lambda {|*args| self[f[*args]] }

else

lambda {|*args| self[*f[*args]] }

end

end

alias * compose

end

第二步:把計算標準差所需要的各個元素的數學表達列示好:

sum = lambda {|x,y| x+y } # A function to add two numbers

mean = (sum<=a)/a.size # Or sum.reduce(a) or a.inject(&sum)

deviation = lambda {|x| x-mean } # Function to compute difference from mean

square = lambda {|x| x*x } # Function to square a number

第三步:像寫標準差的數學表達式一樣,一步到位:

standardDeviation = Math.sqrt((sum<=square*deviation|a)/(a.size-1))

總結

Java之所以流行,并不是因為其語言設計得最優秀,相反地,在很多地方——比如泛型、Lambda、完全面向對象等設計上都存在不足。它的成功在于:揚長避短,把所有牛X的高級語言特性在一開始全部都拋棄,留一個最小核,然后通過營銷,大規模地培養本語言陣營的程序員,建立各種各樣的“輪子”,成就了巨無霸的生態;在站穩格局之后,慢慢地再逐步添加回來一些以前拋棄的其他語言的優秀特性——這是一種比較實用的策略,但是帶來的惡果就是:歷史包袱比較重,導致新特性很多時候是“半殘”的。

回到運算符重載本身,對于高手,可以利用該特性寫出極具“魔性”、接近數學語言的代碼,這樣的代碼可以體現“極簡之美”——但是,一個不利影響就是:數學不好的小伙伴,不容易看得懂,也很難體會其中蘊含的“數學之美”。