你必須知道的Java基礎知識
本篇部落格主要記錄Java中面向對象的概念和Java語法的基礎知識。
面向對象
什麼是面向對象
面向對象是一種優秀的軟體設計思想,是相對於面向過程、面向切面等設計思想的一種軟體設計理念。它的核心思想是運用更加貼近人類思維的方式去設計軟體,將軟體中的各個組件抽象成相應的類,再將這些類組裝成我們所需的軟體系統。
這裡舉個例子:假如用面向對象的方式設計一個電腦,我們會設計CPU類、硬碟類、顯示器類、記憶體類等等,然後將這些類組合在一起設計成Computer類。
而面向過程的思想在解決問題時會將問題分解成一個個小的函數,然後按照某種順序去執行這些方法,當這些方法執行完畢,問題也就解決了。
三大基本特徵和五項基本原則
面向對象的三大基本特徵是:封裝、繼承和多態。正是基於這些特徵,面向對象的開發語言才能擁有更好的可重用性、擴展性和維護性。
- 封裝:將對象的實現細節隱藏起來,然後通過一些公共的方法向外部提供該對象的功能;
- 繼承:繼承是軟體復用的一種重要手段,子類繼承父類之後將直接獲得父類的屬性和方法;
- 多態:對象可以賦給父類對象或者它實現的介面,但是運行時依然表現出子類或實現類的特徵。
面向對象的五大原則如下:
- 單一職責原則(SRP):一個類專註於實現一個功能;
- 開閉原則(OCP):對象或實體應該對擴展開放,對修改封閉;
- 里氏替換原則(LSP):子類可以替換父類並且出現在父類能夠出現的任何地方(這個原則就需要我們面向介面編程);
- 依賴倒置原則(DIP):高層次的模組不應該依賴於低層次的模組,他們都應該依賴於抽象,抽象不應該依賴於具體實現,具體實現應該依賴於抽象;
- 介面隔離原則(ISP):使用多個專門的介面比使用單個介面要好的多:在實際編程中,為了減少介面的定義,將許多方法都放在一個介面中,最後發現,維護和實現介面的時候會花費很多精力,介面所定義的操作相當於對客戶端的一種承諾,這種承諾當然是越少越好,越精練越好,過多的承諾帶來的就是你的大量精力和時間去維護。不要把不相干的方法放在一個介面中定義。
另外還有迪米特原則和合成服用原則,也需要我們在設計系統和介面時考慮到。
迪米特法則:又叫最少知識法則,這個法則主張一個類要儘可能少地知道其他類地細節,並且儘可能少地和其他類進行通訊交互,只和於自己有密切關係地類進行交互。
合成服用原則:合成服用原則又稱為組合/聚合服用原則(Composite/Aggregate Reuse Principle):盡量採用組合(contains-a)、聚合(has-a)的方式而不是繼承(is-a)的關係來達到軟體的復用目的。合成服用原則最主要地原因是繼承會破環封裝:基類的很多內部細節都是對派生類可見的,而有些細節可能是不想讓子類知道的。關於繼承、組合還有聚合的概念可能比較容易搞混,這邊也提下。
繼承:子類擁有父類的某些屬性和方法,子類可以替換父類;
組合:是整體與部分的關係,整體離不開部分,部分離開了整體沒有意義,如飛機翅膀與飛機的關係;
聚合:也是整體與部分的關係,但整體可以分離部分,部分也可以離開整體,如火車與車廂的關係,還有就是聚合支付的列子等。
重載和重寫的區別
重載:是指在一個類裡面存在多個方法名相同,但是方法參數不同的方法。
重寫:是指子類在繼承父類時,重新改寫了父類的某個方法。子類中的這個方法的方法名和方法參數和父類中的完全一樣。
Java基礎語法
Java語言是最流行的程式語言,從剛「出生」,Java語言就號稱「一次編譯,到處運行」。
Java語言能跨平台的關鍵是JVM能跨平台,JVM屏蔽了作業系統的底層差異,讓位元組碼文件在每個平台上都可以執行。
除了Java,JVM還支援的語言有Kotlin、Groovy、JRuby、Jython、Scala等。另外,隨著Oracle對Graal虛擬機的研發,JVM平台將會支援所有的語言,包括JS和C++等語言。
進行Java開發的第一步是下載一個合適版本的JDK,然後配置JAVA_HOME這個環境變數。但是如果你只是需要運行Java程式,那你只需要安裝一個JRE即可。JDK和JRE的關係如下:
JDK包含:Java編譯器、JRE以及常用的Java類庫;
JRE包含:JVM、類載入器、位元組碼校驗器以及核心類庫等。
然後就是編譯執行Java程式
# -d後面的參數指定生成的位元組碼文件的生產路徑,默認當前目錄;
javac -d destDir HelloWorld.java;
# 執行Java程式;
# classpath的作用是提供了一系列路徑讓Java程式去在這些路徑下尋找類,找不到就報錯。在Windows上用;號分割,在Linux上用:號分隔
java -classpath %CLAss_PATH%;.;dir1;dir2 HelloWorld;
三種基本的程式結構
- 順序結構
- 選擇結構
- 循環結構
使用這三種結構能編寫出任意功能的程式。
Java中的注釋
- 單行注釋://
- 多行注釋:/**/
- 文檔注釋:/** */ 使用javadoc可以生成api文檔
Java中的關鍵字
Java中一共有48個關鍵字,2個保留字和三個直接量
- 訪問控制:private、protected、public;
- 類,方法和變數修飾符:abstract、class、extends、final、implements、interface、native、new、static、strictfp、synchronized、transient、volatile;
- 程式控制:break、continue、return、do、while、if、else、for、instanceof、switch、case、default;
- 錯誤處理:try、cathc、throw、throws、finally;
- 包相關:import、package;
- 基本類型:boolean、byte、char、double、float、int、long、short、null、true、false;
- 變數引用:super、this、void;
- 保留字:goto、const;
- 直接量:true、false、null。
重要關鍵字說明:
- native: 用來聲明一個方法是由與機器相關的語言(如C/C++/FORTRAN語言)實現的;
- strictfp:用來聲明FP-strict(雙精度或單精度浮點數)表達式;
- transient:聲明不用序列化的屬性;
- volatile:表明兩個或多個變數必須同步地發生變化。
數據類型
Java中的數據類型分為基本數據類型和引用數據類型。
1. 取值範圍
8種基本數字類型從大類上分的話分別是布爾型,字元型,整形和浮點型,對應bool,byte,char,short,int,long,float和double類型。
- byte:一個位元組,8個bit位,-2^7 ~ 2^7-1
- char : 2個位元組,16個bit位,0 ~ 2^16-1 ;
- short:2個位元組,16個bit位,-2^15 ~ 2^15-1
- int:4個位元組,32個bit位,-2^31 ~ 2^31-1
- long:8個位元組,64個bit位,-2^63 ~ 2^63-1
- float:4個位元組,32個bit位
- double:8個位元組,64個bit位。
上面的float和double都是浮點類型數據,在電腦中,浮點數用來近似表示任意某個實數。浮點數分為雙精度浮點數和單精度浮點數。單精度佔4個位元組,雙精度佔8個位元組,表示的範圍更大。
對於double和float類型的數據,正數除以0得到正無窮,負數除以0得到負無窮,0.0除以0達到NaN。但是整數除以0會得到除0異常。
在要求精確計算的場合,不建議使用浮點型數據。因為浮點數計算的結果不是很精確,是近似的結果。這種情況應該使用BigDecimal。這邊舉個BigDecimal使用的簡單列子:
BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(1.1));
BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(2.223));
String str1 = bigDecimal1.add(bigDecimal2).toString();
//減法
bigDecimal1 = new BigDecimal(String.valueOf(2.2));
bigDecimal2 = new BigDecimal(String.valueOf(10.1));
String str2 = bigDecimal1.subtract(bigDecimal2).toString();
//乘法
bigDecimal1 = new BigDecimal(String.valueOf(1.1));
bigDecimal2 = new BigDecimal(String.valueOf(2.234));
String str3 = bigDecimal1.multiply(bigDecimal2).toString();
//除法
bigDecimal1 = new BigDecimal(String.valueOf(4.4));
bigDecimal2 = new BigDecimal(String.valueOf(3));
//除法需要設置精度和四捨五入的方式
String str4 = bigDecimal1.divide(bigDecimal2,3, RoundingMode.HALF_UP).toString();
//結果
System.out.println("加法結果:" + Double.valueOf(str1));
System.out.println("減法結果:" + Double.valueOf(str2));
System.out.println("乘法結果:" + Double.valueOf(str3));
System.out.println("除法結果:" + Double.valueOf(str4));
2. 基本數據類型之間的轉換
char—————|
byte–>short–>int–>long–>float–>double
對於上面的轉換關係做下說明:char可以自動轉換成int,byte可以自動轉換成short,short可以自動轉換成int。這些轉換過程都是自動完成的。
short a = 3;
int b = a;
那麼將int賦值給short,或者將double賦值給int可不可以呢?答案是可以的,但是最後的數據可能不是我們預期的值。因為int占的位元組數比short長,short盛放不下,會做數據截取。
- 整數之間的強制轉換:比如int轉換為short會縮短位數;
- double向int轉換:會截掉小數部分。
3. 表達式類型自動提升
整個表達式的類型會提升為表達式中最高等級的類型。
short aa = 1;
//這個表達式會報錯,aa+2會自動提升為int
short bb = aa+2;
包裝類類型
包裝類型是相對於基本數據類型來講的。Java中有8種基本數據類型,每個基本數據類型都有相對的包裝類型。比如int的包裝類型是Integer。包裝類型都是是引用類型,而且都是不可變類。
關於包裝類型,有兩個概念需要我們了解:
- 自動裝箱:將基本數據類型賦值給包裝類型的過程,實現原理是編譯器層面new了一個包裝類再賦值給相應的變數(如果是是將包裝類快取過的數值賦值給包裝類的化,不會new新的包裝了,而是直接使用快取的對象);
- 自動拆箱:包裝類型直接賦值給基本數據類型,實現原理類似,也是編譯器層面調用了包裝類的getValue方法再賦值給對應的基本數值類型。
比較有趣的是,包裝類型在載入的過程中都會快取某些值的類。比如Integer會快取-128到127的類。
//不會使用快取的數據
Integer num1 = new Integer(1);
//會使用快取的數據,實際上是調用了Integer.valueOf方法
Integer num2 = 1;
通過設置-XX:AutoBoxCacheMax=?這個參數,可以調整Integer快取的最大值。當然其他包裝類型也有類似的行為,Byte、Short和Long都快取了-128到127的類,Character快取了0到127的類,但是這些類不能像Integer那樣修改快取的最大值。
關於基本數據類型和包裝類型的使用,介紹一個阿里巴巴開發規範中的原則:
所有的POJO類屬性必須使用包裝數據類型;RPC方法的返回值和參數必須使用包裝類型;所有的局部變數盡量使用基本數據類型。
定義布爾型的類變數,變數名不要以is
打頭。
Java中的值傳遞和引用傳遞
基本數據類型,保存的是數據本身的值,按值傳遞;引用類型的變數保存的是對象在記憶體中的地址,按引用傳遞(引用傳遞可以看成是一種特殊的值傳遞)。
一個問題
Java中的bool變數到底佔用多大的記憶體呢?網上的各種說法都有?歡迎大家留言討論。
公眾號推薦
歡迎大家關注我的微信公眾號「程式設計師自由之路」