字串操作 及 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類的常用方法。
-
- 判斷字串是否相等,第三種情況。
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類的常用方法
下面實踐常用的幾個方法:
- 字串空判斷: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)返回指定索引處的字串: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)拷貝整個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
- 比較字串: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;
}
- 為每個唯一字元序列生成一個且僅生成一個String引用:String.intern()
- 原始碼:
public native String intern();//intern():如果在常量池當中沒有字串的引用,那麼就會生成一個在常量池當中的引用;相反:則不生成
- 例:
public class Testdome1024 {
public static void main1(String[] args) {
String str1 = new String("ab")+