1. 程式人生 > >字串操作 及 String類

字串操作 及 String類

n階魔方陣解法優化

思想:(1-9) 將1放在魔方陣第一行的中間位置,從第二個數字開始放在1第一個數字的上一行下一列,若已經存在資料,則放在上一個數字的下一行,列數不變。

package mypratice;
import java.util.Arrays;
/**
 * @Package: mypratice
 * @Author:kkz
 * @Description:
 * @Date:Created in 2018/10/24 0:34
 */
public class Mofang {
    public static void magicScqure(int[][] array,
int n){ array[0][n/2] = 1; //將數字 1 放入魔方陣 int prevRow = 0; int prevCol = n/2; for(int i = 2;i <= n*n;i++) { // 注意:判斷上一行下一列是否有資料所用的演算法,% 求餘 if(array[(prevRow-1+n)%n][(prevCol+1)%n] != 0) { //上一行的下一列有資料 prevRow = (prevRow+1)%
n;//放在當前數的下一行 } else { prevRow = (prevRow-1+n)%n; //有資料,則放在當前數的 上一行,下一列 prevCol = (prevCol+1)%n; } array[prevRow][prevCol] = i; } } public static void main(String[] args) { int row = 3; int[][] array = new
int[row][row]; magicScqure(array,row); System.out.println(Arrays.deepToString(array)); } }
[[8, 1, 6], [3, 5, 7], [4, 9, 2]]

字串操作

 java字串是Unicode字元的有序集合,Unicode字元是使用UTF-16進行編碼的。在Java語言中,字串作為物件,這與在C語言作為字元陣列來處理不同。
 java語言使用java.lang包中的String、StringBuilder 和 StringBuffer來構造自定義字串,執行許多基礎字串操作,如比較字串、搜尋字串、提取子字串等。
 注:String、StringBuilder 和 StringBuffer均為密封類,不能派生子類。(密封類:類和方法 被關鍵字 final 修飾之後,類不能被繼承,方法不能被修改。密封類的優點:密封類可以防止有意的派生。)

