Java語法基礎
注釋
在Java語言中,注釋有以下三種方法:
- 單行注釋:// 注釋內容
- 多行注釋:/* 注釋內容 */
- 檔案注釋:/** 注釋內容 */
示例:
/**
* (檔案注釋)
* @Description HelloWorld
* @Author 惟妙惟霄
*/
public class HelloWorld {
public static void main(String[] args) {
//(單行注釋)這個程式的作用是輸出Hello, world!
System.out.println("Hello, world!");
/*
(多行注釋)
這個程式的作用是輸出Hello, world!
*/
}
}
識別符號
定義:Java所有的組成部分都需要名字,類名、變數名以及方法名都被稱為識別符號,
注意:
- 所有的識別符號都應該以字母(A-Z 或者 a-z),美元符($)、或者下劃線(_)開始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下劃線(_)或數字的任何字符組合
- 關鍵字不能用作識別符號
- 識別符號是大小寫敏感的
- 可以用中文命名,但是極不推薦
- 合法識別符號舉例:age、$salary、_value、__1_value
- 非法識別符號舉例:123abc、-salary
示例:
public class Demo01 {
public static void main(String[] args) {
String hello = "Hello, world!"; //小寫字母開頭,正確
String Hello = "Hello, world!"; //大寫字母開頭,正確
String $Hello = "Hello, world!"; //美元符開頭,正確
String _Hello = "Hello, world!"; //下劃線開頭,正確
String Hello123 = "Hello, world!"; //非開頭位置使用數字,正確
//String 123Hello = "Hello, world!"; //數字開頭,錯誤
//String #Hello = "Hello, world!"; //井號開頭,錯誤
//String *Hello = "Hello, world!"; //星號開頭,錯誤
String 道德經 = "道可道,非常道,"; //使用中文,可以通過,但極不推薦
}
}
資料型別
Java是強型別語言,Java中的資料型別分為兩種:
- 基本型別
- 參考型別
其中,基本資料型別分為以下四種:
- 整數型:byte(占1個位元組)、short(占2個位元組)、int(占4個位元組)、long(占8個位元組)
- 浮點型:float(占4個位元組)、double(占8個位元組)
- 字符型:char(占2個位元組)
- 布爾型:boolean(占1位)
而參考資料型別分為以下三種:
- 類
- 介面
- 陣列
示例:
public class Demo02 {
public static void main(String[] args) {
//八大基本資料型別
//整數
int num1 = 10; //最常用
byte num2 = 20;
short num3 = 30;
long num4 = 30L; //long型別在數字的最后加大寫字母L
//浮點數
float num5 = 3.14159F; //float型別要在數字最后加F
double num6 = 3.14159;
//字符
char a = 'A';
//布林值
boolean flag1 = true;
boolean flag2 = false;
}
}
其中,整數還可以使用不同的進制來表示:
- 二進制:0b開頭
- 八進制:0開頭
- 十進制
- 十六進制:0x開頭
示例:
public class Demo03 {
public static void main(String[] args) {
int num1 = 10; //十進制
int num2 = 0b10; //二進制以0b開頭
int num3 = 010; //八進制以0開頭
int num4 = 0x10; //十六進制以0x開頭
System.out.println(num1); //輸出10
System.out.println(num2); //輸出2
System.out.println(num3); //輸出8
System.out.println(num4); //輸出16
}
}
另外,浮點型因為精度和溢位的問題,盡量不要作為比較物件,
示例:
public class Demo03 {
public static void main(String[] args) {
float f1 = 2313467468515648F;
float f2 = f1 + 1;
System.out.println(f1==f2); //明明f2=f1+1,但仍然輸出true,即f1與f2相等
}
}
而字符型別本質仍是整數,
示例:
public class Demo03 {
public static void main(String[] args) {
char c1 = 'a'; //賦值為a
System.out.println(c1); //輸出a
System.out.println((int)c1); //輸出97
char c2 = '中'; //賦值為中
System.out.println(c2); //輸出中
System.out.println((int)c2); //輸出20013
char c3 = 97; //直接用整數賦值
System.out.println(c3); //輸出a
char c4 = '\u0061'; //轉義為unicode編碼
System.out.println(c4); //輸出a
}
}
型別轉換
由于Java是強型別語言,因而在進行某些整型、浮點型、字符型資料的混合運算中需要進行型別轉換,不同型別的資料先轉化為同一型別,然后進行運算,
低 ---------------------------------------> 高
byte/short/char —> int —> long—> float —> double
資料型別在進行轉換時需注意以下幾點:
- 不能對布爾型進行型別轉換,
- 不能把物件型別轉換成不相關的型別,
- 在把容量小的型別轉換為容量大的型別時會進行自動型別轉換,
- 在把容量大的型別轉換為容量小的型別時必須使用強制型別轉換,
- 轉換程序中可能導致溢位或損失精度,
示例:
public class Demo04 {
public static void main(String[] args) {
//高->低 強制型別轉換 (型別)變數名
int num1 = 128;
byte num2 = (byte)num1;
System.out.println(num2); //記憶體溢位,輸出-128
//低->高 自動型別轉換
double num3 = num1;
System.out.println(num3); //輸出128.0
//精度丟失
float f = 3.5F;
double d = 3.5;
System.out.println((int)f); //輸出3
System.out.println((int)d); //輸出3
//計算中的型別轉型,應先轉型,再計算
int money = 10_0000_0000; //整數中可以任意使用下劃線分割
int years = 20;
int total1 = money*years;
System.out.println(total1); //輸出-1474836480,即結果溢位
long total2 = money*years;
System.out.println(total2); //輸出-1474836480,即結果溢位
long total3 = money*((long)years);
System.out.println(total3); //輸出20000000000,即結果正確
}
}
變數
在Java語言中,所有的變數在使用前必須宣告,宣告變數的基本格式如下:
type varname [ = value] [, varname[= value] ...];
//型別 變數名 = 值; 可以使用逗號隔開來同時宣告多個同型別變數,但不推薦這么做
注意事項:
- 每個變數都有型別,可以是基本型別,也可以是參考型別,
- 變數名必須是合法的識別符號,
- 變數宣告是一條完整的陳述句,因此每一個宣告都必須以分號結束,
- 變數名盡量遵守首字母小寫的駝峰原則,例如:num、lastName、redApple、studentsNameList,
示例:
public class Demo05 {
public static void main(String[] args) {
int num = 123;
String name = "惟妙惟霄";
char x = 'X';
double pi = 3.14159;
}
}
Java語言支持的變數型別有:
- 類變數:獨立于方法之外,且用 static 修飾的變數,
- 實體變數:獨立于方法之外,不用 static 修飾的變數,
- 區域變數:位于方法之中的變數,
示例:
public class Demo06 {
//實體變數:從屬于物件,可以不進行初始化,會賦默認值,
int a; //整數型別的默認值為0
boolean b; //布爾型的默認值為false
String c; //參考型別的默認值為null
//類變數:從屬于類,使用static修飾,可以不進行初始化,會賦默認值,
static int d;
//main方法
public static void main(String[] args) {
//區域變數:必須宣告且必須初始化值
int i = 10;
System.out.println(i);
//實體變數
Demo06 demo06 = new Demo06(); //需創建實體
System.out.println(demo06.a); //輸出0
System.out.println(demo06.b); //輸出false
System.out.println(demo06.c); //輸出null
demo06.a = 10;
System.out.println(demo06.a); //輸出10
demo06.b = true;
System.out.println(demo06.c); //輸出true
demo06.c = "惟妙惟霄";
System.out.println(demo06.c); //輸出惟妙惟霄
//類變數
System.out.println(d); //輸出0
d = 12;
System.out.println(d); //輸出12
}
}
常量
定義:常量是初始化后無法再次改動的值,常量名一般使用大寫字符和下劃線,其基本的宣告格式如下:
final 型別 常量名 = 值;
//例如: final double PI = 3.14;
示例:
public class Demo07 {
//static與final都是修飾符,不存在先后順序
static final double PI = 3.14;
public static void main(String[] args) {
System.out.println(PI); //輸出3.14
}
}
運算子
Java語言支持以下運算子:
- 算術運算子:+、-、*、/、%、++、--
- 關系運算子:>、<、>=、<=、==、!=、instanceof
- 位運算子:&、|、^、~、>>、<<、>>>
- 邏輯運算子:&&、||、!
- 賦值運算子:=、+=、-=、*=、/=
- 條件運算子: ?:
- 其他運算子
算數運算子
示例:
package operator;
public class Demo01 {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 30;
int d = 40;
//二元運算子
System.out.println(a+b); //加法運算,輸出30
System.out.println(b-c); //減法運算,輸出-10
System.out.println(c*d); //乘法運算,輸出1200
System.out.println(a/(double)d); //除法運算,輸出0.25
System.out.println(d%c); //取余運算,輸出10
//一元運算子
System.out.println(a); //輸出10
System.out.println(a++); //輸出10,當++在后時,先運算,后自增,
System.out.println(a); //輸出11
System.out.println(++a); //輸出12,當++在前時,先自增,后運算,
//利用Math類進行運算
double e = Math.pow(2, 3);
System.out.println(e); //輸出8,即2的3次方
int f = Math.abs(-5);
System.out.println(f); //輸出5,即-5的絕對值
}
}
關系運算子
示例:
package operator;
public class Demo02 {
public static void main(String[] args) {
//關系運算的回傳結果是布爾型別,即結果只有true或false
int a = 10;
int b = 20;
System.out.println(a>b); //輸出false
System.out.println(a<b); //輸出true
System.out.println(a==b); //輸出false
System.out.println(a!=b); //輸出true
}
}
邏輯運算子
示例:
package operator;
public class Demo03 {
public static void main(String[] args) {
//邏輯運算子
//與(and) 或(or) 非(not)
boolean a = false;
boolean b = true;
System.out.println(a&&b); //輸出false,邏輯與運算:兩個都為真,結果才為真,
System.out.println(a||b); //輸出true,邏輯或運算:兩個有一個為真,結果就為真,
System.out.println(!a); //輸出true,邏輯非運算:真變為假,假變為真,
//短路運算
int c = 5;
boolean d = (c<4)&&(c++<4);
System.out.println(d); //輸出false
System.out.println(c); //輸出5,說明c++<4并沒有被執行,該陳述句被“短路”了
}
}
位運算子
示例:
package operator;
public class Demo04 {
public static void main(String[] args) {
//位運算
/*
* 設
* A = 1101 0001
* B = 0110 1000
* 則
* A&B = 0100 0000 按位與運算
* A|B = 1111 1001 按位或運算
* A^B = 1011 1001 按位異或運算,即不相等為1,相等為0
* ~B = 1001 0111 按位取反運算
* */
/*
題目:2*8如何運算才最快?
思路:2*8 = 2*2*2*2
0000 0000 0
0000 0001 1
0000 0010 2
0000 0011 3
0000 0100 4
0000 1000 8
0001 0000 16
<<為左移,每次左移等同于數值*2,但效率極高
>>為右移,每次右移等同于數值/2,但效率極高
*/
System.out.println(2<<3); //輸出16
}
}
賦值運算子
示例:
package operator;
public class Demo05 {
public static void main(String[] args) {
int a = 10;
int b = 10;
a += b; //等同于a = a + b;
System.out.println(a); //輸出20
a -= b; //等同于a = a - b;
System.out.println(a); //輸出10
a *= b; //等同于a = a * b;
System.out.println(a); //輸出100
a /= b; //等同于a = a / b;
System.out.println(a); //輸出10
}
}
條件運算子
示例:
package operator;
public class Demo06 {
public static void main(String[] args) {
//條件運算子 a ? b : c
//如果a為true,則執行b,否則執行c
int score = 50;
String mark = score>=60 ? "及格" : "不及格";
System.out.println(mark); //輸出"不及格"
}
}
Java流程控制
Scanner物件
在Java5及以后的版本中,我們可以通過java.util.Scanner來獲取用戶的輸入,創建Scanner物件的基本語法如下:
Scanner sc = new Scanner(System.in);
我們可以通過 Scanner 類的 next() 與 nextLine() 方法獲取輸入的字串,在讀取前,我們一般需要使用 hasNext() 與 hasNextLine() 判斷是否還有輸入的資料,
使用next()時:
- 一定要讀取到有效字符后才可以結束輸入,
- 對輸入有效字符之前遇到的空白,next() 方法會自動將其去掉,
- 只有輸入有效字符后才將其后面輸入的空白作為分隔符或者結束符,
- 不能得到帶有空格的字串,
示例:
package com.wmwx.Scanner;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
//創建一個掃描器物件,用于從鍵盤接收資料
Scanner sc = new Scanner(System.in);
System.out.println("請輸入內容:");
//判斷用戶有沒有輸入字串
if (sc.hasNext()){
//使用next方式接收
String str = sc.next();
System.out.println("輸入的內容為:"+str); //輸入"hello world",輸出"hello"
}
//凡是屬于IO流的類如果不關閉就會一直占用資源
//要養成習慣,用完就關閉
sc.close();
}
}
使用nextLine()時:
- 以Enter為結束符,也就是說 nextLine()方法回傳的是輸入回車之前的所有字符,
- 可以獲得帶有空格的字串,
示例:
package com.wmwx.Scanner;
import java.util.Scanner;
public class Demo02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入內容:");
if (sc.hasNextLine()){
//使用nextLine方式接收
String str = sc.nextLine();
System.out.println("輸入的內容為:"+str); //輸入"hello world",輸出"hello world"
}
sc.close();
}
}
順序結構
Java的基本結構就是順序結構,除非特別指明,否則就按照順序從上到下一句一句執行,
示例:
package com.wmwx.struct;
public class Demo01 {
public static void main(String[] args) {
//順序結構,從上到下依次執行
System.out.println("1");
System.out.println("2");
System.out.println("3");
System.out.println("4");
System.out.println("1");
}
}
選擇結構
Java中的選擇結構包含以下五種:
- if單選擇結構
- if雙選擇結構
- if多選擇結構
- 嵌套的if結構
- switch多選擇結構
if單選擇結構
語法如下:
if (布爾運算式){
//布爾運算式為true時執行的陳述句
}
示例:
package com.wmwx.struct;
import java.util.Scanner;
public class IfDemo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入內容:");
//判斷是否輸入了內容
if (scanner.hasNextLine()){
String str = scanner.nextLine();
//判斷輸入的字串是否與"hello"相等
if (str.equals("hello")){
//如果相等,就輸出這句話
System.out.println("你輸入的是:"+str);
}
}
scanner.close();
}
}
if雙選擇結構
語法如下:
if (布爾運算式){
//布爾運算式為true時執行的陳述句
}
else {
//布爾運算式為false時執行的陳述句
}
示例:
package com.wmwx.struct;
import java.util.Scanner;
public class IfDemo02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入成績:");
int score = scanner.nextInt();
//判斷考試分數不小于60就是及格,否則就是不及格
if (score>=60){
System.out.println("及格");
}else{
System.out.println("不及格");
}
scanner.close();
}
}
if多選擇結構
語法如下:
if (布爾運算式1){
//布爾運算式1為true時執行的陳述句
}
else if (布爾運算式2){
//布爾運算式2為true時執行的陳述句
}
else if (布爾運算式3){
//布爾運算式3為true時執行的陳述句
}
//... ...
else if (布爾運算式n){
//布爾運算式n為true時執行的陳述句
}
else {
//以上布爾運算式都為false時執行的陳述句
}
注意:
-
if 陳述句至多有1 個else陳述句,else 陳述句在所有的else if 陳述句之后,
-
if陳述句可以有若干個else if陳述句,它們必須在else陳述句之前,
-
一旦其中一個else if陳述句檢測為 true,其他的else if 以及else 陳述句都將跳過執行,
示例:
package com.wmwx.struct;
import java.util.Scanner;
public class IfDemo03 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入成績:");
int score = scanner.nextInt();
//判斷考試分數
if (score<100 && score>=95){
System.out.println("學分:4.5");
}else if (score<95 && score>=90){
System.out.println("學分:4.0");
}else if (score<90 && score>=85){
System.out.println("學分:3.5");
}else if (score<85 && score>=80){
System.out.println("學分:3.0");
}else if (score<80 && score>=75){
System.out.println("學分:2.5");
}else if (score<75 && score>=70){
System.out.println("學分:2.0");
}else if (score<70 && score>=65){
System.out.println("學分:1.5");
}else if (score<65 && score>=60){
System.out.println("學分:1.0");
}else if (score<60 && score>=0){
System.out.println("不及格");
}else{
System.out.println("成績不合法!");
}
scanner.close();
}
}
嵌套的if結構
語法如下:
if (布爾運算式1){
//布爾運算式1為true時執行的陳述句
if (布爾運算式2){
//布爾運算式2為true時執行的陳述句
}
}
switch多選擇結構
switch case 陳述句判斷一個變數與一系列值中某個值是否相等,每個值稱為一個分支,
語法如下:
switch(expression){
case value1 :
//當expression與value1相等時執行的陳述句
break; //跳出switch結構
case value2 :
//當expression與value2相等時執行的陳述句
break;
//... ...
case valuen :
//當expression與valuen相等時執行的陳述句
break;
default :
//當expression與value1相等時執行的陳述句
}
示例:
package com.wmwx.struct;
public class SwitchDemo01 {
public static void main(String[] args) {
String grade = "B級";
switch (grade){
case "A級":
System.out.println("優秀!");
break;
case "B級":
System.out.println("良好!");
break;
case "C級":
System.out.println("中等!");
break;
case "D級":
System.out.println("及格!");
break;
case "E級":
System.out.println("掛科!");
break;
default:
System.out.println("未知的等級!");
}
}
}
回圈結構
順序結構的程式陳述句只能被執行一次,如果您想要同樣的操作執行多次,,就需要使用回圈結構,
Java中有以下四種回圈結構:
- while 回圈
- do…while 回圈
- for 回圈
- 針對陣列的增強型 for 回圈
while回圈
while是最基本的回圈,其語法為:
while( 布爾運算式 ) {
//回圈內容
}
注意:
- 只要布爾運算式為 true,回圈就會一直執行下去,
- 大多數情況下會讓回圈停止下來,需要一個讓布爾運算式失效的方式來結束回圈,
- 少部分情況下需要回圈一直執行,比如服務器的請求回應監聽等等,
- 布爾運算式如果恒為true就會造成死回圈
示例:
package com.wmwx.struct;
public class WhileDemo02 {
public static void main(String[] args) {
//輸出1~100并求它們的和
int i = 0;
int sum = 0;
while (i<100){
i++;
sum = sum + i;
System.out.println(i); //輸出i
}
System.out.println(sum); //輸出sum
}
}
do...while回圈
do…while 回圈和 while 回圈相似,不同的是,do…while 回圈至少會執行一次,而對于 while 陳述句而言,如果不滿足條件,則不能進入回圈,
其語法如下:
do {
//代碼陳述句
}while(布爾運算式);
示例:
package com.wmwx.struct;
public class DoWhileDemo01 {
public static void main(String[] args) {
//輸出1~100并求它們的和
int i = 0;
int sum = 0;
do {
i++;
sum = sum + i;
System.out.println(i); //輸出i
}while (i<100);
System.out.println(sum); //輸出sum
}
}
for回圈
for回圈執行的次數是在執行前就確定的,其語法格式如下:
for(初始化; 布爾運算式; 更新) {
//代碼陳述句
}
關于 for 回圈有以下幾點說明:
- 最先執行初始化步驟,可以宣告一種型別,但可初始化一個或多個回圈控制變數,也可以是空陳述句,
- 然后,檢測布爾運算式的值,如果為 true,回圈體被執行,如果為false,回圈終止,開始執行回圈體后面的陳述句,
- 執行一次回圈后,更新回圈控制變數,
- 再次檢測布爾運算式,回圈執行上面的程序,
示例:
package com.wmwx.struct;
public class ForDemo01 {
public static void main(String[] args) {
//計算0~100以內的奇數和及偶數和
int odd = 0; //奇數
int even = 0; //偶數
for (int i = 1; i <= 100; i++) {
if(i%2==0){
//是偶數
even = even + i;
}else{
//是奇數
odd = odd + i;
}
}
System.out.println(odd); //輸出2500
System.out.println(even); //輸出2550
}
}
增強型for回圈
Java5 引入了一種主要用于陣列的增強型 for 回圈,其語法格式如下:
for(宣告陳述句 : 運算式)
{
//代碼句子
}
宣告陳述句:宣告新的區域變數,該變數的型別必須和陣列元素的型別匹配,其作用域限定在回圈陳述句塊,其值與此時陣列元素的值相等,
運算式:運算式是要訪問的陣列名,或者是回傳值為陣列的方法,
示例:
package com.wmwx.struct;
public class ForDemo03 {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50}; //定義一個陣列
//遍歷陣列中的元素
for (int x : numbers){
System.out.println(x);
}
}
}
Java方法詳解
什么是方法?
Java方法是陳述句的集合,它們在一起執行一個功能,
- 方法是解決一類問題的步驟的有序組合
- 方法包含于類或物件中
- 方法在程式中被創建,在其他地方被參考
示例:
package com.wmwx.method;
public class Demo01 {
//main方法
public static void main(String[] args) {
int sum = add(1, 2); //呼叫add方法
System.out.println(sum);
}
//add方法 實作加法功能
public static int add(int a, int b){
return a+b;
}
}
方法的優點
Java中的方法有以下幾個優點:
- 使程式變得更簡短而清晰,
- 有利于程式維護,
- 可以提高程式開發的效率,
- 提高了代碼的重用性,
方法的設計原則
設計方法的原則:方法的本意是功能塊,就是實作某個功能的陳述句塊的集合,我們設計方法的時候,最好保持方法的原子性,就是一個方法只完成1個功能,這樣利于我們后期的擴展,
方法的定義
其基本語法為:
修飾符 回傳值型別 方法名(引數型別 引數名){
...
方法體
...
return 回傳值;
}
Java的方法包含一個方法頭和一個方法體,類似于其他語言中的函式,是一段用來完成特定功能的代碼片段,以下是一個方法的所有組成部分:
- 修飾符:可選,告訴編譯器如何呼叫該方法,定義了該方法的訪問型別,
- 回傳值型別 :方法可能會有回傳值,那么該回傳值的資料型別就是該方法的回傳值型別,有些方法執行所需的操作,但沒有回傳值,在這種情況下,方法的回傳值型別使用關鍵字void,
- 方法名:是方法的實際名稱,方法名和引數表共同構成方法簽名,
- 引數型別:引數像是一個占位符,又被稱為形參,當方法被呼叫時,傳遞值給引數,這個值被稱為實參,引數串列是指方法的引數型別、順序和引數的個數,引數是可選的,一個方法可以不包含任何引數,
- 方法體:方法體包含具體的陳述句,定義該方法的功能,
例圖:

方法的呼叫
Java 支持兩種呼叫方法的方式,根據方法是否回傳值來選擇,
- 當方法回傳一個值的時候,方法呼叫通常被當做一個值,
- 如果方法回傳值是void,方法呼叫一定是一條陳述句,
示例:
package com.wmwx.method;
public class Demo02 {
public static void main(String[] args) {
int maxNum = max(10, 20); //呼叫有回傳值的max方法,作為賦給變數maxNum的值
System.out.println(maxNum);
}
//定義有回傳值的max方法
public static int max(int num1, int num2){
int result = 0;
if (num1==num2){
System.out.println("兩數相等!");
return num1;
}
if (num1>num2){
result = num1;
}else{
result = num2;
}
return result;
}
}
方法的多載
多載:如果一個類的多個方法擁有相同的方法名,但是有不同的引數串列,那么Java編譯器會根據方法簽名判斷哪個方法應該被呼叫,
方法多載的規則:
- 方法名稱必須相同,
- 引數串列必須不同(如:個數不同、引數不同、引數排列順序不同等),
- 方法的回傳型別可以相同,也可以不同
- 僅僅回傳型別不同不足以成為方法的多載
示例:
package com.wmwx.method;
public class Demo03 {
public static void main(String[] args) {
int maxNum1 = max(10, 20); //呼叫有整數型別引數的max方法
System.out.println(maxNum1);
double maxNum2 = max(10.0, 20.0); //呼叫有浮點型別引數的max方法
System.out.println(maxNum2);
}
//定義有整數型別引數的max方法
public static int max(int num1, int num2){
int result = 0;
if (num1==num2){
System.out.println("兩數相等!");
return num1;
}
if (num1>num2){
result = num1;
}else{
result = num2;
}
return result;
}
//多載:
//定義有浮點型別引數的max方法
public static double max(double num1, double num2){
double result = 0;
if (num1==num2){
System.out.println("兩數相等!");
return num1;
}
if (num1>num2){
result = num1;
}else{
result = num2;
}
return result;
}
}
命令列傳參
有的時候,希望一個程式在運行時再給它傳遞訊息,這時就需要傳遞命令列引數給main方法進行實作,
示例:
package com.wmwx.method;
public class Demo04 {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println("args["+i+"]: "+args[i]);
}
}
}
可變引數/不定項引數
從Java5 開始,Java支持傳遞同型別的可變引數(又叫不定項引數)給一個方法,
方法的可變引數的宣告如下所示:
typeName... parameterName
//即:在方法宣告中,在指定引數型別后加一個省略號(...)
注意:
- 一個方法中只能指定一個可變引數,
- 可變引數必須是方法的最后一個引數,
- 任何普通的引數必須在可變引數之前宣告,
示例:
package com.wmwx.method;
public class Demo05 {
public static void main(String[] args) {
//呼叫可變引數的方法
printMax();
printMax(12, 13.6, 22.5, 18.7, 16.0);
printMax(new double[]{12, 13.6, 22.5, 18.7, 16.0});
}
public static void printMax(double...numbers){
if (numbers.length == 0){
System.out.println("沒有傳入資料!");
return;
}
double result = numbers[0];
//找出最大值
for (int i=1;i<numbers.length;i++){
if (numbers[i]>result){
result = numbers[i];
}
}
System.out.println("最大的數是"+result+"!");
}
}
遞回
定義:程式呼叫自身的編程方式稱為遞回,
利用遞回可以用簡單的程式來解決一些復雜的問題,它通常把一個大型復雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞回策略只需少量的程式就可描述出解題程序所需要的多次重復計算,大大地減少了程式的代碼量,遞回的能力在于用有限的陳述句來定義物件的無限集合,
遞回結構包括兩部分:
- 遞回頭:什么時候不呼叫自身方法,如果沒有遞回頭,將造成死回圈,
- 遞回體:什么時候呼叫自身方法,
示例:
package com.wmwx.method;
public class Demo06 {
public static void main(String[] args) {
System.out.println(factorial(5));
}
//求階乘
public static int factorial(int n){
if (n==1){
return 1;
}else{
return n*factorial(n-1); //遞回呼叫
}
}
}
Java陣列詳解
陣列的定義
- 陣列是相同資料型別的有序集合,
- 陣列描述的是相同型別的若干資料,按照一定的先后次序排列組合而成,
- 其中,每一個資料稱作一個陣列元素,每一個陣列元素可以通過下標來訪問它們,
陣列的宣告和創建
首先必須宣告陣列變數,才能在程式中使用陣列,下面是宣告陣列變數的兩種語法:
dataType[] arrayRefVar; // 首選的方法,推薦使用
或
dataType arrayRefVar[]; // 為C/C++程式員保留的方式,不推薦
Java語言使用new運算子來創建陣列,語法如下:
arrayRefVar = new dataType[arraySize];
示例:
package com.wmwx.array;
public class Demo01 {
public static void main(String[] args) {
int[] numbers; //陣列的宣告
numbers = new int[5]; //陣列的創建
}
}
陣列的賦值
陣列可以通過使用下標來執行賦值操作,陣列的下標從0開始,到length-1結束(length為陣列長度),
如果下標超過length-1,就會報錯:ArraylndexOutOfBoundsException ,即陣列下標越界例外,
示例:
package com.wmwx.array;
public class Demo01 {
public static void main(String[] args) {
int[] numbers = new int[5];
numbers[0] = 1; //下標從0開始
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
System.out.println(numbers[0]); //輸出1
System.out.println(numbers[1]); //輸出2
System.out.println(numbers[2]); //輸出3
System.out.println(numbers[3]); //輸出4
System.out.println(numbers[4]); //輸出5
System.out.println(numbers[5]); //報錯:越界例外
}
}
陣列的遍歷
陣列的元素型別和陣列的大小都是確定的,所以當處理陣列元素時候,我們通常使用回圈結構,
示例:
package com.wmwx.array;
public class Demo01 {
public static void main(String[] args) {
int[] numbers = new int[5]; //宣告和創建
numbers[0] = 1; //賦值
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
int sum = 0;
//通過array.length可以得到陣列的長度
for (int i = 0; i < numbers.length; i++) {
sum = sum + numbers[i];
}
System.out.println(sum); //輸出15
}
}
陣列的初始化
陣列的初始化有以下三種方式:
- 靜態初始化
- 動態初始化
- 默認初始化
示例:
package com.wmwx.array;
public class Demo02 {
public static void main(String[] args) {
//靜態初始化:創建+賦值
int[] a = {1, 2, 3, 4};
System.out.println(a[0]); //輸出1
//動態初始化(包含默認初始化)
int[] b = new int[4];
b[0] = 5;
System.out.println(b[0]); //輸出5
//默認初始化
System.out.println(b[1]); //輸出0
System.out.println(b[2]); //輸出0
System.out.println(b[3]); //輸出0
}
}
陣列的基本特點
- 其長度是確定的,陣列一旦被創建,它的大小就是不可以改變的,其元素必須是相同型別,不允許出現混合型別,
- 陣列中的元素可以是任何資料型別,包括基本型別和參考型別,
- 陣列變數屬于參考型別,陣列也可以看成是物件,陣列中的每個元素相當于該物件的成員變數,
- 陣列本身就是物件,而Java中的物件是在堆中的,因此陣列無論保存原始型別還是其他物件型別,陣列物件本身是在堆中的,
For-Each回圈
Java5 引進了一種新的回圈型別,被稱為 For-Each 回圈或者加強型回圈,它能在不使用下標的情況下遍歷陣列,
其語法格式如下:
for(type element: array)
{
System.out.println(element);
}
示例:
package com.wmwx.array;
public class Demo03 {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
//輸出陣列的所有元素
//for回圈
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
//for-each回圈
for (int i: array) {
System.out.println(i);
}
}
}
陣列作為引數和回傳值
示例:
package com.wmwx.array;
public class Demo04 {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
int[] new_array = reverse(array);
for (int i: new_array) {
System.out.println(i); //輸出5、4、3、2、1
}
}
//陣列作為回傳值
public static int[] reverse(int[] array){ //陣列作為引數
int[] result = new int[array.length];
//反轉整個陣列
for (int i=0, j=array.length-1;i<array.length;i++,j--){
result[j] = array[i];
}
return result;
}
}
多維陣列
多維陣列可以看成是陣列的陣列,比如二維陣列就是一個特殊的一維陣列,其每一個元素都是一個一維陣列,
示例:
package com.wmwx.array;
public class Demo05 {
public static void main(String[] args) {
//二維陣列
int[][] array = {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}};
System.out.println(array[0][1]); //輸出2
System.out.println(array[1][2]); //輸出4
System.out.println(array[2][0]); //輸出3
//遍歷二維陣列
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j]);
}
}
}
}
Arrays類
java.util.Arrays 類能方便地操作陣列,它提供的所有方法都是靜態的,
具有以下功能:
- 列印陣列:通過 toString 方法
- 給陣列賦值:通過 fill 方法,
- 對陣列排序:通過 sort 方法,按升序,
- 比較陣列:通過 equals 方法比較陣列中元素值是否相等,
- 查找陣列元素:通過 binarySearch 方法能對排序好的陣列進行二分查找法操作,
示例:
package com.wmwx.array;
import java.util.Arrays;
public class Demo06 {
public static void main(String[] args) {
int[] array = {1, 234, 56, 7890};
//列印陣列
System.out.println(array); //輸出[I@e73f9ac
System.out.println(Arrays.toString(array)); //輸出[1, 234, 56, 7890]
//排序陣列
Arrays.sort(array); //升序排序
System.out.println(Arrays.toString(array)); //輸出[1, 56, 234, 7890]
//查找元素
System.out.println(Arrays.binarySearch(array, 234)); //輸出2
//填充陣列
Arrays.fill(array, 0);
System.out.println(Arrays.toString(array)); //輸出[0, 0, 0, 0]
//比較陣列
System.out.println(Arrays.equals(array, new int[]{0, 0, 0, 0})); //輸出true
}
}
稀疏陣列
當一個陣列中大部分元素為0,或為同一值時,可以使用稀疏陣列來保存該陣列,
稀疏陣列的處理方式是:
- 記錄陣列一共有幾行幾列,有多少個不同的值
- 把具有不同值的元素的行列及值記錄在一個小規模的陣列中,從而縮小程式的規模
示例:
package com.wmwx.array;
import java.util.Arrays;
public class Demo07 {
public static void main(String[] args) {
//11*11的棋盤上:0 空格 1 黑棋 2 白棋
int[][] chess = new int[11][11];
chess[1][2] = 1;
chess[2][3] = 2;
//輸出原始陣列:
System.out.println("原始陣列如下:");
for (int[] arrs: chess) {
for (int i: arrs) {
System.out.print(i+" ");
}
System.out.println();
}
System.out.println("=====================");
//轉換為稀疏陣列并輸出
chess = sparse(chess);
System.out.println("稀疏陣列如下:");
for (int[] arrs: chess) {
for (int i: arrs) {
System.out.print(i+" ");
}
System.out.println();
}
System.out.println("=====================");
//還原成原始陣列并輸出
chess = toArray(chess);
System.out.println("還原陣列如下:");
for (int[] arrs: chess) {
for (int i: arrs) {
System.out.print(i+" ");
}
System.out.println();
}
}
public static int[][] sparse(int[][] array){
//第一步:獲取有效值的個數
int sum = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j]!=0){
sum++;
}
}
}
System.out.println("有效值的個數:"+sum);
System.out.println("=====================");
//第二步:創建一個稀疏陣列
int[][] sparseArray = new int[sum+1][3];
sparseArray[0][0] = array.length;
sparseArray[0][1] = array[0].length;
sparseArray[0][2] = sum;
//第三步:遍歷原陣列,將非零值存放到稀疏陣列中
int count = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j]!=0){
count++;
sparseArray[count][0] = i;
sparseArray[count][1] = j;
sparseArray[count][2] = array[i][j];
}
}
}
//第四步:回傳稀疏陣列
return sparseArray;
}
public static int[][] toArray(int[][] sparse){
//第一步:構建原始陣列
int[][] array = new int[sparse[0][0]][sparse[0][1]];
//第二步:還原其中的值
for (int i = 1; i < sparse.length; i++) {
array[sparse[i][0]][sparse[i][1]] = sparse[i][2];
}
//第三步:回傳原始陣列
return array;
}
}
最終的輸出結果如下:
原始陣列如下:
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
=====================
有效值的個數:2
=====================
稀疏陣列如下:
11 11 2
1 2 1
2 3 2
=====================
還原陣列如下:
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
Java面向物件
面向程序&面向物件
面向程序:
- 步驟清晰簡單,第一步做什么,第二步做什么......
- 面向程序適合處理一些較為簡單的事情
面向物件:
- 物以類聚,分類的思維模式,思考問題首先會解決問題需要哪些分類,然后對這些分類進行單獨思考,最后,才對某個分類下的細節進行面向程序的思索,
- 面向物件適合處理復雜的問題,適合處理需要多人協作的問題,
概述:對于描述復雜的事物,為了從宏觀上把握、從整體上合理分析,我們需要使用面向物件的思路來分析整個系統,但是,具體到微觀操作,仍然需要面向程序的思路去處理,
什么是面向物件?
面向物件(Object-Oriented Programming, OOP)的本質是以類的方式組織代碼,以物件的方式封裝資料,
三大特性:
- 封裝
- 繼承
- 多型
注意:
- 從認識論的角度考慮,是先有物件后有類,因為物件是具體的,而類是抽象的,類是對物件的抽象,
- 從代碼運行的角度考慮,是先有類后有物件,類是物件的模板,
類與物件的關系
類是一種抽象的資料型別,它是對某一類事物的整體描述或定義,但并不能代表某一個具體的事物,
- 如:人、動物、植物、電腦、手機,等等......
物件是抽象概念的具體實體,
- 如:張三、隔壁家的小花貓咪咪、《唐伯虎點秋香》里的那只名叫旺財的狗
初始化與創建物件
創建的方式:使用new關鍵字創建物件
使用new關鍵字創建物件的時候,除了分配記憶體空間之外,還會給創建好的物件賦默認值進行初始化,以及呼叫類中的構造器,
示例:
Student類
package com.wmwx.oop.Demo01;
//學生類
public class Student {
//屬性:欄位
String name;
int age;
//方法
public void study(){
System.out.println("學生"+this.name+"在學習,");
}
}
Application類(啟動類)
package com.wmwx.oop.Demo01;
//啟動類
public class Application {
//一個專案應該只存在一個main方法
public static void main(String[] args) {
//類是抽象的,需要實體化
//類實體化后會回傳一個自己的物件
//student物件是Student類的一個實體
Student student = new Student();
student.study(); //輸出"學生null在學習,"
student.name = "小明";
student.study(); //輸出"學生小明在學習,"
}
}
構造方法
當一個物件被創建時候,構造方法用來初始化該物件,構造方法和它所在類的名字相同,但構造方法沒有回傳值,
一個類即使什么都不寫,也會存在一個構造方法,因為 Java 自動提供了一個默認構造方法,其訪問修飾符和類的訪問修飾符相同,
一旦自己定義了構造方法,默認的構造方法就會失效,
示例:
Person類:
package com.wmwx.oop.Demo01;
public class Person {
String name;
//使用快捷鍵alt+insert可以自動生成構造方法
//無參構造
public Person(){
this.name = "一個無名氏";
}
//有參構造(一旦定義有參構造,就必須顯式定義無參構造)
public Person(String name){
this.name = name;
}
}
Application類:
package com.wmwx.oop.Demo01;
public class Application {
public static void main(String[] args) {
//使用new關鍵字,本質是在呼叫構造方法
Person person1 = new Person(); //呼叫無參構造
System.out.println(person1.name); //輸出"一個無名氏"
//利用構造方法,可以初始化物件
Person person2 = new Person("惟妙惟霄"); //呼叫有參構造
System.out.println(person2.name); //輸出"惟妙惟霄"
}
}
記憶體分析
程序如下:
- 創建類
- 在堆中存放類和類中的靜態方法
- 創建物件
- 在堆中為物件開辟空間
- 在堆疊中存放物件的參考變數名
- 令物件的參考變數名指向堆中開辟的空間
封裝
所謂封裝,即該露的露,該藏的藏,程式設計要追求“高內聚,低耦合”,
高內聚:類的內部資料操作細節自己完成,不允許外部干涉,
低耦合:僅暴露少量的方法給外部使用,
對于代碼而言,總結起來就一句話:屬性私有,get/set,
意義:
- 提升程式的安全性,保護資料
- 隱藏代碼的實作細節
- 統一介面
- 提高了系統的可維護性
示例:
Student類:
package com.wmwx.oop.Demo03;
public class Student {
//屬性私有
private String name;
private int id;
private String gender;
private int age;
//需要提供共有的get和set方法
//get方法:獲取資料
public String getName() {
return name;
}
//set方法:設定資料
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age<0||age>120){
this.age = 3;
}else{
this.age = age;
}
}
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo03.Student;
//啟動類
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.setName("惟妙惟霄");
student.setId(123456);
student.setGender("男");
student.setAge(130);
System.out.println(student.getAge()); //輸出3
}
}
繼承
繼承的本質是對某一批類的抽象,從而實作對現實世界更好的建模,
在 Java 中通過 extends 關鍵字可以宣告一個類是從另外一個類繼承而來的,其語法如下:
class 子類 extends 父類 {
}
extends的意思是擴展,子類是對父類的擴展,
繼承的注意事項:
-
Java只有單繼承,沒有多繼承,
-
在Java中,所有類都默認直接或間接繼承自Object類,
在Java中,可以使用this指代當前類,并使用super指代父類,
super的注意事項:
- super呼叫父類的構造方法,必須在構造方法的第一行,
- super只能出現在子類的方法或構造方法中,
- super和this不能同時呼叫構造方法,
重寫是子類對父類的允許訪問的方法的實作程序進行重新撰寫, 回傳值和形參都不能改變,重寫的好處在于子類可以根據需要,定義特定于自己的行為, 也就是說,子類能夠根據需要實作父類的方法,重寫需要遵守以下規則:
- 方法名必須相同
- 引數串列必須相同
- 修飾符的范圍可以擴大,但不能縮小
- 拋出的例外可以被縮小,但不能擴大
示例:
Person類:
package com.wmwx.oop.Demo04;
//父類:人類
public class Person {
private int money = 10_0000_0000;
protected String name = "惟妙惟霄";
public Person() {
System.out.println("Person的無參構造方法執行了!");
}
public void say(){
System.out.println("說了一句話,");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void print(){
System.out.println("Person");
}
}
Student類:
package com.wmwx.oop.Demo04;
//子類:學生類
public class Student extends Person{
private String name = "妙霄";
public Student() {
//隱藏代碼:super();
//父類的構造方法必須要在子類的構造方法的第一行
System.out.println("Student的無參構造方法執行了!");
}
public void test1(String name){
System.out.println(name); //輸出引數
System.out.println(this.name); //輸出當前類的name
System.out.println(super.name); //輸出父類的name
}
//重寫都是方法的重寫,與屬性無關
//只允許重寫public方法
//可以使用快捷鍵alt+insert來插入重寫方法
@Override
public void print() {
System.out.println("Student");
}
public void test2(){
print();
this.print();
super.print();
}
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo04.Person;
import com.wmwx.oop.Demo04.Student;
//啟動類
public class Application {
public static void main(String[] args) {
Student student = new Student();
//第一行輸出"Person的無參構造方法執行了!"
//第二行輸出"Student的無參構造方法執行了!"
student.say(); //子類繼承父類,就會擁有父類的public方法
System.out.println(student.getMoney()); //可以用父類的get/set方法對屬性進行操作
//可以使用快捷鍵ctrl+H來查看繼承樹
student.test1("MiaoXiao");
//第一行輸出"MiaoXiao"
//第二行輸出"妙霄"
//第三行輸出"惟妙惟霄"
student.test2();
//第一行輸出"Student"
//第二行輸出"Student"
//第三行輸出"Person"
Student stu1 = new Student();
stu1.print(); //輸出"Student"
//父類的參考指向了子類
Person stu2 = new Student();
stu2.print(); //輸出"Student"
}
}
多型
多型是同一個行為具有多個不同表現形式或形態的能力,當使用多型方式呼叫方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;如果有,再去呼叫子類的同名方法,
多型存在的三個必要條件:
- 繼承
- 重寫
- 父類參考指向子類物件:
Parent p = new Child();
不能被重寫的方法:
- static 方法
- final 方法
- private 方法
示例:
Person類:
package com.wmwx.oop.Demo05;
public class Person {
public void run(){
System.out.println("人在跑步,");
}
}
Student類:
package com.wmwx.oop.Demo05;
public class Student extends Person{
@Override
public void run() {
System.out.println("學生在跑步,");
}
public void eat(){
System.out.println("學生在吃東西,");
}
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo05.Person;
import com.wmwx.oop.Demo05.Student;
//啟動類
public class Application {
public static void main(String[] args) {
//一個物件的實際型別是確定的
//但可以指向的參考型別是不確定的
Student s1 = new Student();
Person s2 = new Student(); //父類的參考指向子類
Object s3 = new Student();
s1.run(); //輸出"學生在跑步"
s2.run(); //子類重寫父類方法,將執行子類方法,輸出"學生在跑步,"
s1.eat(); //輸出"學生在吃東西"
//s2.eat(); //不能呼叫,物件能使用哪些方法,要看左邊的型別,
((Student)s2).eat(); //強制型別轉換,輸出"學生在吃東西,"
}
}
instanceof
Java中的instanceof關鍵字可以用來判斷某一個物件是不是某一個類是實體,如果是,回傳true;如果不是,回傳false;如果二者無關,則編譯不通過,
示例:
package com.wmwx.oop;
import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;
import com.wmwx.oop.Demo06.Teacher;
//啟動類
public class Application {
public static void main(String[] args) {
//繼承關系如下:
//Object -> Person -> Student
//Object -> Person -> Teacher
//Object -> String
Object object = new Student();
System.out.println(object instanceof Student); //輸出true
System.out.println(object instanceof Person); //輸出true
System.out.println(object instanceof Object); //輸出true
System.out.println(object instanceof Teacher); //輸出false
System.out.println(object instanceof String); //輸出false
System.out.println("=====");
Person person = new Student();
System.out.println(person instanceof Student); //輸出true
System.out.println(person instanceof Person); //輸出true
System.out.println(person instanceof Object); //輸出true
System.out.println(person instanceof Teacher); //輸出false
//System.out.println(person instanceof String); //編譯時報錯
System.out.println("=====");
Student student = new Student();
System.out.println(student instanceof Student); //輸出true
System.out.println(student instanceof Person); //輸出true
System.out.println(student instanceof Object); //輸出true
//System.out.println(student instanceof Teacher);//編譯時報錯
//System.out.println(student instanceof String); //編譯時報錯
}
}
型別轉換
- 子類轉換為父類,是向上轉型,可自動轉換,
- 父類轉換為子類,是向下轉型,需強制轉換,
示例:
Person類:
package com.wmwx.oop.Demo06;
public class Person {
public void run(){
System.out.println("人在跑步,");
}
}
Student類:
package com.wmwx.oop.Demo06;
public class Student extends Person{
public void walk(){
System.out.println("學生在走路,");
}
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;
//啟動類
public class Application {
public static void main(String[] args) {
//高 ----------------- 低
Person person = new Student();
((Student)person).walk(); //強制型別轉換
Student student = new Student();
Person obj = student; //子類轉換為父類,可能會丟失一些方法
//obj.walk(); //編譯時報錯
}
}
靜態代碼塊
靜態代碼塊會在類加載時執行,且只會執行一次,
示例:
Person類:
package com.wmwx.oop.Demo07;
public class Person {
//第二個執行,可在這里賦初始值
{
System.out.println("匿名代碼塊");
}
//第一個執行,只執行一次
static {
System.out.println("靜態代碼塊");
}
//第三個執行
public Person() {
System.out.println("構造方法");
}
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo07.Person;
//啟動類
public class Application {
public static void main(String[] args) {
Person person = new Person();
//第一行輸出"靜態代碼塊"
//第二行輸出"匿名代碼塊"
//第三行輸出"構造方法"
}
}
抽象類
在Java語言中使用abstract 來定義抽象類,其基本語法如下:
abstract class 類名{
//屬性
//方法
}
抽象類除了不能實體化物件之外,類的其它功能依然存在,成員變數、成員方法和構造方法的訪問方式和普通類一樣,
由于抽象類不能實體化物件,所以抽象類必須被繼承,才能被使用,在Java中一個類只能繼承一個抽象類,但一個類可以實作多個介面,
在Java語言中使用abstract 來定義抽象方法,其基本語法如下:
abstract 訪問修飾符 回傳值型別 方法名(引數);
抽象類與抽象方法的規則:
- 抽象類不能被實體化(即不能被 new ),只有抽象類的非抽象子類可以創建物件,
- 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類,
- 抽象類中的抽象方法只是宣告,不包含方法體,也就是不給出方法的具體實作,
- 構造方法、類方法(用 static 修飾的方法)不能宣告為抽象方法,
- 抽象類的子類必須給出抽象類中的抽象方法的具體實作,除非該子類也是抽象類,
示例:
Action類:
package com.wmwx.oop.Demo08;
//使用abstract宣告抽象類
public abstract class Action {
//抽象方法,只有方法名,沒有方法體
//僅作約束,期待他人實作
public abstract void doSomething();
}
A類:
package com.wmwx.oop.Demo08;
public class A extends Action{
//子類必須實作父類的抽象方法
//除非該子類是抽象類
@Override
public void doSomething() {
}
}
介面
介面在JAVA編程語言中是一個抽象型別,是抽象方法的集合,通常以 interface 來宣告,其基本語法如下:
[訪問修飾符] interface 介面名稱 [extends 其他的介面名稱] {
// 抽象方法
}
介面的特性:
- 介面中每一個方法都是隱式抽象的,介面中的方法會被隱式地指定為 public abstract,并且只能是 public abstract,
- 介面中可以含有變數,但是介面中的變數會被隱式地指定為 public static final ,并且只能是 public static final,
- 介面中的方法不能在介面中實作,只能由實作介面的類來實作介面中的方法,
- 一個介面能繼承另一個介面,使用 extends 關鍵字.子介面會繼承父介面的方法,
當類實作介面的時候,需要實作介面中所有的方法,否則,類必須宣告為抽象的類,Java中使用 implements 關鍵字實作介面,其基本語法如下:
class 類名 implements 方法名{
//實作介面中的抽象方法
}
示例:
UserService介面:
package com.wmwx.oop.Demo09;
//定義介面使用關鍵字interface
public interface UserService {
//介面中的所有屬性都是public static final
//一般不在介面中定義屬性
int age = 60;
//介面中的所有方法都是public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
TimeService介面:
package com.wmwx.oop.Demo09;
public interface TimeService {
void timer();
}
UserServiceImpl類:
package com.wmwx.oop.Demo09;
//類使用關鍵字implements來實作介面
//實作了介面的類,需要重寫介面的所有方法
//一個類可以實作多個介面
public class UserServiceImpl implements UserService, TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
內部類
所謂內部類,就是在一個類的內部再定義一個類,
示例:
Outer類:
package com.wmwx.oop.Demo10;
//外部類
public class Outer {
private int id=10;
public void out(){
System.out.println("這是外部類的方法!");
}
public class Inner{
public void in(){
System.out.println("這是內部類的方法!");
}
//獲得外部類的私有屬性
public int getId(){
return id;
}
}
public void method(){
//區域內部類,在外部類的方法之中
class Inner{
}
}
}
//一個java檔案可以有多個class,但是只能有一個public class
class A{
}
Application類:
package com.wmwx.oop;
import com.wmwx.oop.Demo09.UserService;
import com.wmwx.oop.Demo10.Outer;
//啟動類
public class Application {
public static void main(String[] args) {
//外部類使用new關鍵字
Outer outer = new Outer();
outer.out();
//內部類通過外部類來實體化
Outer.Inner inner = outer.new Inner();
inner.in();
System.out.println(inner.getId());
//匿名類,不用將實體保存到變數中
new Outer().out();
//使用匿名類實作介面
UserService userService = new UserService() {
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
}
}
}
Java例外機制
例外
例外是程式中的一些錯誤,但并不是所有的錯誤都是例外,并且錯誤有時候是可以避免的,
例外的分類:
- 檢查性例外:最具代表的檢查性例外是用戶錯誤或問題引起的例外,這是程式員無法預見的,例如要打開一個不存在檔案時,一個例外就發生了,這些例外在編譯時不能被簡單地忽略,
- 運行時例外: 運行時例外是可能被程式員避免的例外,與檢查性例外相反,運行時例外可以在編譯時被忽略,
- 錯誤(Error): 錯誤不是例外,而是脫離程式員控制的問題,錯誤在代碼中通常被忽略,例如,當堆疊溢位時,一個錯誤就發生了,在編譯時同樣檢查不到,
示例:
package com.wmwx.exception;
public class Demo01 {
public static void main(String[] args) {
new Demo01().a(); //拋出例外:StackOverflowError
System.out.println(11/0); //拋出例外:ArithmeticException
System.out.println() //拋出例外:Error
}
public void a(){
b();
}
public void b(){
a();
}
}
例外體系結構
Java把例外當做物件來處理,并定義了一個基類java.lang.Throwable作為所有例外的超類,這些例外分為兩大類,即例外(Exception)和錯誤(Error),其中,Exception類有兩個主要的子類,即 IOException 類和 RuntimeException 類,
Error
Error類物件由虛擬機生成并拋出,大多數錯誤與代碼撰寫者所執行的操作無關,
常見的錯誤如Java虛擬機運行錯誤(VirtualMachineError),當JVM不再有繼續執行操作所需的記憶體資源時,將出現OutOfMemoryError,這些例外發生時,Java虛擬機一般會選擇將執行緒中止,
還有發生在虛擬機試圖執行應用時的錯誤,如類定義錯誤(NoClassDefFoundError)、鏈接錯誤(LinkageError)等,這些錯誤是不可查的,因為它們在應用程式的控制和處理程式能力之外,而且絕大多數是程式運行時不允許出現的狀況,
Exception
在Exception類的分支中有一個重要的子類 RuntimeException(運行時例外),其中包含以下例外:
-
ArrayIndexOutOfBoundsException(陣列下標越界)
-
NullPointerException(空指標例外)
-
ArithmeticException(算術例外)
-
MissingResourceException(丟失資源)
-
ClassNotFoundException(找不到類)
這些例外是不檢查例外,程式中可以選擇捕獲處理,也可以不處理,這些例外一般是由程式邏輯錯誤引起的,程式應該從邏輯角度盡可能避免這類例外的發生,
Error和Exception的區別:
- Error 通常是災難性的致命的錯誤,是程式無法控制和處理的,當出現這些例外時,Java虛擬機(JVM)一般會選擇終止執行緒
- Exception 通常情況下是可以被程式處理的,并且在程式中應該盡可能的去處理這些例外,
捕獲例外
使用 try 和 catch 關鍵字可以捕獲例外,try/catch 代碼塊放在例外可能發生的地方,
try/catch代碼塊中的代碼稱為保護代碼,其基本語法如下:
try
{
// 程式代碼
}catch(ExceptionName e1)
{
// Catch 塊
}catch(ExceptionName e2) //e2需比e1范圍更大
{
// Catch 塊
}finally {
// 終究會執行
}
示例:
package com.wmwx.exception;
public class Demo02 {
public static void main(String[] args) {
int a = 11;
int b = 0;
//快捷鍵 ctrl+alt+T
try{ //try 監控區域
System.out.println(a/b);
}catch (ArithmeticException e){ //catch 捕獲例外(引數是例外型別)
System.out.println("程式出現例外,變數b不能為0!");
}finally { //finally 善后作業
System.out.println("finally終究會被執行,");
}
try{ //監控區域
new Demo02().a();
}catch (StackOverflowError e){ //捕獲例外,多個類別需要從小到大
System.out.println("StackOverflowError"); //會輸出
}catch (Exception e){
System.out.println("Exception"); //不會輸出
}catch (Throwable t){
System.out.println("Throwable"); //不會輸出
}finally { //善后作業
System.out.println("finally終究會被執行,");
}
}
public void a(){
b();
}
public void b(){
a();
}
}
拋出例外
如果一個方法沒有捕獲到一個檢查性例外,那么該方法必須使用 throws 關鍵字來宣告,throws 關鍵字放在方法簽名的尾部,
也可以使用 throw 關鍵字拋出一個例外,無論它是新實體化的還是剛捕獲到的,
注意:兩種方式的拼寫不同,第一種末尾有 s,第二種沒有,
示例:
package com.wmwx.exception;
public class Demo03 {
public static void main(String[] args) {
int a = 11;
int b = 0;
try {
new Demo03().devide(a, b);
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
}
}
//假設在方法中無法處理例外,可以用throws主動拋出例外
public void devide(int a, int b) throws ArithmeticException{
if (b==0){
throw new ArithmeticException(); //使用throw主動拋出例外,一般用在方法中
}
System.out.println(a / b);
}
}
自定義例外
使用Java內置的例外類可以描述在編程時出現的大部分例外精況,除此之外,用戶還可以自定義例外,只需繼承Exception類即可,
示例:
MyException類(自定義例外類):
package com.wmwx.exception;
//自定義的例外類
public class MyException extends Exception{
//假設:當傳遞過來的數字大于10時拋出例外
private int detail;
//構造方法
public MyException(int a) {
this.detail = a;
}
//toString 列印例外資訊
@Override
public String toString() {
return "MyException{detail=" + detail + "}";
}
}
Demo04類(測驗類):
package com.wmwx.exception;
//自定義例外的測驗類
public class Demo04 {
//可能會存在例外的方法
public void test(int a) throws MyException {
System.out.println("傳遞的引數為:"+a);
if (a>10){
throw new MyException(a); //拋出例外
}
System.out.println("沒有例外!");
}
public static void main(String[] args) {
try {
new Demo04().test(5); //沒有例外
new Demo04().test(15); //有例外
} catch (MyException e) {
System.out.println("MyException => " + e);
}
}
}
經驗總結
- 處理運行時例外時,采用邏輯去合理規避,同時輔助 try-catch 處理,
- 在多重catch塊后面,可以加一個 catch (Exception) 來處理可能會被遺漏的例外,對于不確定的代碼,也可以加上try-catch,處理潛在的例外,
- 盡量去處理例外,切忌只是簡單地呼叫 printStackTrace() 去列印輸出,具體如何處理例外,要根據不同的業務需求和例外型別去決定,
- 盡量添加 finally 陳述句塊去釋放占用的資源,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/266924.html
標籤:其他
