Java學習筆記01 - JavaSE基礎

IT小馬發表於2021-11-15

線上工具

java https://c.runoob.com/compile/10

線上編寫執行 Java 8 https://www.tutorialspoint.co...

SQL 線上執行 https://www.bejson.com/runcod...

Java牛客題庫 https://www.nowcoder.com/inte...

JDK, JRE, JVM

  • JDK : Java Development Kit
  • JRE : Java Runtime Enviroment
  • JVM : Java Virtual Machine

輸出Hello Wolrd

vim Hello.java
public class Hello{
    public static void main(String[] args){
        System.out.print("Hello World!");
    }
}

編譯

javac Hello.java

執行

java Hello

輸出

Hello World!

Java程式執行機制

  • 編譯型:
  • 解釋型:
  • 程式執行機制:

    原始檔(*.java) => Java編譯器 => 位元組碼(.class)

    => JVM ( 類裝載器 =>位元組碼校驗器 => 直譯器 )

    => 作業系統平臺

IDEA

新建工程

File => New => Project… => Empty Project

File => Project Structure => Project => Project SDK (1.8.0) => Project language level (8) => OK

基礎語法

1.註釋,識別符號,關鍵字

註釋
//單行註釋
/* 多行註釋 */
/**
  * 文件註釋
  * @Author itxiaoma
  */
識別符號
類名,變數名,方法名都稱為識別符號
  • 識別符號以字母,美元($),下劃線(_)開始
  • 首字母后可以是字母,美元($),下劃線(_),數字的組合
  • 不能使用關鍵字作為變數名,方法名
  • 大小寫敏感
關鍵字(50+)

avator

2.資料型別

強型別語言:變數使用必須嚴格符合規定,所有變數都必須先定義後才能使用
Java資料型別
  1. 基本型別:(8大基本型別)

    1. 數值

      1. 整數

        1. byte:1個位元組(-128~127)
        2. short:2個位元組(-32768~32767)
        3. int:4個位元組(-2147483648~2147483647)21億+
        4. long:8個位元組(例:long num=40L;)
      2. 浮點

        1. float:4個位元組(例:float num=40F;)
        2. double:8個位元組
      3. 字串char:2個位元組
    2. boolean:1位,true/false
  1. 引用型別:類,介面,陣列

注1:String不是資料型別,是類

注2:1bit表示1位;(bit是計算機內部資料儲存的最小單位)

​ 1Byte表示1個位元組,1B=8b;

​ 1KB = 1024B;

​ 1MB = 1024KB;

​ 1GB = 1024MB;

​ 1TB = 1024GB;

Java資料型別的常見問題
  1. 整數擴充套件

    int a = 10;
    int b = 010;//八進位制
    int c = 0x10;//十六進位制
  2. 浮點型擴充套件

    float f = 0.1f;
    double d = 1.0/10;
    System.out.println(f==d);//false
    
    float d1 = 123123123123f;
    float d2 = d1 + 1;
    System.out.println(d1==d2);//true
    
    //float 有限 離散 舍入誤差 接近但不等於
    //不要用浮點數進行比較
    //數學工具類BigDecimal
  3. 字元類擴充套件

    char a = 'a';
    System.out.println((int)a);//97
    char a1 = '\u0061';
    System.out.println(a1);//a
    //所有的字元本質還是數字
    
    轉義字元:
    \t 製表符
    \n 換行
    ...

3.型別轉換

運算中,不同型別的資料會先轉換位同一型別,再進行計算

優先順序:低 ==> 高

byte,short,char => int => long => float => double

自動轉化:低 => 高

強制轉換: 高 => 低 (型別)變數名

注1:

  1. 不能對布林值進行轉換
  2. 不能把物件型別轉為不相干的型別
  3. 高容量轉低容量,會有記憶體溢位或精度問題

注2:JDK7的新特性,數字間可以用下劃線分割(1000 = 1_000)

4.變數、常量、作用域

