畢向東Java筆記(全部)

第一章 Java概述


基礎常識


軟件開發

  • 什麼是軟件?
    • 軟件:一系列按照特定順序組織的計算機數據和指令的集合。
    • 常見的軟件:
      • 系統軟件:
        • 如DOS、windows、Linux等。
      • 應用軟件:
        • QQ、迅雷等。
    • 什麼是開發?
      • 製作軟件

人機交互

  • 軟件的出現實現了人與計算機之間的更好交互。
  • 交互方式:
    • 圖形化界面:這種方式簡單直觀,使用者已於接收,容易上手操作。
    • 命令行方式:需要有一個控制檯,輸入特定的指令,讓計算機完成一些操作。較爲麻煩,需要記錄住一些命令。

命令行方式

在DOS裏新建文件
copy con Demo.java
class Demo{
	public static void main(String[] args){
		System.out.println("Hello Java");
	}
}
Ctrl+Z 保存
type Demo.java
編譯運行:
javac Demo.java
java Demo

dir 列出當前目錄下的文件以及文件夾
md 創建目錄
rd 刪除目錄
cd 進入指定目錄
cd.. 退回到上一級目錄
cd/ 退回到根目錄
del 刪除文件
exit 退出dos命令行

計算機語言


什麼是計算機語言?

  • 語言:是人與人之間用於溝通的一種方式。
    例如:中國人與中國人用中文溝通。
    而中國人要和韓國人交流,就要學習韓語。
  • 計算機語言:人與計算機交流的方式。
    如果人要與計算機交流,那麼就要學習計算機語。
    計算機語言有很多種,如:C,C++,Java等。
    這裏,我們選擇其中的一種:Java語言。
  • Java語言主要應用在互聯網程序的開發領域。常見的互聯網程序比如天貓、京東、物流系統、網銀系統等,以及服 務器後臺處理大數據的存儲、查詢、數據挖掘等也有很多應用。

Java語言概述

  • 是SUN(Stanford University Network, 斯坦福大學網絡公司)1995年推出的一門高級編程語言。
  • 是一種面向Internet的編程語言。
  • 隨着Java技術在web方面的不斷成熟,已經成爲web應用程序的首選開發語言。
  • 是簡單易學,完全面向對象,安全可靠,與平臺無關的編程語言。

Java語言的三種技術架構

J2EE(Java 2 Platform Enterise Edition)企業版
是爲了開發企業環境下的引用程序提供的一套解決方案。該技術體系中包含的技術如Servlet Jsp等,主要針對於web應用程序開發
J2SE(Java 2 Platform Standard Edition)標準版
是爲開發普通桌面和商務應用程序提供的解決方案。

該技術體系是其他兩者的基礎,可以完成一些桌面應用程序的開發。

J2ME(Java 2 Platform Micro Edition)小型版
是爲開發電子消費產品和嵌入式設備提供的解決方案。
該技術體系主要應用於小型電子消費類產品,如手機中的應用程序等。

Java5.0版本後,更名爲JAVAEE JAVASE JAVAME


Java語言的特點:跨平臺性

  • 什麼是跨平臺性?
    通過Java語言編寫的應用程序在不同的系統平臺上都可以運行。
  • 原理是什麼?
    只要在需要運行Java應用程序的操作系統上,先安裝一個Java虛擬機(JVM JAVA Virtual Machine)即可。
    由JVM來負責Java程序在該系統中的運行。

因爲有了JVM,所以同一個Java程序在三個不同的操作系統中都可以執行。這樣就實現了Java程序的跨平臺性。也稱爲Java具有良好的可移植性。


Java語言的環境搭建

什麼是JRE,JDK?

JRE(Java Runtime Environment Java運行環境)
包括Java虛擬機(JVM Java Virtual Machine)和Java所需的核心類庫等,如果想要運行一個開發好的Java程序,計算機中只需要安裝JRE即可。
JDK(Java Development Kit Java開發工具包)
-
JDK是提供給Java開發人員使用的,其中包含了Java的開發工具,也包括了JRE。所以安裝了JDK,就不用在單獨安裝JRE了。其中的開發工具:編譯工具(javac.exe) 打包工具(jar.exe)等

簡單而言:使用JDK開發完成的Java程序,交給JRE區運行。


配置環境變量

  • 每次執行java的工具都要進入到bin目錄下,是非常麻煩的。
  • 可不可以在任何目錄下都可以執行java的工具呢?
  • 根據windows系統在查找可執行程序的原理,可以將java工具所在路徑定義到path環境變量中,讓系統幫我們去找運行執行的程序。
臨時環境變量
set path=C:\Program Files\Java\jdk1.8.0_181\bin;%path%
隨意目錄下運行Java
set classpath=E:\test
java HelloWorld

Java_HOME環境變量的配置
我的電腦右擊屬性-選擇高級系統設置-環境變量-新建變量名JAVA_HOME,
變量值輸入JDK的安裝目錄C:\Program Files\Java\jdk1.8.0_181
選中path環境變量編輯-輸入%JAVA_HOME%\bin;移到最前面。
環境變量配置完成,重啓DOS命令行,輸入javac命令

第二章 Java基礎語法


關鍵字


關鍵字的定義和特點:
定義:被Java語言賦予了特殊含義的單詞
特點:關鍵字中所有字母都爲小寫

用於定義數據類型的關鍵字

class interface byte short int long float double char boolean void

用於定義數據類型的關鍵字

true false null

用於定義流程控制的關鍵字

if else switch case default while do for break continue return

用於定義訪問權限修飾符的關鍵字

private protected public

用於定義類,函數,變量修飾符的關鍵字

abstract final static synchronized

用於定義類與類之間關係的關鍵字

extends implements

用於定義建立實例及引用實例,判斷實例的關鍵字

new this super instanceof

用於異常處理的關鍵字

try catch finally throw throws

用於包的關鍵字

package import

其他修飾符關鍵字

native strictfp transient volatile assert

標識符


  • 在程序中自定義的一些名稱。
  • 由26個英文字母大小寫,數字:0~9 符號:_$組成
  • 定義合法標識符規則:
    1. 數字不可以開頭。
    2. 不可以使用關鍵字。
  • Java中嚴格區分大小寫。
  • 注意:在起名字的時,爲了提高閱讀性,要儘量有意義。
    Java中的名稱規範:
  • 包名:多單詞組成時所有字母都小寫。
    • xxxyyyzzz
  • 類名接口名:多單詞組成時,所有單詞的首字母大寫。
    • XxxYyyZzz
  • 變量名和函數名:多單詞組成時,第一個單詞首字母小寫,第二個單詞開始每個單詞首字母大寫。
    • xxxYyyZzz
  • 常量名:所有字母都大寫。多單詞時每個單詞用下劃線連接。
    • XXX_YYY_ZZZ

註釋

  • 用於註解說明解釋程序的文字就是註釋。
  • 提高了代碼的閱讀性
  • Java中的註釋格式:
    • 單行註釋
      • 格式:// 註釋文字
    • 多行註釋
      • 格式:/* 註釋文字 */
    • 文檔註釋
      • /** 註釋文字 */
  • 對於單行和多行註釋,被註釋的文字,不會被JVM(Java虛擬機)解釋執行。
  • 對於文檔註釋,是Java特有的註釋,其中註釋內容可以被JDK提供的工具javadoc所解析,生成一套以網頁文件形式體現的該程序的說明文檔。
  • 註釋是一個程序員必須要具有的良好變成習慣。
  • 初學者編寫程序可以養成習慣:先寫註釋再寫代碼
  • 將自己的思想通過註釋先整理出來,在用代碼去體現。
  • 因爲代碼僅僅是思想的一種體現形式而已。
/**
這是我的Hello World程序。
@author 冰冰
*/
class Demo{
	/*
	這是主函數,是程序的入口
	它的出現可以保證程序的獨立運行
	*/
	public static void main(String[] args) {
		// 這是輸出語句用於將括號內的數據打印到控制檯。
		System.out.println("Hello World");
	}
}

常量與變量

  • 常量表示不能改變的數值。
  • Java中常量的分類:
    1. 整數常量。所有整數
    2. 小數常量。所有小數
    3. 布爾型常量。較爲特有,只有兩個數值。true false
    4. 字符常量。將一個數字字母或者符號用單引號(’’)標識。
    5. 字符串常量。將一個或者多個字符用雙引號標識。
    6. null常量。只有一個數值就是:null。
  • 對於整數:Java有三種表現形式。
    • 十進制:0~9,滿0進1
    • 八進制:0~7,滿8進1,用0開頭表示
    • 十六進制:0-9,A-F,滿16進1.用0x開頭表示
  • 進制的基本轉換
    • 十進制 二進制 互轉
      • 十進制轉成二進制 除以2取餘數
      • 二進制轉成十進制 乘以2的冪數
    • 十進制 八進制 互轉
    • 十進制 十六進制 互轉
    • 負數的二進制表現形式
      • 對應的整數二進制取反加1
十進制-->二進制 6的二進制 
原理:對十進制數進行除2運算 
6/2--0 3/2--1 1/2--1 110 
二進制-->十進制 110的十進制 
原理:二進制乘以2的過程。 
0*2(0) + 1*2(1) + 1*2(2) = 0 + 2 + 4 = 6 
128 64 32 16 8 4 2 1   
 5  +  4  = 9 
----------------  
101 + 100 = 1001 --> 9
轉成16進制。四個二進制位就是一個十六進制位。
  0101-1010
  ---------
    5    A  --> 0x5A
轉成8進制。三個二進制位代表一位
001-011-010 = 132
-----------
 1   3   2
負數的二進制表現形式。
6 = 110
-6 其實就是6的二進制取反+1
取反:將二進制的1變成0,0變成1
0000-0000 0000-0000 0000-0000 0000-0110 
 1111-1111 1111-1111 1111-1111 1111-1001
+0000-0000 0000-0000 0000-0000 0000-0001
----------------------------------------
 1111-1111 1111-1111 1111-1111 1111-1010 = -6

負數的最高位都是1.

  • 變量的概念:
    • 內存中的一個存儲區域
    • 該區域有自己的名稱(變量名)和類型(數據類型)
    • 該區域的數據可以在同一類型範圍內不斷變化
  • 爲什麼要定義變量:
    • 用來不斷的存放同一類型的常量,並可以重複使用
  • 使用變量注意:
    • 變量的作用範圍(一對{}之間有效)
    • 初始化值
  • 定義變量的格式:
    • 數據類型 變量名 = 初始化值;
    • 格式是固定的,記住格式,以不變應萬變。
  • 變量就如同數學中的未知數。

Java語言是強類型語言,對於每一種數據都要定義了明確的具體數據類型,在內存總分配了不同大小的內存空間

數據類型:基本數據類型、引用數據類型
基本數據類型:
數值型:整數類型(byte/short/int/long)、浮點類型(float/double)),字符型(char),布爾型(boolean)
引用數據類型:類(class)、接口(interface)、數組([])
整數默認int,小數默認double

  • 自動類型轉換(也叫隱式類型轉換)
  • 強制類型轉換(也叫顯式類型轉換)
  • 類型轉換的原理
  • 什麼時候要用強制類型轉換?
  • 表達式的數據類型自動提升
    • 所有的byte型、short型和char的值將被提升到int型。
    • 如果一個操作數是long型,計算結果就是long型。
    • 如果一個操作數是float型,計算結果就是float型。
    • 如果一個操作數是double型,計算結果就是double型。
  • 分析
    • System.out.println(‘a’)與System.out.println(‘a’+1);的區別

    a在ASCII碼對應值是97
    char和int相加,char會被強制轉換int 97+1=98

  • 自動類型提升
