Java-語法基礎

来源:https://www.cnblogs.com/zhumeizhizhai/archive/2023/06/30/17517775.html
-Advertisement-
Play Games

> JDK8 > > 複習用 ## Java前置知識 1. JavaSE Java Standard Edition 標準版 支持面向桌面級應用(如Windows下的應用程式)的 Java平臺,提供了完整的Java核心API 此版本以前稱為 J2SE 2. JavaEE Java Enterpris ...


JDK8

複習用

Java前置知識

  1. JavaSE

    Java Standard Edition 標準版

    支持面向桌面級應用(如Windows下的應用程式)的 Java平臺,提供了完整的Java核心API

    此版本以前稱為 J2SE

  2. JavaEE

    Java Enterprise Edition 企業版

    一套用於企業環境下的應用程式的應用方案(包含:Servlet、Jsp),主要針對 Web應用程式的開發

    此版本以前稱為 J2EE

  3. JavaME

    Java Micro Edition 小型版

    支持 Java程式 運行在移動端的版本,對 JavaAPI 有所精簡,並且加入了針對移動端的支持

    此版本以前稱為 J2ME

  4. JDK

    Java Development Kit Java開發工具包

    JDK = JRE + Java開發工具(java、javac、javap、javadoc等)

  5. JRE

    Java Runtime Environment Java運行環境

    JRE = JVM + Java核心類庫

  6. JVM

    Java Virtual Machine Java虛擬機

    JVM 是一個虛擬的電腦,具有指令集並使用不同的存儲區域,負責執行指令,管理數據、記憶體、寄存器

    對於不同的平臺有不同的虛擬機,屏蔽了底層運行平臺的差別,實現了“一次編譯,到處運行”

  7. Java運行簡單的大致流程

    Java文件 通過 javac 編譯為 Class文件,再通過 java指令 交給 JVM虛擬機 執行

  8. Java中特殊的轉義字元

    \r : 游標定位到行首

    public class Main {
        public static void main(String[] args) {
            System.out.println("aaaaaaa\rbb");
        }
    }
    
    • 在 IDEA 中 會清空這一行並把游標放到這一行的首位

      上方代碼在IDEA中輸出:bb

    • 在 windows終端 中,只會幫游標定位到該行的行首

      上方代碼在Windows終端中輸出:bbaaaaa

  9. Java程式 中 + 號的使用

    • + 號 的 左邊和右邊 都是數值型時,視為加法運算
    • + 號 的 左邊和右邊 有一方是字元串時,視為拼接運算
    • 運算順序:從左往右
    System.out.println(100 + 98); // 輸出: 198
    System.out.println("100" + 98); // 輸出:10098
    System.out.println(100 + 3 + "hello"); // 輸出:103hello
    System.out.printIn("hello" + 100 + 3); // 輸出:hello1003
    
    • + 號 的 左邊和右邊 有一方是char字元時,視為字元編碼值的運算

      由於 Java 中 char 底層存儲的是 對應字元的Unicode碼值,列印時會對照Unicode表列印出對應的字元

      因此,對char字元的運算相當於對char字元對應的Unicode碼值進行運算

      但當有一方是字元串時,仍然視為拼接運算

      System.out.println(1 + 'a'); // 98
      System.out.println('a' + 1); // 98
      System.out.println('a' + 'b'); // 195 (97+98=195)
      System.out.println('a' + "bc"); // abc
      
  10. JavaAPI

  • API : Application Programming Interface 應用程式編程介面
  • JavaAPI : Java提供的基本編程介面
  • JavaAPI文檔 : Java語言提供了大量的基礎類,Oracle公司也為這些基礎類提供了相應的AP文檔用於告訴開發者如何使用這些類,以及這些類里包含的方法
  1. switch語句 中表達式的值,必須是:byte、short、int、char、這4個基本數據類型的包裝類對象、String對象、枚舉對象

Java變數

