3.1、Java簡介(瞭解)
Java是一門編程語言,Java發展到今天,已經成爲了一個真正意義上的語言標準,如果學習過(C、C++、Java)可以發現語法結構是很類似的,但是Java的標準指的是一種作爲應用層封裝的標準,使用Java可以調用一些底層的操作,例如,今天的Android開發,就是利用了Java調用了Linux內核操作形成的。在2003年的時候,Java成功的應用在了一枚美國的火箭上。
2001年的時候有一份報道:在美國,從事於C++的開發人員的年薪是$6.5,而從事Java開發的人員的年薪是$7W,7 * 9 =¥63W(夢想。。。),第一次在國內的報道上看到Java是1998年的時候。
如果要想追溯Java的發展,那麼首先需要從1991年的GREEN項目開始說起,這個項目當時是在email特別盛行的時候提出來的,指的是使用email去控制各個家電產品的運行(物聯網),最早SUN的工程師打算使用C++進行項目的開發,但是後來考慮到C++的複雜性,所以使用C++開發出了一個新的平臺(Java使用的是C++開發的,但是比C++更加的簡單) —— OAK(橡樹)平臺。不過遺憾的是,在與NetScape的SGL競標的時候不幸落敗(等待淘汰)。不過後來SUN的工程師們開始向網景公司學習瀏覽器技術,推出了HotJava瀏覽器(HotJava程序設計,王克宏),從而向瀏覽器技術開始發展,於是在1995年的時候正式的將OAK更名爲Java(咖啡),但是Java的歷史發展,可以歸納爲如下的幾個階段:
· 第一階段(完善期):JDK 1.0(95) ~ JDK 1.2(98);
· 第二階段(平穩期):JDK 1.3 ~ JDK 1.4;
· 第三階段(發展期):JDK 1.5(05) ~ JDK 1.7;
在1995年的時候推出了JDK 1.0、在1998年的時候推出了JDK 1.2(更名爲Java 2)、2005年的時候推出了JDK 1.5。
對於Java的製造公司 —— SUN(中文翻譯爲:太陽公司,斯坦伏大學網絡),是一家主要從事於硬件生產的公司,其中SUN最爲著名的就是它的小型機(成功的應用案例:應用在Amazon書店上),而最悲催的是 SUN的確是Java的締造者,但是真正用它賺到錢的是IBM(Websphere Studio)。而且SUN公司在2000年之後的互聯網風暴之中就再也沒有緩過勁來,於是在2009年的時候被IBM提議收購,不過沒有談成,馬上Oracle跟進,最終被Oracle以69億美金收購。
面試題:請你談一談,Oracle收購SUN公司有什麼用?
No. |
對比 |
Oracle |
Microsoft |
1 |
操作系統 |
UNIX |
Windows |
2 |
數據庫 |
Oracle大型數據庫 |
SQL Server中小型數據庫 |
3 |
中間件 |
OAS、收購了BEA得到WebLogic |
IIS |
4 |
編程語言 |
PLSQL、收購SUN得到Java |
.NET |
而一旦Oracle收購了SUN公司之後,市場上的編程語言的格局,變爲三家公司:Microsoft、Oracle、Adobe(FLEX,Flash編程),不過這幾年Adobe也比較悲慘,被Microsoft、Oracle、Apple,一起抵制Flash。
那麼從Java的開發地位而言,也分爲以下的幾個方面:
· J2SE(2005年之後更名爲JAVA SE):指的是進行桌面單機程序的開發;
· J2EE(2005年之後更名爲JAVA EE):指的是企業平臺開發;
· J2ME(2005年之後更名爲JAVA ME):進行嵌入式開發。
JAVA EE:只要是進行大型的企業項目開發,像銀行、電信等服務都會使用此架構;
JAVA ME:Nokia盛行的時候,Java的手機遊戲推廣的比較好,但是Java ME並沒有得到很好的發展,而是後來被Android所取代了,而到Android時代,可以說是真正的將Java最早的嵌入式開發的設想給做出來的,並且有了大量的遊戲和軟件出現。而Android的出現,正式的標誌着移動互聯網時代的開啓。
但是對於Android開發而言,國內現在可以做手機的人有,但是可以做整體的人很少。
Java語言的本身的特點如下:
1、 Java語言足夠簡單,相對於其他的任何語言而言,是很容易學的(入門簡單);
2、 Java避免了C/C++之中複雜的指針關係,而使用了更爲簡單的引用方式來進行內存傳遞;
3、 Java是爲數不多的支持多線程開發的編程語言;
4、 Java提供了自動的垃圾收集機制,可以定期釋放出無用的垃圾空間;
5、 Java語言的安全性較高;
6、 Java最大的特點是具備可移植性,即:同一個程序在不同的操作系統上都可以運行。
如果從編程語言的角度而言,應該分爲兩種:
· 編譯型:如果學習過C的同學應該知道,編譯之後會形成出一個*.exe的文件;
· 解釋型:像ASP語言那樣,直接將代碼放到服務器上進行解釋。
但是Java本身卻屬於兩種類型的集合,觀察圖形:
通過如上的圖形可以發現,任何一個*.java程序首先必須經過編譯,編譯之後會形成一個*.class的文件(字節碼文件),而後在電腦上執行的不是*.java,而是編譯之後的*.class文件(這個文件可以理解爲“加密”的文件),但是解釋程序的電腦並不是一臺真正意義上的電腦,而是一臺由軟件和硬件模擬出來的電腦 —— Java虛擬機。
Java虛擬機的最大作用是起到平臺的支持上,通過如上的圖形可以發現,所有要解釋的程序在JVM上執行,但是由不同版本的JVM去匹配不同的操作系統,這樣只要JVM的支持不變,程序可以任意的在不同的操作系統上運行。但是這種運行方式很明顯沒有直接運行在操作系統上性能高,不過隨着硬件技術的發展,這些問題幾乎可以忽略了。
3.2、JDK的安裝與配置(重點)
如果要進行Java的程序開發,必須有JDK的支持,JDK指的是Java的開發工具,本次使用的版本是JDK 1.7(不過在實際的開發之中,可能JDK 1.5還是主流使用版本),可以直接登錄www.oracle.com(www.sun.com)上進行下載。
在進行JDK的安裝之前,建議關閉本機的病毒防火牆。
爲了日後的方便維護,所以將JDK安裝到:d:\java目錄下。
安裝JDK的過程之中還提示是否安裝JRE(Java運行時解釋),主要的功能是解釋*.class程序的,此處的安裝目的是要更新本機的JRE版本,不過JDK本身是可以解釋程序的。
安裝完成之後會出現以下的提示信息。
對於Java程序開發而言,主要會使用JDK的兩個命令:javac.exe、java.exe。路徑:D:\Java\jdk 1.7.0 _09\bin。但是這些命令由於不屬於windows自己的命令,所以要想使用,就需要進行路徑配置。
配置步驟:【我的電腦】 è 【屬性】 è 【高級】 è 【環境變量】 è 【添加新的PATH】,不同的PATH之間使用“;”分隔,修改如下:
3.3、第一個Java程序:永遠的“Hello World !”(重點)
第一個要測試的程序永遠從“Hello World !”開始,Java程序的文件後綴必須是*.java。
範例:定義一個新的文件:Hello.java
public class Hello { public static void main(String args[]) { System.out.println("Hello World !") ; } } |
當一個*.java程序編寫完成之後,可以按照如下的步驟執行:
· 編譯程序,通過命令行進入到程序所在的路徑,執行:javac Hello.java,形成“Hello.class”(字節碼);
· 解釋程序,對生成的Hello.class在JVM上執行,輸入:java Hello。
在正常的情況下,本程序已經可以執行了,但是現在發現出現瞭如下的錯誤提示:
Exception in thread "main" java.lang.UnsupportedClassVersionError: Hello (Unsupported major.minor version 51.0) |
直接提示“UnsupportedClassVersionError”(不支持的類版本錯誤),現在編譯的時候使用的是JDK 1.7,那麼解釋的時候也應該JDK 1.7,那麼來驗證一下當前的JRE版本,輸入:java -version,信息如下:
java version " 1.4.2 _03" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2 _03-b02) Java HotSpot(TM) Client VM (build 1.4.2 _03-b02, mixed mode) |
發現現在解釋程序的版本是JRE 1.4,因爲Oracle 10g 安裝之後,本身就默認提供了JDK,而這個JDK在path中的配置如下:
D:\oracle\product\ 10.1.0 \db_1\jre\1.4.2\bin\client; D:\oracle\product\ 10.1.0 \db_1\jre\1.4.2\bin; |
那麼現在有兩種解決方法:
· 方法一:刪除掉Oracle的所有JRE配置,太殘忍了;
· 方法二:由於path的內容採用的是順序讀取方式,可以將新的配置寫在最前面,修改PATH:
3.4、第一個程序解釋(重點)
第一個程序編寫完成之後,下面來對此程序的組成進行說明:
1、 關於類的定義:
所有的java程序一定要被類所管理,那麼定義類的格式如下:
[public] class 類名稱 {} |
對於類的定義現在就有了兩種形式:
· public class定義:類名稱必須和文件名稱保持一致,在一個*.java之中只能有一個public class;
· class定義:類名稱可以和文件名稱不一致,但是生成的是class定義的名稱,在一個*.java程序之中可以同時存在多個class的定義,編譯之後會分爲不同的*.class文件;
額外聲明:
· 在講課過程之中爲了方便理解,所以在一個*.java程序之中會同時存在public class和class定義的類,而在日後的自己編寫的代碼過程之中,一個*.java文件之中基本上都只包含一個public class,不會有其他class單獨定義;
· 所有類名稱必須有自己的命名規範,每一個單詞的開頭首字母大寫,例如:TestDemo;
2、 主方法
主方法表示的是一個程序起點,要放在一個類之中,主方法定義格式如下:
public static void main(String args[]) {} |
這些字母的組成是完全固定的,今天先記住,以後進行完整的講解。
額外聲明:日後主方法所在的類都將其稱爲主類,一般主類都使用public class聲明。
今天的所有程序都在主類之中編寫,而至於類是什麼,以後再介紹。
3、 系統輸出
可以直接在屏幕上顯示輸出信息,操作語法:
輸出後加換行: |
System.out.println(輸出內容) ; |
輸出後不加換行: |
System.out.print(輸出內容) ; |
3.5、classpath(重點)
如果說現在要想執行某一個java程序,那麼一定要進入到程序所在的路徑下纔可以執行,例如:現在程序的路徑是在d:\testjava文件夾之中,如果要想執行這個文件夾之中的所有的*.class文件,則需要進入到此目錄下執行,那麼如果現在希望在不同的目錄下也可以執行呢?那麼會直接提示用戶,找不到這個類。那麼現在非要執行的話,則必須配置CLASSPATH,配置語法如下:
SET CLASSPATH=*.class文件所在的路徑 |
範例:將CLASSPATH配置到d:\testjava目錄之中
SET CLASSPATH=d:\testjava |
此時,再次執行“java Hello”命令,發現程序可以正常的執行完畢。而通過這個演示也可以得出一個結論:當使用java命令執行一個類的時候,會首先通過CLASSPATH找到指定的路徑,而後在此路徑下加載所需要的*.class文件。
但是,如果像本程序這樣,到處亂指CLASSPATH也是不可能的,最好的做法還是從當前所在的路徑下加載所需要的*.class文件比較合適,那麼這個時候往往將CLASSPATH設置爲“.”。(回到本地硬盤設置纔有效)
SET CLASSPATH=. |
這個“.”也屬於默認的配置,之所以要強調“.”的問題主要原因是在於,日後可能有一些其他的程序自動的修改本機的CLASSPATH,那麼這個時候只能依靠手工配置,不過以上的配置方式都只是針對於一個命令行完成的,如果要針對於所有的命令行方式完成,則就需要增加一個新的環境屬性。
配置步驟:【我的電腦】 è 【屬性】 è 【高級】 è 【環境變量】 è 【新建】 è 【輸入屬性的名稱和內容】
面試題:請解釋PATH和CLASSPATH的區別?
· PATH:是操作系統的環境屬性,指的是可以執行命令的程序路徑;
3.6、標識符和關鍵字(重點)
在程序之中用於定義名稱的都表示標識符,例如:類的名稱、方法名稱或變量名稱等等,在java之中的標識符的定義格式:由字母、數字、_、$所組成,其中不能以數字開頭,不能是Java中的保留字。
但是在這裏面需要提示的是,所有的標識符之中用戶不要去使用“$”定義,而且標識符一定要有自身的意義,不要隨意起名稱,一般都建議使用英文字母組成,例如:studetName,但是在定義變量(標識符)或方法的時候也有一個明確的要求:第一個單詞的首字母小寫,之後每個單詞的首字母大寫,例如:studentName。而在定義類名稱的時候(標識符),每一個單詞的首字母大寫,例如:TestDemo。
關鍵字也被稱爲保留字,指的是一些有特殊含義的內容,在定義標識符的時候不能夠去使用,而Java之中的保留字定義如下:
一共有49個關鍵字,但是嚴格來講,這些關鍵有如下幾個說明:
· 未使用到的關鍵字:goto(無條件跳轉)、const(定義常量);
· 有特殊含義的標記(嚴格來講不算關鍵字):true、false、null;
· JDK 1.4之後引入的新關鍵字:assert;
· JDK 1.5之後引入的新關鍵字:enum。
3.7、數據類型(重點)
任何一門語言都是由若干種不同的數據類型所組成,在java之中數據類型一共分爲兩類:
· 基本數據類型(數值操作): 默認值
|- 數值型:
|- 整型:byte、short、int、long; è 0
|- 浮點型:float、double; è 0.0
|- 字符型:char; è '\u0000'
|- 布爾型:boolean; è false
· 引用數據類型(內存操作):
|- 數組、類、接口; è null
今天主要講解基本類型的數據,而且每種基本數據類型也都有其自己的保存數據範圍,這些範圍如下。
· byte的數據長度是8位,-128 ~ 127;
· int數據的長度爲32位,-2147483648 ~ 2147483647;
· double可以保存的數據範圍是最大的。
但是對於以上給出的基本數據類型的定義,如果從實際的開發角度上,以下的幾種類型最爲常用:
· int型:只要是看見了整型的定義,其類型都是int;
· double型:只要是看見了小數的定義,其類型都是double;
· byte型:日後進行數據傳輸的時候使用此類型,講解到IO,和編碼轉換的操作上使用;
· boolean:用於程序的邏輯操作使用;
· long:表示日期時間、表示文件長度的時候。
3.7.1 、整型
整型就表示一個基本的整數,可以直接使用int定義,而且在java之中默認的一個整數,其類型就是int。
public class Hello { public static void main(String args[]) { int x = 10 ; // 10是一個整數,就屬於int型 int result = x * 2 ; // int型 * int型 = int型 System.out.println(result) ; } } |
但是,對於以上的操作代碼,下面有兩點說明:
· 說明一:請保持良好的編程習慣,在每一個操作之中都加上一個“ ”。
· 說明二:所有的變量在使用之前一定要爲其賦予默認值。
範例:錯誤的操作
public class Hello { public static void main(String args[]) { int x ; // 按照道理來講,x是int型,沒有賦值,結果應該是0 System.out.println(x) ; } } |
因爲x變量只定義了而未被初始化,修改程序:
public class Hello { public static void main(String args[]) { int x ; // 按照道理來講,x是int型,沒有賦值,結果應該是0 x = 10 ; // 在使用之前爲x變量賦值 System.out.println(x) ; } } |
但是這種代碼的成功編譯只能針對於JDK 1.5之上的版本完成,而在JDK 1.4之前,以上的代碼是錯誤的,是不能使用的,所以爲了防止這種版本的差異,明確給出要求:所有的變量一定要在其定義的時候直接賦值。
public class Hello { public static void main(String args[]) { int x = 10 ; // 定義變量給出默認值 System.out.println(x) ; } } |
int型數據本身也是有自己的保存範圍的,那麼如果說現在操作的數據已經超過了其int的範圍呢?
爲了方便驗證,下面給出兩個操作,這兩個操作日後講解,可以通過它得出int的最大值和最小值:
· 取得int的最大值:Integer.MAX_VALUE;
· 取得int的最小值:Integer.MIN_VALUE。
範例:極限操作
public class Hello { public static void main(String args[]) { int max = Integer.MAX_VALUE ; // 最大值 int min = Integer.MIN_VALUE ; // 最小值 System.out.println(max) ; // 複製當前行代碼:CTRL + J System.out.println(min) ; // 最大值 + 1 = 最小值、最小值 - 1 = 最大值 System.out.println(max + 1) ; // int型 + int型 = int型,-2147483648 System.out.println(max + 2) ; // int型 + int型 = int型,-2147483647 System.out.println(min - 1) ; // int型 - int型 = int型,2147483647 } } |
這個地方就好象出現了一個循環的操作,這種情況在程序上稱爲數據的溢出,而要想解決這種數據溢出的主要方法就可以通過擴大數據範圍來完成,比int大的範圍是long,所以現在有如下的兩種方式完成:數字L、(long)數字。
public class Hello { public static void main(String args[]) { int max = Integer.MAX_VALUE ; // 最大值 int min = Integer.MIN_VALUE ; // 最小值 System.out.println(max) ; // 複製當前行代碼:CTRL + J System.out.println(min) ; // 最大值 + 1 = 最小值、最小值 - 1 = 最大值 System.out.println(max + 1L ) ; // int型 + long型 = long型,2147483648 System.out.println(min - (long) 1) ; // int型 - long型 = long型,-2147483649 } } |
所有的程序的操作之中的數據類型轉換:
· 如果小範圍和大範圍操作,小範圍自動變爲大範圍,例如:int + long = long;
· 如果現在把表示範圍大的數據變成表示範圍小的數據,則必須強制完成,例如:int型 = (int) long型;
當然,下面再通過一個簡單的代碼進一步說明轉性的操作。
public class Hello { public static void main(String args[]) { int x = 10 ; // int型數據 long y = x ; // int變爲long型 long result = x * y ; // int * long = long ; int temp = (int) result ; // long --> int,強制轉換 System.out.println(temp) ; } } |
另外還需要強調的是byte型數據,這個表示的是字節的定義。此類型的範圍是:-128 ~ 127之間。
public class Hello { public static void main(String args[]) { int x = 200 ; // 超過了byte範圍 byte b = (byte) x ; // 強制轉換,溢出數據 System.out.println(b) ; } } |
可是,說到byte型數據,額外提醒一下,有一個問題,算是一個特殊支持:
public class Hello { public static void main(String args[]) { byte b = 20 ; // 20是int型 System.out.println(b) ; } } |
在爲byte類型賦值的時候,如果其給出的數據範圍在byte範圍之中,則自動的將int變爲byte型數據,當然這種操作只是在直接賦值的情況下完成。
3.7.2 、浮點型
浮點型指的是小數,在java之中,默認的一個小數實際上對應的類型就是double型數據。
public class Hello { public static void main(String args[]) { double x = 10.02 ; // 定義浮點型數據 System.out.println(x * x) ; } } |
這個時候的計算結果爲:“ 100.40039999999999” 。按照數學的角度,肯定結果不正確,但是這個結果是由於JVM本身的bug所決定。
而在浮點型數據之中,實際上也分爲兩種:double、float,float的範圍要小於double的範圍,那麼既然默認的小數屬於double型數據,如果要爲float賦值呢?必須強制轉換,而轉換的方式:數字F、(float)數字;
public class Hello { public static void main(String args[]) { float x = 10.02F ; // double --> float float y = (float) 10.02 ; // double --> float System.out.println(x * y) ; } } |
但是需要說明的是,整型數據也可以自動的向浮點型轉換。
public class Hello { public static void main(String args[]) { int x = 10 ; double y = x ; // int --> double System.out.println(y * x) ; // double * int = double } } |
一般在進行數學計算的時候,需要將一些數據變爲浮點型,例如:以下的計算:
public class Hello { public static void main(String args[]) { System.out.println(9 / 2) ; // 4 } } |
這個時候的結果是4,但是實際上的結果應該是4.5,因爲現在的計算都是兩個整型數據完成的,所以其計算結果也一定還是int,int不包含小數位,所以小數位如果存在則直接取消,如果要想得出正確的結果,則需要將其中的一個數據變爲double或float即可。
public class Hello { public static void main(String args[]) { System.out.println(9 / (double)2) ; // int / double = double } } |
以後定義變量的時候,是整型就使用int定義,是小數就使用double進行定義。而且所有數據的轉型:
· 自動轉型(由小到大):byte è short è int è long è float è double;
· 強制轉型(由大到小):double è float è long è int è short è byte。
至於說到底使用到何種的轉換,我個人的認爲是幾乎不要去轉換,只需要表示出該有的數據即可。例如,定義年齡肯定是int型數據,定義成績是double(能使用double就使用double,不要用float)型數據。
3.7.3 、字符型
在Java之中使用單引好“'”定義的內容就表示一個字符,例如:'A'、'B',那麼定義字符的時候類型使用char完成。
在各個語言之中,char和int之間是可以互相轉換的,在C語言之中轉換的編碼是ASC II碼,當時的編碼範圍:
· 大寫字母範圍:65 ~ 90;
· 小寫字母範圍:97 ~ 122。
大寫字母和小寫字母之間查了32。
範例:定義字符
public class Hello { public static void main(String args[]) { char c = 'A' ; // 定義一個字符 int x = c ; // char --> int x += 32 ; // 變爲小寫編碼 char temp = (char) x ; // int --> char System.out.println(temp) ; } } |
但是需要提醒的是,Java在定義字符的時候所使用的並不是ASC II碼,而是UNICODE編碼,這是一種使用十六進制定義的編碼,可以表示出任意的文字,這就包含了中文定義。
public class Hello { public static void main(String args[]) { char c = '張' ; // 定義一個字符,23452 int x = c ; // char --> int System.out.println(x) ; } } |
UNICODE設計的時候包含了所有的ASC碼,所以有一部分的編碼是完全和ASC II碼重複的,但是也有許多是不重複的編碼。
3.7.4 、布爾型
布爾型主要表示的是一種邏輯的判斷,其中布爾是一個數學家的名字,而布爾型數據只有兩種取值:true、false。
public class Hello { public static void main(String args[]) { boolean flag = true ; // 定義布爾型數據 // if語句判斷的就是布爾型數據 if (flag) { // flag == true System.out.println("Hello World .") ; } } } |
但是需要提醒的是,在許多的語言之中,布爾型也使用0(false)或非0(true)來表示,不過此概念在Java之中無效,只有true和false兩個內容。
3.7.5 、初見String
String本身不屬於Java的基本數據類型,因爲它屬於一個類(引用型數據),但是這個類使用起來可以像基本數據類型那樣方便的操作,而且也使用很多,只要是開發都會存在字符串,字符串是使用“"”定義的一串數據。
在字符串之中可以使用“+”進行字符串的連接操作。
範例:定義字符串
public class Hello { public static void main(String args[]) { String str = "Hello " ; // 定義字符串 str += " World " ; // 字符串連接 str = str + "!!!" ; // 字符串連接 System.out.println(str) ; } } |
但是在使用字符串的過程之中,也需要注意一點,在char類型之中實際上除了定義單個字符之外,也存在了一組轉義字符:\\(單個\)、\t(表示按下了tab鍵)、\n(換行)、\"、\'。
public class Hello { public static void main(String args[]) { String str = "\"Hello World !!!\"\n\tHello MLDN\\" ; // 定義字符串 System.out.println(str) ; } } |
在講課的過程之中,這些符號還是會出現的。
範例:觀察以下程序的運行結果
public class Hello { public static void main(String args[]) { double x = 10.2 ; int y = 20 ; String result = "加法計算結果:" + ( x + y ) ; System.out.println(result) ; } } |
3.8、運算符(重點)
+、-、*、/都屬於運算符,在Java之中運算符太多了。並且這些運算符之間是存在着優先級的,可是正常人,真的不怎麼背它。但是在現實之中比較無奈的事,以下的代碼會經常出現。
public class Hello { public static void main(String args[]) { int x = 10 ; int y = 20 ; int result = ++ x * y -- / y * 10 + ++x * -- y ; System.out.println(result) ; } } |
以上的程序本人絕對不會分析,一般國家的計算機等級考試都這些爛玩意。如果非要有人寫,你可以心裏把這個人的祖宗十八代一代代的使勁罵,包括這個人可能產生的後代也要狠狠的罵,譬如:孩子沒屁眼。
3.8.1 、三目運算符
三目運算是一種賦值運算符,其語法格式如下:
數據類型 變量 = 布爾表達式?滿足條件設置的內容:不滿足條件設置的內容 ; |
範例:將兩個int型數據大的數值賦值給變量
public class Hello { public static void main(String args[]) { int x = 10 ; int y = 20 ; int result = x > y ? x : y ; System.out.println(result) ; } } |
當然,對於這樣的計算,也可以通過if…else完成。
public class Hello { public static void main(String args[]) { int x = 10 ; int y = 20 ; int result = 0 ; // 定義變量,保存結果 if (x > y) { result = x ; } else { result = y ; } System.out.println(result) ; } } |
這樣的三目運算,在日後從事的開發之中,一定會出現,最近的出現時間斷:4周之後。
3.8.2 、邏輯運算符
邏輯運算一共包含三種:與(多個條件一起滿足)、或(多個條件有一個滿足)、非(true變false,false變true)。
1、 與操作:表示將若干個條件一起進行連接判斷,同時滿足返回true,有一個不滿足返回false,對於與操作有兩種運算符:&、&&。
範例:普通與操作,&
public class Hello { public static void main(String args[]) { if (1 == 2 & 10 / 0 == 0) { System.out.println("條件滿足。") ; } } } |
此時程序出現了錯誤,而這個錯誤是由“10 / 0 == 0” 造成的,那麼證明所有的條件都進行了驗證,但是與操作的特點是屬於 —— 有一個條件不滿足,結果就是false,那麼如果前面已經存在了不滿足條件的運算,後面不管有多少個滿足的條件,其結果都是false,那麼就真的沒有必要進行判斷了,這個時候可以換一個符號 —— 短路與;
範例:短路與操作,&&
public class Hello { public static void main(String args[]) { if (1 == 2 && 10 / 0 == 0) { System.out.println("條件滿足。") ; } } } |
因爲前面的條件(1 == 2)的結果是false,那麼後面的就沒有必要再繼續進行判斷了,最終的結果就是false。
2、 或操作:若干個條件一起判斷,其中只要有一個返回true,結果就是true,只有都返回false的時候結果纔是false,或操作有兩種運算:|、||
範例:普通或操作,|
public class Hello { public static void main(String args[]) { if (1 == 1 | 10 / 0 == 0) { System.out.println("條件滿足。") ; } } } |
使用普通或操作的過程之中,發現即使前面的條件滿足了,後面的也進行正常的判斷,但是後面的判斷似乎沒有任何的意義,因爲不管返回是何種結果都不會影響最終的結果就是true。
範例:短路或操作,||
public class Hello { public static void main(String args[]) { if (1 == 1 || 10 / 0 == 0) { System.out.println("條件滿足。") ; } } } |
可以發現,前面的條件(1 == 1)滿足了就會返回true,那麼不管後面是何條件最終的結果都是true。
3.8.3 、位運算符(瞭解)
位運算在Java之中存在:&、|、^、~、>>、<<、>>>,但是如果要想進行位運算之前,那麼首先必須先知道如何將十進制數據變爲二進制數據,原則:數據除2取餘,最後倒着排列,例如,下面演示一個操作。
19 è 十進制 , 00000000 00000000 00000000 0010011
÷ 2
9 …… 1 ↑
÷ 2
4 …… 1 ↑
÷ 2
2 …… 0 ↑
÷ 2
1 …… 0 ↑
÷ 2
0 …… 1 ↑
範例:觀察位與運算
public class Hello { public static void main(String args[]) { int x = 19 ; int y = 20 ; System.out.println(x & y) ; } } |
19的二進制數據: 00000000 00000000 00000000 0010011
20的二進制數據: 00000000 00000000 00000000 0010100
&的結果: 00000000 00000000 00000000 0010000 è 16
範例:觀察或操作
public class Hello { public static void main(String args[]) { int x = 19 ; int y = 20 ; System.out.println(x | y) ; } } |
19的二進制數據: 00000000 00000000 00000000 0010011
20的二進制數據: 00000000 00000000 00000000 0010100
|結果: 00000000 00000000 00000000 0010111 è 23
public class Hello { public static void main(String args[]) { int x = 19 ; System.out.println(x >>> 2) ; } } |
19的二進制數據: 00000000 00000000 00000000 0010011
向右邊移位: 00000000 00000000 00000000 0000100 è 4
面試題:請問如何可以更快的計算出2的3次方
向左邊移位2位。
public class Hello { public static void main(String args[]) { int x = 2 ; System.out.println(x << 2) ; } } |
2到二進制數據: 00000000 00000000 00000000 00000010;
向左邊移位: 00000000 00000000 00000000 00001000; è 8
面試題:請解釋&和&&、|和||的區別?
· 邏輯運算上:
|- &:表示普通與,所有的判斷條件都要依次執行;
|- &&:表示短路與,若干個條件,如果前面的條件返回了false,那麼後面的不再判斷,結果就是false;
|- |:表示普通或,所有的判斷條件都要依次執行;
|- ||:表示短路或,若干個條件,如果前面的條件返回了true,後面的不再判斷,結果就是true。
· 位運算:&表示位與計算、|表示位或的計算。
3.9、程序結構(重點)
程序結構在語言之中一共分爲三種:順序結構、選擇結構、循環結構。
3.9.1 、順序結構
所有的代碼按照先後的順序依次進行執行,例如,如下代碼:
public class Hello { public static void main(String args[]) { int x = 2 ; x = x + 2 ; System.out.println(x) ; } } |
3.9.2 、分支結構(選擇結構)
就相當於提供了一些條件判斷,根據判斷的結果來選擇執行何種操作,對於分支結構主要操作語法:if、if..else、if..else if…else,這三種結構的完整語法如下:
if語法: |
if…else語法: |
if…else if…else語法: |
if (布爾表達式) { 條件滿足時執行的程序 ; } |
if (布爾表達式) { 條件滿足時執行的程序 ; } else { 條件不滿足時執行的程序 ; } |
if (布爾表達式1) { 條件滿足時執行的程序 ; } else if (布爾表達式2) { 條件滿足時執行的程序 ; } ... else { 所有條件都不滿足時執行的程序 ; } |
範例:if語句
public class Hello { public static void main(String args[]) { int age = 16 ; if (age < 18) { System.out.println("少兒不宜觀看。") ; } } } |
範例:if..else語句
public class Hello { public static void main(String args[]) { int age = 26 ; if (age < 18) { System.out.println("少兒不宜觀看。") ; } else { System.out.println("青年觀看的教育片。") ; } } } |
範例:if…else if…else操作
public class Hello { public static void main(String args[]) { int age = 260 ; if (age <= 18) { System.out.println("您屬於青少年。") ; } else if (age > 18 && age <= 50) { System.out.println("您屬於青狀年。") ; } else if (age > 50 && age <250) { System.out.println("您屬於老年。") ; } else { System.out.println("妖怪,您不是人。") ; } } } |
但是對於多條件判斷使用if..else if…else是可以判斷布爾條件的,如果是多數值判斷,可以通過switch完成,語法:
switch (判斷值) { case 數值1: 滿足此數值時執行的語句 ; [break ;] case 數值2: 滿足此數值時執行的語句 ; [break ;] case 數值3: 滿足此數值時執行的語句 ; [break ;] ... default: 所有條件都不滿足時執行的語句 ; [break ;] } |
對於switch操作,在最早主要使用的是整型或者是字符來完成。
public class Hello { public static void main(String args[]) { int ch = 0 ; switch(ch) { case 0 : System.out.println("數值是0。") ; break ; case 1 : System.out.println("數值是1。") ; break ; case 2 : System.out.println("數值是2。") ; break ; default : System.out.println("沒有條件滿足。") ; break ; } } } |
但是對於switch隨着版本的不同,也有所更改,JDK 1.5之後也可以利用枚舉作爲判斷條件,而JDK 1.7之後,switch裏面也可以判斷字符串了(String),這個可以理解爲JDK 1.7才支持的新功能。
public class Hello { public static void main(String args[]) { String str = "two" ; switch(str) { case "one" : System.out.println("壹") ; break ; case "two" : System.out.println("貳") ; break ; case "three" : System.out.println("叄") ; break ; default : System.out.println("沒有") ; break ; } } } |
3.9.3 、循環結構
循環的概念主要指的是某一塊代碼可以被重複執行多次。而循環的操作,分爲兩種語法:while循環、for循環。
1、 while循環:
do…while(98%不會看見使用): |
while(布爾表達式): |
do { 循環體 ; 循環條件修改 ; } while (循環判斷) ; |
while (循環判斷) { 循環體 ; 循環條件修改 ; } |
通過這樣的語法就可以發現,實際上do..while表示先執行後判斷,而while循環表示先判斷後執行,如果循環條件都不滿足的情況下,do..while至少執行一次,而while一次都不會執行。
通過以上給出的兩個格式,應該可以發現出循環結構的特點:
· 循環的結束判斷;
· 每次循環體執行的時候,循環條件要求修改。
範例:使用while兩種循環實現1 ~ 100的累加
do…while: |
while(布爾表達式): |
public class Hello { public static void main(String args[]) { int sum = 0 ; // 保存累加的結果 int x = 1 ; // 進行結束的判斷 do { sum += x ; // 累加 x ++ ; // x自增長 } while (x <= 100) ; // 滿足則繼續執行 System.out.println(sum) ; } } |
public class Hello { public static void main(String args[]) { int sum = 0 ; // 保存累加的結果 int x = 1 ; // 進行結束的判斷 while (x <= 100) { sum += x ; // 累加 x ++ ; // x自增長 } System.out.println(sum) ; } } |
2、 for循環:
for循環的最大特點是已經明確的知道了循環次數,for循環的語法如下:
for (循環的初始值 ; 循環的判斷條件 ; 循環條件的修改) { 循環體 ; } |
範例:實現1 ~ 100的累加
推薦作法: |
不推薦作法: |
public class Hello { public static void main(String args[]) { int sum = 0 ; // 保存累加的結果 for (int x = 1 ; x <= 100 ; x ++) { sum += x ; } System.out.println(sum) ; } } |
public class Hello { public static void main(String args[]) { int sum = 0 ; // 保存累加的結果 int x = 1 ; // 初始值 for ( ; x <= 100 ; ) { sum += x ; x ++ ; // 循環條件修改 } System.out.println(sum) ; } } |
個人總結,關於循環的出現情況:
· while循環:在不確定循環次數,但是確定循環結束條件的情況下使用;
· for循環:確定循環次數的情況下使用。
對於循環而言,也可以進行循環的嵌套操作。
範例:輸出一個乘法口訣表,需要兩層循環
public class Hello { public static void main(String args[]) { for (int x = 1 ; x <= 9 ; x ++) { // 控制循環行 for (int y = 1; y <= x ; y ++ ) { System.out.print(x + "*" + y + "=" + x * y + "\t") ; } System.out.println() ; // 換行 } } } |
範例:打印三角型
public class Hello { public static void main(String args[]) { int line = 9 ; // 打印9行 for (int x = 0 ; x < 9 ; x ++) { // 循環次數,控制行 for (int y = 0 ; y < line - x ; y ++) { System.out.print(" ") ; } for (int y = 0 ; y <= x ; y ++) { System.out.print("* ") ; } System.out.println() ; } } } |
3.10、方法(重點)
如果說之前的所有語法和各個語言類似,那麼現在的方法就稍微特殊一些了。
3.10.1 、方法的基本定義
方法在很多地方又被稱爲函數(Java之中的英文單詞是Method,而其他語言之中的英文單詞是Function),方法是一段可以被重複調用代碼塊。但是需要說明的是,今天所講解的方法,本身是在主類之中定義的,並且由主方法調用的。所以方法的定義格式爲:
public static 返回值類型 方法名稱 (參數列表) { [return [返回值] ;] } |
對於返回值類型有兩種:
· void:表示此方法沒有返回值;
· 數據類型:基本類型和引用類型。
範例:定義一個無參的無返回值的方法
public class Hello { public static void main(String args[]) { printInfo() ; // 主方法之中直接調用 printInfo() ; // 主方法之中直接調用 printInfo() ; // 主方法之中直接調用 } public static void printInfo() { // 方法名稱 System.out.println("*******************") ; System.out.println("* Hello World *") ; System.out.println("*******************") ; } } |
方法名稱的命名要求|:第一個單詞的首字母小寫,之後每個單詞的首字母大寫,例如:printInfo()。
範例:定義一個有參的,無返回值方法,例如:將之前打印三角形程序定義唯一個方法,每次只需要傳入打印的行即可。
public class Hello { public static void main(String args[]) { printInfo(3) ; // 主方法之中直接調用 printInfo(5) ; // 主方法之中直接調用 printInfo(9) ; // 主方法之中直接調用 } public static void printInfo(int line) { // 方法名稱 for (int x = 0 ; x < line ; x ++) { // 循環次數,控制行 for (int y = 0 ; y < line - x ; y ++) { System.out.print(" ") ; } for (int y = 0 ; y <= x ; y ++) { System.out.print("* ") ; } System.out.println() ; } } } |
方法負責完成某一特定功能,而後用戶就可以根據方法定義的格式進行方法的調用。
範例:定義一個有參有返回值的方法
· 定義一個方法,用於判斷一個數字是奇數還是偶數。很明顯,這個方法的返回值類型應該定義爲boolean比較合適,而且如果一個方法上返回的是boolean型數據,則這個方法的名稱應該以isXxx()的形式命名。
public class Hello { public static void main(String args[]) { if (isType(3)) { System.out.println("偶數") ; } else { System.out.println("奇數") ; } } // true表示是偶數,false表示爲奇數 public static boolean isType(int num) { return num % 2 == 0; } } |
講解到方法的時候需要額外強調一點,如果一個方法使用了void聲明,理論上此方法不能夠返回數據,但是這個方法卻可以通過return結束調用(即:return之後的程序不再執行)。
public class Hello { public static void main(String args[]) { fun(10) ; fun(30) ; } public static void fun(int num) { if (num == 10) { return ; // 結束方法調用 } System.out.println("數值:" + num) ; } } |
而這一結束的操作和循環控制的break與continue是一樣的。
· break:表示的是退出整個循環;
· continue:表示的是退出一次循環;
break控制: |
continue控制: |
public class Hello { public static void main(String args[]) { for (int x = 0 ; x < 10 ; x ++) { if (x == 3) { break ; } System.out.println(x) ; } } } |
public class Hello { public static void main(String args[]) { for (int x = 0 ; x < 10 ; x ++) { if (x == 3) { continue ; } System.out.println(x) ; } } } |
這三種操作都離不開if語句判斷,只要是結束的操作都肯定需要使用if判斷。
3.10.2 、方法的重載(重點)
在講解重載操作之前,首先完成這樣的一種定義,要求定義方法,此方法可以完成兩個整數的相加,或者是兩個小數的相加,或者是三個整數的相加,那麼如果按照習慣性的思路,現在一定要定義三個方法,可能方法就編寫如下了:
public class Hello { public static void main(String args[]) { System.out.println("兩個整型相加:" + add1(10,20)) ; System.out.println("三個整型相加:" + add2(10,20,30)) ; System.out.println("兩個浮點型相加:" + add3(10.2,20.3)) ; } public static int add1(int x,int y) { return x + y ; } public static int add2(int x,int y,int z) { return x + y + z ; } public static double add3(double x,double y) { return x + y ; } } |
現在已經成功的完成了代碼的調用,但是如果按照這種思路,現在有1000種這樣的增加方法,這個時候調用起來就很麻煩,還要首先區分出方法的編號是多少,這種不合適的操作一定不是我們所使用的。
在這種情況下可以使用方法的重載(Overloading)來解決問題,方法重載指的是方法名稱相同,參數的類型或個數不同,調用的時候將會按照傳遞的參數類型和個數完成不同的方法體的執行。
public class Hello { public static void main(String args[]) { System.out.println("兩個整型相加:" + add(10,20)) ; System.out.println("三個整型相加:" + add(10,20,30)) ; System.out.println("兩個浮點型相加:" + add(10.2,20.3)) ; } public static int add(int x,int y) { return x + y ; } public static int add(int x,int y,int z) { return x + y + z ; } public static double add(double x,double y) { return x + y ; } } |
它是自動的根據參數的類型和個數的不同調用不同的方法體進行執行。
但是討論一下,以下的代碼屬於方法重載嗎?
public class Hello { public static void main(String args[]) { System.out.println("兩個整型相加:" + add(10,20)) ; System.out.println("兩個浮點型相加:" + add(10,20)) ; } public static int add(int x,int y) { return x + y ; } public static double add(int x,int y) { // 返回值不同 return x + y ; } } |
可以發現,這個時候除了方法的返回值類型不一樣之外,方法的參數類型及個數完全相同,所以這種操作不符合於方法重載的定義。
額外提醒:
方法重載的時候並沒有規定出返回值類型必須統一,即:重載的方法返回值類型可以不一樣,但是從開發的角度而言,建議所有方法重載之後返回值類型統一,但是這種規則不是死的,至少在我們自己編寫的代碼之中,80%的情況下可以滿足。
範例:繼續觀察如下代碼
public class Hello { public static void main(String args[]) { System.out.println("Hello World") ; // 輸出String System.out.println(100) ; // 輸出int System.out.println(3000.9) ; // 輸出double System.out.println('A') ; // 輸出char System.out.println(true) ; // 輸出boolean } } |
所以,可以得出一個結論:System.out.println()實際上就是進行了方法的重載。
3.10.3 、遞歸調用(瞭解)
遞歸操作指的是方法自己調用自己的形式,但是在進行遞歸操作的時候必須滿足如下的幾個條件:
· 必須有結束條件;
· 每次調用的時候都需要改變傳遞的參數。
範例:完成一個1 ~ 100的累加
public class Hello { public static void main(String args[]) { int sum = 0 ; int x = 1 ; while( x <= 100 ) { sum += x ; x ++ ; } System.out.println(sum) ; } } |
幾乎所有的while循環都可以改變爲遞歸操作。
範例:遞歸操作
public class Hello { public static void main(String args[]) { System.out.println(add(100)) ; } public static int add(int num) { if (num == 1) { // 結束條件 return 1 ; // 不再向後繼續加了 } return num + add(num - 1) ; // 修改參數內容 } // 第1次調用:return 100 + add(99); // 第2次調用:return 100 + 99 + add(98); // 倒數第2次調用:return 100 + 99 + ... + 3 + add(2) ; // 最後一次調用:return 100 + 99 + ... + 3 + 2 + 1 ; } |
對於遞歸操作,現在只要求可以理解這個含義即可,而在實際的工作之中,遞歸儘量少去使用,因爲使用不當,就可能造成內存溢出。