byte b = 3;
int x = 4;
x = x + b; // b會自動提升爲int類型進行運算。
  • 強制類型轉換
byte b = 3;
b = b + 4; // 報錯
b = (byte)b + 4; // 強制類型轉換,強制將b+4的結果轉換位byte類型,再賦值給b。
  • 思考:
byte b1 = 3,b2 = 4,b;
b = b1 + b2;
b = 3 + 4;

哪句是編譯失敗的呢?爲什麼呢?

b = b1 + b2; //報錯,因爲java虛擬機在運算時會自動將b1和b2轉換成int類型相加,所得的值是一個int類型的值,所以需要強轉
b = 3 + 4;// byte類型的取值範圍是-128到127,兩個值相加編譯器能夠知道結果是多少,直接賦值沒有問題,如果換成b=b1+4,就會報錯,因爲編譯器不知道b1的值,他只知道b1是一個byte類型的變量,一個byte變量和一個int類型相加,會自動轉換成int類型

數據類型 變量名 = 初始化值;
int x = 4;
System.out.println(x); // 4
x = 10;
System.out.println(x); // 10

byte b = 2; // -128~127
// byte b1 = 128;
short s = 30000;
long l = 4L;
float f = 2.3F;
double d = 24.56;
char ch3 = ' ';

boolean bo = true;
boolean bo1 = false;

int a = 5;
a = a + 6;
System.out.println('a'); // a
System.out.println('a' + 1) // 98
// 所有的byte、short、char的值將被提升到int型。
byte b = 3;
// b = b + 2;
b = (byte)(b + 2);
System.out.println(b); // 5

double d = 3.14;
int i = (int) d;
System.out.println(i); // 3

System.out.println((char)97); // a

byte b = 3;
b = 3 + 4;
// b = b + 4;

byte b1 = 3, b2 = 4, b;
// b = b1 + b2;
b = (byte) (b1 + b2);
b = 3 + 4;
\n 回車換行
\b 退格 
\r 回車
\t tab

運算符


算術運算符

運算符 運算 範例 結果
+ 正號 +3 3
- 負號 b=4,-b; -4
+加 5+5 10
- 6-4 2
* 3*4 12
/ 5/5 1
% 取模 5%5 1
++ 自增(前) a=2;b=++a; a=3,b=3
++ 自增(後) a=2;b=a++; a=3,b=2
自減(前) a=2;b=–a; a=1;b=1
自減(後) a=2;b=a– a=1;b=2
+ 字符串相加 “he”+“llo” “hello”
  • 算術運算符的注意問題
    • 如果對負數取模,可以把模數負號忽略不記,如:5%-2=1。但被模數的負數就另當別論
    • 對於除號"/",它的整數除和小數除是有去別的:整數之間做除法時,只保留整數部分而捨棄小數部分。
    • 例如:int x = 3510;x=x/1000*1000; x的結果是?3000
    • "+"除字符串相加功能外,還能把非字符串轉換成字符串
    • 例如:System.out.println(“5+5=”+5+5); // 打印結果是?5+5=55
int x = 4270;
x = x / 1000 * 1000; 
System.out.println(x); // 4000

System.out.println(-1%5); // -1
int a = 3,b;
a++; // a = a + 1; 
b = ++a;
System.out.println("a = " + a + "b = " + b); // a = 5,b = 5
System.out.println("5+5="+(5+5)); // 5+5=10

賦值運算符

  • 符號:
    =,+=,-=,*=,/=,%=
  • 示例:
int a,b,c;
a=b=c=3;
int a=3;
a+=5; //等同運算a=a+5;
  • 思考:
short s = 3;
// 2是int類型的常量 s+2會自動轉換成int型,int型賦給一個short型的s自然會出錯
s = s + 2; // 報錯 改爲(short)(s+2)
s += 2;

有什麼區別?

編譯器自動將+=運算符後面的操作數強制轉換爲前面變量的類型
同時類似的還有: -= *= /= %=

int x = 3;
// += -= *= /= %=
short s = 4;
// s = (short) (s + 5);
s += 5;
System.out.println(s);

int a,b,c;
a = b = c = 5;

比較運算符

運算符 運算 範例 結果
== 相等於 4==3 false
!= 不等於 4!=3 true
< 小於 4<3 false
> 大於 4>3 true
<= 小於等於 4<=3 false
>= 大於等於 4>=3 false
instanceof 檢查是否類的對象 “Hello” instance String true
  • 比較運算符的結果都是boolean型,也就是要麼是true,要麼是false。
  • 比較運算符"==“不能誤寫成”="。

邏輯運算符

運算符 運算 範例 結果
& AND(與) false&true false
| OR(或) false|true true
^ XOR(異或) true^false true
! Not(非) !true false
&& AND(短路) !true false
|| OR(短路) false||true true
  • 邏輯運算符用於連接布爾型表達式,在Java中不可以寫成3<x<6,應該寫成x>3&x<6。
  • "&“和”&&"的區別:
    • &時,左邊無論真假,右邊都進行運算
    • &&時,如果左邊爲真,右邊參與運算,如果左邊爲假,那麼右邊不參與運算。
      "|“和”||"的區別同理,爽或時,左邊爲真,右邊不參與運算。
  • 異或(^)與或(|)的不同之處是:當左右都爲true時,結果爲false。
int x = 7;
x > 3 & x < 6; // true & false = false
true & true = true;
true & false = false;
false & true = false;
false & false = false;

&(與) 只要兩邊的boolean表達式結果,有一個爲false。那麼結果就是false。

true & true = true;
true & false = true;
false & true = true;
false & false = false;

|(或) 兩邊只要有一個爲true,結果爲true。只有兩邊都有false,結果爲false。

true ^ true = false;
true ^ false = true;
false ^ true = true;
false ^ false = false;

^(異或) 兩邊相同結果是false。
!(非) !true = false、 !false = true

int a = 2;
a>3 && a<6;

短路
&和&&的特點:
& 無論左邊是true還是false,右邊都運算。
&& 當左邊爲false時,右邊不運算。

| 兩邊都參與運算
|| 當左邊爲true。右邊不運算


位運算符

運算符 運算 範例
<< 左移 3<<2=12–>322=12
>> 右移 3 >>1=1‐‐>3/2=1
>>> 無符號右移 3 >>>1=1‐‐>3/2=1
& 與運算 6&3==2
| 或運算 6|3=7
^ 異或運算 6^3=5
~ 反碼 ~6=-7

位運算是直接對二進制進行運算。
位運算符的細節

位運算符的細節
<< 空位補0,被移除的高位丟棄,空缺位補0
>> 被移位的二進制最高位是0,右移後,空缺位補0;最高位是1,空缺位補1
>>> 被移位二進制最高位無論是0或者是1,空缺位都用0補
& 二進制位進行&運算,只有1&1時結果是1,否則是0;
| 二進制位進行|運算,只有0|0時結果是0,否則是1;
^ 任何相同二進制位進行 ^ 運算,結果是0;1 ^ 1 = 0, 0 ^ 0 = 0 不相同二進制位 ^ 運算結果是1。1 ^ 0=10 ^ 1=1
3 << 2 = 12;(3*4=12)  3 << 1 = 6;(3*2=6)  3 << 3 = 24;(3*8=24)
0000-0000 0000-0000 0000-0000 0000-0011 3
<< 2
0000-0000 0000-0000 0000-0000 0000-1100 12

6 >> 2 = 1;(6/4=1)  6 >> 1 = 3;(6/2=3) 
0000-0000 0000-0000 0000-0000 0000-0110 6
>> 2
0000-0000 0000-0000 0000-0000 0000-0001 1

3 << 2 --> 3*22次冪
<< 其實就是乘以2的移動的位數次冪
>> 就是除以2的移動的位數次冪

1111-1111 1111-1111 1111-1111 1111-1010 = -6
>> 2
1111-1111 1111-1111 1111-1111 1111-1110
>>> 2
0011-1111 1111-1111 1111-1111 1111-1110
>> 最高位補什麼由原有數據的最高位值而定。
如果最高位0,右移後,用0補空位。
如果最高位1,右移後,用1不空位。
>>> 無論最高位是什麼,右移後,都用0補。

& 
6 & 3 = 2
 110
&011
-----
 010 = 2

|
6 | 5 = 7
 110
|101
------
 111 = 7

^
6 ^ 5 = 3
 110
^101
------
 011 = 3
 
System.out.println(~6); // -7
0000...000110
1111...111001
0000...000001
1111...111000
0000...000111

System.out.println(7 ^ 4);
7 ^ 4
 111
^100
-----
 011
^100
-----
 111 = 7 ^ 4 = 4 ^ 4 = 7
 一個數異或同一個數兩次,結果還是那個數。

練習

1. 最有效率的方式算出2乘以8等於幾? 2<<3

2. 對兩個整數變量的值進行互換(不需要第三方變量)
int n = 3, m = 8;
System.out.println("n = " + n + ",m = " + m);
// 1. 通過第三方變量
int temp = n;
n = m;
m = temp;
// 2. 不用第三方變量
// 如果n和m的值非常大,容易超出int範圍。
n = n + m; // 11 = 3 + 8
m = n - m; // 3 = 11 + 8
n = n - m; // 8 = 11 - 8

n = n ^ m; //
m = n ^ m; // (n^m)^m
n = n ^ m; // n^(n^m)
System.out.println("n = " + n + ",m = " + m);

十六進制形式

0000-0000 0000-0000 0100-1100 1110-0110
----------------------------------------
		    		  4   12   14   6

 0000-0000 0000-0000 0100-1100 1110-0110
&0000-0000 0000-0000 0000-0000 0000-1111
-----------------------------------------
 0000-0000 0000-0000 0000-0000 0000-0110
===========================================

0000-0000 0000-0000 0000-0000 0011-1100 = 60
60&15 = 12
0000-0000 0000-0000 0000-0000 0011-1100
0000-0000 0000-0000 0000-0000 0000-1111
-----------------------------------------
0000-0000 0000-0000 0000-0000 0000-1100 = 12

temp = 60>>>4
temp & 15 = 3
0000-0000 0000-0000 0000-0000 0000-0011	1100
0000-0000 0000-0000 0000-0000 0000-1111
----------------------------------------
0000-0000 0000-0000 0000-0000 0000-0011 = 3

三元運算符

格式:(條件表達式)?表達式1:表達式2;

  • 如果條件爲true,運算後的結果是表達式1;
  • 如果條件爲false,運算後的結果是表達式2;
	System.out.println(Integer.toBinaryString(60)); // 二進制 111100
	System.out.println(Integer.toHexString(60)); // 十六進制 3c
	System.out.println(Integer.toOctalString(60)); // 八進制 74
	int num = 60;
	// 獲取60的最低4位,通過&15
	int n1 = num & 15;
	System.out.print(n1 > 9 ? (char) (n1 - 10 + 'a') : n1 + ""); // c
	// 要獲取下一組四位,將60右移4位
	int temp = num >>> 4;
	// 對temp的值進行最低四位的獲取。
	int n2 = temp & 15;
	System.out.print(n2 > 9 ? (char) (n2 - 10 + 'a') : n2); // 3
	System.out.println();
	/*
	0-9 'a' 'b' 'c' 'd' 'e' 'f'
		 97  98  99
		 10  11  12  13  14  15
		     
		 12 - 10 = 2 + 'a' = (char)99;
	*/

	int x = 1, y;
	y = (x > 1) ? 100 : 200;
	System.out.println("y = " + y);