不論使用哪種高級程式語言編寫程式,變數都是程式的基本組成單位

  1. 變數三要素:

    類型、名稱、值

  2. 變數相當於記憶體中一個存儲空間的表示,即 聲明變數時就是先開闢了一定空間的空房間,變數相當於門牌號,通過 門牌號 可以找到目標房間,從而放入、取出房間中的填充物(也就是變數值),一個房間是有最大容量限制的,超過這個容量就會導致溢出

    • 變數類型的不同,其占用記憶體空間的大小也不同
    • 此區域有自己的變數名、數據類型,且可以在同一類型內不斷變化
    • 變數必須先聲明後使用
    • 變數在同一個作用域內,不能重名
  3. 數據類型

    • 基本數據類型

      • 數值型

        • 整數類型

          1. byte : 1個位元組
          2. short : 2個位元組
          3. int : 4個位元組
          4. long : 8個位元組
        • 浮點數類型

          1. float : 4個位元組
          2. double : 8個位元組

          浮點數計算陷阱:

          2.7 和 8.1/3 的值在電腦中會不相等

          因為在二進位方面 8.1/3 是無限小數,double的精度太低,導致在記憶體中存儲的 2.7 和 8.1/3 的值在二進位層面不相等

      • 字元型

        1. char : 2個位元組(Java中可以使用2個char來表示1個字元,用於彌補單個char存儲空間小的限制)
      • 布爾型

        1. boolean : 1個位元組
    • 引用數據類型

      • 介面
      • 數組
    flowchart RL byte([byte 1位元組]) short([short 2位元組]) int([int 4位元組]) long([long 8位元組]) float([float 4位元組]) double([double 8位元組]) char([char 2位元組]) boolean([boolean 1位元組]) CLASS([類 class]) interface([介面 interface]) array([數組 arrary]) NUMBER([數值型]) CHARACTER([字元型]) BOOLEAN([布爾型]) BASIC([基本數據類型]) REFERENCE([引用數據類型]) Java([Java數據類型]) byte --> short --> int --> long --> NUMBER float --> double --> NUMBER char --> CHARACTER boolean --> BOOLEAN NUMBER --> BASIC CHARACTER --> BASIC BOOLEAN --> BASIC BASIC --> Java CLASS --> REFERENCE interface --> REFERENCE array --> REFERENCE REFERENCE --> Java
  4. 字元類型

    • 字元類型(char)可以表示單個字元,占用兩個位元組(可以存放漢字),多個字元使用字元串(String類)

    • String類底層仍然是多個char

    • Java中的char本質存儲的是Unicode表中,對應字元的整數位值,因此一些特殊符號(\n\t)也可以賦值給char,使對應的char在列印時具備對應特殊符號的功能

  5. 布爾類型

    • 布爾類型也叫boolean類型,booolean類型數據只允許取值true和false,不允許賦予null值
    • boolean類型占1個位元組
    • boolean類型適於邏輯運算(if、while、do-while、for等)
  6. 基本數據類型的相互轉換

    • 自動類型轉換

      當java程式在進行賦值或者運算時,精度小的類型自動轉換為精度大的數據類型,這個就是自動類型轉換

      flowchart LR byte --> short --> int char --> int int --> long --> float --> double
      • 註意事項

        1. 有多種類型的數據混合運算時,系統首先自動將所有數據轉換成容量最大的那種數據類型,然後再進行計算

        2. 當我們把精度(容量)大的數據類型賦值給精度(容量)小的數據類型時,就會報錯,反之就會進行自動類型轉換

        3. (byte,short)和char之間不會相互自動轉換

          flowchart LR byte & short x--無法自動轉換---x char
        4. byte、short、char他們三者可以計算,在計算時首先轉換為int類型

        5. boolean不參與轉換

        6. 自動提升原則:表達式結果的類型自動提升為操作數中最大的類型

    • 強制類型轉換

      自動類型轉換的逆過程,將容量大的數據類型轉換為容量小的數據類型

      使用時要加上強制轉換符(),但可能造成精度降低或溢出,格外要註意

      1. 數據類型從大—>小(或多態的向下轉型)時,就需要使用到強制轉換

      2. 強轉符號只針對於最近的操作數有效,實際中經常會使用小括弧提升優先順序

      3. char類型可以保存int的常量值,但不能保存int的變數值,需要強轉

        char c1 = 100; //ok
        int m = 100; //ok
        char c2 = m; //錯誤
        char c3 = (char)mi; //ok
        System.out.printIn(c3):/100對應的字元
        
      4. byte、short、char類型在進行運算時,會被當做int類型處理

      5. 易錯題

        short s = 12; //ok
        s = s - 9; // 錯誤 int -> short
        
        byte b = 10;//ok
        b = b + 11; // 錯誤 int -> byte
        b = (byte)(b+11); //正確,使用了強轉
        
        char c = 'a'; // ok
        int i = 16; // ok
        
        float d = .314F; // ok
        double result = c i d; // ok float -> double
        
        byte b = 16;// ok
        short s = 14;// ok
        short t = s + b; // 錯誤 int -> short
        
    • 基本數據類型 和 String類 的轉換

      1. 轉 String類

        int aInt = 1;
        String aStr = 1 + "";
        
      2. 轉 基本數據類型

        String aStr = "1";
        int aInt = Integer.parseInt(aStr);
        
      3. String類 轉 char

        String類底層維護的就是char數組,因此只需要取出數組中的某個索引位置的值即可

        String str = "Hello world!";
        char e = str.charAt(1); // 數組索引下標從0開始
        
      4. 註意事項

        • 在將String類型轉成基本數據類型時,要確保String類型能夠轉成有效的數據

          比如我們可以把"123",轉成一個整數,但是不能把"hello"轉成一個整數

        • 若String類無法轉換為數值基本類型,會拋出異常:java.lang.NumberFormatException

        • String類 轉 boolean 時,除了字元串為true時,得到true的boolean值,其他情況均會得到false的boolean值

          String str1 = "Hello world!";
          boolean b1 = Boolean.parseBoolean(str1);
          System.out.println(b1); // 輸出 : false
          
          String str2 = null;
          boolean b2 = Boolean.parseBoolean(str2);
          System.out.println(b2); // 輸出 : false
          

