String系列01 - String 60%
1.String简介
- String类实现CharSequence接口。(同时,实现Serializable, Comparable 接口)。
- String类使用final修饰符,为final类,不可被继承,同样的,其方法自然就不可被覆盖。
- String 内部通过数组来实现。
- Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过
StringBuilder(或StringBuffer)类及其append方法实现的。 - 字符串在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%的更多相关文章
- 实战c++中的string系列--std::string与MFC中CString的转换
搞过MFC的人都知道cstring,给我们提供了非常多便利的方法. CString 是一种非常实用的数据类型. 它们非常大程度上简化了MFC中的很多操作,使得MFC在做字符串操作的时候方便了非常多.无 ...
- String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
本章主要介绍String和CharSequence的区别,以及它们的API详细使用方法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/string01. ...
- java‘小秘密’系列(一)---String、StringBuffer、StringBuilder
java'小秘密'系列(一)---String.StringBuffer.StringBuilder 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现b ...
- java基础解析系列(九)---String不可变性分析
java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...
- java基础解析系列(一)---String、StringBuffer、StringBuilder
java基础解析系列(一)---String.StringBuffer.StringBuilder 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bu ...
- 实战c++中的string系列--std:vector 和std:string相互转换(vector to stringstream)
string.vector 互转 string 转 vector vector vcBuf;string stBuf("Hello DaMao!!!");----- ...
- Java String系列
String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1) StringBuilder 详解 (String ...
- String系列
String 简介 String 是java中的字符串,它继承于CharSequence.String类所包含的API接口非常多.为了便于今后的使用,我对String的API进行了分类,并都给出的演示 ...
- [Java] 01 String 内存分析
public class StringTest{ public static void main(String[] args){ String str1 = new String("123& ...
随机推荐
- JSP九个内置对象及指令、动作标签
一.JSP九大内置对象 (一)JSP中无需创建就可以使用的9个对象 输入输出对象 1.response(HttpServletResponse):处理JSP生成的响应,然后将响应结果发送给客户端.是s ...
- Windows 环境下 NodeJs 开发 Log
安装 NodeJs, npm. 环境变量配置. 1, Grunt 安装 : npm install -g grunt-clinpm install -g grunt package.json { & ...
- BZOJ4833: [Lydsy1704月赛]最小公倍佩尔数
Problem 传送门 Sol 容易得到 \[f_n=e_{n-1}+f_{n-1},e_{n-1}=f_{n-1}+e_{n-1},f_1=e_1=1\] 那么 \[f_n=2\times \sum ...
- iView开始结束时间组件
演示地址:https://run.iviewui.com/TGIKGkIt 测试页面文件: <template> <div> <startEndTime @newEndT ...
- Python 关于bytes类方法对数字转换的误区, Json的重要性
本文起源于一次犯错, 在发觉bytes()里面可以填数字, 转出来的也是bytes类型, 就心急把里面的东西decode出来. 结果为空.搞来搞去以为是命令不熟练事实上错在逻辑. a1 = bytes ...
- 初始react native遇到的问题
转载自Andriod 使用react native时遇到的问题 打开现有项目报错: 从第一行Error可以知道是一个zip的压缩文件打不开,往下看应该是下载的Gradle文件有问题,提示也是让 ...
- 如何正确地在SOE中输出日志信息
ArcGIS for Server提供完善的日志管理机制,用于日志的记录.查询和自动清除.开发人员在开发编写SOE代码时,应该采用该机制进行日志记录的输出.如果不采用该机制,输出的日志消息会写到Arc ...
- js 捕捉回车键触发登录,并验证输入内容
js 捕捉回车键触发登录,并验证输入内容 有时候我们会遇到 web 页面中捕捉按键,触发一些效果, 比如常见的回车键触发登录,并验证输入内容,下面会介绍,截图: 一.最简单的捕捉回车键:判断按下的是不 ...
- 近期关于CI/CD策略以及git分支模型的思考
近两个月由于个人处于新环境.新项目的适应阶段,没怎么提笔写些文章.中间有好几个想法想记录下来分享,但受限于没有很好的时间段供自己总结思考(也可以总结为间歇性懒癌和剧癌发作),便啥也没有更新.借这个周末 ...
- springDataJpa学习笔记
目录 前言 springData 准备 引用 xml配置初始化JPA pojo dao层接口 使用 新增.修改:save 删除 查询所有 根据ID查询findById 命名规则查询(条件查询) 自定义 ...