變數
int a = 1;
常量 - final
常量:初始化後不能改變,一般為大寫
static final double PI = 3.14;
作用域
  1. 類變數
  2. 例項變數
  3. 區域性變數
public class Hello {
    //類變數:static
    static int a = 1;
    //例項變數:屬於物件,不需要初始化(會自動初始化為型別預設值)
    //布林值預設false,除基本型別以外其他變數都是null
    String b;
    public static void main(String[] args) {
        System.out.println(a);

        int c = 3;//區域性變數:必須宣告和初始化
        System.out.println(c);

        Hello obj = new Hello();
        System.out.println(obj.b);//null
    }
}
命名規則:
  1. 類變數,區域性變數,方法名:駝峰(首字母小寫)
  2. 常量:大寫 + 下劃線
  3. 型別:駝峰(首字母大寫)

5.基本運算子

  1. 算術運算子:+, -, *, /, %, ++, --
  2. 賦值運算子:=
  3. 關係運算子:>, <, >=, <=, ==, !=, instanceof
  4. 邏輯運算子:&&,||,!
  5. 位運算子:&, |, ^, ~, >>, << , >>>
  6. 條件運算子:? :
  7. 擴充套件賦值運算子:+=, -=, *= ,/=

例:

long a = 123L;
int b = 123;
short c = 10;
byte d = 8;
System.out.println(a+d);//long
System.out.println(b+c);//int
System.out.println(c+d);//int
//結論:有long型別時轉long,否則轉int

冪運算:2^3

double pow = Math.pow(2, 3);
System.out.println(pow);//8.0

位運算

<< 乘2 
>> 除2

6.包機制

包的本質就是資料夾
  1. 包機制是為了更好地組織類,用於區別類名的名稱空間
  2. 一般用公司名倒置作為報名 pakage com.baidu.www;
  3. 使用import匯入包(import 包名.* 表示匯入包下所有類)

7.JavaDoc生成文件

註釋引數

/**
 * @author 作者
 * @version 版本
 * @since 需要最早使用的jdk版本
 * @param 引數
 * @return 返回值
 * @throws 異常丟擲
 */

中文編碼

javadoc -encoding UTF-8 -charset UTF-8 Demo.java

流程控制

1.使用者互動Scanner (Java5新特性)

基礎使用

import java.util.Scanner;

public class Demo {
    public static void main(String[] args) {
        //建立掃描器物件,用於接收鍵盤資料
        Scanner s = new Scanner(System.in);
        //判斷使用者輸入
        if(s.hasNextLine()){
            String str = s.nextLine();
            System.out.println(str);
        }
        //IO流的類會一直佔用記憶體,用完需要關閉
        s.close();
    }
}
//next()以空格為結束符,nextLine()以回車為結束符

使用進階

計算多個數字的總和與平均數,非數字結束
Scanner s = new Scanner(System.in);
double sum = 0;
int num = 0;
while(s.hasNextDouble()){
    double x = s.nextDouble();
    sum += x;
    num++;
}
System.out.println("和是:" + sum);
System.out.println("平均值是" + (sum/num));
s.close();

2.九九乘法表

/*
1*1=1    
2*1=2    2*2=4    
3*1=3    3*2=6    3*3=9    
4*1=4    4*2=8    4*3=12    4*4=16    
5*1=5    5*2=10    5*3=15    5*4=20    5*5=25    
6*1=6    6*2=12    6*3=18    6*4=24    6*5=30    6*6=36    
7*1=7    7*2=14    7*3=21    7*4=28    7*5=35    7*6=42    7*7=49    
8*1=8    8*2=16    8*3=24    8*4=32    8*5=40    8*6=48    8*7=56    8*8=64    
9*1=9    9*2=18    9*3=27    9*4=36    9*5=45    9*6=54    9*7=63    9*8=72    9*9=81    
*/
for (int m = 1; m <= 9; m++) {
    for (int n = 1; n <= m; n++) {
        System.out.print(m + "*" + n + "=" + (m * n) + "\t");
    }
    System.out.println();
}
//System.out.print 不換行輸出