Java運算符

  1. 運算符是一種特殊的符號,用以表示數據的運算、賦值和比較等

    Java中存在的運算符:算術運算符、關係運算符 [比較運算符]、邏輯運算符、位運算符、賦值運算符、三元運算符

  2. 測試算術運算符

    運算符 運算 範例 結果
    + 正號 + 7 7
    - 負號 - 7 -7
    + 加號 9 + 9 18
    - 減號 9 - 9 0
    * 乘號 9 * 9 81
    / 除號(保留整數部分) 10 / 3 3
    % 取模(保留小數部分) 10 % 3 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;
    + 字元串相加(拼接) "hello" + "world" "helloworld"
    • 註意:
      1. 取模 的 本質: a % b = a - a / b * b

      2. 自增、自減 在前在後 的簡化理解:看作一個整體

        例如下麵的例子

        • x++ 看作一個整體,因為自增在後,所以此時 x++ 整體的值為 5 ,x 的值為6

        • ++y 看作一個整體,因為自增在前,所以此時 ++y 整體的值為6,y 的值為6

        int x = 5;
        int y = 5;
        if (x++==6 & ++y==6){ // F & T -> F
            x=11;
        }
        System.out.print("x -> " + x + "\t"); // 6
        System.out.println("y -> " + y); // 6
        
  3. 關係運算符(比較運算符)

    關係運算符的 結果 都是 boolean類型,即 都是 true 或 false

    常用於 條件判斷 中

    運算符 運算 範例 結果
    == 相等於 8 == 7 fasle
    != 不等於 8 != 7 true
    < 小於 8 < 7 false
    > 大於 8 > 7 true
    <= 小於等於 8 <= 7 false
    >= 大於等於 8 >= 7 true
    instanceof 檢查左邊(對象)是否右邊(類)相等 或 子類關係 "hello world" instanceof String true
  4. 邏輯運算符、位運算符

    用於連接多個條件(多個關係表達式,關係表達式也就是前面關係運算符所連接的一串表達式)

    最終的結果也是一個 boolean 值

    • & : 邏輯與

      左邊、右邊同為 true 時,結果為 true,否則為 false

    • && : 短路與

      在滿足 邏輯與 的基礎上,添加了短路機制:當左邊為 false 時,不會計算右邊,直接返回 false

    • | : 邏輯或

      左邊、右邊同為 false 時,結果為 false,否則為 true

    • || : 短路或

      在滿足 短路或 的基礎上,添加了短路機制:當左邊為 true 時,不會計算右邊,直接返回 true

    • ^ : 邏輯異或

      左邊、右邊 不同 時,返回 true

      左邊、右邊 相同 時,返回 false

    • ! : 取反

      對 ! 右側的 boolean值進行取反

      true –> false

      false –> true

    a b a & b a && b a | b a || b a ^ b !a
    true true true true true ture false false
    true false false false true true true false
    false true false false true true true true
    false false false false false false false true
    • 複習題

      //題1
      public static void test01(){
          int x = 5;
          int y = 5;
          if (x++==6 & ++y==6){ // F & T -> F
              x=11;
          }
          System.out.print("x -> " + x + "\t"); // 6
          System.out.println("y -> " + y); // 6
      }
      
      //題2
      public static void test02(){
          int x = 5;
          int y = 5;
          if (x++==5 | ++y==5){ // T | F -> T
              x=11;
          }
          System.out.print("x -> " + x + "\t"); // 11
          System.out.println("y -> " + y); // 6
      }
      
      //題3
      public static void test03(){
          int x = 5;
          int y = 5;
          if (x++==6 && ++y==6){ // F && (短路不運算)
              x=11;
          }
          System.out.print("x -> " + x + "\t"); // 6
          System.out.println("y -> " + y); // 5
      }
      
      //題4
      public static void test04(){
          int x = 5;
          int y = 5;
          if (x++==5 || ++y==5){ // T || (短路不運算)
              x=11;
          }
          System.out.print("x -> " + x + "\t"); // 11
          System.out.println("y -> " + y); // 5
      }
      
  5. 賦值運算

    賦值運算符就是將某個運算後的值,賦給指定的變數

    • 基本賦值運算符

      int a = 1; // 此處的 = 號,便是基本賦值運算符,可以理解為: 有一個存儲int的4位元組空間,空間名稱為a,現在將 1 這個值存放到這個空間中
      
    • 複合賦值運算符

      int a = 10;
      int b = 20;
      
      a += b; // 等價於: a = a + b;
      
      a -= b; // 等價於: a = a - b;
      
      a *= b; // 等價於: a = a * b;
      
      a /= b; // 等價於: a = a / b;
      
      a %= b; // 等價於: a = a % b;
      
    • 賦值運算符的特點

      1. 運算順序從右往左

      2. 賦值運算符

        • 左邊 只能是變數
        • 右邊 可以是變數、表達式、常量值
      3. 複合賦值運算符會進行類型轉換

        byte b = 3;
        b += 2; // 等價 b = (byte)(b + 2);
        b++; // b = (byte)(b+1);
        
  6. 三元運算符

    • 基本語法 : 條件表達式 ? 表達式1 : 表達式2

      當條件表達式為 true 時,返回 表達式1 的 結果

      當條件表達式為 false 時,返回 表達式2 的 結果

    • 舉例 :

      int a = 10;
      int b = 20;
      
      int res = a > b ? a++ : --b; // res -> 21 ; a -> 10 ; b -> 21 ;
      
    • 細節

      1. 三元運算符返回基本數據類型時,會自動轉換為表達式中精度最高的類型

        int a = 10;
        double b = 10.1;
        System.out.println(true ? a : b); // 輸出 : 10.0
        
  7. 運算符優先順序

    所謂優先順序就是表達式運算中的運算順序

    下表中的運算符中,上一行運算符總優先於下一行

    只有單目運算符、賦值運算符是從右向左運算的

    運算方向 運算符
    . () {} ; ,
    右 -> 左 ++ -- ~ !(data type)
    左 -> 右 * / %
    左 -> 右 + -
    左 -> 右 << >> >>> 位移
    左 -> 右 < > <= >= instanceof
    左 -> 右 == !=
    左 -> 右 &
    左 -> 右 ^
    左 -> 右 |
    左 -> 右 &&
    左 -> 右 ||
    左 -> 右 xx ? xx : xx(三元運算符)
    右 -> 左 = *= /= %=
    右 -> 左 += -= <<= >>=
    右 -> 左 >>>= &= ^= |=
  8. 標識符的命名規範

    Java對各種變數、方法和類等命名時使用的字元序列稱為標識符
    凡是自己可以起名字的地方都叫標識符

    • 標識符的命名規則(必須遵守)

      1. 26個英文字母大小寫(Java中區分大小寫)、0-9、_ 、$ 組成

        最好不要用 $

      2. 數字 不能 開頭

      3. 不可以 使用 保留字、關鍵字,但能夠包含 保留字、關鍵字

      4. 長度 不受限制

      5. 不能包含 空格

    • 標識符的命名規範(約定俗成)

      1. 包名

        多單片語成時所有字母都小寫

        com.zhumei.study

      2. 類名、介面名

        多單詞時使用大駝峰

        XxxYyyZzz

      3. 變數名、方法名

        多單詞時使用小駝峰

        xxxYxxZzz

      4. 常量名

        字母全大寫

        多單詞時使用下劃線分隔

        XXX_YYY_ZZZ

