使用Editplus工具,編輯Java代碼時,各類字體顏色所表達的含義
黑色:標識符
藍色:關鍵字
綠色:註釋
紅色:表示這個類是SUN公司的JDK寫好的一個類。
標識符
什麼是標識符:
凡是程序員自己有權力命名的單詞都是標識符。
例如:類名;方法名;變量名;接口名;常量名…
但是!!!main不能更改
標識符命名規則:
1,標識符只能由數字;字母(包括中文);下劃線;美元符號¥組成。
2,標識符不能以數字開頭
3,關鍵字不能作爲標識符
4,標識符是嚴格區分大小寫的:大寫A與小寫a是不一樣的
5,理論上沒有長度限
標識符命名規範:
優點:有利於代碼的可讀性;讓其它程序員更加容易理解。
1,見名知意(最好一看單詞就能知道什麼意思)
2,遵循駝峯命名方式(一高一低。例如:BiaoShiFuTest,一眼就能看出來意思)
3,類名,接口名特殊要求:首字母大寫,後面每個單詞首字母大寫
4,變量名,方法名特殊要求:首字母小寫,後面每個單詞首字母大寫
5,所有常量名:全部大寫,並且單詞與單詞之間採用下劃線_銜接
關鍵字
提前定義好了的一些具有特殊含義的單詞。
這些單詞全部小寫,具有特殊含義,不能用作標識符
變量
三要素:數據類型;變量名;值
類型決定空間大小
名字方便以後訪問
值是變量保存的數據
變量聲明: 數據類型 變量名;
變量分類:
在方法體內聲明的變量稱爲**局部變量**;
在方法體外,類體中聲明的變量稱爲**成員變量**;
注意:對於成員變量來說,沒有手動賦值時,系統會默認賦值
變量作用域(變量的有效範圍):
出了大括號就不認識了。
遵循就近原則:誰近訪問誰。
數據類型
作用:用來聲明變量,爲變量分配空間。
第一種:基本數據類型:
基本數據類型可以分爲4大類8小種
四大類:
第一類:整數型
byte;short;int;long
第二類:浮點型
float;double
第三類:布爾型
boolean:只有false和true;false假,true真
第四類:字符型
char:必須用單引號括起來,屬於文字
8小種:
byte;short;int;long
float;double
boolean
char
第二種數據類型:引用型數據類型
字符串型String屬於引用數據類型
Java中除了基本數據類型外,其他的都是引用數據類型
引用數據類型後期面向對象纔會接觸
8種類型的區別:
所佔空間不同
類型 佔用字節數量(byte) 取值範圍
byte 1 【-128 ~ 127】
short 2 【-32768 ~ 32767】
int 4 【-2147483648 ~ 2147483647】
long 8
folat 4
double 8
booleam 1
char 2 【0 ~ 65535】
關於計算機存儲單位:
計算機只能識別二進制,(0001101100)
1字節 = 8bit ---> 1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
關於二進制(電腦中有計算機可以直接計算除進制,切換到程序員):
在計算機中,一個二進制最左邊是符號位,爲0表示正數,爲1表示負數
二進制轉化十進制:注意!!!遇到二進制0時,就是2的n次方*0
舉例說明:(1111;1001)
1 1 1 1
2的3次方 2的2次方 2的1次方 2的0次方
8 4 2 1
8*1 + 4*1 + 2*1 + 1*1 = 15
-----------------------------------------------------------
1 0 0 1
2的3次方 2的2次方 2的1次方 2的0次方
8 4 2 1
8*1 + 4*0 + 2*0 + 1*1 = 9
十進制轉換二進制:
該數除2;餘數逆序輸出。
字符編碼(編碼與解碼必須是同一種方式!)
含義:
字符編碼是認爲定義的一套轉換表
在字符編碼中規定了一系列的文字對應的二進制
字符編碼是人爲規定的。
ASCII碼(26個字母編碼)
‘a’--(採用二進制碼進行編碼)-->01100001
01100001--(採用ASCII碼進行解碼)-->‘a’
‘a’---->97
'b'---->98
......
'A'---->65
'B'----->66
......
'0'----->48(文字“0”)
國際標準組織制定了ISO-8859-1編碼
中文編碼方式:GB2312<GBK<GB18030(容量大小關係)
Java中字符編碼方式:unicode(支持所有文字);包括:UTF-8,UTF-16
注意!!!unicode編碼是十六進制的。
原碼,反碼,補碼(只需瞭解)
前提:
計算機在任何情況下都只能識別二進制。
計算機在底層儲存數據時,都是採用二進制補碼形式,原因是:補碼形式效率更高。
二進制有:原碼,反碼,補碼
對於一個正數來說:二進制的原碼,反碼,補碼是完全相同的。
例如:
byte i = 1;
對應的二進制原碼:00000001
對應的二進制反碼:00000001
對應的二進制補碼:00000001
對於一個負數來說:二進制原碼,反碼,補碼的關係是?
舉例:
byte i = -1;
對應的二進制原碼是:10000001
對應的二進制反碼是(在原碼基礎上,符號位不變,其他位取反):11111110
對應的二進制補碼是(在編譯後的反碼進行+1):11111111
在計算機中一個字節的最左邊位爲0時表示正數,爲1時表示負數。
舉例:
byte i = 150;
可以採用逆推導的方式推算出這個二進制補碼對應的原碼是啥。
該數二進制補碼形式是:10010110
該數二進制反碼形式是:10010101
該數二進制原碼形式是:11101010
輸出結果爲:-106
轉義字符(字符型):
'\t'是製表符,相當於鍵盤上的tab鍵。
'\n'是換行符
'\''表示普通的“'”單引號字符
'\\'表示普通的"\"反斜槓字符
'\"\"'表示普通的“""”雙引號字符
class Test_LianXi2
{
public static void main(String[] arg){
//普通的‘t’字符
char c1 = 't';
System.out.println(c1);
//製表符‘\t‘相當於鍵盤的tad鍵
char c2 = '\t';
System.out.println("這個"+c2+"\\t是製表符");
System.out.println("這個\\t是製表符");
//’\n‘表示換行符。
char c3 = '\n';
System.out.println("這個\\n是換行符");//這行輸出結果是換行兩次
//'\''表示普通的“'”單引號字符
char c4 = '\'';
System.out.println("這個\\'表示普通的\"'\"單引號字符 ");
//'\"\"'表示普通的“"”雙引號字符
char c5 = '\"';
System.out.println("這個"+"\\\""+"\\\""+"表示普通的“\"\"”雙引號字符");
// '\\'表示普通的"\"反斜槓字符
char c6 = '\\';
System.out.println("這個\\表示普通的\"\\\"反斜槓字符");
//反斜槓u表示unicode編碼
//unicode編碼是十六進制的。
char c7 = '\u4e2d';
System.out.println(c7);
}
}
輸出結果:(最後一個輸出反斜槓字符代碼沒弄好)
整型變量:
在Java中有一條非常重要的結論:
在任何情況下,整型的"字面量/數據"默認被當作int類型處理。
如果希望該”字面量/數據“被當作long類型來處理,需要在"字面量/數據"後面加"L/l"(大寫L或者小寫l)。
例題:
class Test_LianXi3
{
public static void main(String[]arg)
{
//214783647默認當作int來處理,這個數是int範圍的最大值,
long a = 214783647;
System.out.println(a);
//214783648默認當作int來處理,但是超出了int範圍,如果想要不報錯只能在這個數後面+L;
long b = 214783648L;
System.out.println(b);
}
}
輸出結果:
類型轉換
1,小容量可以直接賦值爲大容量,被稱爲自動類型轉換。
2,大容量不能直接賦值爲小容量,必須加強制類型轉換符進行強制轉換。需要注意的是:加了強制類型轉換符後,運行時可能會損失精度。
例題:
class Test_LianXi3
{
public static void main(String[]arg)
{
//將100賦值給c;默認當作int類型處理
int c = 100;
System.out.println(c);
//將c的值複製一份給d。
int d = c;
System.out.println(d);
//將200賦值給e,數據類型爲long
long e = 200L;
//強制類型轉換,將long類型轉換爲int類型
int f = (int)e;
System.out.println(f);
/*
300默認當作int類型處理,但是它超過了byte的最大取值範圍,
這裏想要運行通過,必須加強制類型轉換符,但是會損失精度。
300這個int類型對應的二進制爲:00000000 00000000 0000001 00101100
byte佔用1個字節,砍掉前3個字節,結果是:00101100;轉化爲十進制則爲44
所以最後輸出結果爲44
*/
byte a1 = (byte)300;
System.out.println(a1);
//100默認當作int類型處理,未超出byte的最大取值範圍
byte a2 = 100;
System.out.println(a2);
}
}
輸出結果:
注意!!!
當一個整數沒有超出char;short;long的取值範圍的時候,這個整數是可以直接賦值給char,short,long類型的變量。
當一個整數賦值給char類型變量的時候,會自動轉換成charyuann字符型,最終輸出結果是一個字符。
例外~!!!!char,short,long做混合運算時,會先轉換爲int類型再進行運算。
多種數據類型做混合運算時,最終結果類型是”最大容量“對應的類型(但是!!!上面char,short,long混合運算是例外)
舉例:
class Test_LianXi4
{
public static void main(String[] arg)
{
//這裏的a是ASCII碼編譯後的十進制數字97
char a1 = 'a';
long b = 2;
//先將a1,b轉換爲int類型後再進行運算,輸出結果爲99
System.out.println(a1 + b);
//a1,b轉換爲int類型後,再將其結果強制轉換爲short類型
short c = (short)(a1+b);
//輸出結果爲99
System.out.println(c);
}
}
浮點型
1,float和double存儲數據都是近似值。(有無限循環的小數,但是計算機內存有限無法儲存。)
2,任意一個浮點型都比整數型空間大。
3,Java中規定,任何一個浮點型數據默認被當作double類型處理,如果要當做float處理,需要在字面量後面+F/f
4,當在財務系統等高精度領域軟件使用時,通常不使用浮點型,使用java.math.BigDecimal(它是引用數據類型)
布爾型
1,在Java語言中boolean類型只有兩個值,沒有其它值!!!
2,通常使用在邏輯運算中(充當條件)
綜合上述:在類型轉換是需要遵循哪些規則?(筆試,面試可能用到!!!)
第一條:八種數據類型中,除了boolean類型不能轉換外,其它七種都可以進行轉換
第二條:如果整數型字面量沒有超出byte,short,char的取值範圍,可以直接將其賦值爲byte,short,char類型的變量。
第三條:小容量向大容量轉換稱爲自動類型轉換,容量從小到大的排序爲:byte<short(char)<int<long<float<double,其中short和char都表示兩個字節,但是char表示更大的正整數。
第四條:大容量轉換爲小容量,稱爲強制類型轉換,編寫時必須添加”強制類型轉換符“,但可能出現精度損失,謹慎使用。
第五條:(例外)byte,short,char類型混合運算時,先各自轉換成int類型再做運算。
第六條:多種數據類型混合運算,各自先轉換撐容量最大的那一種再做運算。
運算符
算術運算符
重點掌握**++:自加1,–:自減1**
++可以出現在變量前也可以出現在變量後,++執行完之後,都會自加1
語法:當++出現在變量後,會先做賦值運算,再自加1
當++出現在變量前,會先自加1,再做賦值運算。
舉例:
class Test_LianXi5
{
public static void main(String[] arg)
{
int a = 10;
//先進行賦值運算:將a=10賦值給b,即b=10,再進行a++,即a=11
int b = a++;
System.out.println(a);//輸出結果爲:11
System.out.println(b);//輸出結果爲:10
int c = 20;
//先進行++c運算:即c = 21,再進行賦值運算:即:d = 21;
int d = ++c;
System.out.println(c);//輸出結果爲:21
System.out.println(d);//輸出結果爲:21
int e = 30;
//這裏的e++等同於:
//int e2 = e++;
//System.out.println(e2);
System.out.println(e++);//輸出結果爲30
System.out.println(e);//輸出結果爲31
int f = 40;
//這裏的++f等同於:
//int f2 = ++f;
//System.out.println(f2);
System.out.println(++f);//輸出結果爲41
System.out.println(f);//輸出結果爲41
}
}
–:自減運算可以自己根據以上代碼測試。
關係運算符
規則:
所有關係運算符的運算結果都是布爾類型,不是true就是false,不可能爲其它值。
關係運算符中如果有兩個符號,符號之間不能有空格。
舉例:
class Test_LianXi6
{
public static void main(String[] arg)
{
int a = 10;
int b = 10;
System.out.println(a > b);//false
System.out.println(a < b);//false
System.out.println(a >= b);//true
System.out.println(a <= b);//true
System.out.println(a == b);//true
System.out.println(a != b);//false
}
}
邏輯運算符:
&:邏輯與(並且):兩邊都是true,結果纔是true
(不管第一個表達式結果是什麼,第二個表達式一定會執行)
|:邏輯或(或者):有一邊是true,結果就是true
(不管第一個表達式結果是什麼,第二個表達式一定會執行)
!:邏輯非(取反):取相反的結果
&&:短路與:兩邊都是true,結果纔是true;相比邏輯與&,效率高
(如果第一個表達式爲false,第二個表達式不會執行)
||:短路或:有一邊是true,結果就是true
(如果第一個表達式爲true,第二個表達式不會執行)
特點:
邏輯運算符兩邊要求都是布爾類型,並且最終的運算結果也是布爾類型。
舉例:
class Test_LianXi7
{
public static void main(String[] arg)
{
//只要有一邊是false,那結果就是false.兩個都是true,最終結果就爲true
System.out.println(true & true);//true
System.out.println(true & false);//false
System.out.println(false & false);//false
System.out.println(100>90 & 100<110);//true
//只要有一邊是true,那結果就是true,兩個都是false,那結果就是false
System.out.println(true | true);//true
System.out.println(true | false);//true
System.out.println(false | false);//false
System.out.println(100>90 | 100>110);//true
//取反(不是...):
System.out.println(!true);//false;真的——》取相反的結果——》假
System.out.println(!false);//true;假的——》取相反的結果——》真
//這裏100>110需要加括號,優先級問題
System.out.println(!(100>110));//true;100不大於110——》爲假——》取相反的結果——》爲真
int a = 10;
int b = 11;
//第一個表達式a>b結果爲false,所以整個結果已經確定爲false,但是它會繼續執行第二個表達式a<b++
System.out.println(a > b & a < b++);
System.out.println(b);//輸出結果爲12
//測試短路與&&
int c = 10;
int d = 11;
//使用短路與&&時,當第一個表達式爲false,不會執行第二個表達式,這種現象被稱爲短路.
System.out.println(c > d && c < d++);
System.out.println(d);//輸出結果爲11
int aa = 10;
int bb = 11;
//第一個表達式a<b結果爲true,所以整個結果已經確定爲true,但是它會繼續執行第二個表達式a<b++
System.out.println(aa < bb | aa > bb++);
System.out.println(bb);//輸出結果爲12
//測試短路或||
int cc = 10;
int dd = 11;
//使用短路或||時,當第一個表達式爲true,不會執行第二個表達式,這種現象被稱爲短路或.
System.out.println(cc < dd || cc < dd++);
System.out.println(dd);//輸出結果爲11
}
}
賦值運算符
1,包括基本賦值運算符和擴展賦值運算符
基本賦值運算符:=
擴展賦值運算符:+=,-=,*=,/=,%= (兩個符號之間不能有空格)
使用擴展運算符時,永遠不會改變變量類型。
探索:x +=10真的完全等同於x = x+10嗎?
結論:不是完全等同。
舉例說明:
class Test_LianXi8
{
public static void main(String[] arg)
{
int a = 10;
a += 10;//類似於a = a+10;但是本質上並不是完全相同
byte x = 100;//100沒有超出byte的取值範圍,可以直接賦值
System.out.println(x);//輸出結果爲100
//以下代碼會編譯報錯:不兼容的類型———10+i是int類型,int類型不能直接賦值給byete類型變量x
//x = x+10; 編譯報錯
//這裏的x +=10,等同於:x = (byte)(x + 10);強制類型轉換。
x += 10;
System.out.println(x);//輸出結果爲110
byte y = 100;
y += 200;//由於相加後超出了byte取值範圍,結果會自動損失精度
System.out.println(y);//輸出結果爲44
int i = 100;
i += 100;
System.out.println(i);//200
i -= 100;
System.out.println(i);//100
i *= 10;
System.out.println(i);//1000
i /= 10;
System.out.println(i);//100
i %= 30;
System.out.println(i);//10
}
}
條件運算符
語法格式:
布爾表達式 ? 表達式1 : 表達式2
執行原理:
當布爾表達式爲true時,表達式1的結果作爲整個表達式結果
當布爾表達式爲false時,表達式2的結果作爲整個表達式結果
舉例:
class Test_LianXi9
{
public static void main(String[] arg)
{
boolean a = true;
//注意前面的數據類型需要根據表達式1和表達式2決定。
char b = a ? '男' : '女';
System.out.println(b);//輸出男
//在println裏面可以存放任何數據類型的變量
System.out.println(a ? '男' : '女');//輸出結果:男
}
}
字符串運算符
運算符:+
注意!!!
當 + 運算符兩邊的”任意一邊“時字符串類型,那麼這個 + 會進行字符串拼接操作。
遵循從左至右的順序進行運算,出現括號,則先運算括號內的
口訣:
加一個雙引號:”“,然後雙引號中間加兩個加號:”++“,然後兩個加號中間加變量名”+變量名+“
控制語句:
選擇語句
if語法:
分支語句,也叫條件語句。
if 語句格式:
一:if(布爾表達式){
java語句;
}
二:if(布爾表達式){
Java語句
}else{
Java語句
}
三:if(布爾表達式){
Java語句;
}else if(布爾表達式){ //分支
Java語句;
}...
四:if(布爾表達式){
Java語句;
}else if(布爾表達式){ //分支
Java語句;
}else{
Java語句;
}
注意:
1,對於if語句來說,在任何情況下只能有一個分支執行,並且執行後就表示if語句結束了。
2,只要是帶有else分支的,一定會有一個分支執行,,沒有else分支的可能會導致最後一個分支不執行。
3,控制語句之間是可以嵌套的,建議一個語句一個語句的進行分析,不要雜亂在一起分析。
代碼演示:
class Test_if
{
public static void main(String[]arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.print("請輸入您的年齡:");
int i = s.nextInt();
System.out.println();
/*if(i >= 0 && i <= 5){
System.out.println("幼兒");
}else if(i >= 6 && i <= 10){
System.out.println("少兒");
}else if(i >= 11 && i <= 18){
System.out.println("青年");
}else if(i >= 19 && i <= 45){
System.out.println("中年");
}else if(i >= 46 && i <= 150){
System.out.println("老年");
}else{
System.out.println("對不起,您已成仙!");
}*/
String str = "老年";
if(i >= 0 && i <= 5){
str = "幼兒";
}else if(i >= 6 && i <= 10){
str = "少兒";
}else if(i >= 11 && i <= 18){
str = "青年";
}else if(i >= 19 && i <= 45){
str = "中年";
}else{
str = "對不起,您已成仙!";
}
System.out.println(str);
}
}
class Test_if2
{
public static void main(String[] arg)
{
java.util.Scanner i = new java.util.Scanner(System.in);
System.out.print("請輸入你的成績:");
double score = i.nextDouble();
String str = "優秀";
if(score < 0 || score > 100)
{
str = "請輸入0~100之間正確成績!";
}else if(score < 60){
str = "不及格";
}else if(score < 70){
str = "及格";
}else if(score < 80){
str = "中等";
}else if(score < 90){
str = "良好";
}
System.out.println(str);
}
}
class Test_if3
{
public static void main(String[] arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("請輸入天氣所對應的數字:\n 1表示:雨天\t 0表示:晴天");
/*
boolean num1 = true;
boolean num0 = false;
num1 = 1;
num0 = 0;
*/
int weather = s.nextInt();
//System.out.println("您輸入的天氣是:"+ weather);
//System.out.println("您輸入的性別是:"+ sex);
String str = "您所輸入的數字有誤。";
if(weather == 1){
System.out.println("請輸入您的性別所對應的數字:\n 1表示:男\t 0表示:女");
int sex1 = s.nextInt();
if(sex1 == 1){
str = "男:打一把大黑傘";
}else if(sex1 == 0){
str = "女:打一把小花傘";
}else{
str = ("您所輸入的數字有誤。");
}
}else if(weather == 0){
System.out.println("請輸入您的性別所對應的數字:\n 1表示:男\t 0表示:女");
int sex2 = s.nextInt();
if(sex2 == 1){
str = "男:直接走起";
}else if(sex2 == 0){
str = "女:塗防曬霜";
}else{
str = ("您所輸入的數字有誤。");
}
}else{
str = ("您所輸入的數字有誤。");
}System.out.println(str);
}
}
switch語句:
1,switch也是選擇語句,又叫分支語句。
2,switch語法格式:
switch(值){
case 值1:
java語句;
...
break;
case 值2:
java語句
...
break;
default:
java語句;
}
其中break;語句不是必須的。default分支也不是必須的。
switch語句本質上支持int類型以及int類型的值,但是byte,char,short也可以使用(因爲它們可以進行自動類型轉換)。
技巧:
使用switch語句時,如果遇到數字較大的,可以先進行加減乘除,儘量讓其的數字進行縮小,可以減少代碼量,前提是不影響其最終效果。
代碼演示:
class Test_Switch1
{
public static void main(String[] arg){
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("請輸入天氣所對應的數字:\n 1表示:雨天\t 0表示:晴天");
int weather = s.nextInt();
//System.out.println("您輸入的天氣是:"+ weather);
//System.out.println("您輸入的性別是:"+ sex);
String str = "男:打一把大黑傘";
switch(weather){
case 1:
System.out.println("請輸入您的性別所對應的數字:\n 1表示:男\t 0表示:女");
int sex1 = s.nextInt();
switch(sex1){
case 1:
str = "男:打一把大黑傘";
break;
case 0:
str = "女:打一把小花傘";
break;
default:
str = "您輸出的數字有誤,請重新輸入!";
}
break;
case 0:
System.out.println("請輸入您的性別所對應的數字:\n 1表示:男\t 0表示:女");
int sex2 = s.nextInt();
switch(sex2){
case 1:
str = "男:直接走起";
break;
case 0:
str = "女:塗防曬霜";
break;
default:
str = "您輸出的數字有誤,請重新輸入!";
}
break;
default:
str = "您輸出的數字有誤,請重新輸入!";
}System.out.println(str);
}
}
class Test_Switch2
{
public static void main(String[] arg){
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("請輸入您的成績(0~100)");
double score = s.nextDouble();
int grade = (int)score/10;//將double類型進行強制轉換爲int類型並賦值給grade
String str = "";
switch(grade){
case 0: case 1: case 2: case 3: case 4: case 5:
str = "不及格";
break;
case 6: case 7:
str = "及格";
break;
case 8:
str = "良好";
break;
case 9: case 10:
str = "優秀";
break;
default :
str = "請輸入正確的成績數字!";
}System.out.println(str);
}
}
循環語句
for循環:
語法:
for(初始化表達式;條件表達式;更新表達式){
循環體;
}
技巧:
for循環進行嵌套時,如果兩個變量的條件相同,可以將嵌套內的循環變量 = 外循環變量。
經典例子:九九乘法表—1:共九行,1行1列,n行n列
代碼:
class Test_Math2
{
public static void main(String[] arg){
for(int i = 1; i < 10 ; i ++ ){
for(int j = 1; j <= i; j++){
System.out.print(i+"*"+j+"="+i*j+"\t");//
}
System.out.println("");
}
}
}
while循環:
語法:
while(布爾表達式){
循環體
(可以在此加入更新表達式)
}
布爾表達式true則運行循環體,false則終止循環。
循環次數:0~n次
do…while循環:
語法:
do{
循環體
(可在此加入更新表達式)
}(while);
它時先執行再判斷,執行次數是1~n次
代碼演示: 判斷大於n的最小素數。
class Method3
{
public static void main(String[] arg)
{
java.util.Scanner s = new java.util.Scanner(System.in);
System.out.println("請輸入一個整數:");
int n = s.nextInt();
System.out.println(circulation(n));
//以上代碼等同於:int n = circulation(n);System.out.println(n);
}
public static int circulation(int n)
{
while(true)
{
n++;
if(decide(n))//判斷decide(n)的返回值是true or false,正確則繼續運行,運行到break則表示n爲素數。然後程序終止
{
break;
}
}
return n;//如果n爲素數則爲main函數返回m的值。
}
public static boolean decide(int a)
{
boolean x = true;
for(int i = 2; i < a; i++)
{
if (a%i == 0)//如果a取i的餘數爲0則表示這個數不爲餘數,判斷錯誤。
{
x = false;
}
}
//程序運行到這一步表示該數爲素數。
return x;//返回boolean x的值,true或false。
}
}
轉向語句
break語句:
break翻譯成折斷,弄斷。
用在兩個位置(其他位置不行):
第一個位置:switch語句當中,用來終止switch語句的執行。防止case穿透
第二個位置:用在循環語句(for;while;do..while)中,用來終止循環執行(遵循就近原則,終止離它最近的循環)。
用break語句終止指定的循環:
第一步:需要先給循環起名:
a : for(){
b : for(){
}
}
第二步:終止 : break a;
continue;語句
作用:終止當前本次循環。
注意與break的區別:break是終止循環。
return 值;語句
作用:用來終止離他最近的方法。
方法:
意義:方法是一段可以完成某個特定功能的並且可以被重複利用的代碼片段。方法的出現,讓代碼有了很強的複用性。
方法的語法機制:
[修飾符列表] 返回值類型 方法名(形式參數列表){
方法體;
}
返回值類型:
返回值是一個方法執行結束之後的結果。
注意:
1,中括號內的內容[修飾符列表]表示不是必須的,可選擇的。
2,返回值可以是8種基本數據類型和引用數據類型
3,返回值void意思是方法執行結束後不返回任何結果。
4,如果返回值不是void,那就必須在程序結束後加上return;
5,只要有”return“關鍵字的語句執行,那當前所在的方法結束(不是程序結束!)。
6,除了void之外,其它類型都必須得是:return 值;(void,可以用return,後面不能加值!!!)
形式參數列表:
簡稱:形參
注意:
形式參數列表中的每一個參數都是”局部變量“,方法結束之後內存釋放。
形參個數是:0~N個。多個形參用 英文逗號,隔開。
形參的數據類型起決定性作用,形參對應的變量名可隨意更改。
方法調用:
語法:類名.方法名(實際參數列表)
實際參數列表,簡稱:實參。
實參與形參的類型,個數,必須一一對應。
調用同一個類的方法時”類名.“可以省略,跨類調用時不能省略。
一種經典的數據結構。
棧數據結構:stack–存儲每個方式執行時所需要的內存空間(局部變量)
1,什麼是數據結構:
數據結構通常是:存儲數據結構的容器。而該容器可能存在不同的結構。
常見的數據結構:數組,鏈表,圖,二叉樹,棧,隊列。
棧數據結構的特點:== 先進後出,後進先出。==
注意!!!處於棧頂部的元素具備活躍權。
名詞:
棧頂元素,棧幀(永遠指向棧頂元素),棧底元素。
進棧,入棧,壓棧,push,
出棧,彈棧,pop。
方法重載:
在同一個類種,如果”功能1“與”功能2“它們的功能是相似的,那麼可以考慮將它們的方法名一致,這就叫方法重載。
注意:
方法重載overload不能隨便使用,如果兩個功能壓根不相干,不相似,根本沒關係,此時兩個方法使用重載機制的話,會導致編碼更麻煩,無法進行方法功能區分。
什麼時候代碼會發生方法重載?
條件1:在同一個類當中。
條件2:方法名相同
條件3:參數列表不同。(個數,類型,順序不同!)
只要同時滿足以上3個條件,那麼我們可以認定方法和方法之間發生了重載機制。
方法遞歸:
意思:方法自己調用自己,這就是方法遞歸。
注意:
遞歸沒有結束條件的時候或壓棧太深,內存不夠,都會發生內存溢出錯誤。即棧溢出錯誤。
所以:遞歸必須要有結束條件。
建議:
在實際開發中,不建議輕易選擇遞歸
儘量使用循環語句代替,循環效率高,耗費內存少。
遞歸耗費的內存較大,使用不當會導致JVM死機。
(但是在極少數情況下,不用遞歸,這個程序沒法實現。)
假如在實際開發中,假設有一天你真正的遇到了StackOverflowError,如何解決問題?
第一步:先檢查遞歸的結束條件,如果遞歸結束條件不對,必須對條件進一步修改,直到正確爲止。
第二步:假設遞歸條件沒問題,怎麼辦?
這時候需要手動調整JVM的棧內存初始化大小。可以將棧內存空間調大。
打開控制檯,輸入java -x ; java -Xss xxxGB(不能超出你電腦實際內存。)
java -x 可以查看調整棧大小的參數。
面向對象
面向過程
面向過程的開發方式主要特點:
注意步驟,注重的是實現這個功能的步驟。
第一步幹什麼
第二步幹什麼
.......
面向過程也注重實現功能的因果關係。
因爲A所以B
因爲B所以C
因爲C所以D
........
面向過程中沒有對象的概念,知識實現這個功能的步驟以及因果關係。
面向過程缺點:
面向過程最主要的是每一步與每一步的因果關係,其中A步驟因果關係到B步驟,A和B聯合起來形成一個子模版,
子模版與子模版之間又因爲因果關係結合在一起。
如果其中一個因果關係出了問題,此時整個系統的運轉都會出現問題。
(代碼和代碼之間的耦合度太高,擴展力太差)
面向過程優點:
對於小型項目(功能),採用面向過程的方式進行開發,效率較高。
不需要前期進行對象的提取,模型的建立,採用面向過程方式可以直接開始幹活。
一上來直接寫代碼,編寫因果關係,從而實現功能。
面向對象
形容:
採用面向對象的方式進行開發,更符合人類的思維方式。
面向對象就是將現實世界分割成不同單元,每一個單元都實現成對象,然後驅動一下,讓各個對象之間協作起來。
優點:
耦合度低,擴展力強。
案例:
蛋炒飯:雞蛋和米飯完全混合在一起,沒有獨立對象概念。
假如客戶只想喫米飯,怎麼辦?
客戶提出需求,軟件開發者必須滿足這個需求,於是開始擴展,(很難擴展,耦合度太高)
蓋飯:
魚香肉絲蓋飯:魚香肉絲是一道菜,可以看成獨立對象,米飯可以看成獨立對象。
假如客戶提出新需求,則只需要將其中一個或多個對象換掉即可。
面向過程主要關注的是:實現步驟以及整個過程。
面向對象主要關注的是:對象A,對象B,對象C,或者對象ABC組合,對象CBA組合。
當我們採用面向對象的方式貫穿整個系統時,涉及三個術語:
- OOA:面向對象分析;
- OOD:面向對象設計;
- OOP:面向對象編程;
整個軟件開發過程,都是採用OO進行貫穿。
實現程序的步驟:
OOA----OOD----OOP
面向對象包括三大特徵:
- 封裝;
- 繼承;
- 多態;
- 任何一個面向對象的編程語言都包括這三個特徵:如:Python。
類和對象的概念:
面向對象中最主要的是”對象“;
類:
類 = 屬性+方法;
屬性描述的是:狀態;
方法描述的是:行爲動作;(一個方法代表了一個動作)
在現實當中是不存在的,是一個抽象的該你那,是一個模板。是我們人類大腦進行思考,總結,抽象的一個結果。(類是對象特徵的總結)
舉例:明星----是一個類。
對象(又叫實例):對象是真實存在的個體。
舉例:宋小寶,劉德華,周星馳就是對象。屬於”明星“類。
抽象:多個對象具有共同特徵,進行思考總結抽取共同特徵的過程。
實例化:通過類這個模板創建對象的過程,叫做:實例化。
- 類----【實例化】----對象
- 對象----【抽象】----類
- 在Java中要想得到”對象“,必須先定義”類“,對象屬於類。這個模板是創造出來的。
- 類就是一個模板:類中描述的是所有對象的”共同特徵信息“。對象就是通過類創建出來的個體。
類的定義:
語法格式:
[修飾符列表] class 類名{
類體 = 屬性 + 方法
屬性在代碼上以變量的形式存在(描述狀態)
方法描述動作/行爲
}
當一個類沒有提供任意一個構造方法,系統會默認提供一個無參構造方法。
這個無參構造方法叫做:缺省構造器。
但是如果定義了一個有參數的構造方法,就不會再提供方法。
建議:將無參數構造方法手動寫出來,這樣編譯時一定不會出現問題。
構造方法(Constructor):
作用:創建對象,並且創建對象的過程中給屬性賦值(初始化。)
語法格式:
[修飾符列表] 構造方法名(形式參數列表){
構造方法體;
}
注意:
第一:修飾符列表目前統一寫:public。千萬不要寫public static。
第二:構造方法名和類名必須一致。
第三:構造方法不需要返回值類型,也不能寫void,寫上void表示普通方法,而不是構造方法。
調用構造方法:
使用new運算符來調用構造方法。
語法格式:
new 構造方法名(實際參數列表);
代碼:
public class Adress
{
String street;
String home;
String home2;
//無參構造方法
public Adress(){
}
//有參構造方法:創建對象,並給對象賦初始值。
public Adress(String a2, String a3, String a4){
street = a2;
home = a3;
home2 = a4;
}
}
public class Student
{
//屬性(描述狀態),以成員變量的狀態存在
int numble;
String name;
int age;
boolean sex;
Adress adr;
//無參構造方法
public Student(){
}
//有參構造方法:
public Student(int num, String na, int ag){
//給實例化變量賦值,(初始化實例變量,初始化屬性)
numble = num;
name = na;
age = ag;
}
public Student(int num, String na, int ag, boolean se){
numble = num;
name = na;
age = ag;
sex = se;
}
public Student(int num, String na, int ag, boolean se,Adress ad){
numble = num;
name = na;
age = ag;
sex = se;
adr = ad;
}
}
public class StudentTest
{
public static void main(String[] arg){
Adress a = new Adress("湖北","武漢","漢陽區");
//調用不同的構造方法創建對象。
//創建學生對象1
Student s1 = new Student();
System.out.println(s1.numble);
System.out.println(s1.name);
System.out.println(s1.age);
System.out.println(s1.sex);
//s1.adr.home可以拆分爲:
//Adress ss = s1.adr;
//String hm = ss.home;
//System.out.println(ad);
//System.out.println(s1.adr.home);
//創建學生對象2
Student s2 = new Student(1000, "李某", 10);
System.out.println(s2.numble);
System.out.println(s2.name);
System.out.println(s2.age);
System.out.println(s2.sex);
//System.out.println(s1.adr.home);
//創建學生對象3
Student s3 = new Student(2000, "tete", 15, true);
System.out.println(s3.numble);
System.out.println(s3.name);
System.out.println(s3.age);
System.out.println(s3.sex);
//System.out.println(s1.adr.home);
//創建學生對象4
Student s4 = new Student(2000, "tete", 15, true);
s4.adr = a;
System.out.println(s4.numble);
System.out.println(s4.name);
System.out.println(s4.age);
System.out.println(s4.sex);
System.out.println(s4.adr.street+s4.adr.home+s4.adr.home2);
}
}
運行結果:
封裝:
面向對象三大特徵:
== 封裝;繼承;多態; ==
有了封裝纔有繼承,有了繼承纔有多態。
封裝的意義:
將內部用一個堅硬的殼保護起來。保證內部的東西是安全的。
讓使用者只需要通過幾個按鈕就可以完成操作。
作用:
- 一:保證內部結構的安全。
- 二:屏蔽複雜,暴露簡單。
代碼級別上的作用:
一個類體當中的數據,假設封裝之後,對於代碼的調用人員來說,不需要關心代碼的複雜實現,只需要通過一個簡單的入口就可以訪問了。
另外,類體中安全級別較高的數據封裝起來,外部人員不能隨意訪問,保證數據的安全性。
如何封裝?代碼實現:
- 第一步:屬性私有化(使用private關鍵字進行修飾)
- 第二步:對外提供簡單的操作入口。(並且都不帶有static)
- 外部程序只能通過set方法修改,只能通過get方法讀取,可以在set方法中設立關卡保證數據的安全性。
注意: Java開發規範中有要求,set方法和get方法要滿足以下格式:
get方法要求:
public 返回值類型 get+屬性名首字母大寫(無參){
return ***;
}
set方法的要求:
public void set+屬性名首字母大寫(有1個參數){
*** = 參數;
}
代碼:
public class Person
{
//private 表示私有的,被這個關鍵詞修飾之後,該數據只能在本類中訪問。
//出了這個類,age屬性就無法訪問了,私有的。
//age是成員變量,在Person類中直接調用。
private int age;
//對外提供簡單的訪問入口
//外部程序只能通過調用一下的代碼來完成訪問。
public int getAge()
{
return age;
}
public void setAge(int nianling)
{
//設定關卡。
if(nianling < 0 || nianling > 150)
{
System.out.println("參數錯誤。");
return;
}
age = nianling;
}
}
public class PersonTest
{
public static void main(String[] args){
//創建對象
Person ag = new Person();
//這裏是讀取age年齡
//讀取調用getAge()方法:
//int aa = ag.getAge;
//System.out.println(ag.getAge());
//11行代碼等同於8,9行代碼的結合
System.out.println(ag.getAge());
//因爲setAge沒有返回值,不需要變量去接收。
ag.setAge(10);
System.out.println(ag.getAge());
ag.setAge(-20);
System.out.println(ag.getAge());
}
}
static:
帶static 和不帶static :
方法中帶static,main方法就使用“類名.”的方式訪問
方法中不帶static(稱爲:實例方法),main方法需要先new 一個對象,再通過“引用.“的方式去訪問
- 1,static翻譯爲”靜態“;
- 2,所有static關鍵字修飾的都是類相關的,類級別的。
- 3,所有static修飾的,都是採用”類名.“的方式訪問。
- 4,static修飾的變量:靜態變量;
- 5,static修飾的方法:靜態方法;
成員變量:實例變量(不帶static);靜態變量(帶static)
實例都是對象相關的,訪問時採用”引用.“的方式訪問。需要先new對象。
實例相關的,必須現有對象,才能訪問,可能會出現空指針異常。
靜態的都是類相關的,訪問是採用”類名.“的方式訪問,不需要new對象
靜態變量在類加載時初始化,不需要new對象,靜態變量的空間就開出來了,存儲在方法區。
什麼時候使用靜態,什麼時候使用實例?
如果這個類型的所有對象的某個屬性值都是一樣的,不建議定義爲實例變量,浪費內存空間。建議定義爲類級別特徵,定義爲靜態變量,在方法去只保留一份,節省內存開銷。
一個對象一份的是實例變量,所有對象都有一份是靜態變量。
當這個方法體中,直接訪問了實例變量,那麼這個方法一定是實例方法
靜態訪問:建議使用”類名.“來訪問,但使用”引用.“也行(不建議)
靜態——空指針異常
只有在”空引用“訪問”實例“相關的,都會出現空指針異常。
在代碼正確編譯的情況下,靜態不會出現空指針異常
class StaticTest
{
public static void main(String[] arg){
//通過“類名.”的方式去訪問靜態變量;
System.out.println(Chinese.country);
//創建對象
Chinese card = new Chinese("123123123","張三");
System.out.println(card.idCard);
System.out.println(card.name);
System.out.println(card.country);//建議使用“類名.”
//card是空引用
card = null;
//這個地方不會出現空指針異常,因爲靜態變量不需要對象的存在。
System.out.println(card.country);
}
}
class Chinese
{
//實例變量
String idCard;
String name;
//靜態變量
static String country = "中國";
//構造方法
public Chinese(){
}
public Chinese(String x, String y){
idCard = x;
name = y;
}
}
假如靜態方法中訪問實例變量,必須先在靜態方法中new 一個對象,再用“引用.”去訪問。
實例方法中訪問靜態變量,採用“類名.”;
靜態代碼塊:(使用不多)
語法:
static {
java語句;
java語句;
}
static靜態代碼塊在什麼時候執行呢?
類加載時執行,並只執行一次。
靜態代碼塊特徵/特點:
靜態代碼塊在類加載器時執行,並且在main方法執行之前。
靜態代碼塊一般是按照自上而下的順序執行。
一個類中可以寫多個靜態代碼塊。
代碼:
class StaticTest05
{
//靜態代碼塊
static{
System.out.println("A");
}
//一個類當中可以編寫多個靜態代碼塊
static{
System.out.println("B");
}
//入口
public static void main(String[] arg){
System.out.println("Hallo,World!!");
}
//編寫一個靜態代碼塊
static{
System.out.println("c");
}
}
實例代碼塊:
語法:
{
java語句;
java語句;
java語句;
}
實例語句塊在類加載時並沒有執行。
只要是構造方法執行,必然在構造方法執行之前,自動執行”實例語句塊“中的代碼。
代碼:
class InstanceCode
{
public static void main(String[] arg)
{
System.out.println("main begin");
new InstanceCode();
}
//實例語句塊,實例塊語句存放在堆內存中。
{
System.out.println("實例語句塊執行!");
}
//Constructor無參構造方法
public InstanceCode()
{
System.out.println("無參構造方法!");
}
//有參構造方法
public InstanceCode(String name)
{
System.out.println("有參數的構造方法");
}
}
判斷運行順序:
//執行順序。
class CodeOrder
{
static{
System.out.println("A");
}
public static void main(String[] arg){
System.out.println("B");
new CodeOrder();
System.out.println("F");
}
{
System.out.println("C");
}
public CodeOrder(){
System.out.println("D");
}
static{
System.out.println("E");
}
}
this
介紹:
- this是一個關鍵字,全部小寫;
- 一個對象一個this,this是一個變量,是一個引用。this保存當前對象的內存地址,指向自身,所以嚴格意義來說:this代表的就是”當前對象“。
- this存儲在堆內存當前對象中
- this.可以省略不寫,省略掉還是默認訪問”當前對象“。
- this代表的是當前對象,而靜態方法調用的是“類名.”,矛盾了。
不可省略的標準:
在實例方法與構造方法中,爲了增強代碼可讀性,會出現同樣命名,
爲了區分局部變量和實例變量,這種情況下:"this."是不可省略的。
this 出了可以使用在實例方法中,還可以用在構造方法中。
新語法:
通過當前的構造方法去調用另一個本類的構造方法,
可以使用以下語法格式:
this(實際參數列表);
this(***,***,***);
作用是:
通過構造方法1去調用構造方法2,可以做到代碼複用。
注意:
- 所調用的構造方法必須在同一個類中!
- 對“this”的調用必須是構造器中的第一個語句!
代碼:
//銀行存取錢
class Bank
{
public static void main(String[] arg){
Account baby = new Account("Jane Smith", 1000L, 2000.0, 1.25);
Customer baby2 = new Customer("陳某",baby);
//把Account類的地址賦給baby2,第一個getId是baby2中的Id,第二個getId是baby中的Id
System.out.println(baby2.getName()+ baby2.getId().getId());
baby.deposit(100.0);
baby.giao();
baby.withdraw(960);
baby.withdraw(2000);
baby.giao();
}
}
//聲明一個顧客類
class Customer
{
private String name;
private Account id;
//構造無參方法
public Customer()
{
}
//定義有參數構造器
public Customer(String name,Account id)
{
this.name = name;
this.id = id;
}
//set,get方法
//Name名字
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
//Id 銀行卡號
public Account getId()
{
return id;
}
public void getId(Account id)
{
this.id = id;
}
public void giao2(){
}
}
//聲明一個賬戶類
class Account
{
private String name;
private long id;
private double balance;
private double annualInterestRate;
public Account()
{
//無參構造方法調用有參構造方法1。
//這裏this();不能省略。
this("陳某",1111L,50000,1.56);
}
public Account(String name,long id,double balance, double annualInterestRate)
{
this.name = name;
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
//get.set名字
public String getName()
{
return name;
}
public void setName(String name){
//this.的作用:區分局部變量和實例變量,這裏不能省略,
//因爲String name 省略編譯器會分不清誰是局部變量,誰是實例變量
//this.name 表示實例對象
//增強可讀性
this.name = name;
}
//get.set賬戶ID
public long getId()
{
return id;
}
public void setId(long id){
this.id = id;
}
//get.set餘額
public double getBalance()
{
return balance;
}
public void setBalance(double balance){
if(this.balance < 0)
{
System.out.println("餘額不足,取錢失敗");
return;
}
this.balance = balance;
}
//get.set年利率
public double getAnnualInterestRate()
{
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate){
this.annualInterestRate = annualInterestRate;
}
//取款方法:
public double withdraw(double with)
{
if(balance < with)
{
System.out.println("餘額不足,取錢失敗。您的餘額還有:" + balance);
return balance;
}else
{
//else裏面的代碼等同於:this.setBlance(this.getBalance() - with)
balance -= with;
System.out.println("您的餘額還有:" + balance);
return balance;
}
}
//存款方法:
public double deposit(double dep)
{
//this.setBalance(this.getBalance() + with);
balance += dep;
System.out.println("成功存入" + dep +"元,餘額還剩:"+balance+"元");
return balance;
}
public void giao()
{
//this.默認隱藏的。
System.out.println("貴賓姓名:" + this.name);
System.out.println("貴賓銀行ID:" + this.id);
System.out.println("貴賓餘額:" + this.balance);
System.out.println("銀行年利率:" + annualInterestRate +"\n");
}
}
運行結果:
繼承extends
基本作用:子類繼承父類,代碼可以得到複用。
主要作用:因爲有了繼承關係,纔有了後期方法覆蓋和多態機制。
繼承的相關特性:
- B類繼承A類,則稱A類爲超類(superclass),父類,基類, B類則稱爲子類(subclass),派生類,擴展類。
- Java中的繼承只支持單繼承,不支持多繼承,C++中支持多繼承
- 雖然Java中不支持多繼承,但有時候會產生間接繼承的效果。
- Java中規定,子類繼承父類,除構造方法不能繼承外,剩下的都可以繼承。但是私有(private)屬性無法在子類中直接訪問
- Java中的類沒有顯示的繼承任何類,則默認繼承Object類,Object類是Java語言中提供的根類(老祖宗類),也就是說,一個對象與生俱來就有Object類型中所有的特徵。
- 繼承也存在一些缺點,例如耦合度太高,而導致類發生改變時,會影響到另一個類。
滿足什麼條件的時候可以使用繼承extends?
凡是採用“is a”能描述的,都可以繼承
例如:Cat is a Animal:貓是一隻動物。
代碼:
class Extends
{
public static void main(String[] arg){
Cat c = new Cat();
c.name = "笑話";
c.move();
}
}
class Animal
{
//名字:
String name;
//提供一個動物移動方法
public void move(){
System.out.println(name + "正在移動!");
}
}
//Cat繼承Animal類,Cat 是子類
class Cat extends Animal
{
}
方法覆蓋
什麼時候進行方法覆蓋:
子類繼承父類之後,當繼承過來的方法無法滿足當前子類的業務需求時,子類有權對這個方法進行重新編寫,有必要進行“方法覆蓋”
方法覆蓋又叫做:方法重寫,英文單詞叫做:Override,Overwrite都可以。
方法覆蓋條件:
- 兩個類必須要有繼承關係。
- 重寫之後的方法和之前方法必須有:
相同的返回值類型,相同的方法名,相同的形式參數列表 - 訪問權限不能更低,可以更高。
- 重寫之後的方法不能比之前的方法拋出更多異常,可以更少。
注意:
- 方法覆蓋只是針對方法,和屬性無關。
- 私有方法無法覆蓋。
- 構造方法不能被繼承,所以構造方法也不能被覆蓋。
- 方法覆蓋只是針對於實例方法,靜態方法覆蓋沒有意義。
toString()方法
存在的作用就是將jva對象轉換成字符串形式,大多數的java類toString()方法都是需要覆蓋的。因爲Object類中提供的toString()方法輸出的是一個java對象的內存地址。
格式可以自己定義,或者聽取項目要求。
方法重載和方法覆蓋的區別:
- 方法重載發生在同一個類當中,方法覆蓋發生在具有繼承關係的父子類之間。
- 方法重載是一個類中,方法名相同,參數列表不同。
- 方法覆蓋是具有繼承關係的父子類,並且重寫之後的方法必須和之前的方法一致:方法名一致,參數列表一致,返回值一致。
代碼:
//方法覆蓋經典例子
class OverrideTest
{
public static void main(String[] args)
{
//創建一箇中國人對象c
//暫時無法在()內填寫屬性,因爲該類中暫時沒有構造方法。
ChinaPeople c = new ChinaPeople();
//創建一個美國人對象a
AmericanPeople a = new AmericanPeople();
c.setName("李某");
c.speak();
a.setName("李某");
a.speak();
}
}
//人
class People
{
//屬性
private String name;
//無參構造方法
public People()
{
}
//有參構造方法
public People(String name)
{
this.name = name;
}
//set改寫
public void setName(String name)
{
this.name =name;
}
//get讀取
public String getName()
{
return name;
}
//動作speak方法.
public void speak()
{
System.out.println(name + "正在。。。");
}
}
//"中國人" 類 繼承了"人" 類 ,等同於將People類中的方法複製了一份在ChinaPeople中。
class ChinaPeople extends People
{
public void speak(){
//由於繼承關係,這裏的this.是表明這個People類中的當前對象。可省略
System.out.println(this.getName() + "正在說漢語。");
}
}
//"美國人" 類 繼承了"人" 類 ,等同於將People類中的方法複製了一份在American中。
class AmericanPeople extends People
{
public void speak()
{
//由於繼承關係,這裏的this.是表明這個People類中的當前對象。可省略
System.out.println(this.getName() + "正在說英語.");
}
}
多態
多態的基礎語法:
1,普及兩個概念:
第一個:向上轉型:子——>父(自動類型轉換)(upcasting)
第二個:向下轉型:父——>子(強制類型轉換,需要加強制類型轉換符)(downcasting)
當你需要訪問的是子類中特有的方法,則需要向下轉型,需要加強制類型轉換符。
注意:
Java中允許向上轉型,也允許向下轉型,無論向下轉型,還是向上轉型,必須要有繼承關係!!!
新運算符:instanceof(運行階段動態判斷)
在向下轉型時,一定要寫。
-
第一:instanceof可以在運行階段動態判斷引用指向的對象的類型。
-
第二:instanceof語法:(引用 instanceof 類型)
-
第三:instanceof運算符的運算結果只能是true/false
-
第四:c是一個引用,c變量保存了內存地址指向了堆中的對象
假設(c instanceof Cat)爲true: c引用指向的堆內存中的Java對象是一個Cat 假設(c instanceof Cat)爲false: c引用指向的堆內存中的Java對象不是一個Cat
多態作用:
降低程序的耦合度,提高程序的擴展力。(幾乎天天使用)
多種形態,多種狀態,編譯和運行有兩個不同的狀態
編譯期叫做靜態綁定;
運行期叫做動態綁定;
Animal a = new Cat();
//編譯的時候編譯器發現a類型是Animal,
所以編譯器會去Animal類中找move()方法,
找到後,綁定,編譯通過。
但是運行的時候和底層堆內存中的實際對象有關,
真正執行的時候會自動調用“堆內存中真實對象”相關方法。
a.move();
多態典型代碼:父類型的引用指向子類型的對象。(Java中允許這樣寫代碼)
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
}
以上代碼中表示:Master和Dog以及Cat的關係很緊密(耦合度高)。導致擴展力差。
public class Master{
public void feed(Pet pet){}
}
以上代碼中表示:Master和Dog以及Cat的關係就脫離了,Master關注的是Pet類。
這樣Master和Dog以及Cat的耦合度就降低了,提高了軟件的擴展性。
代碼:
public class Homework
{
public static void main(String[] arg)
{
//第一種寫法:
Erhu e = new Erhu();
Piano p = new Piano();
Violin v = new Violin();
Musician m = new Musician();
m.play(e);
m.play(p);
m.play(v);
//第二種寫法:
/*
Instrument e = new Erhu();
Instrument p = new Piano();
Instrument v = new Violin();
Musician m = new Musician();
m.play(e);
m.play(p);
m.play(v);
*/
//第三種寫法:
/*
Musician m = new Musician();
m.play(new Erhu());
m.play(new Piano());
m.play(new Violin());
*/
}
}
//樂器父類
class Instrument
{
public void makeSound()
{
System.out.println("樂器的聲音!");
}
}
//子類
class Erhu extends Instrument
{
//方法重寫
public void makeSound()
{
System.out.println("二胡的聲音!");
}
}
class Piano extends Instrument
{
public void makeSound()
{
System.out.println("鋼琴的聲音!");
}
}
class Violin extends Instrument
{
public void makeSound()
{
System.out.println("小提琴的聲音!");
}
}
//樂手類
class Musician
{
/*
第一種寫法:
Instrument i;
public Musician(){}
public Musicain(Instrument i)
{
this i = i;
}
public void play(Instrument i)
{
i.makeSound();
}
*/
//第二種寫法:
//把m.play()括號中的變量傳給i,
//編譯器會去Instrument類中去查找makeSound方法,
//然後調出子類方法重寫後的makeSound
public void play(Instrument i)
{
i.makeSound();
}
}
問題:靜態方法存在方法覆蓋嗎?
方法覆蓋與方法相互聯繫,多態必須有對象。
多態自然就和對象有關係了。
而靜態方法的執行不需要對象
所以,一般情況下,我們會說靜態方法“不存在”方法覆蓋。
不探討靜態方法覆蓋。
問題:私有方法不能覆蓋。
問題:在方法覆蓋中,方法的返回值類型?
對於返回值類型是基本數據類型來說,必須一致。
對於引用數據類型,大轉小可以,小轉大不行(意義不大,實際開發一般不會用到。)
問題:什麼條件滿足後,會構成方法覆蓋呢?
發生具有繼承關係的兩個類之間。
父類中的方法和子類重寫之後的方法。
具有相同的方法名,相同的形式參數列表,相同的返回值類型。
super
super是一個關鍵字,全部小寫。
語法格式:
"super."和"this."可以訪問方法和屬性。
super.屬性名;【訪問父類的屬性】
super.方法名(實參);【訪問父類的方法】
super(實參);【調用父類的構造方法】
super與this對比:
this:
- this 能出現在實例方法和構造方法中。
- this的語法是:”this.““this()”
- this不能使用在靜態方法中。
- this.大部分情況下可以省略。
- this.什麼時候不能省略?在區分局部變量和實例變量時不能省略。
- this()只能出現在構造方法第一行,通過當前的構造方法去調用”本類“中其它構造方法,目的是:代碼複用。
super:
- super能出現在實例方法和構造方法中。
- super的語法是:”super.““super()”
- super不能使用在靜態方法中。
- super.大部分情況下可以省略。
- super.什麼時候不能省略?
父類和子類中有同名屬性,或者有同樣的方法,想在子類中訪問父類的,super.不能省略。 - super()只能出現在構造方法第一行,通過當前的構造方法去調用”本類“中其它構造方法,目的是:創建子類對象的時候先初始化父類特徵。
super()
表示通過子類的構造方法調用父類的構造方法。
模擬現實世界中的這種場景:要想有兒子,需要先有父親。
super(實參)的作用:初始化當前對象的父類型特徵,並不是創建新對象。實際對象只創建了一個對象
結論:
當一個構造方法第一行:即沒有thi()又沒有super()的話,默認會有一個super();
表示通過當前子類的構造方法調用父類的無參數構造方法。
如果super()括號中有變量,則會調用父類的有參構造類型。
所以必須保證父類的無參數構造方法是存在的。
this()與super()不能共存,它們都只能出現在構造方法的第一行。
super不是引用。super也不保存內存地址,super也不指向任何對象。
super只是代表當前對象內部的那一塊父類型的特徵。
super.什麼時候不能省略?
區分子類和父類的同名屬性:
this.name:當前對象的name屬性
super.name:當前對象的父類型特徵中的name屬性。
如果父類和子類有同名屬性,並且想要通過子類訪問父類屬性,則不能省略。
代碼:
public class superTest03
{
public static void main(String[] arg)
{
Vip p = new Vip("張三");
p.shopping();
}
}
class Customer
{
String name;
public Customer(){
}
public Customer(String name)
{
this.name = name;
}
}
class Vip extends Customer
{
//假設子類也有一個同名屬性,java中允許在子類中出現和父類同名的變量。
String name;
public Vip(){}
public Vip(String name)
{
super(name);
//this.name = null; 這是省略,默認給name賦值null。
}
public void shopping()
{
//this表示當前對象
System.out.println(this.name+"正在購物");
//super表示的是當前對象的父類型特徵。(super是this指向的那個對象中的一塊空間)
System.out.println(super.name+"正在購物");
//name前面省略了this.
System.out.println(name+"正在購物");
}
}