獲取兩個數中大數。

int x = 3, y = 4,z;
z = (x > 1) ? x: y;
System.out.println("z = " + z);

流程控制


判斷結構

格式:

	if(條件表達式){
		// 執行語句;
	}else if(條件表達式){
		// 執行語句;
	}else {
		// 執行語句;
	}

特點:

條件表達式無論寫成什麼樣子,只看最終的結果是否是true或者false

	int x = 1;
	if(x>1) {
		System.out.println("yes"):
	}else {
		System.out.println("a");
	}
/*
	if else結果簡寫格式:
	變量 = (條件表達式)?表達式1:表達式2;
	三元運算符:
	好處:可以簡化if else代碼
	弊端:因爲是一個運算符,所以運算完必須要有一個結果。
*/
	int a = 9,b;
	b = (a>1)?100:200;
		
	if(a>1)
		b = 100;
	else
		b = 200;
		
	int n = 3;
	if(n > 1)
		System.out.println("a");
	else if(n > 2)
		System.out.println("b");
	else if(n > 3)
		System.out.println("c");
	else 
		System.out.println("d"):
/*
	if(n>1)
		System.out.println("a");
	if(n>2)
		System.out.println("b");
	if(n>3)
		System.out.println("c");
	else
		System.out.println("d");
		
	System.out.println("over");
*/
	// 需求1:根據用戶定義的數值不同。打印對應的星期英文。
	int num = 1;
	if(num == 1) {
		System.out.println("Monday");
	}else if(num == 2) {
		System.out.println("Tuesday");
	}else {
		System.out.println("no");
	}
	// 需求2:根據用於指定月份,打印該月份所屬的季節。
	int x = 4;
	if(x>12 || x<1) {
		System.out.println(x + "月份不存在");
	}else if(x>=3 && x<=5) {
		System.out.println(x + "春季");
	}else if(x>=6 && x<=8) {
		System.out.println(x + "夏季");
	}else if(x>=9 && x<=11) {
		System.out.println(x + "秋季");
	}else {
		System.out.println(x + "冬季");
	}
/*
已知學生成績以100分爲滿分,共分5個等級:A,B,C,D,E。
90~100爲等級A,80~89爲等級B,70~79爲等級C,
60~69爲等級D,0~59爲等級E。
要求定義一個成績變量,當成績變化時,可直接知道該成績對應的等級。
例如:當成績爲100時,該學生的等級時A。
*/
	//定義一功能,通過給定分數,獲取該分數對應的等級。
	/*
	1,明確該功能的結果:等級 char
	2,有沒有未知內容。分數。int
	*/
	public static String getLevel(int num) {
		char level; // 等級
		if(num>=90 && num<=100)
			level = 'A';
		else if(num>=80 && num<=89)
			level = 'B';
		else if(num>=70 && num<=79)
			level = 'C';
		else if(num>=60 && num<=69)
			level = 'D';
		else
			level = 'E';

		return level;
	}
	public static void main(String[] args) {
		char ch = getLevel(35);
		System.out.println("level="+ch);
	}

選擇結構

格式:

	switch(表達式) {
		case 取值1:
			執行語句;
			break;
		case 取值2:
			執行語句;
			break;
		...
		default:
			執行語句;
			break;
	}
  1. switch語句選擇的類型只有四種:byte、short、int、char。
  2. case之間與default沒有順序。先執行第一個case,沒有匹配的case執行default。
  3. 結果switch語句的兩種情況:遇到break,執行到switch語句結束。
  4. 如果匹配的case或者default沒有對應的break,那麼程序會繼續向下執行,運行可以執行的語句,直到遇到break或者switch結尾結束。

習題

	int x  = 3;
	// byte short int char
	switch(x) {
		default:
			System.out.println("d"):
			//break;
		case 4:
			System.out.println("a");
			//break;
		case 6:
			System.out.println("b");
			break;
		case 2:
			System.out.println("c");
			break;
	}
	// 輸出:d a b 
	int a = 4,b = 2;
	char ch = '+';
		
	switch(ch) {
		case '-':
			System.out.println(a-b);
			break;
		case '+':
			System.out.println(a+b); // 6
			break;
		case '*':
			System.out.println(a*b);
			break;
		case '/':
			System.out.println(a/b);
			break;
		default:
			System.out.println("非法");
	}
	// 需求2:根據用於指定月份,打印該月份所屬的季節。
	int x = 4;
	switch (x) {
	case 3:
	case 4:
	case 5:
		System.out.println(x + "春季"); // 春季
		break;
	case 6:
	case 7:
	case 8:
		System.out.println(x + "夏季");
		break;
	case 9:
	case 10:
	case 11:
		System.out.println(x + "秋季");
		break;
	case 12:
	case 1:
	case 2:
		System.out.println(x + "冬季");
		break;
	default:
		System.out.println("no");
		break;
}

if和switch語句很像。
具體什麼場景下,應用哪個語句呢?
如果判斷的具體數值不多,而是符合byte、short、int、char四種類型。
雖然兩個語句都可以使用,建議使用switch語句,因爲效率稍高。
其他情況:對區間判斷,對結果爲boolean類型判斷,使用if,if的使用範圍更廣。


語句練習if-switch

第一題

int x = 1, y = 1;
if (x++ == 2 & ++y == 2) {
	x = 7;
}
System.out.println("x=" + x + ",y=" + y); // x=2,y=2

第二題

int x = 1, y = 1;
if (x++ == 2 && ++y == 2) {
	x = 7;
}
System.out.println("x = " + x + ",y = " + y); // x = 2,y = 1

第三題

int x = 1, y = 1;
if (x++ == 1 | ++y == 1) {
	x = 7;
}
System.out.println("x = " + x + ",y = " + y); // x = 7,y = 2

第四題

int x = 1, y = 1;
if (x++ == 1 || ++y == 1) {
	x = 7;
}
System.out.println("x = " + x + ",y = " + y); // x = 7,y = 1

第五題

boolean b = true;

if (b == false) // 如果寫成if(b=false)有結果嗎?如果有,結果是? c
	System.out.println("a");
else if (b)
	System.out.println("b"); // b
else if (!b)
	System.out.println("c");
else
	System.out.println("d");

第六題

int x = 2,y = 3;
switch(x) {
	default:
		y++;
	case 3:
		y++;
	case 4:
		y++;
}
System.out.println("y = " + y); // 6

循環結構

while

語句格式:
	while(條件表達式) {
		執行語句;
	}
		
 	int x = 1;
	while (x < 3) {
		System.out.println("x = " + x);
		x++;
	}

	int x = 1;
	do {
		System.out.println("do: x = " + x); // 1
		x++;
	} while (x < 0);

	int y = 1;
	while (y < 0) {
		System.out.println("y = " + y);
		y++;
	}

while:先判斷條件,只有條件滿足才執行循環體。
do while:先執行循環體,再判斷條件,條件滿足,再繼續執行循環體。
do while:特點是無論條件是否滿足,循環體至少執行一次


for

語句格式:
	for(初始化表達式;循環條件表達式;循環後的操作表達式) {
		執行語句;
	}
  1. for裏面表達式運行的順序,初始化表達式只讀一次,判斷循環條件,爲真就執行循環體,然後再執行循環後的操作表達式,接着繼續判斷循環條件,重複找的過程,直到條件不滿足爲止。
  2. while與for可以互換,區別在於for爲了循環而定義的變量在for循環結束就是在內存中釋放。而while循環使用的變量在循環結束後還可以繼續使用。
  3. 最簡單無限循環格式:while(true),for( ; ; ),無限循環存在的原因是並不知道循環多少次,而是根據某些條件,來控制循環。
	for (int x = 0; x < 3; x++) {
		System.out.println("x = " + x); // 0 1 2
	}
	// System.out.println("x = " + x);
	System.out.println("============");
	int y = 0;
	while (y < 3) {
		System.out.println("y = " + y); // 0 1 2
		y++;
	}
	System.out.println("y = " + y); // 3
	/*
	1. 變量有自己的作用域。
	對於for來講: 如果將用於控制循環的增量定義在for語句中,那麼變量只在for語句中那麼該變量只在for語句內有效。for語句執行完畢。該變量在內存中被釋放。 
 	2. for和while可以進行互換。如果需要定義循環增量。用for更爲合適。
	*/
	// 總結:什麼時候使用循環結構? 當要對某些語句執行很多次時,就是用循環結構。
	int x = 1;
	for (System.out.println("a"); x < 3;
		System.out.println("c"), x++) {
		System.out.println("d");
	}
	// adcdc

	for (int y = 0; y < 3; y++) {
	
	}
	// 無限循環的最簡單表現形式。
	for (;;) {
			
	}
	while(true) {
			
	}

練習題

	// 1. 獲取1~10的和,並打印。

	// 1. 定義變量用於存儲不斷變化的和。
	int sum = 0;

	// 2. 定義變量,記錄住不斷變化的被加的數。
	int x = 1;
	// 3. 定義循環,重複加法的過程。
	while (x <= 10) {
		sum = sum + x;
		x++;
	}
	System.out.println("sum=" + sum);

	/*
	 * 循環注意:一定要明確哪些語句需要參與循環,哪些不需要。
	 */
	 0 + 1
		 1 + 2
		  	 3 + 3
		 	     6 + 4
	// 用for來實現。
	int sum = 0;
	for (int x = 0; x <= 10; x++) {
		sum += x;
	}
	System.out.println("for sum = " + sum);
	/*
	 * 其實這就是累加思想。
	 * 原理:通過變量記錄每次變化的結果。
	 * 通過循環的形式。進行累加動作。
	 * */
/*
2. 1~100之間 7的倍數的個數。並打印。
思路:
1. 先對1~100進行循環(遍歷)通過循環的形式。
2. 在遍歷的過程中,定義條件。只對7的倍數進行操作。
2. 因爲7的倍數不確定,只要符合條件,就通過一個變量來記錄住這個變化的次數。

步驟:
 - 定義循環語句,選擇for語句。
 - 在循環中定義判斷。只要是7的倍數即可。使用if語句。條件:7的倍數 x%7==0;
 - 定義變量,該變量隨着7的倍數的出現而自增。
*/
	int count = 0;
	for (int i = 1; i <= 100; i++) {
		if (i % 7 == 0) {
			System.out.println(i);
			count++;
		}
	}
	System.out.println("count = " + count);
	/*
	 * 計數器思想。 
	 * 通過一個變量記錄數據的狀態變化。 
	 * 也需要通過循環完成。
	 */
	// 循環嵌套 其實就是語句中還有語句
	// ****
	// ****
	// ****

	for (int x = 0; x < 3; x++) {
		for (int y = 0; y < 4; y++) {
			System.out.print("*");
		}
		System.out.println(); // 只有一個功能就是換行。
	}

	// *****
	// ****
	// ***
	// **
	// *

	for (int x = 0; x < 5; x++) { // x<5因爲外循環控制行數。一共5行
		for (int y = 5; y > x; y--) {
			System.out.print("*");
		}
		System.out.println();
	}

	// *
	// **
	// ***
	// ****
	// *****

	for (int x = 1; x <= 5; x++) {
		for (int y = 0; y < x; y++) {
			System.out.print("*");
		}
		System.out.println();
	}

	// 1
	// 12
	// 123
	// 1234
	// 12345

	for (int x = 1; x <= 5; x++) {
		for (int y = 1; y <= x; y++) {
			System.out.print(y);
		}
		System.out.println();
	}

	// 九九乘法表
	// 1*1=1
	// 1*2=2 2*2=4
	// 1*3=3 2*3=6 3*3=9

	for (int x = 1; x <= 9; x++) {
		for (int y = 1; y <= x; y++) {
			System.out.print(y + "*" + x + "=" + x * y + "\t");
		}
		System.out.println();
	}
		
	// ----*
	// ---* *
	// --* * *
	// -* * * *
	// * * * * *
	Scanner c = new Scanner(System.in);
	int i = c.nextInt();
	for (int x = 0; x < i; x++) {
		for (int y = x; y < i - 1; y++) {
			System.out.print(" ");
		}
		for (int z = 0; z <= x; z++) {
			System.out.print("* ");
		}
		System.out.println();
	}
	// * * * * *
	// -* * * *
	// --* * *
	// ---* *
	// ----*

	for (int x = 0; x < i; x++) {
		for (int y = 0; y < x; y++) {
			System.out.print(" ");
		}
		for (int z = i; z > x; z--) {
			System.out.print("* ");
		}
		System.out.println();
	}