Java流程式控制制

  1. 順序控制

    沒什麼好說的,就是從上往下按代碼順序執行

  2. 分支控制

    • 單分支 if

      if (條件表達式) {
          // 條件表達式的值為 ture 則執行此代碼塊中的代碼(false則不執行)
          代碼;
      }
      
      flowchart TD A[Start] --> B{條件表達式} B -->|true| C[代碼塊] C --> D[end] B -->|false| D
    • 雙分支 if - else

      if (條件表達式) {
          // 條件表達式的值為 ture 則執行此代碼塊中的代碼1(false則不執行)
          代碼1;
      } else{
          // 條件表達式的值為 false 則執行此代碼塊中的代碼2(true則不執行)
          代碼2;
      }
      
      flowchart TD A[Start] --> B{條件表達式} B -->|true| C[代碼塊1] C --> E[end] B -->|false| D[代碼塊2] D --> E
    • 多分枝 if - else if - … - else

      if (條件表達式1) {
          代碼1; // 條件表達式1為true則執行代碼1,並不再繼續執行與條件表達式1處於同一分支的表達式與其對應的代碼
      } else if (條件表達式2){
          代碼2; // 條件表達式2為true則執行代碼2,並不再繼續執行與條件表達式2處於同一分支的表達式與其對應的代碼
      } else if (條件表達式N){
          代碼n; // 條件表達式n為true則執行代碼n,並不再繼續執行與條件表達式n處於同一分支的表達式與其對應的代碼
      } else{
          代碼n+1; // 若所有的表達式都為false,則執行此代碼塊 
      }
      
      flowchart TD A[Start] --> B{條件表達式1} B -->|true| C[代碼塊1] C --> D[end] B -->|false| E{條件表達式2} E -->|true| F[代碼塊2] F --> D E -->|false| G{條件表達式n} G -->|true| H[代碼塊n] G -->|false| I[代碼n+1] H --> D I --> D
    • 嵌套分支

      在 一個分支結構 中又 完整的 嵌套了 另一個完整的分支結構

      建議不超過3層,嵌套層數與可讀性呈負相關,層數越多可讀性越差

      if (條件表達式a){
          代碼1;
          if (條件表達式b){
              代碼2;
          }else if (條件表達式c){
              代碼3;
          }else {
              代碼4
          }
      }
      
    • switch分支

      1. 在Java中:
        • switch表達式的值可以是變數(byte、short、int、char、這4個基本數據類型的包裝類對象、String對象、枚舉對象)
        • case後的值不能為變數,必須是常量
      2. default語句是可選的,若沒有default語句又沒有匹配上對應的case中的常量,就表示不會執行switch中的任何代碼(switch中的表達式是一定會執行的)
      3. 在case中的代碼不寫break,會導致case穿透
      switch(表達式){
          case 常量1:
              代碼1;
              break;
          case 常量2:
              代碼2;
              break;
          case 常量n:
              代碼n;
              break;
          default:
              代碼default;
              break;
      }
      
      switch語句執行流程圖
  3. 迴圈控制

    • for迴圈

      1. for迴圈的四要素:

        • 迴圈變數初始化
        • 迴圈條件
        • 迴圈操作(需要迴圈的代碼)
        • 迴圈變數迭代
      2. 迴圈變數初始化、迴圈條件、迴圈變數迭代,都可以不放在for迴圈的括弧中

      3. 迴圈條件是一個返回布爾值的表達式,若在for迴圈中沒有寫迴圈條件,則預設為true

      4. 退出for迴圈的方式:

        • 迴圈條件結果為false
        • 執行break語句
        • 執行return語句
      for(迴圈變數初始化;迴圈條件;迴圈變數迭代){
          需要迴圈的代碼;
      }
      
      for迴圈執行流程
    • while迴圈

      while迴圈和for迴圈一樣,也有相同的迴圈四要素,只不過放的位置和for迴圈不一樣

      簡單來說,可以把while迴圈看作另一種寫法的for迴圈

      不必糾結寫法上的細枝末節,重點在於知道執行的代碼在哪種情況下被迴圈了幾次

      迴圈變數初始化;
      while(迴圈條件){
          需要迴圈的代碼;
          迴圈變數迭代;
      }
      
      while迴圈執行流程
    • do…while迴圈

      和while迴圈相比,do…while迴圈會先執行一次尋妖迴圈的代碼,再進行

      迴圈變數初始化;
      do{
          需要迴圈的代碼;
          迴圈變數迭代;
      }while(迴圈條件);
      
      while迴圈執行流程
    • 多重迴圈控制

      將一個迴圈放在另一個迴圈中,外層迴圈和內層迴圈均可使用for迴圈、while迴圈、do…while迴圈

      一般建議多重迴圈不超過3層,層數越多,代碼可讀性越差

      for (int i = 0; i < 10; i++) { // 外層迴圈
          for (int j = 0; j < 20; j++) { // 內層迴圈
              System.out.print("*"); // 需要xun
          }
          System.out.println(); // 表示換行
      }
      
      • 經典題
        1. 列印 九九乘法表

          for (int i = 1; i <= 9; i++) { // 表示輸出多少行
              for (int j = 1; j <= i; j++) { // 表示每行輸出多少列
                  System.out.print(j + "*" + i + "=" + j * i);
                  System.out.print("\t");
              }
              System.out.println(); // 換行
          }
          
        2. 列印 實心 / 空心 三角形

          //1. 實心三角
          for (int i = 1; i <= 6; i++) { // 表示列印多少行
              for (int j = 1; j <= 6-i; j++) { // 每一列要列印的空格
                  System.out.print(" ");
              }
              for (int j = 1; j <= (2*i-1) ; j++) { // 每一列要列印的*號數量
                  System.out.print("*");
              }
              System.out.println();
          }
          
          //2. 空心三角
          for (int i = 1; i <= 6; i++) { // 表示列印多少行
              for (int j = 1; j <= 6-i; j++) { // 每一列要列印的空格
                  System.out.print(" ");
              }
              for (int j = 1; j <= (2*i-1) ; j++) { // 每一列要列印的*號數量
                  //當要列印的是 最後一行 或者 這一列第一個和最後一個 時,輸出*
                  if (i==6||j==1||j==(2*i-1)){
                      System.out.print("*");
                  }else {
                      // 其餘輸出空格
                      System.out.print(" ");
                  }
              }
              System.out.println();// 換行
          }
          
        3. 列印 空心 / 實心 菱形

          //3. 實心菱形
          for (int i = 1; i <= 12; i++) {// 控制列印的行數
              if (i <= 6) {
                  //列印菱形的上半部分
                  for (int j = 1; j <= (6 - i); j++) {
                      System.out.print(" ");
                  }
                  for (int j = 1; j <= (2 * i - 1); j++) {
                      System.out.print("*");
                  }
              } else {
                  //列印菱形的下半部分
                  for (int j = 1; j <= (i - 6); j++) {
                      System.out.print(" ");
                  }
                  for (int j = 1; j <= (2 * (12 - i) - 1); j++) {
                      System.out.print("*");
                  }
              }
              System.out.println(); // 換行
          }
          
          //4. 空心菱形
          for (int i = 1; i <= 12; i++) {// 控制列印的行數
              if (i <= 6) {
                  //列印菱形的上半部分
                  //1. 先列印空格
                  for (int j = 1; j <= (6 - i); j++) {
                      System.out.print(" ");
                  }
                  //2. 列印邊框和內部空格
                  for (int j = 1; j <= (2*i-1) ; j++) {
                      if (j == 1 || j == (2 * i - 1)){
                          System.out.print("*");
                      }else {
                          System.out.print(" ");
                      }
                  }
              } else {
                  //列印菱形的下部分
                  //1. 列印空格
                  for (int j = 1; j <= (i - 6); j++) {
                      System.out.print(" ");
                  }
                  //2. 列印邊框和內部空格
                  for (int j = 1; j <= (2 * (12 - i) - 1); j++) {
                      if (j == 1 || j == (2 * (12 - i) - 1)){
                          System.out.print("*");
                      }else {
                          System.out.print(" ");
                      }
                  }
              }
              System.out.println(); // 換行
          }
          
    • break跳轉控制語句

      break語句用於終止某個語句塊的執行,一般使用在switch或者迴圈[for,while,do-while]中

      //使用方式1
      for (int i = 0; i < 10; i++) {
          if (i == 5) {
              break; // 退出最近的某個迴圈體
          }
      }
      
      //使用方式2
      label1:
      for (int i = 0; i < 10; i++) {
          label2:
          for (int j = 0; j < 10; j++) {
              if (j == 5) {
                  break label1; // 退出了label1標簽所標識的for迴圈
              }
              System.out.println("j -> " + j);
          }
      }
      
    • continue跳轉控制語句

      continue語句用於結束本次迴圈,繼續執行下一次迴圈。

      //使用方式1
      for (int i = 0; i < 10; i++) {
          //當i=5時,不會執行後續的輸出語句,而是進入下一次迴圈
          if (i == 5) {
              continue; // 結束本次迴圈,進入下一次迴圈
          }
          System.out.println("i -> " + i);
      }
      
      //使用方式2
      label1:
      for (int i = 0; i < 4; j++) {
          label2:
          for (int j = 0; j < 10; i++) {
              if (i == 5) {
                  continue label1; // 執行下一次 label1 標簽所指的For迴圈(for i的迴圈)
              }
              System.out.println("j = " + j + "\t");
          }
      }
      
    • return跳轉控制語句

      return 使用在方法,表示跳出所在的方法,意味著所在方法算為執行完畢

      return寫在主方法中,則會退出Java程式

    • 易錯陷阱題

      1. 求出1-1/2+1/3-1/4..1/100的和

        易錯點:

        • 1/2 在Java中等於0,需要使用1.0/2才能得到0.5

          所以在做 / 號時,除數與被除數必須有一個為浮點型

        double res = 0.0;
        double temp = 0.0;
        for (double i = 1.0; i <= 100; i++) {
            if (i%2==0){
                //符號為負
                temp = -(1/i);
            }else {
                //符號為正
                temp = 1/i;
            }
            res += temp;
        }
        System.out.println(res);
        

