第一章 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 符號:_$組成
- 定義合法標識符規則:
- 數字不可以開頭。
- 不可以使用關鍵字。
- 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中常量的分類:
- 整數常量。所有整數
- 小數常量。所有小數
- 布爾型常量。較爲特有,只有兩個數值。true false
- 字符常量。將一個數字字母或者符號用單引號(’’)標識。
- 字符串常量。將一個或者多個字符用雙引號標識。
- 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*2的2次冪
<< 其實就是乘以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;
}
- switch語句選擇的類型只有四種:byte、short、int、char。
- case之間與default沒有順序。先執行第一個case,沒有匹配的case執行default。
- 結果switch語句的兩種情況:遇到break,執行到switch語句結束。
- 如果匹配的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(初始化表達式;循環條件表達式;循環後的操作表達式) {
執行語句;
}
- for裏面表達式運行的順序,初始化表達式只讀一次,判斷循環條件,爲真就執行循環體,然後再執行循環後的操作表達式,接着繼續判斷循環條件,重複找的過程,直到條件不滿足爲止。
- while與for可以互換,區別在於for爲了循環而定義的變量在for循環結束就是在內存中釋放。而while循環使用的變量在循環結束後還可以繼續使用。
- 最簡單無限循環格式: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語句:應用於循環結構
- 這兩個語句離開應用範圍,存在時沒有意義的。
- 這兩個語句單獨存在下面都不可以有語句,因爲執行不到
- continue語句結束本次循環繼續下次循環。
- 標號的出現,可以讓這兩個語句作用於指定的範圍。
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;
}
}
/*
* 記錄原則:定義單例,建議使用餓漢式。
* */