其他流程控制語句

break(跳出) continue(繼續)
break語句應用範圍:選擇結構和循環結構
continue語句:應用於循環結構

  1. 這兩個語句離開應用範圍,存在時沒有意義的。
  2. 這兩個語句單獨存在下面都不可以有語句,因爲執行不到
  3. continue語句結束本次循環繼續下次循環。
  4. 標號的出現,可以讓這兩個語句作用於指定的範圍。
w: for (int x = 0; x < 3; x++) {
	for (int y = 0; y < 4; y++) {
		System.out.println("x = " + x); // 0
		break w;
	}
}

	// continue 只能作用於循環結構。繼續循環。特點:結束本次循環,繼續下一次循環
	for (int x = 1; x <= 10; x++) {
		if (x % 2 == 1)
			continue;
		// System.out.println("x = " + x); // 2 4 6 8 10
	}

	w: for (int x = 0; x < 3; x++) {
		for (int y = 0; y < 4; y++) {
			System.out.println("x = " + x); // 0 1 2
			continue w;
		}
	}
	/*
	 * 記住:
	 * 1. break和continue語句作用的範圍。 
	 * 2. break和continue單獨存在時,下面不可以有任何語句。因爲都執行不到。
	 */
	// break;
	// continue;

函數


函數的定義

  • 什麼是函數?
    • 函數就是定義在類中的具有特定功能的一段獨立小程序。
    • 函數也稱爲方法。
  • 函數的格式:
修飾符 返回值類型 函數名(參數類型 形式參數1, 參數類型 形式參數2, ...) {
	執行語句;
	return 返回值;
}
返回值類型:函數運行後的結果是數據類型。
參數類型:是形式參數的數據類型。形式參數:傳遞給參數的具體數值。
return:用於結束函數。
返回值:該值會返回給調用者。

public static void main(String[] args) {
	int x = 4;
	System.out.println(x * 3 + 5); // 17

	x = 6;
	System.out.println(x * 3 + 5); // 23

	// int y = 4*3+5;
	// int z = 6*3+5;

	int y = getResultInt(4);
	System.out.println("y=" + y); // y = 17
	int z = getResultInt(6);
	getResultVoid(5); // 20
}

// 發現以上的運算,因爲獲取不同數據的運算結果,代碼出現了重複。
// 爲了提高代碼的複用性。對代碼進行抽取。
// 將這個部分定義成一個獨立的功能。方便與日後使用。
// java中對功能的定義是通過函數的形式來體現的。

// 需要定義功能,完成一個整數的*3+5的運算,

// 1. 先明確函數定義的格式。
/*
 * 修飾符 返回值類型 函數名(參數類型 形式參數1,參數類型 形式參數2,) { 執行語句; return 返回值; }
 * 
 * 當函數運算後,沒有具體的返回值時,這是返回值類型用一個特殊的關鍵字來標識。 該關鍵字就是void。void:代表的是函數沒有具體返回值的情況。
 * 當函數的返回值類型是void時,函數中的return語句可以省略不寫。
 */
public static int getResultInt(int num) {
	return num * 3 + 5;
}

public static void getResultVoid(int num) {
	System.out.println(num * 3 + 5);
	return;// 可以省略
}

函數的特點

  • 定義函數可以將功能代碼進行封裝
  • 函數只有被調用纔會被執行
  • 函數的出現提高了代碼的複用性
  • 對於函數沒有具體返回值的情況,返回值類型用關鍵字void表示,那麼該函數中的return語句如果在最後一行可以省略不寫。
  • 函數中只能調用函數,不可以在函數內部定義函數。
  • 定義函數時,函數的結果應該返回給調用者,交給調用者處理。

函數的應用

  • 兩個明確
    • 明確要定義的功能最後的結果是什麼?
    • 明確在定義該功能的過程中,是否需要未知內容參與運算
  • 實例:
    • 需求:定義一個功能,可以實現兩個整數的加法運算。
    • 分析:
      • 該功能的運算結果是什麼?兩個數的和,也是一個整數(int)
      • 在實現該功能的過程中是否有未知內容參與運算?加數和被加數是不確定的。(兩個參數int,int)
      • 代碼
        int getSun(int x,int y) {
        	return x+y;
        }
        

	public static void main(String[] args) {
		draw(5, 6);
		printHr();
		draw(7, 9);
		printHr();
		print99();
	}

	/*
	 * 定義一個打印99乘法表功能的函數。
	 */
	public static void print99() {
		for (int x = 1; x <= 9; x++) {
			for (int y = 1; y <= x; y++) {
				System.out.print(y + "*" + x + "=" + y * x + "\t");
			}
			System.out.println();
		}
	}

	/*
	 * 定義一個功能,用於打印矩形。 
	 * 思路: 
	 * 1. 確定結果:沒有,因爲直接打印。所以返回值類型是void 
	 * 2. 有未知內容嗎?有,兩個,因爲矩形的行和列不確定。
	 */
	public static void draw(int row, int col) {
		for (int x = 0; x < row; x++) {
			for (int y = 0; y < col; y++) {
				System.out.print("*");
			}
			System.out.println();
		}
	}

	public static void printHr() {
		System.out.println("------------------------------");
	}

函數的重載(overload)

重載的概念
在同一個類中,允許存在一個以上的同名函數,只要它們
重載的特點:
與返回值類型無關,只看參數列表。
重載的好處:
方便於閱讀,優化了程序設計。

重載示例:

// 返回兩個整數的和
int add(int x,int y) {
	return x + y;
}
// 返回三個整數的和
int add(int x,int y,int z) {
	return x+y+z;
}
// 返回兩個小數的和
double add(double x,double y) {
	return x+y;
}
/*
什麼時候用重載?
當定義的功能相同,但參與運算的未知內容不同。
那麼,這時就定義一個函數名稱以表示起功能,方便閱讀,而通過參數列表的不同來區分多個同名函數。
*/
public static void main(String[] args) {

	System.out.println(add(4, 5)); // 9
	System.out.println(add(4, 5, 6)); // 15
	print99();
}

public static void print99(int num) {
	for (int x = 1; x <= num; x++) {
		for (int y = 1; y <= x; y++) {
			System.out.print(y + "*" + x + "=" + y * x + "\t");
		}
		System.out.println();
	}
}

// 打印99乘法表
public static void print99() {
	print99(9);
}

// 定義一個加法運算,獲取兩個整數的和。
public static int add(int x, int y) {
	return x + y;
}

// 定義一個加法,獲取三個整數的和。
public static int add(int x, int y, int z) {
	return add(x, y) + z;
}

數組


數組的定義

概念
同一種類型數據的集合。其實數組就是一個容器。
數組的好處
可以自動給數組中的元素從0開始編號,方便操作這些元素。
格式1:
元素類型[] 數組名 = new 元素類型[元素個數或數組長度];
示例:int[] arr = new int[5];
格式2:
元素類型[] 數組名 = new 元素類型[] {元素, 元素, …}
int[] arr = new int[]{3, 5, 1, 7};
int[] arr = {3, 5, 1, 7};
//元素類型[] 數組名 = new 元素類型[元素個數或數組長度];
		
//需求:想定義一個可以存儲3個整數的容器。
int[] x = new int[3];

//打印數組中角標爲0的元素的值。
System.out.println(x[1]); // 0

	public static void main(String[] args) {
		int sum = getSum(4, 6);
		System.out.println("sum=" + sum);
		sum = getSum(2, 7);
		System.out.println("sum=" + sum);

		get(4,5);
		int x = getSum(4, 4);
		int y = getSum(7, 9);
		int num = getMax(x, y);
	}

	/*
	 * 這個功能定義思想有問題,爲什麼呢? 
	 * 因爲只爲完成加法運算,至於是否要對和進行打印操作, 那是調用者的事,不要在該功能中完成。
	 */
	public static void get(int a, int b) {
		System.out.println(a + b);
		return;
	}

	/*
	 * 如何定義一個函數呢? 
	 * 1. 既然函數是一個獨立的功能,那麼該功能的運算結果是什麼先明確 因爲這是在明確函數的返回值類型。
	 * 2. 在明確在定義該功能的過程中是否需要未知的內容參與運算。 因爲是在明確函數的參數列表(參數的類型和參數的個數)。
	 */

	// 需求:定義一個功能。完成3+4的運算。並將結果返回給調用者。
	/*
	 * 1. 明確功能的結果:是一個整數的和。 
	 * 2. 在實現該功能的過程中是否有未知內容參與運算,沒有。 其實這兩個功能就是在明確函數的定義。
	 * 1. 是在明確函數的返回值類型。
	 * 2. 明確函數的參數列表( 參數的類型和參數的個數)。
	 */
	public static int getSum() { 
		return 3+4; 
	}
	
	/*
	 * 以上這個函數的功能,結果是固定的,毫無擴展性而言。 
	 * 爲了方便用戶需求。由用戶來指定加數和被加數。這樣,功能纔有意義。 
	 * 思路:
	 * 1. 功能結果是一個和。返回值類型是int。 
	 * 2. 有未知內容參與運算。有兩個。這個兩個未知內容的類型都是int。
	 */
	public static int getSum(int x, int y) {
		return x + y;
	}

	/*
	 * 需求:判斷兩個數是否相同。 
	 * 思路:
	 * 1. 明確功能的結果:結果是:boolean 。 
	 * 2. 功能是否有未知內容參與運算。有,兩個整數。
	 */
	public static boolean compare(int a, int b) {
		// if (a == b)
		// return true;
		// else
		// return false;

		// return (a==b) ? true : false;

		return a == b;
	}

	/*
	 * 需求:定義功能,對兩個數進行比較。獲取較大的數。
	 */
	public static int getMax(int a, int b) {
		// if (a > b) {
		// return a;
		// } else {
		// return b;
		// }

		return (a > b) ? a : b;
	}

內存結構

Java程序在運行時,需要在內存中的分配空間。爲了提高運算效率,有對空間進行了不同區域的劃分,因爲每一片區域都有特定的處理數據方式和內存管理方式。

棧內存
用於存儲局部變量,當數據使用完,所佔空間會自動釋放。
堆內存
數組和對象,通過new建立的實例都存放在堆內存中。
每一個實體都有內存地址值
實體中的變量都有默認初始化值
實體中的變量都有默認初始化值
實體不在被使用,會在不確定的時間內被垃圾回收器回收
方法區
存儲可以運行的class文件。
本地方法區
JVM在使用操作系統功的時候使用,和我們開發無關。
寄存器
給CPU使用,和我們開發無關。