Java數組

  1. 簡介

    數組可以存放多個同一類型的數據

    數組也是一種數據類型,是引用類型

    當數組存儲基本數據類型時,預設值為基本數據類型對應的預設值

    當數組存儲引用數據類型(如:包裝類對象、String類對象)時,預設值為null

    數據就是在記憶體空間中連續存儲的同一類型數據

    數組索引從0開始

    註意:數組是引用數據類型,變數中存儲的是數組在堆中的地址

  2. 數組的幾種初始化方式

    • 方式一

      double[] a = new double[5]; // 直接分配記憶體空間
      a[0] = 1d;
      
      double b[]; // 先聲明
      b = new double[5]; // 再分配記憶體空間
      b[0] = 2d;
      
      // double[] a 和 double a[] 是一樣的,建議使用 double[]
      
    • 方式二

      double[] c = {1.0,2.0,3.0}; // 靜態初始化
      
  3. 數組反轉

    有很多方法,比如:

    • 開闢一個同樣長度的數組,便利舊數組,在新數組中從後往前放值
    • 數組第一個和最後一個進行交換位置,第二個和倒數第二個,直到數組完全反轉
    Integer[] arrayInter = {1, 2, 3, 4, 5, 6, 7};
    for (int i = 0; i < arrayInter.length / 2; i++) {
        Integer temp = arrayInter[i];
        arrayInter[i] = arrayInter[arrayInter.length - 1 - i];
        arrayInter[arrayInter.length - 1 - i] = temp;
    }
    for (int i = 0; i < arrayInter.length; i++) {
        System.out.print(arrayInter[i] + "\t");
    }
    
  4. 數組排序/查找

    有多種數組排序和查找的演算法,這裡演示冒泡排序

    • 冒泡排序

      冒泡排序(Bubble Sorting)的基本思想是:通過對待排序序列從後向前(從下標較大的元素開始),依次比較相鄰元素的值,若發現逆序則交換,使值較大的元素逐漸從前移向後部,就象水底下的氣泡一樣逐漸向上冒。

      舉例:(從小到大)

      int[] arrayInt = {41, 23, 65, 21, 78, 45};
      int temp = 0;
      for (int i = 0; i < arrayInt.length - 1; i++) {
          for (int j = 0; j < arrayInt.length - 1 - i; j++) {
              if (arrayInt[j] > arrayInt[j+1]){
                  temp = arrayInt[j];
                  arrayInt[j] = arrayInt[j+1];
                  arrayInt[j+1] = temp;
              }
          }
      }
      for (int i = 0; i < arrayInt.length; i++) {
          System.out.print(arrayInt[i] + "\t");
      }
      
    • 二分查找

      在演算法筆記中

  5. 二維數組

    • 幾種定義方式

      int[][] aint[] a[]int a[][] 都可以,但建議使用 int[][] a

      1. 方式一

        int[][] a = new int[2][3];
        
        int[][] b;
        b = new int[2][3];
        
      2. 方式二

        int[][] a = new int[10][];
        a[1] = new int[1];
        a[2] = new int[2];
        a[3] = new int[3];
        
      3. 方式二

        int[][] a = {
            {1,2,3,4},
            {1,2,3},
            {1,2},
            {1}
        };
        
    • 易錯點

      int[] x,y[]; // x是一維數組,y是二維數組
      
      // 初學時會有點搞混匿名內部類和數組靜態初始化的代碼
      
      //1. 數組的靜態初始化
      String[] arrayStr = new String[]{"a","b"};
      
      //2. 匿名內部類
      String arrayStr = new String(){...};
      // 註意: 這裡編譯會報錯,因為String為final類 (為了通過編譯報錯來確定這是創建匿名內部類的方式)
      