3.增強for迴圈(JDK1.5新特性)

int[] numbers = {1, 2, 3, 4, 5};
for (int x : numbers) {
     System.out.println(x);
}

4.label

列印101 - 150間的所有質數
outer:for (int i = 101; i <= 150; i++) {
    for (int j = 2; j < i / 2; j++) {
        if (i % j == 0) {
            continue outer;
        }
    }
    System.out.println(i);
}

Java方法

方法是用來完成特定功能的程式碼片段,由方法名和方法體組成

方法名:修飾符 返回值型別 方法名 (引數型別 引數名){}

方法體:return 返回值;

引數型別:實參,形參

注:java都是值傳遞,沒有引用傳遞

1.方法的過載

過載就是在一個類中,有相同的函式名稱,但形參不同的函式

方法過載規則:

  1. 方法名稱必須相同
  2. 引數列表必須不同(個數,型別,引數順序不同)
  3. 返回型別可相同可不同

2.命令列傳參

程式執行時傳遞引數,可以通過main方法傳遞
public static void main(String[] args) {
    for (int i = 0; i < args.length; i++) {
        System.out.println(args[i]);
    }
}

3.可變引數(JDK1.5新特性)

public static void main(String[] args) {
    test(1,2,3);
}
public static void test(int... i){
    System.out.println(i[0]);
    System.out.println(i[1]);
    System.out.println(i[2]);
}

4.遞迴

遞迴頭:什麼時候不呼叫自身方法。如果沒有頭,將陷入死迴圈。

遞迴體:什麼時候需要呼叫自身方法。

Java陣列

陣列是相同型別資料的有序集合
dataType[] arrayRefVar = new dataType[size];

int nums[] = new int[10];
//二維陣列
int[][] n = new int[2][2];
int[][] n = {{1,2},{3,4}} 

基本特點

  1. 長度是確定的,一旦建立,長度不可變
  2. 元素型別必須相同
  3. 陣列物件本身在堆中(陣列是引用型別,可看做物件,陣列元素相當於物件的成員變數,Java的物件在堆中)

記憶體分析

graph LR
A(java記憶體)
A --> B(堆)
      B -->B1[存放new的物件和陣列]
      B -->B2[可以被所有執行緒共享,不會存放別的物件引用] 
A --> C(棧)
      C -->C1[存放基本變數型別,包含具體數值]
      C -->C2[引用物件的變數,存放引用在堆中的地址] 
A --> D(方法區)
      D -->D1[可以被所有執行緒共享]
      D -->D2[包含所有calss和static變數] 
//1.宣告陣列
int[] nums;//在棧中
//2.建立陣列
nums = new int[10];//在堆中

三種初始化狀態

//靜態初始化
int[] a = {1, 2, 3};
Man[] mans = {new Man(1),new Man(2)}

//動態初始化(包含預設初始化)
int[] b = new int[10];//預設分配10個0
b[0] = 10;

注:陣列是引用型別,陣列元素相當於類的例項變數,陣列建立時分配空間,陣列元素也會按預設值初始化。

陣列工具類java.util.Arrays

列印陣列元素Arrays.toString(a);
陣列填充Arrays.fill(a, 0 , 1, 0);陣列下標0-1的元素用0填充
陣列排序Arrays.sort(a);
比較陣列equals
查詢陣列元素binarySearch對排序好的陣列進行二分法查詢

氣泡排序

  1. 共有八大排序
  2. 時間複雜度為O(n2)

稀疏陣列

當一個陣列中大部分元素為0或值相同時,可以使用稀疏陣列儲存

處理方式:

1.記錄陣列行列數,不同值數

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    
*/
public class Demo {
    public static void main(String[] args) {
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        int sum = 0;
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (array1[i][j] != 0) {
                    sum++;
                }
            }
        }
        int[][] array2 = new int[sum + 1][3];
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;
        int count = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0) {
                    count++;
                    array2[count][0] = i;
                    array2[count][1] = j;
                    array2[count][2] = array1[i][j];
                }
            }
        }
        System.out.println("稀疏陣列");
        for (int j = 1; j < array2.length; j++) {
            System.out.println(array2[j][0] + "\t" + array2[j][1] + "\t" + array2[j][2]);
        }
        System.out.println("還原陣列");
        int[][] array3 = new int[array2[0][0]][array2[0][1]];
        for (int j = 1; j < array2.length; j++) {
            array3[array2[j][0]][array2[j][1]] = array2[j][2];
        }
        for (int[] ints : array3) {
            for (int num : ints) {
                System.out.print(num + "\t");
            }
            System.out.println();
        }
    }
}

物件導向

以類的方式組織程式碼。以物件組織(封裝)資料

三大特性:封裝,繼承,多型

1.建立類與物件

一個專案應該只存在一個main方法
建立物件
使用new建立物件時,除了分配記憶體空間,還會給建立好的物件進行預設初始化,及呼叫類中的構造器。

com/oop/demo/Application.java

package com.oop.demo;
public class Application {
    public static void main(String[] args) {
        //類:抽象的,例項化後會返回一個自己的物件
        Student xiaoming = new Student();
        Student xiaohong = new Student();
        xiaoming.name = "小明";
        xiaoming.age = 20;
        xiaohong.name = "小紅";
        xiaohong.age = 21;
        System.out.println("姓名:" + xiaoming.name + "\t年齡:" + xiaoming.age);
        xiaoming.study();
        System.out.println("姓名:" + xiaohong.name + "\t年齡:" + xiaohong.age);
        xiaohong.study();
    }
}

com/oop/demo/Student.java

package com.oop.demo;
public class Student {
    //屬性
    String name;
    int age;
    //方法
    public void study() {
        System.out.println(this.name + "在學習");
    }
}
構造器(構造方法)
  1. 必須和類名相同
  2. 必須沒有返回型別(不能寫void)
  3. 一旦定義了有引數的構造器,new物件時想不傳引數,就必須寫一個無引數構造器
public class Student {
    //屬性
    String name;
    int age;
    //無參(預設)構造器
    public Student(){
        
    }
    //有參
    public Student(String name){
        this.name = name;
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    } 
}

建立物件記憶體分析

public class Application {
    public static void main(String[] args) {
        //類:抽象的,例項化後會返回一個自己的物件
        Student xiaoming = new Student();
        Student xiaohong = new Student();
        xiaoming.name = "小明";
        xiaoming.age = 20;
        xiaohong.name = "小紅";
        xiaohong.age = 21;
        System.out.println("姓名:" + xiaoming.name + "\t年齡:" + xiaoming.age);
        xiaoming.study();
        System.out.println("姓名:" + xiaohong.name + "\t年齡:" + xiaohong.age);
        xiaohong.study();
    }
}

方法區也在堆中;

靜態方法區和類一起載入,所以靜態方法可以直接呼叫,不需要例項化

  1. 載入Application和Student類資訊到方法區
  2. 載入main()方法到棧中
  3. 載入xiaoming和xiaohong引用變數名到棧中
  4. 載入Student xiaoming = new Student();和Student xiaohong = new Student();例項到堆中
  5. xiaoming和xiaohong呼叫方法區的study方法

注:基本型別外的變數都是引用型別,是通過引用來操作的;引用名在棧中,指向物件實體在堆中的地址。

封裝

禁止直接訪問一個物件中資料的實際表示,應通過介面操作來訪問。

屬性私有(private),get/set

public class Student {
    private String name;
    private int age;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
}

繼承extends

繼承的本質是對某一批類的抽象,從而實現更好的建模;