數組操作常見問題

數組下標越界異常(ArrayIndexOutOfBoundsException)
int[] arr = new int[2];
System.out.println(arr[3]):
訪問到了數組中的不存在的下標時發生。
空指針異常(NullPointerException)
int[] arr = null;
System.out.println(arr[0]);
arr引用沒有指向實體,卻在操作實體中的元素時。
int[] arr = new int[2];
int arr[] = new int[2];
int[] arr = new int[] { 3, 1, 6, 5, 4 };
int[] arr = {3,1,6,5,4};
System.out.println(arr[2]);
int[] arr = new int[5];
arr[0] = 90;
arr[1] = 80;

int[] arr = new int[3];
System.out.println(arr[3]);
// ArrayIndexOutOfBoundsException: 操作數組時,訪問到了數組中不存在的角標。

arr = null;
System.out.println(arr[1]);
// NullPointerException:空指針異常:當引用沒有任何指向值爲null的情況,該引用還在用於操作實體。

public static void main(String[] args) {
	// 獲取數組中的元素。通常會用到遍歷。
	int[] arr = { 3, 6, 5, 1, 8, 9, 7, 2, 4, 10 };

	// 數組中有一個屬性可以直接獲取到數組元素個數。length
	// 使用方式:數組名稱.length
	System.out.println(arr.length); // 10
	int sum = 0;
	for (int x = 0; x < arr.length; x++) {
		sum += arr[x];
		System.out.println("arr[" + x + "] = " + arr[x] + ";");
	}
	System.out.println(sum); // 55

	printArray(arr); // [3,6,5,1,8,9,7,2,4,10]
	System.out.println(arr); // [I@52e922
}

// 定義功能,用於打印數組中的元素。元素間用逗號隔開。
public static void printArray(int[] arr) {
	System.out.print("[");
	for (int x = 0; x < arr.length; x++) {
		if (x != arr.length - 1) {
			System.out.print(arr[x] + ",");
		} else {
			System.out.print(arr[x] + "]");
		}
	}
	System.out.println();
}

數組常見操作

  • 獲取最值(最大值,最小值)
	/*
	 * 獲取數組中的最大值。 
	 * 思路: 
	 * 1. 獲取最值需要進行比較。每一次比較都會有一個較大的值。因爲該值不確定。 通過一個變量進行臨時存儲。 
	 * 2. 讓數組中的每一個元素都和這個變量中的值進行比較。 如果大於了變量中的值,就用該該變量記錄較大值。 
	 * 3. 當所有的元素都比較完成,那麼該變量中存儲的就是數組中的最大值了。
	 * 
	 * 步驟: 
	 * 1. 定義變量。初始化爲數組中任意一個元素即可。 
	 * 2. 通過循環語句對數組進行遍歷。 
	 * 3. 在變量過程中定義判斷條件,如果遍歷到的元素比變量中的元素大,就賦值給該變量。
	 * 
	 * 需要定義一個功能來完成。以便提高複用性。 
	 * 1. 明確結果,數組中的最大元素 int。 
	 * 2. 未知內容:一個數組。int[]
	 */
	public static int getMax(int[] arr) {
		int max = arr[0];
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] > max) {
				max = arr[x];
			}
		}
		return max;
	}

	/*
	 * 獲取最大值的另一種方式。 可不可以將臨時變量初始化爲0呢?可以。這種方式,其實在初始化爲數組中任意一個下標。
	 */
	public static int getMax_2(int[] arr) {
		int max = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] > arr[max])
				max = x;
		}
		return arr[max];
	}

	/*
	 * 獲取最小值。
	 */
	public static int getMin(int[] arr) {
		int min = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] < arr[min]) {
				min = x;
			}
		}
		return arr[min];
	}

	// 獲取double類型數組的最大值。因爲功能一致,所以定義相同函數名稱。以重載形式存在。
	// public static double getMax(double[] arr) {
	//
	// }

	public static void main(String[] args) {
		int[] arr = { 3, 6, 5, 1, 8, 9, 7, 2, 4, 10 };
		int max = getMax(arr);
		System.out.println("max = " + max); // 10
		int min = getMin(arr);
		System.out.println("min = " + min); // 1

		boolean[] ar = new boolean[3];
		System.out.println(ar[1]); // false
	}

  • 排序(選擇排序,冒泡排序)
public static void main(String[] args) {
	int[] arr = { 3, 6, 5, 1, 8, 9, 7, 2, 4, 10 };
	// 排序前:
	printArray(arr);
	// 排序
	selectSort(arr);
	bubbleSort(arr);
	Arrays.sort(arr); // Java中已經定義好的一種排序方式。開發中,對數組排序。要使用該句代碼。
	// 排序後:
	printArray(arr);

	// 反轉後:
	reverseArray(arr);
	printArray(arr);
}
/*
 * 選擇排序。 內循環結束一次,最值出現頭角標位置上。
 */
public static void selectSort(int[] arr) {
	// 沒有必要遍歷最後一個角標
	for (int x = 0; x < arr.length - 1; x++) {
		for (int y = x + 1; y < arr.length; y++) {
			if (arr[x] > arr[y]) {
				// int temp = arr[x];
				// arr[x] = arr[y];
				// arr[y] = temp;
				swap(arr, x, y);
			}
		}
	}
}

/*
 * 冒泡排序
 */
public static void bubbleSort(int[] arr) {
	for (int x = 0; x < arr.length - 1; x++) {
		for (int y = 0; y < arr.length - x - 1; y++) { // -x讓每一次比較的元素減少,-1避免角標越界。
			if (arr[y] > arr[y + 1]) {
				// int temp = arr[y];
				// arr[y] = arr[y + 1];
				// arr[y + 1] = temp;
				swap(arr, y, y + 1);
			}
		}
	}
}

public static void reverseArray(int[] arr) {
	for(int start = 0,end = arr.length - 1; start < end; start++, end--) {
		swap(arr, start, end);
	}
}

public static void printArray(int[] arr) {
	System.out.print("[");
	for (int x = 0; x < arr.length; x++) {
		if (x != arr.length - 1) {
			System.out.print(arr[x] + ",");
		} else {
			System.out.print(arr[x] + "]");
		}
	}
	System.out.println();
}

/*
 * 發現無論什麼排序。
 * 都需要對滿足條件的元素進行位置置換。 
 * 所以可以把這部分相同的代碼提取出來,單獨封裝成一個函數。
 */
public static void swap(int[] arr, int a, int b) {
	int temp = arr[a];
	arr[a] = arr[b];
	arr[b] = temp;
}

  • 折半查找(二分查找)
import java.util.Arrays;

/*
數組的查找操作。

練習:有一個有序的數組,想要將一個元素插入到該數組中,
還要保證該數組是有序的。如何獲取該元素在數組中的位置。
*/
	public static void main(String[] args) {
		int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16 };
		int index = getIndex(arr, 2);
		System.out.println("index = " + index); // 0
		int index1 = halfSearch(arr, 32);
		System.out.println("index1 = " + index1); // -1
		int index2 = halfSearch_2(arr, 14);
		System.out.println("index2 = " + index2); // 6
		int index3 = getIndex_2(arr, 15); 
		System.out.println("index3 = " + index3); // 7

		int x = Arrays.binarySearch(arr, 11); // Java提供好的一個進行折半查找的功能。開始時使用這個。
		System.out.println("x = " + x); // -插入點 - 1 = -6
	}

	public static int getIndex_2(int[] arr, int key) {
		int min = 0, max = arr.length - 1, mid;
		while (min <= max) {
			mid = (max + min) >> 1;
			if (key > arr[mid])
				min = mid + 1;
			else if (key < arr[mid])
				max = mid - 1;
			else
				return mid;
		}
		return min;
	}

	/*
	 * 折半的第二種方式。
	 */
	public static int halfSearch_2(int[] arr, int key) {
		int min = 0, max = arr.length - 1, mid;
		while (min <= max) {
			mid = (max + min) >> 1;
			if (key > arr[mid])
				min = mid + 1;
			else if (key < arr[mid])
				max = mid - 1;
			else
				return mid;
		}
		return -1;
	}

	/*
	 * 折半查找。提高效率,但是必須要保證該數組是有序的數組。
	 */
	public static int halfSearch(int[] arr, int key) {
		int min, max, mid; // 小大中
		min = 0;
		max = arr.length - 1;
		mid = (max + min) / 2;

		while (arr[mid] != key) {
			if (key > arr[mid]) {
				min = mid + 1;
			} else if (key < arr[mid]) {
				max = mid - 1;
			}
			if (min > max) {
				return -1;
			}
			mid = (max + min) / 2;
		}
		return mid;
	}

	// 定義功能,獲取key第一次出現在數組中的位置。如果返回是-1,那麼代表該key在數組中不存在。
	public static int getIndex(int[] arr, int key) {
		for (int x = 0; x < arr.length; x++) {
			if (arr[x] == key) {
				return x;
			}
		}
		return -1;
	}