String類

  String 物件是不可變的(只讀),因為一旦建立了該物件,就不能修改物件的值。有些字串操作看來似乎修改了String物件,實際上返回了一個包含修改內容的新String物件。如果需要修改字串物件的實際內容,可以使用StringBuilder 或 StringBuffer 類。String類原始碼:

 //final 所修飾的類不能改變其值, String類是不可變類
 public final class String
     implements java.io.Serializable, Comparable<String>, CharSequence {
      /** The value is used for character storage.
       private final char value[];  //value[] 陣列用於儲存字串
  • 例:1. 宣告和初始化字串,並判斷輸出結果是否相等:
public class Testdome1024 {
    public static void main(String[] args) {
        String str1 = "hello";    //str1  變數(變數在執行時才可知其值)   hello 字串常量(常量在編譯時統一處理)
        String str2 = new String("hello");  //new 例項化 產生物件
        String str3 = "he" +"llo";  //常量
        String str4 = new String("he") + new String("llo");
        System.out.println(str1 == str2);
        System.out.println(str3 == str1);
        System.out.println(str3 == str2);
        System.out.println(str4 == str3);
    }
}
false
true
false
false
  • 記憶體分配圖如下:
    在這裡插入圖片描述

談談棧與堆的儲存:

1.堆(物件):
 引用型別的變數 ,其記憶體分配在上或者常量池(字串常量,基本資料型別常量),需要通過new等方式建立。
 堆記憶體的主要作用是存放執行時new建立的物件。(主要用於存放物件,存取速度慢,可以執行時動態分配記憶體,生存期不需要提前確定)。
2.棧(基本資料型別變數,物件的引用變數):
 基本資料型別的變數(int、short、long、byte、float、double、boolean、char等)以及物件的引用變數,其記憶體分配在棧上,變量出了作用域就會自動釋放。
 棧記憶體的主要作用是存放基本資料型別和引用變數。棧的記憶體管理是通過棧的"後進先出"模式來實現的。(主要用來執行程式,存取速度快,大小和生存期必須確定,缺乏靈活性)

  • 2.運用“+”連線字串,判斷是否相等:
public class Stringa {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "world";
        String str3 = "helloworld";
        System.out.println(str1 + str2);
        System.out.println(str3);
        
        System.out.println(str3 == (str1 + str2));
        System.out.println(str3 == ("hello"+"world"));
    }
}
helloworld
helloworld
false
true
  • 記憶體分配圖如下:
    在這裡插入圖片描述
     運用jdk自帶的工具javap來反編譯以上程式碼,命令為:
    javac src\java檔案儲存位置   javap -c src.java檔案儲存位置
    顯示位元組碼如下:
G:\javacode\HelloWorld>javac src\mypratice\Stringa.java

G:\javacode\HelloWorld>javap -c src.mypratice.Stringa
警告: 二進位制檔案src.mypratice.Stringa包含mypratice.Stringa
Compiled from "Stringa.java"
public class mypratice.Stringa {
  public mypratice.Stringa();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String hello
       2: astore_1
       3: ldc           #3                  // String world
       5: astore_2
       6: ldc           #4                  // String helloworld
       8: astore_3
       9: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: new           #6                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      19: aload_1
      20: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: aload_2
      24: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      33: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: aload_3
      37: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      40: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      43: aload_3
      44: new           #6                  // class java/lang/StringBuilder
      47: dup
      48: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      51: aload_1
      52: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      55: aload_2
      56: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      59: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      62: if_acmpne     69
      65: iconst_1
      66: goto          70
      69: iconst_0
      70: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V
      73: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      76: aload_3
      77: ldc           #4                  // String helloworld
      79: if_acmpne     86
      82: iconst_1
      83: goto          87
      86: iconst_0
      87: invokevirtual #11                 // Method java/io/PrintStream.println:(Z)V
      90: return
}

 從生成的位元組碼檔案中可以看出,"+"操作符在程式碼中的實現過程實際上是編譯器自動引用了java.lang.StringBuilder()類,為每一個字串呼叫了StringBuilder的append()方法,接下來會具體寫到String類的常用方法。

    1. 判斷字串是否相等,第三種情況。
public class Stringa {
    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = "hello";
        System.out.println(str1 == str2);//false
        
        String str3 = "he"+new String("llo");
        System.out.println(str1 == str3);//false
        System.out.println(str2 == str3);//false

        String str4 = "he"+"llo";
        System.out.println(str4 == str2);//true

        char[] array = {'h','e','l','l','o'};
        String str5 = new String(array);
        System.out.println("=============");
        System.out.println(str1 == str5);//false
        System.out.println(str2 == str5);//false
        System.out.println(str3 == str5);//false
        System.out.println(str4 == str5);//false
    }
 }
  • 記憶體分配圖如下:
    在這裡插入圖片描述

String類的常用方法

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
下面實踐常用的幾個方法:

  1. 字串空判斷:String.isEmpty()
  • 原始碼:
public boolean isEmpty() {
        return value.length == 0;
    }
  • 例:
public class Stringa {
    public static void main(String[] args) {
        String str1 ="world";
        str1.length();
        str1.isEmpty();
        System.out.println(str1.length()); //返回字串長度
        System.out.println(str1.isEmpty());//判斷字串是否為空,如果字串的length()為0,則返回true
    }
5
false
  1. 獲取字元、擷取字串:
    (1)返回指定索引處的字串:String.ChatAt()
  • 原始碼:
 public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

(2)擷取子字串:(從begindex到結束):String.substring()

  • 原始碼:
public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }//開始索引小於0,丟擲異常
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

(3)擷取部分子字串(從begindex到endindex):String.substring()

  • 原始碼:
 public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }//開始索引小於0,丟擲異常
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }//結束索引大於字串長度,丟擲異常
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
  • 例:
public class Stringa {
    public static void main(String[] args) {
        String str1 ="world";
     
        System.out.println(str1.charAt(4));
        System.out.println(str1.substring(0));//擷取整個字串
        System.out.println(str1.substring(0,3));//擷取部分字串
        }
}
d
world
wor
  1. (1)拷貝整個char陣列給目標陣列:String.getChars()
  • 原始碼:
  //拷貝整個陣列給dst 陣列
    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { //起始索引,結束索引,目標陣列,目標陣列起始索引
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); //源陣列,起始索引,目的陣列,目的陣列起始索引,源陣列拷貝長度
    }  //底層呼叫的是System。arraycopy()方法

(2)複製byte到目標陣列:String.getBytes()

@Deprecated        註解
    //已經過時的 方法          呼叫時會有橫線劃掉
    public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        Objects.requireNonNull(dst);

        int j = dstBegin;
        int n = srcEnd;
        int i = srcBegin;
        char[] val = value;   /* avoid getfield opcode */

        while (i < n) {
            dst[j++] = (byte)val[i++];
        }
    }
  • 例:
public class Stringa {
    public static void main(String[] args) {
        String str1 ="myprogrammingworld";
      
        char[] a2 = new char[15];
        str1.getChars(0,12,a2,0);
        System.out.println(a2); //拷貝char到目標陣列
        byte[] a3 = new byte[10];
        str1.getBytes(0,10,a3,0); //已經過時的方法,使用時會有劃線提示
        System.out.println(a3);//拷貝byte到目標陣列
        }
 }
myprogrammin   
[B@154617c
  1. 比較字串:String.equals()
          String.compareTo()
    注:equals、compareTo方法用於比較字串內容,“==”運算子用於比較物件。
  • 原始碼:
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
		//anObject是否為String的例項
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
  1. 為每個唯一字元序列生成一個且僅生成一個String引用:String.intern()
  • 原始碼:
public native String intern();//intern():如果在常量池當中沒有字串的引用,那麼就會生成一個在常量池當中的引用;相反:則不生成
  • 例:
public class Testdome1024 {
    public static void main1(String[] args) {
        String str1 = new String(