繼承是類之間的關係,子類繼承(extends)父類的全部public方法;

私有的屬性和方法無法被繼承

注:

  1. Java中只有單繼承,沒有多繼承 (一個子類只能有一個父類)
  2. Java中所有類,都預設直接或間接繼承Object類

Super

注意點
  1. super呼叫父類的構造方法,必須在構造方法的第一行
  2. super只能出現在子類的方法或構造方法中
  3. super和this不能同時在構造方法中呼叫(都需要在第一行)
super和this的區別
thissuper
代表物件不同呼叫者本身的物件父類物件的引用
使用前提不同沒有繼承也能使用只能在有繼承時使用
呼叫構造方法不同呼叫本類的構造方法呼叫父類的構造方法

com/oop/demo/Application.java

package com.oop.demo;

public class Application {
    public static void main(String[] args) {
        Student xiaoming = new Student();
        xiaoming.test1();
        //Person無參構造
        //Student無參構造
        //Student
        //Student
        //Person
    }
}

com/oop/demo/Person.java

package com.oop.demo;

public class Person {
    public Person() {
        System.out.println("Person無參構造");
    }
    public void print(){
        System.out.println("Person");
    }
}

com/oop/demo/Student.java

package com.oop.demo;

public class Student extends Person{
    public Student() {
        //隱藏程式碼:呼叫了父類的無參構造super();
        //super();
        System.out.println("Student無參構造");
    }
    public void print(){
        System.out.println("Student");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }
}

方法重寫@Override

子類的方法和父類必須要一致,方法體不同

重寫都是方法的重寫,和屬性無關

靜態方法不能被重寫 !

注意點
  1. 方法名,引數列表必須相同
  2. 修飾符範圍可以擴大不能縮小
  3. 丟擲異常範圍可以縮小不能擴大
程式碼示例

靜態方法

public class B {
    public static void test(){
        System.out.println("B=>test()");
    }
}
public class A extends B{
    public static void test(){
        System.out.println("A=>test()");
    }
}
public class Application {
    public static void main(String[] args) {
        //靜態方法:方法呼叫只和左邊定義的資料型別有關
        A a = new A();
        a.test();//A=>test()
        //父類的引用指向了子類
        B b = new A();
        b.test();//B=>test()
    }
}

方法重寫

public class B {
    public void test(){
        System.out.println("B=>test()");
    }
}
public class A extends B{
    @Override
    public void test() {
        System.out.println("A=>test()");
    }
}
public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.test();//A=>test()
        B b = new A();
        b.test();//A=>test()
    }
}

多型

同一方法根據傳送物件不同,採用多種不同的行為方式;

一個物件的型別是確定的,但可以指向物件的引用型別有很多(可以是子類,父類,Object)

多型存在的條件:

  1. 有繼承關係
  2. 子類重寫父類方法
  3. 父類引用指向子類物件

注:多型是方法的多型,屬性沒有多型。

無法重寫的方法
  1. static方法,屬於類,不屬於例項
  2. final 常量 (final修飾的類不能被繼承)
  3. private方法
//子類能呼叫的方法都是自己的或繼承父類的
A a = new A();
B b = new B();
//物件能執行哪些方法看左邊的引用型別
//父類引用可以指向子類,但不能呼叫子類獨有的方法
B c = new A();
a.test();//A=>test()
b.test();//B=>test()
//子類重寫了父類方法,會執行子類的方法
c.test();//A=>test()

instanceof和型別轉化

  1. 父類引用可以指向子類的物件,反過來不行
  2. 子類轉換為父類稱為向上轉型,可能丟失自己本來的一些方法
  3. 父類轉換為子類稱為向下轉型,需要強制轉換
public class Application {
    public static void main(String[] args) {
        //子類特有方法go
        Student s = new Student();
        s.go();
        //向上轉型,轉型後無法再呼叫go方法
        Person p = s;
        //向下轉型
        ((Student) p).go();
    }
}

static關鍵字