練習進制轉換

	public static void main(String[] args) {
		toBin(6);
		System.out.println(Integer.toBinaryString(60));
		toHex(60);
	}

	/*
	 * 十進制 --> 十六進制
	 */
	public static void toHex(int num) {
		StringBuffer sb = new StringBuffer();
		for (int x = 0; x < 8; x++) {
			int temp = num & 15;
			if (temp > 9) {
				// System.out.println((char) (temp - 10 + 'A'));
				sb.append((char) (temp - 10 + 'A'));
			} else {
				// System.out.println(temp);
				sb.append(temp);
			}
			num = num >>> 4;
		}
		System.out.println(sb.reverse());
	}

	/*
	 * 十進制 --> 二進制
	 */
	public static void toBin(int num) {
		StringBuffer sb = new StringBuffer();
		while (num > 0) {
			sb.append(num % 2);
			num = num / 2;
		}
		System.out.println(sb.reverse());
	}

	public static void main(String[] args) {
		toHex(60);
	}

	/*
	 * 0 1 2 3 4 5 6 7 8 9 A B C D E F == 十六進制中的元素。 0 1 2 3 4 5 6 7 8 9 10 11 12 13
	 * 14 15
	 * 
	 * 查表法:將所有的元素臨時存儲起來。建立對應關係。 每一次&15後的值作爲索引去查建立好的表。就可以找對應的元素。 這樣比 -10+'a'簡單的多。
	 * 
	 * 這個表怎麼建立呢? 可以通過數據的形式來定義。 發現終於出結果了。但是是反着的。想要正過來呢?可以通過StringBuffer reverse功能來完成。
	 * 但是這個工具還沒有學習。
	 * 
	 * 所以可以使用已經學習過額容器,數組來完成存儲。
	 */
	public static void toHex(int num) {
		char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

		// 定義一個臨時容器。
		char[] arr = new char[8]; // '\u0000'
		int pos = arr.length;
		while (num != 0) {
			int temp = num & 15;
			arr[--pos] = chs[temp];
			num = num >>> 4;
		}
		// for (int x = 0; x < 8; x++) {
		// int temp = num & 15;
		// arr[x] = chs[temp];
		// num = num >>> 4;
		// }
		System.out.println("pos = " + pos);
		for (int x = pos; x < arr.length; x++) {
			System.out.print(arr[x]);
		}
	}

	public static void main(String[] args) {
		toHex(60); // 3C
		System.out.println();
		toBin(-6); // 11111111111111111111111111111010
		System.out.println();
	}

	public static void toBin(int num) {
		// 定義二進制的表
		char[] chs = { '0', '1' };
		// 定義一個臨時存儲容器
		char[] arr = new char[32];
		// 頂一個操作數組的指針
		int pos = arr.length;

		while (num != 0) {
			int temp = num & 1;
			arr[--pos] = chs[temp];
			num = num >>> 1;
		}
		for (int x = pos; x < arr.length; x++) {
			System.out.print(arr[x]);
		}
	}

	/*
	 * 0 1 2 3 4 5 6 7 8 9 A B C D E F == 十六進制中的元素。 0 1 2 3 4 5 6 7 8 9 10 11 12 13
	 * 14 15
	 * 
	 * 查表法:將所有的元素臨時存儲起來。建立對應關係。 每一次&15後的值作爲索引去查建立好的表。就可以找對應的元素。 這樣比 -10+'a'簡單的多。
	 * 
	 * 這個表怎麼建立呢? 可以通過數據的形式來定義。 發現終於出結果了。但是是反着的。想要正過來呢?可以通過StringBuffer reverse功能來完成。
	 * 但是這個工具還沒有學習。
	 * 
	 * 所以可以使用已經學習過額容器,數組來完成存儲。
	 */
	public static void toHex(int num) {
		char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

		// 定義一個臨時容器。
		char[] arr = new char[8]; // '\u0000'
		int pos = arr.length;
		while (num != 0) {
			int temp = num & 15;
			// System.out.println(chs[temp]);
			arr[--pos] = chs[temp];
			num = num >>> 4;
		}
		System.out.println("pos = " + pos); // pos = 6
		// 存儲數據的arr數組遍歷。
		for (int x = pos; x < arr.length; x++) {
			System.out.print(arr[x]);
		}
	}

	public static void main(String[] args) {
		toBin(6); // 110
		toOctal(60); // 74
		toHex(-60); // FFFFFFC4
	}

	// 十進制 --> 二進制
	public static void toBin(int num) {
		trans(num, 1, 1);
	}

	// 十進制 --> 八進制
	public static void toOctal(int num) {
		trans(num, 7, 3);
	}

	// 十進制 --> 十六進制
	public static void toHex(int num) {
		trans(num, 15, 4);
	}

	public static void trans(int num, int base, int offfset) {
		if (num == 0) {
			System.out.println(0);
			return;
		}
		char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		char[] arr = new char[32];
		int pos = arr.length;
		while (num != 0) {
			int temp = num & base;
			arr[--pos] = chs[temp];
			num = num >>> offfset;
		}

		for (int x = pos; x < arr.length; x++) {
			System.out.print(arr[x]);
		}
		System.out.println();
	}

二維數組

格式1:int[][] arr = new int[3][2];
定義了名稱爲arr的二維數組
二維數組中有3個一維數組
每一個一維數組中有2個元素
一維數組的名稱分別爲arr[0],arr[1],arr[2]
給第一個一維數組1角標位賦值爲78寫法是:arr[0][1] = 78;
格式2:int[][] arr = new int[3][];
二維數組中有3個一維數組
每個一維數組都是默認初始化值null
可以對這個三個一維數組分別進行初始化
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
格式3:int[]arr = {{3,8,2},{2,7},{9,0,1,6}};
定義一個名稱爲arr的二維數組
二維數組中的有三個一維數組
每一個一維數組中具體元素也都已初始化
第一個一維數組arr[0] = {3,8,2};
第二個一維數組arr[1] = {2,7};
第三個一維數組arr[2] = {9,0,1,6};
第三個一維數組的長度表示方式:arr[2].length;
練習:獲取arr數組中所有元素的和。使用for的嵌套循環即可。
注意特殊寫法情況:int[]x,y[];x是一維數組,y是二維數組。
	int[] arr1 = new int[3]; // 一維數組
		// 定義了名稱爲arr的二維數組。二維數組中有3個一維數組。每一個一維數組中有四個元素。
	int[][] arr2 = new int[3][4];

	int[][] arr3 = new int[3][];
	arr3[0] = new int[3];
	arr3[1] = new int[1];
	arr3[2] = new int[2];
	System.out.println(arr3); // [[I@52e922
	System.out.println(arr3[0]); // [I@25154f
	System.out.println(arr3[0][0]); // 0
	// 打印是二維數組的長度
	System.out.println(arr3.length); // 3
	// 打印二維數組中第一個一維數組長度
	System.out.println(arr3[0].length);

	int[][] arr4 = { { 3, 5, 1, 7 }, { 2, 3, 5, 8 }, { 6, 1, 8, 2 } };
	int sum = 0;
	for (int x = 0; x < arr4.length; x++) {
		for (int y = 0; y < arr4[x].length; y++) {
			sum += arr4[x][y];
		}
	}
	System.out.println("sum = " + sum);
	
		int[] x;
		int x[];
		
		int[][] y;
		int y[][];
		int[] y[];
		
		int[] x,y[]; // x一維,y二維
		int[] x;
		int[] y[];
		
		x[0] = y; // error 
		y[0] = x; // yes
		y[0][0] = x; // error
		x[0][0] = y; // error
		y[0][0] = x[0]; // ye
		x = y; // error

第三章 面向對象

  • 面向對象概念
  • 類與對象的關係
  • 封裝
  • 構造函數
  • this關鍵字
  • static關鍵字
  • 單例設計模式

面向對象概念


  • 理解面向對象
  • 面向對象的特點

理解面向對象

  • 面向對象是相對面向過程而言
  • 面向對象和麪向過程都是一種思想
  • 面向過程
    • 強調的是功能行爲
  • 面向對象
    • 將功能封裝進對象,強調具備了功能的對象。
  • 面向對象是基於面向過程的。

面向過程:打開冰箱 -> 存儲進冰箱 -> 關閉冰箱
面向對象:冰箱.打開 -> 冰箱.存儲 -> 冰箱.關閉

面向對象的特點

  • 是一種符合人們思考習慣的思想
  • 可以將複雜的事情簡單化
  • 將程序員從執行者轉換成了指揮者
  • 完成需求時:
    • 先要去找具有所需的功能的對象來用。
    • 如果該對象不存在,那麼創建一個具有所需功能的對象。
    • 這樣簡化開發並提高複用。

面向對象開發,設計,特徵

  • 開發的過程:其實就是不斷的創建對象,使用對象,指揮對象做事情。
  • 設計的過程:其實就是在管理和維護對象之間的關係。
  • 面向對象的特徵:
    • 封裝(encapsulation)
    • 繼承(inheritance)
    • 多態(polymorphism)

類與對象的關係


  • 使用計算機語言就是不斷的在描述現實生活中的事物。
  • Java中描述事物通過類的形式體現,類是具體事物的抽象,概念上的定義。
  • 對象即是該類事物實實在在存在的個體。
/*
	人開門:名詞提煉法。
*/{
	開門(){.():
	}
}{(){
		操作門軸等。
	}
}

類與對象(圖例)

類與對象


類的定義

  • 生活中描述事物無非就是描述事物的屬性行爲
    • 如:人有身高,體重等屬性,有說話,打球等行爲。
  • Java中用類class來描述事物也是如此
    • 屬性:對應類中的成員變量。
    • 行爲:對應類中的成員函數。
  • 定義類其實在定義類中的成員(成員變量和成員函數)。

成員變量和局部變量的區別?

  • 成員變量:
    • 成員變量定義在類中,在整個類中都可以被訪問。
    • 成員變量隨着對象的建立而建立,存在於對象所在的堆內存中。
    • 成員變量有默認初始化值。
  • 局部變量:
    • 局部變量只定義在局部範圍內,如:函數內,語句內等。
    • 局部變量存在於棧內存中。
    • 作用的範圍結束,變量空間會自動釋放。
    • 局部變量沒有默認初始化值。

創建對象,使用對象

public class Car { // 對Car這類事物進行描述
	String color = "red";
	int num = 4;
	void show() {
		System.out.println("color = " + color + "..num = " + num); // color = black..num = 4
}

class CarDemo {
	public static void main(String[] args) {
		demo c = new demo(); // 建立對象
		c.color = "black"; // 對象的屬性進行修改
		c.show(); // 使用對象的功能。
	}
}

對象內存結構

對象內存結構


匿名對象

  • 匿名對象是對象的簡化形式
  • 匿名對象兩種使用情況
    • 當對對象方法僅進行一次調用的時候
    • 匿名對象可以作爲實際參數進行傳遞

/*
 * 面向對象:三個特徵:封裝,繼承,多態。
 * 以後開發:其實就是找對象使用。沒有對象,就創建一個對象。
 * 找對象,建立對象,使用對象。維護對象的關係。
 * 
 * 類和對象的關係。
 * 現實生活中的對象:張三 李四。
 * 想要描述:提取對象中共性內容。對具體的抽象。
 * 描述時:這些對象的共性有:姓名,年齡,性別,學習Java功能。
 * 
 * 映射到Java中,描述就是class定義的類。
 * 具體對象就是對應Java在堆內存中用new建立實體。
 * 
 * 類就是:對現實生活中事物的描述。
 * 對象:就是這類事物,實實在在存在個體。
 * */

// 需求:描述汽車(顏色,輪胎數)。描述事物其實就是在描述事物的屬性和行爲。
// 屬性對應是類中變量,行爲對應類中的函數(方法)。
// 定時定義類,就是在描述事物,就是在定義屬性和行爲。屬性和行爲共同成爲類中的成員(成員變量和成員方法)。

/*
 * 成員變量和局部變量
 * 作用範圍:
 * 成員變量作用於整個類中。
 * 局部變量作用於函數中,或者語句中。
 * 在內存中的位置:
 * 成員變量:在堆內存中,因爲對象的存在,纔在內存中存在。
 * 局部變量:存在棧內存中。
 * */
public class Car {

	// 描述顏色
	String color = "red";
	// 描述輪胎數
	int num = 4;

	// 運行行爲
	void run() {
		System.out.println(color + ".." + num);
	}

	public static void main(String[] args) {

		// 生產汽車。在Java中通過new操作符來完成。
		// 其實就是在堆內存產生一個實體。
		Car c = new Car(); // c就是一個類類型變量。記住:類類型變量指向對象。
		// 需求:將已有車的顏色改成藍色。指揮該對象做使用。在Java指揮方式是:對象.對象成員
		c.color = "blue";
		c.run(); // blue..4
		Car c1 = new Car();
		c1.run(); // red..4

		Car c2 = new Car();
		c2.num = 5;
		Car c3 = c2;
		c3.color = "green";
		c3.run(); // green..5
		c2.run(); // green..5

		new Car().num = 5;
		new Car().color = "blue";
		new Car().run(); // red.4

		Car c4 = new Car();
		c4.run(); // red..4
		c4.num = 4;
		new Car().run(); // red..4
		/*
		 * 匿名對象是用方式一: 當對對象的方法只調用一次時,可以用匿名對象來完成,這樣寫比較簡化。 如果對一個對象進行多個成員調用,必須給這個對象起個名字。
		 * 匿名對象使用方式二: 可以將匿名對象作爲實際參數進行傳遞。
		 */
		Car q = new Car();
		show(q); // black..3

		show(new Car()); // black..3
	}

	// 需求:汽車修配廠。對汽車進行改裝,將來的車都改成黑車,三個輪胎。
	public static void show(Car c) {
		c.num = 3;
		c.color = "black";
		c.run();
	}
}


封裝(Encapsulation)


