c++ char 转 string_4.2String类
4.2String類
?????? 這一節(jié),我們學(xué)習(xí)第一個(gè)類:String類。String翻譯成漢語就是“字符串”,是字符的序列。我們知道,在Java中,默認(rèn)采用Unicode字符集,因此字符串就是Unicode字符的序列。例如字符串“Java大失叔”,就是由7個(gè)Unicode字符‘J’、‘a(chǎn)’、‘v’、‘a(chǎn)’、‘大’、‘失’、‘叔’組成。在JDK中,把字符串抽象成一個(gè)類String提供給我們使用。String類在java.lang包中。
4.2.1構(gòu)造String對象
上面我們說了,想看電視得先買一臺(tái)電視,電視在出廠的時(shí)候廠家會(huì)初始化它的狀態(tài)。想使用String類,得先得到一個(gè)String的對象,然后指定屬性的初始狀態(tài),然后才能使用它。得到對象的過程,叫做構(gòu)造對象。在Java中,我們用構(gòu)造器(constructor)來構(gòu)造實(shí)例,構(gòu)造器其實(shí)是一種特殊的方法,用來構(gòu)造并初始化對象。我們采用在構(gòu)造器前面加上new關(guān)鍵字來實(shí)現(xiàn),例如:
new 構(gòu)造器();
我們查看String類的API文檔(怎么查這里不再贅述),構(gòu)造方法截圖如下:
發(fā)現(xiàn)String類的構(gòu)造方法有幾個(gè)特點(diǎn):
足足有15個(gè)構(gòu)造方法
有的方法上標(biāo)有Deprecated,這個(gè)標(biāo)簽的含義是不推薦使用,將來在新版本中可能會(huì)移除
構(gòu)造方法的名字和類名相同
構(gòu)造方法的名字和類名相同,這是Java構(gòu)造器的特點(diǎn),也是規(guī)定。我們挑選其中一個(gè)構(gòu)造方法:String(char[]?value)
我們看到,這其實(shí)就是用一個(gè)char數(shù)組來構(gòu)造一個(gè)字符串,那么首先我們得有一個(gè)char數(shù)組才行,例如我們想要得到一個(gè)字符串“Java大失叔,你真棒”。那么代碼如下:
char[] a = { 'J', 'a', 'v', 'a', '大', '失', '叔', ',', '你', '真', '棒' };String s = new String(a);System.out.println(s);// 結(jié)果輸出:Java大失叔,你真棒事實(shí)上,由于String太常用了,Java給我們提供了更加簡便的構(gòu)造方法,直接用雙引號將一段字符序列包起來,就得到了一個(gè)String的實(shí)例:
String s = "Java大失叔,你真棒";OK,我們得到了一個(gè)String對象了,下面我們來使用這個(gè)對象。我們可以看到,API中有幾十個(gè)方法,我們挑選一些常用的演示一下。
4.2.2代碼點(diǎn)和代碼單元
?????? 首先,我們回憶一下關(guān)于char和Unicode的知識。Unicode定義了U+0000到U+10FFFF一共1114112個(gè)碼位(code point),英文直譯為代碼點(diǎn)。一個(gè)代碼點(diǎn)表示一個(gè)字符。char是用來存放UTF-16編碼中的一個(gè)代碼單元(code unit),即2個(gè)字節(jié)。平面0的代碼點(diǎn)用一個(gè)代碼單元即一個(gè)char就可以表示,其余的代碼點(diǎn)需要用2個(gè)代碼單元即2個(gè)char才能表示。
?????? 我們知道Stirng是Unicode字符的序列,但是底層的實(shí)現(xiàn)實(shí)際上是用char構(gòu)成的。String類提供了一些關(guān)于代碼點(diǎn)和代碼單元相關(guān)的方法,請看下面摘抄的幾個(gè)方法:
修飾和類型 | 方法 | 描述 |
int | length() | 返回字符串的長度 |
int | codePointCount(int?beginIndex, int?endIndex) | 返回beginIndex和endIndex-1之間的代碼點(diǎn)的數(shù)量。 |
char | charAt(int?index) | 返回index索引處的char |
int | codePointAt(int?index) | 返回index索引處的代碼點(diǎn) |
我們想獲得字符的數(shù)量(即代碼點(diǎn)的數(shù)量),需要用codePointCount方法,而length方法返回的是char的數(shù)量(即代碼單元的數(shù)量)。調(diào)用對象的方法很簡單,用如下形式:
對象.方法();
代碼示例如下:
String s = "大失叔喜歡打麻將??????";// System.out.println("字符串s的代碼單元數(shù)量為:" + s.length());System.out.println("字符串s的代碼點(diǎn)數(shù)量為"?+?s.codePointCount(0,?s.length()));輸出結(jié)果:
字符串s的代碼單元數(shù)量為:20 字符串s的代碼點(diǎn)數(shù)量為:14我們可以看到,對于??????,這6個(gè)字符,每個(gè)字符占用2個(gè)代碼單元,所以length方法的結(jié)果是20,而codePointCount方法的結(jié)果是14。
?????? 我們再看看后面2個(gè)方法,這應(yīng)該就相對簡單了,一個(gè)是返回index處的代碼單元,一個(gè)是返回index處的代碼點(diǎn)。我們直接看代碼:
String s = "大失叔喜歡打麻將??????";// int c = s.charAt(8);// 把char賦值給一個(gè)int,對應(yīng)這個(gè)代碼單元對應(yīng)的十進(jìn)制,結(jié)果是55356,十六進(jìn)制為0xD83Cint?d?=?s.codePointAt(8);//?結(jié)果是126976,十六進(jìn)制為0x1F0004.2.3對象與變量
?????? 上面我們看到,創(chuàng)建出來一個(gè)String對象,一般我們會(huì)賦值給一個(gè)變量。那么對象和變量之間有什么關(guān)系和區(qū)別呢?我們先看幾行代碼:
String a;String b;a = "大失叔喜歡打麻將";b?=?a;這幾行代碼,會(huì)涉及到下面一些行為:
第1、2行,我們定義了2個(gè)String類型的變量a和b。這時(shí)候Java會(huì)在內(nèi)存中分別分配一塊空間給a和b,但是這時(shí)候這2塊內(nèi)存空間中沒有存放任何值。
第3行,我們把一個(gè)字符串賦值給變量a。Java會(huì)在內(nèi)存中分配一塊空間,存放這個(gè)字符串,然后把這塊空間的地址存放到變量a的內(nèi)存空間中。
第4行,把變量a賦值給b,相當(dāng)于把變量a內(nèi)存空間中的地址存放到變量b的內(nèi)存空間中,這時(shí)候a和b同時(shí)指向字符串“大失叔喜歡打麻將”對應(yīng)的內(nèi)存空間。
我們用一張圖示意如下:
我們需要牢牢記住一點(diǎn):在Java中,任何對象的值都是存放在堆內(nèi)存中的,而對象類型的變量對應(yīng)的內(nèi)存中保存的是對象的內(nèi)存地址,我們稱之為對象引用。因此new操作符返回的結(jié)果其實(shí)是一個(gè)引用。
?????? 我們可以顯式的把一個(gè)對象變量設(shè)置為null,這時(shí)候該變量的內(nèi)存存放的將是空值,表明它不引用任何對象。如果我們對一個(gè)值為null的變量進(jìn)行方法調(diào)用,程序在運(yùn)行時(shí)則會(huì)拋出異常。
4.2.4字符串拼接
?????? 在Java中,字符串的拼接有一種很簡單的方法,就是用加號(+)連接兩個(gè)字符串,結(jié)果會(huì)構(gòu)造出一個(gè)新的字符串對象。我們看代碼:
String a = "Java大失叔";String b = "喜歡打麻將";String c = a + b;System.out.println(c);// 結(jié)果將輸出:"Java大失叔喜歡打麻將"在這段代碼中,堆內(nèi)存中將會(huì)分配3塊空間,分別對應(yīng)字符串"Java大失叔"、"喜歡打麻將"、" Java大失叔喜歡打麻將"。我們用一張圖來演示這個(gè)過程:
我們還可以將一個(gè)字符串和一個(gè)非字符串用+連接起來,這時(shí)候非字符串對象會(huì)被轉(zhuǎn)換為字符串(具體如何轉(zhuǎn)換,后續(xù)會(huì)詳細(xì)探討)。例如:
String?a?=?"Java大失叔卡里只有";int?b?=?200;String?c?=?"元錢了";System.out.println(a + b + c);// 結(jié)果將輸出:Java大失叔卡里只有200元錢了String類的API中還提供了一個(gè)方法concat用來拼接字符串,方法摘抄如下:
修飾和類型 | 方法 | 描述 |
String | concat(String str) | 將str拼接在本字符串后面 |
使用起來也很簡單,代碼如下:
String a = "Java大失叔";String b = "喜歡打麻將";String c = a.concat(b);System.out.println(c);// 結(jié)果將輸出:Java大失叔喜歡打麻將????????有的時(shí)候,需要將很多個(gè)字符串拼接成一個(gè)大字符串,這時(shí),如果用+的方式,不是很合適了。因?yàn)橛?#43;的方式,每次都會(huì)構(gòu)建一個(gè)新的對象,比較耗時(shí),還占內(nèi)存,效率比較低。好在Java提供了另外一種方式,就是采用StringBuilder類和StringBuffer類。一般情況下我們都會(huì)采用StringBuilder類,因?yàn)樗男事愿摺6鳶tringbuffer類是線程安全的,關(guān)于線程會(huì)在后面專門討論。這2個(gè)類的API幾乎完全一樣。用StringBuilder非常簡單,代碼演示如下:
StringBuilder sb = new StringBuilder();// 首先構(gòu)建StringBuilder對象sb.append("Java");// 然后用append方法添加小字符串sb.append("大失叔");sb.append("太帥了");String s = sb.toString();// 最后調(diào)用toString()方法,返回一個(gè)字符串對象System.out.println(s);// 結(jié)果將輸出:Java大失叔太帥了其實(shí)append方法返回的依然是StringBuilder對象,因此還可以采用一種更為簡潔的方式:String s = new StringBuilder().append("Java").append("大失叔").append("太帥了").toString();System.out.println(s);// 結(jié)果將輸出:Java大失叔太帥了關(guān)于加號、concat、StringBuilder這三者的比較,筆者給出如下結(jié)論:對于拼接少量的字符串,用哪種方式都差不多,加號書寫起來更加方便。筆者幾乎沒用過concat方法。
加號和StringBuilder都可以拼接非字符串類型(可以查看API,有很多個(gè)append方法)。
對于需要拼接多個(gè)字符串的時(shí)候,強(qiáng)烈建議使用StringBuilder。(筆者在早年編寫一個(gè)網(wǎng)絡(luò)程序的時(shí)候,吃過虧)
4.2.5字符串截取和比較
?????? 關(guān)于字符串還會(huì)經(jīng)常使用比較和截取的方法,先列出方法如下:
修飾和類型 | 方法 | 描述 |
boolean | startsWith(String?prefix) | 檢查字符串是否以指定的前綴prefix開始 |
boolean | endsWith(String?suffix) | 檢查字符串是否以指定的后綴suffix結(jié)尾 |
String | trim() | 刪除字符串前后的空白,并返回一個(gè)新字符串 |
boolean | equals(Object?anObject) | 檢測2個(gè)字符串是否相等 |
boolean | equalsIgnoreCase(String?anotherString) | 檢測2個(gè)字符串在忽略大小寫的情況下是否相等 |
String | substring(int?beginIndex) | 截取從beginIndex到末尾的字符串并返回 |
String | substring(int?beginIndex, int?endIndex) | 截取從beginIndex到endIndex的字符串并返回,不包括endIndex |
我們經(jīng)常會(huì)比較一個(gè)字符串是否以某個(gè)字符串開頭或結(jié)尾,代碼如下:
String a = "Java大失叔";boolean b1 = a.startsWith("Java");// 結(jié)果為trueboolean b2 = a.startsWith("java");// 結(jié)果為falseboolean b3 = a.endsWith("叔");// 結(jié)果為true????有時(shí)候,經(jīng)過網(wǎng)絡(luò)傳輸后的字符串經(jīng)常前后會(huì)帶一些空白,眼睛又看不見,很不利于比較,會(huì)用trim方法去掉前后的空白:
String a = " Java大失叔 ";String b = a.trim();System.out.println(b);// 結(jié)果將輸出:Java大失叔需要注意,這里的空白指的是Unicode編碼小于或等于”\u0020”的字符。
?????? 對于字符串的截取,用subString方法將非常方便:
String a = "Java大失叔 ";String b = a.substring(4);// 結(jié)果是:大失叔String c = a.substring(2, 6);// 結(jié)果是:va大失這里要注意的是,返回的結(jié)果字符串是包括beginIndex位置的代碼單元,但是不包括endIndex位置的代碼單元。
????比較2個(gè)字符串是否相等,用equals方法,如果相等返回ture,否則返回false。如果想不區(qū)分大小寫比較是否相等,則可以使用equalsIgnoreCase方法。表達(dá)式為:
a.equals(b)其中,a和b即可以是變量,也可以是字符串常量。
String a = "Java大失叔";String b = "java大失叔";System.out.println(a.equals(b));// 結(jié)果為falseSystem.out.println(a.equalsIgnoreCase(b));// 結(jié)果為trueSystem.out.println("JAVA大失叔".equalsIgnoreCase(b));// 結(jié)果為true這里需要特別注意,千萬不能用==運(yùn)算符來比較2個(gè)字符串是否相等。因?yàn)?#61;=運(yùn)算符比較的是2個(gè)字符串是否存放在同一個(gè)內(nèi)存位置上。但是事實(shí)上,對于2個(gè)字符內(nèi)容完全一樣的字符串,是很有可能存放在不同的內(nèi)存空間的,因此用==比較結(jié)果將為false。這個(gè)問題Java新手經(jīng)常會(huì)犯。
????最后我們很容易發(fā)現(xiàn),String的API中沒有提供修改字符串內(nèi)容的方法。這其實(shí)是因?yàn)镾tring類被定義為final的(關(guān)于final后面也會(huì)介紹),我們看一下String的源代碼(在Eclipse中,可以很輕松的查看源代碼,鼠標(biāo)移動(dòng)的任意一個(gè)String字符上,按住Ctrl鍵后,點(diǎn)擊鼠標(biāo)左鍵):
public final class String implements java.io.Serializable, Comparable<String>, CharSequence用final修飾一個(gè)類后,這個(gè)類的對象將不能被修改。
??? String類提供了50個(gè)多個(gè)方法,這些方法都很有用,但是我們不可能記住所有的方法名和參數(shù)要求,這里還有一個(gè)Eclipse的小技巧,當(dāng)我們敲完變量名加“點(diǎn)”后,Eclipse會(huì)自動(dòng)彈出提示,或者還可以用Ctrl+/自動(dòng)補(bǔ)全,如下圖:
總結(jié)
以上是生活随笔為你收集整理的c++ char 转 string_4.2String类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: supervisor nginx_Sup
- 下一篇: c++ cstring 转换 char_