靜態變數
private static int age;
靜態方法
public class Application {
    private static void test(){
        System.out.println("Static Function");
    }
    public static void main(String[] args) {
        test();
    }
}
靜態程式碼塊
public class Person {
    {
        System.out.println("匿名程式碼塊");
    }
    static {
        System.out.println("靜態程式碼塊");//只會在類載入時執行一次
    }
    public Person() {
        System.out.println("構造方法");
    }
    public static void main(String[] args) {
        Person p = new Person();
        //靜態程式碼塊
        //匿名程式碼塊
        //構造方法
    }
}
靜態匯入包
import static java.lang.Math.random;
public class Person {
    public static void main(String[] args) {
        System.out.println(random());
    }
}

抽象類 abstract

//抽象類 (介面可以多繼承)
abstract class Person {
    public abstract void doSomething();//抽象方法:只有方法名,沒有方法體
}

注:

  1. 抽象類不能new,只能靠子類實現
  2. 抽象方法必須在抽象類中,但抽象類可以包含普通方法

介面 interface

對物件的抽象,約束和實現分離:面向介面程式設計

注:

  1. 介面不能被例項化,介面中沒有構造方法
  2. 介面中所有方法都是抽象的(public abstract)
  3. 介面中只有常量(public static final)
  4. 類通過implements實現介面,一個類可以實現多個介面,實現多繼承
  5. 實現介面的類,必須重寫介面中所有方法
public interface UserService {
    void userTest1();
    void userTest2();
}
public interface TimeService {
    void time1();
    void time2();
}
public class UserTime implements UserService,TimeService{
    @Override
    public void userTest1() {
    }
    @Override
    public void userTest2() {
    }
    @Override
    public void time1() {
    }
    @Override
    public void time2() {
    }
}

內部類

匿名物件:不將例項儲存到變數(棧)中,只在堆記憶體中使用物件

public class Application {
    public static void main(String[] args) {
        new Apple().eat();
    }
}
class Apple{
    public void eat(){
        System.out.println("吃蘋果");
    }
}

匿名內部類

public interface UserService {
    void userTest1();
    void userTest2();
}
public class Application {
    UserService u = new UserService() {
        @Override
        public void userTest1() {
        }
        @Override
        public void userTest2() {
        }
    };
}

異常Error Exception

Error

Error類物件由JVM生成並丟擲,大多數錯誤與操作無關,發生錯誤時JVM一般會終止執行緒;

如記憶體溢位(OutOfMemeryError),棧溢位,類定義錯誤(NoClassDefFoundError),連結錯誤(LinkageError)

Exception

異常通常由邏輯錯誤引起,應儘量避免
  1. 非執行時異常(IO異常...)
  2. 執行時異常(RuntimeException)

注:Error通常是致命性錯誤,程式無法處理;Exception通常可以且應該儘可能的處理。

異常處理機制

  1. try 監控區域 (必要)
  2. catch 捕獲異常 (必要)
  3. finally 最終處理 (釋放佔用資源)
  4. throw 丟擲異常(一般在方法中使用 )
  5. throws

注:捕獲多個異常需要從小到大XXXException < XXXException < Throwable

public class Application {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        try{
            if(b == 0){
                throw new ArithmeticException();
            }
            System.out.println(a/b);
        }catch (ArithmeticException e){
            e.printStackTrace();//列印錯誤的棧資訊
        }catch (Exception e){
            
        }catch (Throwable e){
            
        }finally {
            
        }
    }
}

自定義異常

使用者自定義異常類,只需要繼承Exception類即可
public class MyException extends Exception {
    String msg;

    public MyException(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MyException{" + msg + "}";
    }
}
public class Application {
    static void test(String msg) throws MyException{
        throw new MyException(msg);
    }
    public static void main(String[] args) {
        try{
            test("test");
        }catch (MyException e){
            System.out.println(e);//MyException{test}
        }
    }
}

相關文章