  • 封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
  • 好處:
    • 將變化隔離。
    • 便於使用。
    • 提高重用性。
    • 提高安全性。
  • 封裝原則:
    • 將不需要對外提供的內容都隱藏起來。
    • 把屬性都隱藏,提供公共方法對其訪問。

private(私有)關鍵字


  • private關鍵字:
    • 是一個權限修飾符。
    • 用於修飾成員(成員變量和成員函數)
    • 被私有化的成員只在本類中有效。
  • 常用之一:
    • 將成員變量私有化,對外提供對應的set,get方法對其進行訪問。提高對數據訪問的安全性。

/*
 * private:私有,權限修飾符:用於修飾類中的成員(成員變量,成員函數。)
 * 私有隻在本類中有效。
 * 
 * 將age私有化以後,類以外即使建立了對象也不能直接訪問。
 * 但是人應該有年齡,就需要在Person類提供對應訪問age的方式。
 * 
 * 注意:私有僅僅是封裝的一種表現形式。
 * 
 * 之所以對外提供訪問方式,就因爲可以在訪問方式中加入邏輯判斷等語句。
 * 對訪問的數據進行操作。提高代碼健壯性。
 * */
class Person {
	private int age;

	public void setAge(int a) {
		if (a > 0 && age < 130) {
			age = a;
			speak();
		} else {
			System.out.println("非法年齡");
		}
	}

	public int getAge() {
		return age;
	}

	void speak() {
		System.out.println("age = " + age);
	}
}

class PersonDemo {
	public static void main(String[] args) {
		Person p = new Person();
		// p.age = -20;
		p.setAge(20); // age = 20
		p.setAge(-20); // 非法年齡
		// p.speak();
	}
}

構造函數


  • 特點:

    • 函數名與類名相同
    • 不用定義返回值類型
    • 不可以寫return語句
  • 作用:給對象進行初始化。

  • 注意:

    • 默認構造函數的特點。
    • 多個構造函數是以重載的形式存在的。

構造函數、構造代碼塊

/*
 * 對象一建立就會調用與之對應的構造函數。
 * 
 * 構造函數的作用:可以用於給對象進行初始化。
 * 
 * 構造函數的小細節:
 * 當一個類中沒有定義構造函數時,那麼系統會默認給該類加入一個空參數的構造函數。
 * 當在類中自定義了構造函數後,默認的構造函數就沒有了。
 * 
 * 構造函數和一般函數在寫法上不同。
 * 在運行上也有不同。
 * 構造函數時在對象一建立就運行。給對象初始化。
 * 而一般方法是對象調用才執行,是給對象添加對象具備的功能。
 * 
 * 什麼時候定義構造函數呢?
 * 當分析事物時,該事物存在具備一些特性或者行爲,那麼將這些內容定義在構造函數中。
 * */
class Person {
	private String name;
	private int age;
	/*
	 * 構造代碼塊。 
	 * 作用:給對象進行初始化。 
	 * 對象一建立就運行,而且優先於構造函數執行。 
	 * 和構造函數的區別: 
	 * 構造代碼塊是給所有對象進行統一初始化。
	 * 而構造函數是給對應的對象初始化。 
	 * 構造代碼塊中定義的是不同對象共性的初始化內容。
	 */
	{
		System.out.println("person code run");
		cry();
	}

	public void setName(String n) {
		name = n;
	}

	public String getName() {
		return name;
	}

	public void setAge(int a) {
		age = a;
	}

	public int getAge() {
		return age;
	}

	public Person() {
		System.out.println("A: name = " + name + ",age = " + age);
	}

	public Person(String n) {
		name = n;
		System.out.println("B: name = " + name + ",age = " + age);
	}

	public Person(String n, int a) {
		name = n;
		age = a;
		System.out.println("C: name = " + name + ",age = " + age);
	}

	public void cry() {
		System.out.println("cry......");
	}

}
class PersonDemo2 {
	public static void main(String[] args) {
		// person code run
		// cry......
		// A: name = null,age = 0
		Person p1 = new Person();
		// p1.cry();

		// person code run
		// cry......
		// B: name = lisi,age = 0
		// 3
		// libusi
		Person p2 = new Person("lisi");
		p2.setAge(3);
		p2.setName("libusi");
		System.out.println(p2.getAge());
		System.out.println(p2.getName());

		// person code run
		// cry......
		// C: name = wangwu,age = 3
		Person p3 = new Person("wangwu", 3);
	}
}

this關鍵字


  • 特點:this代表其所在函數所屬對象的引用。
  • 換言之:this代表本類對象的引用。
  • 什麼時候使用this關鍵字呢?
    • 當在函數內需要用到調用該函數的對象時,就用this。

this關鍵字的應用

/*
 * this:看上去,是用於區分局部變量和成員變量同名情況。
 * this爲什麼可以解決這個問題?
 * this到底代表的是什麼呢?
 * 
 * this:就代表本類的對象,到底代表哪一個呢?
 * 			this代表它所在函數所屬對象的引用。
 * 			簡單說:哪個對象在調用this所在的函數,this就代表哪個對象。
 * this的應用:當定義類中功能時,該函數內部要用到調用該函數的對象時,這時用this來表示這個對象。
 * 			  但凡本類功能內部使用了本來對象,都用this表示。
 * */
class Person {
	private String name;
	private int age;

	public Person(int age) {
		this.age = age;
	}

	public Person(String name) {
		this.name = name;
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public void speak() {
		System.out.println("name = " + this.name + "..age = " + this.age);
		show();
	}

	public void show() {
		System.out.println(this.name);
	}

	/*
	 * 需求:給人定義一個用於比較年齡是否相同的功能。也就是是否同齡人。
	 */
	public boolean compare(Person p) {
		return this.age == p.age;
	}
}
class PersonDemo3 {
	public static void main(String[] args) {
		Person p = new Person("lisi");
		Person p1 = new Person("zhangsan");

		// name = lisi..age = 0
		// lisi
		p.speak();

		// name = zhangsan..age = 0
		// zhangsan
		p1.speak();

		// name = ss..age = 0
		// ss
		new Person("ss").speak();

		Person p2 = new Person(12);
		Person p3 = new Person(12);
		boolean b = p2.compare(p3);
		System.out.println(b); // true
	}
}

this關鍵字在構造函數間調用

/*
 * this語句:用於構造函數之間進行互相調用。
 * this語句只能定義在構造函數的第一行。因爲初始化要先執行。
 * */
class Person {
	private String name;
	private int age;

	{
		System.out.println("code run");
	}

	Person() {
		System.out.println("person run");
	}

	Person(String name) {
		this();
		this.name = "haha";
	}

	Person(String name, int age) {
		this(name); // p(name)
		this.name = name;
		this.age = age;
	}

	public void speck() {
		System.out.println(name + ".." + age);
	}
}
class PersonDemo4 {
	public static void main(String[] args) {
		Person p = new Person("lisi1", 30);
		p.speck(); // code run/person run/lisi1..30
		Person p1 = new Person("lisi2", 36);
		p1.speck(); // code run/person run/lisi2..36
	}
}

static(靜態)關鍵字


  • static關鍵字:
    • 用於修飾成員(成員變量和成員函數)
  • 被修飾後的成員具備以下特點:
    • 隨着類的加載而加載
    • 優先於對象存在
    • 被所有對象所共享
    • 可以直接被類名調用
  • 使用注意
    • 靜態方法只能訪問靜態成員
    • 靜態方法中不可以寫this,super關鍵字
    • 主函數是靜態的

/*
 * 靜態:static
 * 用法:是一個修飾符,用於修飾成員(成員變量,成員函數)。
 * 當成員被靜態修飾後,就多了一個調用方式,除了可以被對象調用外。
 * 還可以直接被類名調用。類名.靜態成員。
 * 
 * static特點:
 * 1. 隨着類的加載而加載
 * 	    也就說,靜態會隨着類的消失而消失,說明它的生命週期最長。
 * 2. 優先於對象存在
 * 	  明確一點,靜態是先存在,對象是後存在的。
 * 3. 被所有對象所共享
 * 4. 可以直接被類名所調用
 * 
 * 實例變量和類變量的區別:
 * 1. 存放位置:
 * 	  類變量隨着類的加載而存在於方法區中。
 * 	  實例變量隨着對象的建立而存在於堆內存中。
 * 2. 生命週期:
 * 	 類變量生命週期最長,隨着類的消失而消失。
 * 	 實例變量生命週期隨着對象的消失而消失。
 * 
 * 靜態使用注意事項:
 * 1. 靜態方法只能訪問靜態成員。
 * 	    非靜態方法即可以訪問靜態也可以訪問非靜態。
 * 2. 靜態方法中不可以定義this,super關鍵字。
 * 	    因爲靜態優先於對象存在,所以靜態方法中不可以出現this。
 * 3. 主函數是靜態的。
 * 
 * 靜態有利有弊:
 * 利處:對對象共享數據進行單獨空間的存儲,節省空間。沒有必要每一個對象中都存儲一份。
 * 	     可以直接被類名調用。
 * 弊端:生命週期過長
 * 		 訪問出現侷限性(靜態雖好,只能訪問靜態。)
 * */
class Person {
	String name; // 成員變量(實例變量)
	static String country = "CN"; // 靜態的成員變量(類變量)

	public void show() {
		System.out.println(name + "::" + country); // lisi::CN
		System.out.println(this.country); // CN
		haha();
	}

	public static void show1() {
		System.out.println(country); // CN
		// System.out.println(this.country); // error
		// System.out.println(name + "::" + country); // error
		// haha(); // error
	}

	public void haha() {

	}
}
class StaticDemo {
	public static void main(String[] args) {
		Person p = new Person();
		p.name = "lisi";
		p.show(); 

		System.out.println(p.country); // CN
		System.out.println(Person.country); // CN

		Person.show1();
	}
}

main函數

/*
 * public static void main(String[] args)
 * 
 * 主函數:是一特殊的函數,作爲程序的入口,可以被Java使用。
 * 
 * 主函數的定義:
 * public:代表着該函數訪問權限是最大的。
 * static:代表主函數隨着類的加載就已經存在了。
 * void:主函數沒有具體的返回值。
 * main:不是關鍵字,但是是一個特殊的單詞,可以被jvm識別。
 * (String[] args):函數的參數,參數類型是一個數組,該數組中的元素是字符串,字符串類型的數組。
 * 
 * 主函數是固定格式的:jvm識別。
 * 
 * jvm在調用主函數時,傳入的是new String(0);
 */
class MainDemo {
	public static void main(String[] arguments) { // new String[]
		System.out.println(arguments); // [Ljava.lang.String;@52e922
		System.out.println(arguments.length); // 0
		// System.out.println(arguments[0]); // java.lang.ArrayIndexOutOfBoundsException越界

		String[] arr = { "haha", "hehe", "xixi", "heihei", "giaogiao", "hiahia" };
		MainTest.main(arr);
	}
}
class MainTest {
	public static void main(String[] args) {
		for (int x = 0; x < args.length; x++) {
			System.out.println(args[x]);
		}
	}
}

靜態是什麼時候使用?

/*
 * 什麼時候使用靜態?
 * 
 * 要從兩方面下手:
 * 因爲靜態修飾的內容有成員變量和成員函數。
 * 什麼時候定義靜態變量(類變量)呢?
 * 		當對象中的出現共享數據時,該數據被靜態所修飾。
 * 		對象中的特有數據要定義成非靜態存在於堆內存中。
 * 什麼時候定義靜態函數(類函數)呢?
 * 		當功能內部沒有訪問到非靜態數據(對象的特有數據),
 * 		那麼該功能可以定義成靜態的。
 * */	

靜態的應用-工具類

/*
 * 靜態的應用:
 * 
 * 每一個應用程序中都有共性的功能
 * 可以將這些功能進行抽取,獨立封裝。以便複用。
 * 
 * 雖然可以通過建立ArrayTool的對象使用這些工具方法,對數組進行操作。
 * 發現了問題:
 * 1. 對象是用於封裝數據的,可是ArrayTool對象並未封裝特有數據。
 * 2. 操作數組的每一個方法都沒有用到ArrayTool對象中的特有數據。
 * 
 * 這時就考慮,讓程序更嚴謹,是不需要對象的。
 * 可以將ArrayTool中的方法都定義成static的,直接通過類名調用即可。
 * 
 * 將方法都靜態後,可以方便於使用,但是該類還是可以被其他程序建立對象的。
 * 爲了更爲嚴謹,強制讓該類不能建立對象。
 * 可以通過將構造函數私有化完成。
 * */

class ArrayTool {
	private ArrayTool() {

	}
	