Java面向對象

  1. Java對象在記憶體中的存在形式(簡化)

    class Cat {
        private String color;
        private String name;
        private int age;
    
        public Cat(String color, String name, int age) {
            this.color = color;
            this.name = name;
            this.age = age;
        }
    }
    
    public static void main(String[] args) {
        Cat cat = new Cat(new String("blue"), "tom", 6);
    }
    
    Java對象在記憶體中的存在形式(簡化)
  2. JVM記憶體結構的簡單分析

    • 棧:存儲基本數據類型(局部變數)
    • 堆:存儲對象
    • 方法區:常量池,類文件
  3. Java創建對象的流程(簡化)

    • 先載入對應類的信息(載入屬性和方法信息,且只會載入一次)
    • 在堆中分配空間,進行預設初始化
    • 將對象在堆中的地址賦值給棧中的局部變數
  4. 成員方法傳參機制

    本質:都是值傳遞,即 拷貝一份副本然後將副本值傳遞給目標方法

    方法返回值也是同理,本質都是值拷貝,返回的是基本數據類型時拷貝的就是其值,返回的是引用數據類型時拷貝的是就是其在堆記憶體中的地址

    成員方法傳參機制
  5. 方法遞歸調用

    在演算法筆記中有較為詳細的介紹

    • 使用遞歸的重要知識點
      1. 執行一個方法時,就會創建一個新的受保護的獨立空間(棧空間)

        方法的局部變數是獨立的,不會相互影響

      2. 如果方法中使用的是引用類型變數(比如數組,對象),就會共用該引用類型的數據。

      3. 遞歸必須向退出遞歸的條件逼近,否則就是無限遞歸,出現 StackOverflowError 棧溢出,即棧空間被撐爆了

      4. 當一個方法執行完畢,或者遇到return就會返回,遵守誰調用,就將結果返回給誰

  6. 方法重載

    java 中允許同一個類中,多個同名方法的存在,但要求 形參列表不一致

    • 重載的好處
      1. 減輕了 起名 、記名 的麻煩
    • 重載的要求
      1. 方法名 必須 相同
      2. 形參列表 必須 不同(類型、個數、順序 至少一個不同)(形參名無要求)
      3. 返回類型 沒有要求
  7. 方法重寫

    方法重寫(覆蓋)就是子類有一個方法,和父類的某個方法的名稱、返回類型、參數一樣,那麼我們就說子類的這個方法重寫了父類的方法

    • 達成方法重寫的要求
      1. 子類方法的 形參列表、方法名 必須 要和父類方法的 形參列表、方法名 完全一致
      2. 子類方法的 返回類型,必須 要和 父類方法的返回類型一致 或 是父類方法返回類型的子類
      3. 子類方法 不能 縮小父類方法的訪問許可權(public > protected > 預設 > private)
  8. 可變參數

    java 允許將同一個類中多個同名同功能但參數個數不同的方法,通過可變參數的形式,封裝成一個方法

    簡單點就是說方法可以傳入無限多個指定類型的參數值

    public String study(String... arrayStr){
        String str = "";
        for (int i = 0; i < arrayStr.length; i++) {
            str += arrayStr[i];
        }
        return str;
    }
    
    • 一些細節
      1. 可變參數的實參可以是 0個任意多個
      2. 可變參數的本質 就是 數組
      3. 可變參數 和 普通參數 一起放在形參列表時,必須保證 可變參數類型 放在最後
      4. 一個形參列表中只能出現一個可變參數
  9. 作用域

    • Java中作用域的分類

      1. 全局變數:也就是屬性,作用域為整個類體

        全局變數(屬性)可以不賦值,就可以直接使用,因為有預設值

      2. 局部變數:除了屬性之外的其他變數,作用域為定義它的代碼塊中

        局部變數沒有預設值,必須賦值後使用

    • 一些細節

      1. 屬性和局部變數可以重名,訪問時遵循就近原則

      2. 在同一個作用域中,比如在同一個成員方法中,兩個局部變數,不能重名

      3. 生命周期不同

        • 屬性生命周期較長,伴隨著對象的創建而創建,伴隨著對象的銷毀而銷毀

        • 局部變數,生命周期較短,伴隨著它的代碼塊的執行而創建,伴隨著代碼塊的結束而銷毀

          即:在一次方法調用過程中

      4. 作用域範圍不同

        • 全局變數/屬性:可以被本類使用,或其他類使用(通過對象調用)
        • 局部變數:只能在本類中對應的方法中使用
      5. 修飾符不同

        • 全局變數/屬性可以加修飾符
        • 局部變數不可以加修飾符
  10. 構造器

    構造方法又叫構造器(constructor),是類的一種特殊的方法,它的主要作用是完成對新對象的初始化

    • 特點

      1. 方法名 和 類名 相同
      2. 沒有返回值
      3. 在創建對象時,系統會自動的調用該類的構造器完成對象的初始化
    • 一些細節

      1. 一個類可以定義多個不同的構造器,即構造器重載

      2. 構造器是用來完成對象初始化的,不是用於創建對象的

      3. 在創建對象時,系統自動的調用該類的構造方法

      4. 如果程式員沒有定義構造器,系統會自動給類生成一個預設無參構造器(預設構造器)

      5. 一旦定義了自己的構造器,預設的構造器就覆蓋了

        即:不能再使用預設的參構造器,除非顯式的定義一下

  11. this關鍵字

    Java虛擬機會給每個對象分配this,代表當前對象

    即:每個實例都有一個隱藏的變數this,存儲了該對象在堆記憶體中的地址

    • JVM記憶體圖(簡化)

      Cat cat = new Cat(
          new String("blue"), // 堆中String對象的地址
          "tom", // 常量池中的地址
          6 // 基本數據類型的值
      );
      
      this關鍵字JVM記憶體圖
    • 一些註意事項

      1. this 不能在類定義的外部使用,只能在類定義的方法中使用

      2. this 關鍵字可以用來訪問本類的屬性、方法、構造器

      3. this 用於區分當前類的屬性和局部變數

      4. 訪問成員方法的語法:this.方法名(參數列表)

      5. 訪問構造器語法:this(參數列表)

        即只能在構造器中訪問另外一個構造器,且必須放在第一條語句

        this() 和 super() 都需要放在構造器的第一行,所以無法同時使用

      6. 在哪個對象的方法中調用,this就代表哪個對象

        看的不是編譯類型,而是運行類型。

        後期框架中使用了大量的設計模式,導致了很難判斷this到底是指的哪個對象,最好的辦法是使用IDEA的debug

  12. 訪問修飾符

    java 提供四種訪問控制修飾符號,用於控制方法和屬性(成員變數)的訪問許可權(範圍)

    • 四種訪問修飾符

      訪問級別 訪問修飾符 同類 同包 子類 不同包
      公開 public
      受保護 protected ×
      預設 沒有修飾符 × ×
      私有 private × × ×
    • 實際開發中,當某個方法需要 A類 的實例傳入,但 A類 的 構造方法的protected

      此時,就可以使用匿名內部類的方式

      package com.test; // 註意和 MainApp類 在不同包下
      
      public class A {
          protected A(){}
      }
      
      package com.zhumei; // 註意和 A類 在不同包下
      import com.test.A;
      
      public class MainApp {
          public static void main(String[] args) {
              MainApp mainApp = new MainApp();
              mainApp.test01(new A(){}); // new A(){} 相當於創建了一個 MainApp$1 extends A 類(繼承了A類),這樣就突破了protected修飾符導致的無法使用不同包下類的構造器
          }
      
          public void test01(A a){
              System.out.println(a.getClass());
          }
      }
      
    • 使用修飾符的註意事項

      1. 修飾符可以用來修飾類中的屬性,成員方法以及類

      2. 只有 預設修飾符 和 public修飾符 才能修飾類

      3. 子類繼承了父類的方法、欄位後,調用父類的方法、欄位需要遵守父類設定的訪問修飾符的規則

        即:父類設置為private的欄位、方法,子類無法通過正常方式進行訪問使用(可以使用反射爆破的方式強行使用)

  13. 面向對象三大特征

    1. 封裝

      封裝(encapsulation)就是把抽象出的數據[屬性]和對數據的操作(方法)封裝在一起

      數據被保護在內部,程式的其它部分只有通過被授權的操作(方法),才能對數據進行操作

      • 封裝的好處
        1. 隱藏具體的實現細節
        2. 可以對封裝的數據進行校驗
      • 封裝的實現步驟
        1. 將數據私有化(private)
        2. 提供一個公共的(public)set方法,對外提供修改數據的方式,也可對外界提供的數據進行校驗
        3. 提供一個公共的(public)get方法,對外提供獲取數據的方式,也可對外界進行許可權判斷來不同的值
    2. 繼承

      繼承可以解決代碼復用,讓我們的編程更加靠近人類思維

      當多個類存在相同的屬性和方法時,可以從這些類中抽象出父類

      在父類中定義這些相同的屬性和方法,所有的子類不需要重新定義這些屬性和方法,只需要通過 extends 來聲明繼承父類即可

      • super關鍵字

        super代表父類的引用,用於訪問父類的屬性、方法、構造器(但受到父類訪問修飾符的限定)

        註意:

        1. super的訪問不限於直接父類,而是所有繼承的類,使用super若在父類中找不到會去找父類的父類,直到找到為止 或 所有的父類均沒有而報錯
        2. 若在父類中找到了,但由於修飾符關係無法直接訪問,則會直接報錯,而不會繼續向更上層的父類進行尋找
      • 一些細節:

        1. 子類會擁有父類的所有信息(欄位、方法),但是會受到父類訪問修飾符的影響,對父類私有、預設訪問修飾符修飾的欄位和方法都無法直接使用

          可以通過父類提供的其他可訪問方法來間接獲取、修改、使用欄位或方法

        2. final類無法被繼承

          • 子類必須調用父類的構造器,完成父類的初始化

            當創建子類對象時,不管使用子類的哪個構造器,預設情況 下總會去調用父類的無參構造器

            如果父類沒有提供無參構造器,則必須在子類的構造器中用 super 去指定使用父類的哪個構造器完成對父類的初始化工作,否則編譯不通過

        3. 如果希望指定去調用父類的某個構造器,則顯式的調用一下 : super(參數列表)

          • super(參數列表)在使用時必須放在構造器第一行

            super() 和 this() 都只能放在構造器第一行,因此這兩個方法不能共存在一個構造器

          • this 和 super

            public class MainApp {
                public static void main(String[] args) {
                    B b = new B(); 
                }
            }
            
            class A{
                public A(){
                    System.out.println("A -> null"); // 無參構造器
                }
                public A(String str){
                    System.out.println("A -> String"); // 有參構造器
                }
            }
            
            class B extends A{
                public B(){
                    this("str");
                    System.out.println("B -> null"); // 無參構造器
                }
                public B(String str){
                    super(str);
                    System.out.println("B -> String"); // 有參構造器
                }
            }
            

            輸出:

            A -> String
            B -> String
            B -> null

        4. java 所有類都是 Object 類的子類, Object 是所有類的基類

        5. 父類構造器的調用不限於直接父類,將一直往上追溯直到 Object 類(頂級父類)

        6. 子類最多只能繼承一個父類(指直接繼承),即 java 中是單繼承機制

        7. 不能濫用繼承,子類和父類之間必須滿足 is-a 的邏輯關係

      • 創建繼承類實例時,JVM記憶體分析(簡化)

        class GrandPa{
            String name = "大頭爺爺";
            protected int age = 70;
        }
        
        class Father extends GrandPa{
            String name = "大頭爸爸";
            private String job = "程式員";
            public String getJob(){
                return this.job;
            }
        }
        
        class Son extends Father{
            String name = "大頭兒子";
        }
        
        public class MainApp {
            public static void main(String[] args) {
                Son son = new Son(); // 研究創建一個有繼承關係的類的實例時,JVM中的記憶體分佈圖(簡化)
            }
        }
        

        創建實例的流程(簡化):

        1. 首先會載入類信息進入到記憶體中

          先從頂級父類開始載入,比如這裡會先載入 Object類,然後是 GrandPa類,接著是 Father類,最後是 Son類

        2. 在堆中開闢一個空間用於存儲son實例

          這個空間會分成幾個部分,用於存儲從不同類中繼承而來的信息

          比如這裡主要會划出3個關鍵的部分:Son類、Father類、GrandPa類,每個部分都相互獨立,即使有相同的欄位名也不會造成衝突

        3. 將堆中的地址賦值給在棧中的變數

        JVM記憶體分析-繼承類實例
      • 註意:

        若父類方法中有獲取欄位值的行為,該值只會去父類本身或父類的父類去找,並不會從子類中向上找

        public class MainApp {
            public static void main(String[] args) {
                B b = new B();
                b.study1(); // 輸出的是10
            }
        }
        
        class A {
            public int number = 10;
            
            public void study() {
                System.out.println(this.number); // this.number 會去本類(A類),以及Object類中尋找 (若A類中沒有的話)
            }
        }
        
        class B extends A {
            public int number = 120;
        }
        
    3. 多態

      方法或對象具有多種形態

      比如說你可以是大學生的同時,也可以是高中生的課外輔導班老師,具體是什麼身份要看在哪一種場景中做什麼事情

      多態是面向對象的第三大特征,多態是建立在封裝和繼承基礎之上的

      • 實現多態的三大條件

        1. 必須在繼承體系下
        2. 子類必須對父類中的方法進行重寫
        3. 通過父類的引用調用重寫的方法
      • 方法的多態

        重寫和重載就是多態的體現

        調用的方法名是同一個,但是會根據 調用方的對象不同、傳入的參數不同 導致最終調用的方法也不同

        1. 重載:在調用方法時,傳入不同的參數,就會調用不同的方法

        2. 重寫:在調用方式時,根據對象的不同,就會調用不同的方法

      • 對象的多態

        一個編譯類型能夠表達多個不同的運行類型,真正運行時根據真正的運行類型來確定運行的結果,這就體現了多態

        class A {
            public String study() {
                return "a";
            }
        }
        
        class B extends A {
            @Override
            public String study() {
                return "b";
            }
        }
        
        public class MainApp {
            public static void main(String[] args) {
                //這就是多態的體現,編譯類型A既可以表達A實例對象也可以表達B實例對象
                A a = new B(); // A是編譯類型,B是運行類型
                String str = a.study();
            }
        }
        
        1. 多態的向上轉型

          父類的引用指向了子類的對象

          即:子類的對象地址,保存在了父類類型的變數中

          通過向上轉型,子類可以調用父類中的所有成員(但要遵守訪問許可權的限制),但是不能調用子類的特有成員

          最終的運行效果,仍然是看子類的具體實現,從運行類型開始查找然後調用,與之前繼承的實例方法調用一致

          class A {
              public String study() {return "a";}
          }
          
          class B extends A {
              @Override
              public String study() {return "b";}
          }
          
          public class MainApp {
              public static void main(String[] args) {
                  // 父類的引用指向了子類的對象
                  A a = new B(); // A是編譯類型,B是運行類型
              }
          }
          
        2. 多態的向下轉型

          將父類的引用交給子類的類型

          即:原本父類變數中保存的是子類對象的地址,現在將地址交給子類變數

          只能強轉父類的引用,不能強轉父類的對象

          要求父類的引用必須指向的是當前目標類型的對象

          當向下轉型後,可以調用子類類型中所有的成員

          class A {
              public String study() {return "a";}
          }
          
          class B extends A {
              @Override
              public String study() {return "b";}
          }
          
          public class MainApp {
              public static void main(String[] args) {
                  // 父類的引用指向了子類的對象
                  A a = new B(); // A是編譯類型,B是運行類型
                  // 父類的引用交給子類的類型(向下轉型)
                  B b = (B)a; // B是編譯類型,B是運行類型
              }
          }
          
      • Java的動態綁定機制

        1. 當調用對象方法時,該方法會和該對象的記憶體地址(運行類型)綁定
        2. 當調用對象屬性時,沒有動態綁定機制,哪裡聲明哪裡使用
        public class MainApp {
            public static void main(String[] args) {
                A a = new B();
                System.out.println(a.study()); // 動態綁定機制,先去 子類(B類) 中尋找sutdy方法,沒找到再去父類中找
                System.out.println(a.number); // 直接在編譯類型A類(或A類的父類)中尋找對應的欄位,欄位(屬性)沒有動態綁定機制
            }
        }
        
        class A {
        
            public int number = 10;
        
            public String study() {
                return "a";
            }
        }
        
        class B extends A {
        
            public int number = 120;
        
            @Override
            public String study() {
                return "b";
            }
        }
        
      • 多態的常見應用

        1. 多態數組

          public class MainApp {
              public static void main(String[] args) {
                  Person[] person = new Person[3];
                  person[0] = new Student(); // 編譯類型 -> Person ; 運行類型 -> Student
                  person[1] = new Teacher(); // 編譯類型 -> Person ; 運行類型 -> Teacher
                  person[2] = new Student(); // 編譯類型 -> Person ; 運行類型 -> Student
          
                  for (int i = 0; i < person.length; i++) {
                      String name = person[i].name();
                      System.out.println(name);
                  }
              }
          }
          
          interface Person{
              String name();
          }
          
          class Student implements Person{
              @Override
              public String name() {return "學生";}
          }
          
          class Teacher implements Person{
              @Override
              public String name() {return "教師";}
          }
          
        2. 多態參數

          public class MainApp {
              public static void main(String[] args) {
                  test(new Teacher());
                  test(new Student());
              }
          
              public static void test(Person person){
                  String name = person.name(); // name方法的具體運行邏輯是根據運行類型決定的
                  System.out.println(name);
              }
          }
          
          interface Person{
              String name();
          }
          
          class Student implements Person{
              @Override
              public String name() {
                  return "學生";
              }
          }
          
          class Teacher implements Person{
              @Override
              public String name() {
                  return "教師";
              }
          }
          
  14. 類變數、類方法 (static)

    • 類變數

      類變數也叫靜態變數/靜態屬性,是該類的所有對象共用的變數


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 儘管寫過 outlet 路由的配置。 考慮到 token 判定和 路由頁 變更,我不瞭解v6是不是有更詳解的做法。 決定調一下配置,期望 在任何頁面非同步更新時,token 都可以在跳轉前 被檢測到,防止無 token 跳轉發生。 補上404頁面( 地址欄 頁面不存在時,展示404頁面 ) ![](h ...
  • [回到目錄](https://www.cnblogs.com/lori/p/3896484.html) # 說明 複合的責任鏈,類似於管道模式,只要符合條件,說會向下傳遞,不會終止 # 演算法說明 * 按最高優先順序去使用,符合就用,不符合就走下一個策略 * 具體鏈條,有點像pipeline管道模式 * ...
  • 業界有很多大促活動,像618、雙11、雙12等等。每一次大促不只是給業務帶來了新高,對於技術同樣也有很重要的意義,縱觀一些優秀的技術團隊,都是跟著業務一起成長的。在高併發大流量的背景下,如何支撐好業務運營,是一件很有挑戰性的事情,它可以從多方面檢驗我們的技術能力,對我們的系統架構和應急保障都提出了很... ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202306/3076680-20230628115834099-2000661347.png) # 1. 握手 ## 1.1. 發送方和接收方之間的信號傳遞過程 ## 1.2. 模擬數據機使用一種握手形式 ...
  • ### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本文是《JavaCV的攝像頭實戰》系列的 ...
  • 某日二師兄參加XXX科技公司的C++工程師開發崗位第30面: > 面試官:什麼是空指針? > > 二師兄:一般我們將等於`0`/`NULL`/`nullptr`的指針稱為空指針。空指針不能被解引用,但是可以對空指針取地址。 ```c++ int* p = nullptr; //空指針 *p = 42 ...
  • #String解析及其方法 1.[前言](#jump1) 2.[什麼是字元串(String)](#jump2) 3.[字元串(String)的兩種創建方式及其區別](#jump3) 4.[字元串(String)的方法及其部分原碼解析](#jump4) 5.[字元串(String)的弊端](#jump ...
  • 業務數據的存儲,少不了數據記錄的id序列,id序列(或稱序列)的生成方式有很多種,比如當前時間戳、資料庫的序列值(Oracle的序列,MySQL的自增ID等)、UUID等方式,但這些生成方式均存在一定的局限性,本文介紹一種通用高性能的分散式id序列的設計思路…… ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...