1.String简介

  1. String类实现CharSequence接口。(同时,实现Serializable, Comparable 接口)。
  2. String类使用final修饰符,为final类,不可被继承,同样的,其方法自然就不可被覆盖。
  3. String 内部通过数组来实现。
  4. Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其append 方法实现的。
  5. 字符串在java内存中总是按unicode编码存储的。

2.CharSequence接口定义

public interface CharSequence {
int length();
/*@throws IndexOutOfBoundsException*/
char charAt(int index);
/* @throws IndexOutOfBoundsException */
CharSequence subSequence(int start, int end);
public String toString();
}

已知的实现类有 CharBuffer, Segment, String, StringBuffer, StringBuilder。

3.String类详解

  • 变量
// 类静态常量
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
private static final int HASHING_SEED; // 在statick块中初始化了
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
private static final long serialVersionUID = -6849794470754667710L;

// 成员变量
private final char value[];// 用于存储字符串
private int hash;// 存储String的hash值
private transient int hash32 = 0;// Cached value of the alternative hashing algorithm result
  • 构造函数
public    String()
public String(String original)
public String(char[] value)
public String(char[] value, int offset, int count)
public String(byte[] bytes)
public String(byte[] bytes, int offset, int length)
public String(byte[] ascii, int hibyte)
public String(byte[] ascii, int hibyte, int offset, int count)
public String(byte[] bytes, String charsetName)
public String(byte[] bytes, int offset, int length, String charsetName)
public String(byte[] bytes, Charset charset)
public String(byte[] bytes, int offset, int length, Charset charset)
public String(int[] codePoints, int offset, int count)
public String(StringBuffer buffer)
public String(StringBuilder builder)

// 部分构造函数代码 // 思考:为什么一般不用这个构造方法? 因为String是不可变类,使用此构造方法没什么用。
public String(){
this.value = new char[0];
} public String(String original) {
this.value = original.value;
this.hash = original.hash;
} public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
} // 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String
// 扩展学习1:平台默认字符集 指的是操作系统默认的字符集,同时可通过 -Dfile.encoding="GBK"来设置jvm字符集
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
} // 通过使用指定的charset解码指定的 byte 子数组,构造一个新的 String
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
} public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
} public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

演示程序

字符编码

        //切记一点:字符串在java内存中总是按unicode编码存储的!!

        System.out.println("平台默认字符集 = " + Charset.defaultCharset()); // 在eclipse中 可将 text-file-encoding 改为其它试试看
String str1 = "中文"; // 中文 unicode编码
byte[] b1 = str1.getBytes("unicode");
System.out.print("unicode编码 = ");
for(byte b : b1){
System.out.print(Integer.toHexString(b & 0xFF) + " ");
}
System.out.println();
String str2 = new String(b1, "unicode");
System.out.println(str2); // 中文utf-8编码 utf8中部分汉字占3个字节,有21000多个(大部分是原GBK中的字符); 部分汉字占4个字节 中日韩超大字符集里面的汉字,有 5 万多个
b1 = str1.getBytes();
System.out.print(Charset.defaultCharset() + "编码 = ");
for(byte b : b1){
System.out.print(Integer.toHexString(b & 0xFF) + " ");
}
System.out.println(); // 中文gbk编码
b1 = str1.getBytes("gbk");
System.out.print("gbk编码 = ");
for(byte b : b1){
System.out.print(Integer.toHexString(b & 0xFF) + " ");
}
System.out.println(); // 中文iso8859-1编码
b1 = str1.getBytes("iso8859-1");
System.out.print("iso8859-1编码 = ");
for(byte b : b1){
System.out.print(Integer.toHexString(b & 0xFF) + " ");
}
System.out.println(); // 中文 在ios8859-1编码下打印出来为乱码
String str5 = new String(b1, "iso8859-1");
System.out.println(str5); // unicode编码
String str13 = new String(new int[] {0x4e2d, 0x6587}, 0, 2);
System.out.println(str13); // utf-8编码 0xE4B8AD 0xE69687
String str09 = new String(new byte[]{
(byte)0xE4, (byte)0xB8, (byte)0xAD,
(byte)0xE6, (byte)0x96, (byte)0x87},0, 6, "utf-8");
System.out.println(str09); // GBK编码 0xD6D0 0xCEC4
String str12 = new String(new byte[]{
(byte)0xD6,(byte)0xD0,
(byte)0xce,(byte)0xc4}, 0, 4,"GBK");
System.out.println(str12);

jvm 对 String的优化

        // “中文”的unicode编码  =  0x4e2d 0x6587
