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& ...
随机推荐
- Tomcat的学习和使用(一)
一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件是配置的核心文件. 如果想修改Tomcat服务器的启动端口,则可以在server.xml ...
- 跨域方法:JSONP、iframe
同源策略:浏览器出于安全考虑,会限制文档或脚本中发起的跨域请求(但src请求不受此限)资源的加载.实际上通过抓包软件可以发现请求和响应都会成功,但是响应数据并不会被浏览器加载.不同源的客户端脚本(ja ...
- GAN背后的数学原理
模拟上帝之手的对抗博弈——GAN背后的数学原理 简介 深度学习的潜在优势就在于可以利用大规模具有层级结构的模型来表示相关数据所服从的概率密度.从深度学习的浪潮掀起至今,深度学习的最大成功在于判别式 ...
- 2 pygraphviz在windows10 64位下的安装问题(反斜杠的血案)
可以负责任的说,这篇文档是windows10安装pygraphviz中,在中文技术网站中最新的文档,没有之一.是自己完全结合各种问题,包括调试等,总结出来的. 问题来源:主要是可视化RvNN网络的树结 ...
- Gitlab installtation
环境:Centos7 安装配置(安装开启http和sshd): 1 yum -y install curl openssh-server postfix 2 systemctl enable sshd ...
- Scratch www 系统搭建
原文地址:https://blog.csdn.net/litianquan/article/details/82735809 Scratch www要基于Nodejs的环境才可以运行,我尝试了在Win ...
- HBuilder设置APP状态栏
一. 前言 状态栏就是手机屏幕最顶部的区域,包括了:信号.运营商.电量等信息.通常APP都有属于自己的色调风格,为了达到整体视觉美观,通常会设置状态栏和标题栏的色调设置成一致. 图例: 二.状态栏状态 ...
- 图书管理系统 基于form组件
models: from django.db import models # Create your models here. class Book(models.Model): name = mod ...
- Java学习---面向对象的远程方法调用[RMI]
基础知识 分布式计算是一门计算机科学,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果. 常见的分 ...
- [T-ARA][나 어떡해/1977 기억 안나][我怎么办/1977我不记得了]
歌词来源: 我怎么办:https://music.163.com/#/song?id=28111191 1977我不记得了:https://music.163.com/#/song?id=281111 ...