	public static int getMax(int[] arr) {
		int max = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] > arr[max]) {
				max = x;
			}
		}
		return arr[max];
	}

	public static int getMin(int[] arr) {
		int min = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] < arr[min]) {
				min = x;
			}
		}
		return arr[min];
	}

	public static void selectSort(int[] arr) {
		for (int x = 0; x < arr.length - 1; x++) {
			for (int y = x + 1; y < arr.length; y++) {
				if (arr[x] > arr[y]) {
					swap(arr, x, y);
				}
			}
		}
	}

	public static void bubblesort(int[] arr) {
		for (int x = 0; x < arr.length - 1; x++) {
			for (int y = 0; y < arr.length - x - 1; y++) {
				if (arr[y] > arr[y + 1]) {
					swap(arr, y, y + 1);
				}
			}
		}
	}

	private static void swap(int[] arr, int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}

	public static void printArray(int[] arr) {
		System.out.print("[");
		for (int x = 0; x < arr.length; x++) {
			if (x != arr.length - 1) {
				System.out.print(arr[x] + ", ");
			} else {
				System.out.print(arr[x] + "]\n");
			}
		}
	}
}
public class ArrayToolDemo {
	public static void main(String[] args) {
		int[] arr = { 1, 3, 9, 4, 2 };
		int max = ArrayTool.getMax(arr);
		System.out.println("max = " + max); // 9
		// ArrayTool tool = new ArrayTool();
		
		/*
		 * ArrayTool tool = new ArrayTool(); 
		 * int max = tool.getMax(arr);
		 * System.out.println("max = " + max); // 9 
		 * int min = tool.getMin(arr);
		 * System.out.println("min = " + min); // 1 
		 * tool.printArray(arr); // [1, 3, 9,4, 2] 
		 * tool.selectSort(arr); 
		 * tool.printArray(arr); // [1, 2, 3, 4, 9]
		 */
	}
}

幫助文檔的製作JavaDOC

javadoc -d myhelp -author -version ArrayTool.java
/**
 * 接下來,將ArrayTool.class文件發送給其他人,其他人只要將該文件設置到classpath路徑下,就可以使用該工具類。
 * 但是,很遺憾,該類中到底定義了多少個方法,對方卻不清除,因爲該類並沒有使用說明書。
 * 開始製作程序的說明書,Java的說明書通過文檔註釋來完成。
 */

/**
 * 這是一個可以對數組進行操作的工具類,該類中提供了,獲取最值,排序等功能。
 * 
 * @author bing
 * @version v1.1
 */
public class ArrayTool {
	/**
	 * 空參數構造函數
	 */
	private ArrayTool() {

	}

	/**
	 * 獲取一個整型數組中的最大值。
	 * 
	 * @param arr
	 *            接收一個int類型的數組
	 * @return 會返回一個該數組中最大值。
	 */
	public static int getMax(int[] arr) {
		int max = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] > arr[max]) {
				max = x;
			}
		}
		return arr[max];
	}

	/**
	 * 獲取一個整型數組中的最小值。
	 * 
	 * @param arr
	 *            接收一個int類型的數組
	 * @return 會返回一個該數組中最小值。
	 */
	public static int getMin(int[] arr) {
		int min = 0;
		for (int x = 1; x < arr.length; x++) {
			if (arr[x] < arr[min]) {
				min = x;
			}
		}
		return arr[min];
	}

	/**
	 * 給int數組進行選擇排序。
	 * 
	 * @param arr
	 *            接收一個int類型的數組
	 */
	public static void selectSort(int[] arr) {
		for (int x = 0; x < arr.length - 1; x++) {
			for (int y = x + 1; y < arr.length; y++) {
				if (arr[x] > arr[y]) {
					swap(arr, x, y);
				}
			}
		}
	}

	/**
	 * 給int數組進行冒泡排序。
	 * 
	 * @param arr
	 *            接收一個int類型的數組
	 */
	public static void bubblesort(int[] arr) {
		for (int x = 0; x < arr.length - 1; x++) {
			for (int y = 0; y < arr.length - x - 1; y++) {
				if (arr[y] > arr[y + 1]) {
					swap(arr, y, y + 1);
				}
			}
		}
	}

	/**
	 * 給數組中元素進行位置的置換。
	 * 
	 * @param arr
	 *            接收一個int類型的數組
	 * 
	 * @param a
	 *            變量換的位置
	 * 
	 * @param b
	 *            變量換的位置
	 */
	private static void swap(int[] arr, int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}

	/**
	 * 用於打印數組中的元素。打印形式是:[elemet1, elemet2, ...]
	 */
	public static void printArray(int[] arr) {
		System.out.print("[");
		for (int x = 0; x < arr.length; x++) {
			if (x != arr.length - 1) {
				System.out.print(arr[x] + ", ");
			} else {
				System.out.print(arr[x] + "]\n");
			}
		}
	}
}

/*
 * 一個類中默認會有一個空參數的構造函數,這個默認的構造函數的權限和所屬類一致。
 * 如果類被public修飾,那麼默認的構造函數也帶public修飾符。
 * 如果類沒有被public修飾,那麼默認的構造函數,也沒有public修飾。
 * 
 * 默認構造函數的權限是隨着類的變化而變化的。
 */

靜態代碼塊

/*
 * 靜態代碼塊。
 * 格式:
 * static {
 *		靜態代碼塊中的執行語句。
 * }
 * 特點:隨着類的加載而執行,只執行一次,並優先於主函數。
 * 用於給類進行初始化的。
 * */
class StaticCode {
	int num = 9;

	public StaticCode() {
		System.out.println("b");
	}

	static {
		System.out.println("a");
	}
	{
		System.out.println("c" + this.num);
	}

	StaticCode(int x) {
		System.out.println("d");
	}

	public static void show() {
		System.out.println("show run");
	}
}

class StaticCodeDemo {
	static {
		System.out.println("b");
	}

	public static void main(String[] args) {

		new StaticCode();
		new StaticCode();
		System.out.println("over"); 
		StaticCode.show();
		StaticCode a = null;
		a = new StaticCode();
		new StaticCode(4);
	}

	static {
		System.out.println("c");
	}
}

運行結果

b
c
a
c9
b
c9
b
over
show run
c9
b
c9
d

對象的初始化過程

class Person {
	public Person() {
	}

	private String name = "hah";
	private int age;
	private static String country = "cn";

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	{
		System.out.println(name + ".." + age);
	}

	public void setName(String name) {
		this.name = name;
	}

	public void speak() {
		System.out.println(this.name + "..." + this.age);
	}

	public static void showCountry() {
		System.out.println("country=" + Person.country);
		Person.method();
	}

	public static void method() {
		System.out.println("method run");
	}
}

public class PersonDemo {
	public static void main(String[] args) {
		Person p = new Person("zhangsan", 20);
		p.setName("lisi");
		new Person();
	}
}
/*
 * Person p = new Person("zhangsan", 20); 
 * 該句話都做了什麼事情?
 * 1. 因爲new用到了Person.class文件,所以會先找到Person.class文件並加載到內存中。 
 * 2. 會執行該類中的static代碼塊,如果有的話,給Person.class類進行初始化。
 * 3. 在堆內存中開闢空間,分配內存地址。 
 * 4. 在堆內存中建立對象的特有屬性,並進行默認初始化。 
 * 5. 對屬性進行顯示初始化。 
 * 6. 對對象進行構造代碼塊初始化。 
 * 7. 對對象進行對應的構造函數初始化。
 * 8. 將內存地址賦給棧內存中的p變量。
 */

單例設計模式

/*
 * 設計模式:解決某一類問題最行之有效的方法。
 * Java中23種設計模式:
 * 單例設計模式:解決一個類在內存中只存在一個對象。
 * 
 * 想要保證對象唯一。
 * 1. 爲了避免其他程序過多建立該類對象,先禁止其他程序建立類對象。
 * 2. 還爲了讓其他程序可以訪問到該類對象,只好在本類中自定義一個對象。
 * 3. 爲了方便其他程序對自定義對象的訪問,可以對外提供一些訪問方式。
 * 
 * 這三步怎麼用代碼體現呢?
 * 1. 將構造函數私有化。
 * 2. 在類中創建一個本類對象。
 * 3. 提供一個方法可以獲取該對象。
 * 
 * 對於事物該怎麼描述,還怎麼描述。
 * 當需要將該事物的對象保證在內存中唯一時,就將以上的三步加上即可。
 * 
 * */
class Single {
	private int num;

	public void setNum(int num) {
		this.num = num;
	}

	public int getNum() {
		return num;
	}

	private Single() {
	}

	private static Single s = new Single();

	public static Single getInstance() {
		return s;
	}
}

class SingleDemo {
	public static void main(String[] args) {
		Single ss = Single.getInstance();
		System.out.println(ss); // test9.Single@52e922

		// Single s1 = new Single();
		// Single s2 = new Single();
		// s1.setNum(40);
		// System.out.println(s2.getNum()); // 0

		Single s1 = Single.getInstance();
		Single s2 = Single.getInstance();
		s1.setNum(23);
		System.out.println(s2.getNum()); // 23

		// Student s1 = new Student();
		// s1.setAge(30);
		// Student s2 = new Student();
		// s2.setAge(12);

		// Student s1 = Student.getInstance();
		// Student s2 = Student.getInstance();
	}
}

class Student {
	private int age;

	private Student() {
	}

	private static Student s = new Student();

	public static Student getInstance() {
		return s;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getAge() {
		return age;
	}
}

單例設計模式方式二

/*
 * 這個是先初始化對象。
 * 稱爲:餓漢式。
 * 
 * Single類一進內存,就已經創建好了對象。
 * */
class Single {
	private static Single s = new Single();

	private Single() {
	}

	public static Single getInstance() {
		return s;
	}

}

/*
 * 對象是方法被調用時,才初始化,也叫做對象的延時加載。
 * 稱爲:懶漢式。
 * Single類進內存,對象還沒有存在,只有調用了getInstance方法時,才建立對象。
 * */
class Single {
	private static Single s = null;

	private Single() {

	}

	public static Single getInstance() {
		if(s==null) {
			synchronized(Single.class) {
				if (s == null) {
					s = new Single();
				}
			}
		}
		return s;
	}
}

/*
 * 記錄原則:定義單例,建議使用餓漢式。
 * */

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章