char[] v1 = {0x4e2d, 0x6587};
String str14 = new String(v1); // new,存放在堆中 String str15 = "中文"; // 存放在常量池中(常量池自jdk7后移入堆中)
System.out.println(str15 == str14); String str16 = "中文"; // 此处常量池中已有“中文”,不再创建新的对象,
System.out.println(str15 == str16); String str17 = "中" + "文"; // 编译时优化, 在编译时,即将其转为“中文”
System.out.println(str15 == str17); String w = "文";
String str18 = "中" + w; // 有变量w, 编译期间不能确定其值,无法合并, 运行时会new一个新的对象
System.out.println(str15 == str18); String str19 = new String("中文");
System.out.println(str15 == str19); String str20 = str14.intern(); // intern(), 在常量池通过equals方法寻找“中文”,此时,常量池中已有str15,则将常量池中“中文”对象的引用
System.out.println(str20 == str15); // true System.out.println(Integer.toHexString(str15.hashCode()));
System.out.println(Integer.toHexString(str20.hashCode()));

部分函数实现

public char    charAt(int index)
public int compareTo(String anotherString)
public boolean endsWith(String suffix)
public boolean equals(Object anObject)
public String intern()
public String replace(char oldChar, char newChar)
public boolean startsWith(String prefix, int toffset)
public boolean startsWith(String prefix)
public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)
public String trim()
/**
*1.若长度不相等,返回长度差值;
2.若长度相等,则依次比较相同位置char, 若某个char不相等,则返回char差值;
由此可见,若结果大于0,则当前字符串大; 若结果等于0,则两字符串相等; 若结果小于0,则参数中的字符串大。
*/
  public int compareTo(MyString anString){
int len1 = value.length;
int len2 = anString.value.length; int limin = Math.min(len1, len2); char v1[] = value;
char v2[] = anString.value; int k = 0;
while(k < limin){
char c1 = v1[k];
char c2 = v2[k];
if(c1 != c2)
return c1 - c2;
k++;
}
return len1 - len2;
}
 /*
* 1. == 号比较,(两个变量在栈中存放的内容),若相等, true
2. 若参数不属于String类型,false
3. 若长度不等,false
4. 若长度相等,则从后向前,依次比较char,若出现不等, false
*/
1 public boolean equals(Object anObject){
if(this == anObject){
return true;
}
if(anObject instanceof String){
String anotherString = (String) anObject;
int n = value.length;
if(n == anotherString.length()){
char v1[] = this.value;
char v2[] = anotherString.value;
int i = 0;
while(n-- != 0){
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
    /*
* replace方法并没有一上来就创建新数组,循环复制;
* 而是
* 第一步 找出oldChar第一次出现的位置【index】
* 第二步 创建新数组,将【index】之前的char复制到新数组
* 第三步 再从index的位置开始循环比较, 将剩余的char添加到新数组
* 代码妙处:只有原串中出现了 oldChar, 这时才创建新数组,赋值;既没有重复比较操作,又避免了从头到尾的零差异复制操作。
*/
public MyString replace(char oldChar, char newChar){
if(oldChar != newChar){
int len = value.length;
char val[] = value; int i = -1;
while(i++ < len){
if(val[i] == oldChar){
break;
}
}
if(i <= len){
char buf[] = new char[len];
for(int j = 0; j<i; j++){
buf[j] = val[i];
}
while (i < len){
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new MyString(buf,true);
}
}
return this;
}
   public String trim(){
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */扩展学习2: getfield指令 及 String此处的优化在哪里 while((st < len ) && (val[st] <= ' ')){
st ++;
}
while((st < len) && (val[len - 1] <= ' ')){
len --;
}
return ((len < value.length) || (st>0)) ? subString(st, len) : this;
}
     public boolean startsWith(MyString prefix){
return startsWith(prefix,0);
} public boolean endsWith(MyString suffix) {
return startsWith(suffix, value.length - suffix.value.length);
} public boolean startsWith(MyString prefix, int toffset){
char[] ta = value;
int to = toffset;
char[] pa = prefix.value;
int po = 0;
int pc = prefix.value.length;
// Note: toffset might be near -1>>>1.
/*
* 扩展学习3:逻辑右移或叫无符号右移运算符“>>>“只对位进行操作,没有算术含义,它用0填充左侧的空
* -1 >>> 1 = int型最大值 2147483647
*-1 二进制 11111111 11111111 11111111 11111111
*-1 >>> 1 二进制 1111111 11111111 11111111 11111111
*/
if((toffset < 0) || (toffset > value.length - pc)){
return false;
}
while(--pc >= 0){
if(ta[to++] != pa[po++]){
return false;
}
}
return true;
}
     @Override
public CharSequence subSequence(int start, int end) {
return this.subString(start, end);
} public MyString substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new MyString(value, beginIndex, subLen);
} public MyString subString(int beginIndex, int endIndex){
if(beginIndex < 0){
throw new StringIndexOutOfBoundsException(beginIndex);
}
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 MyString(value, beginIndex, subLen);
}
  public native String intern();
//intern方法是Native调用,它的作用是在常量池里通过equals方法寻找等值的对象,如果没有找到则在常量池中开辟一片空间存放字符串并返回该对应String的引用,
否则直接返回常量池中已存在String对象的引用
 
 
 

String系列01 - String 60%的更多相关文章

  1. 实战c++中的string系列--std::string与MFC中CString的转换

    搞过MFC的人都知道cstring,给我们提供了非常多便利的方法. CString 是一种非常实用的数据类型. 它们非常大程度上简化了MFC中的很多操作,使得MFC在做字符串操作的时候方便了非常多.无 ...

  2. String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)

    本章主要介绍String和CharSequence的区别,以及它们的API详细使用方法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/string01. ...

  3. java‘小秘密’系列(一)---String、StringBuffer、StringBuilder

    java'小秘密'系列(一)---String.StringBuffer.StringBuilder 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现b ...

  4. java基础解析系列(九)---String不可变性分析

    java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...

  5. java基础解析系列(一)---String、StringBuffer、StringBuilder

    java基础解析系列(一)---String.StringBuffer.StringBuilder 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bu ...

  6. 实战c++中的string系列--std:vector 和std:string相互转换(vector to stringstream)

    string.vector 互转 string 转 vector vector  vcBuf;string        stBuf("Hello DaMao!!!");----- ...

  7. Java String系列

    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1) StringBuilder 详解 (String ...

  8. String系列

    String 简介 String 是java中的字符串,它继承于CharSequence.String类所包含的API接口非常多.为了便于今后的使用,我对String的API进行了分类,并都给出的演示 ...

  9. [Java] 01 String 内存分析

    public class StringTest{ public static void main(String[] args){ String str1 = new String("123& ...

随机推荐

  1. 工厂模式的认识(GOF23)

    ---恢复内容开始--- 对于所有的设计模式来说,其本质是哪里变化封装哪里.寻找变化点,没有万能的模式,只有适合情况的应用 工厂模式从简单工厂开始演化 1.简单工厂的主要作用在于从源头开始封装实例化, ...

  2. error: unpack failed: error Missing tree

    最近新建一个仓库,push时遇到如下问题,试了好多方法,最后在stackoverflow上找到解决办法了,可是在开始时就试过这方法,但不成.至于为嘛出现的这种错误,还是不明白原因. git.exe p ...

  3. Maven学习总结(三):修改从Maven中心仓库下载到本地的jar包的默认存储位置

    一:修改从Maven中心仓库下载到本地的jar包的默认存储位置 从Maven中心仓库下载到本地的jar包的默认存放在”${user.home}/.m2/repository”中,${user.home ...

  4. PyCharm导入包的问题

    在此之前,我们说一下虚拟环境这个概念: 在django项目中,直接就安装各种package,可能会造成系统混乱,因为package之间会有依赖的.比方说,你现在直接装django,他会依赖其他的包(开 ...

  5. js 中concat()和slice()方法介绍

    1.concat() concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. <script type="text/javascr ...

  6. Directly output the object name

    package basic.java; public class Case { public static void main(String[] args) { Student s = new Stu ...

  7. 交叉编译 Cross-compiling for Linux

    @(134 - Linux) Part 1 交叉编译简介 1.1 What is cross-compiling? 对于没有做过嵌入式编程的人,可能不太理解交叉编译的概念,那么什么是交叉编译?它有什么 ...

  8. 【Oracle】DBMS_STATS.GATHER_TABLE_STATS详解

    由于Oracle的优化器是CBO,所以对象的统计数据对执行计划的生成至关重要!    作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息(默认参数下是对表进行直 ...

  9. sql 2000 无法连接远程数据库 sqlserver不存在或访问被拒绝、不能打开到主机的连接,在端口1433:连接失败等 解决方案

    问题: sql 2000 无法连接远程数据库 sqlserver不存在或访问被拒绝 telnet 127.0.0.1 1433     提示:不能打开到主机的连接,在端口1433:连接失败 解决方案: ...

  10. 打通版微社区(3):在Web服务器上部署memcache For DZ3.2

    写在前面:首先这个数据库加速程序的原理,是将数据库内容缓存到Web服务器的内存上,也就是内存换速度.我本次微社区的应用其实应该用不了这个,只是看到好多DZ论坛部署的都安装了这个,我就练手一下以便不时之 ...