String
先来介绍一下字符串的存储
字符串相加是通过StringBuffer类的append()和toString()实现的, 而toString()返回的字符串是通过构造函数创建的
强调: 两个字符串常量相加, 在编译的时候之间改为一个字符串常量.
而字符串引用相加则是调用StringBuffer类的append()和toString() 这个时候就会在堆中创建一个新的对象。
比较对象的时候==和euqals比较的都是对象的内存地址
对于其他对象类来说 hascode默认代表是内存地址 equals判断的是地址
但是String类重写了equals和hascode 只要值一样 那么hascode就一样 比较的是两个字符串对象内容是否相一致
所以一般都是equals来比较字符串是否相等
注意:了解一下String继承了Comparable重写了compareTo(compareTo)主要是放在集合里判断大小用
编程习惯 常量调用equals方法 比如: “sdf”.equals(str);因为 如果 调用者是空的话会抛异常
String name1="hello";
String name2=new String(“hello”);
创建字符串的时候 jvm会检查字符串常量池是否存在“hello”的字符串
如果存在就不会在里面创建字符串对象了
如果是第一个那么就会返回的是字符串常量池的地址
如果是第二个 都会拷贝一份字符串常量池的对象内容到堆内存中
字符串常量池只能有一个对象
而堆内存中可以有多个对象而且地址不一样
字符串常量池在方法区中
name1等引用在栈内存中
对象内存中new的话
例子:
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println("str1==str2?"+(str1==str2)); // true
System.out.println("str2==str3?"+(str2==str3)); //false
System.out.println("str3==str4?"+(str3==str4)); // false
System.out.println("str3.equals(str2)?"+(str3.equals(str4))); //true
字符串判断是否内容相等
public static void test(String str){
if("中国".equals(str))
{
System.out.println("回答正确");
}else{
System.out.println("回答错误");
}
}
字符串的构造
public static void main(String[] args) {
String name=new String(); //空内容
byte[] buf= {97,98,99};
name=new String(buf,0,2); //0是索引 2是个数 输出ab
char[] arr= {'我','爱','你'};
name=new String(arr,0,2); //同理byte 输出我爱
int[] buf2= {97,98,99};
name=new String(buf,0,2); //同类byte 输出ab
name=new String("wocainima00"); //输出wocainima00
name="xxx"; //输出xxx
System.out.print(name);
}
字符串获取长度,位置或者获取字串:
int length() 获取字符串的长度
char charAt(int index) 获取特定位置的字符 (角标越界)
int indexOf(String str) 查找子串第一次出现的索引值,如果子串没有出现 在字符串中,那么则返回-1表示。
int lastIndexOf(String str) 查找子串最后一次出现的索引值 , 如果子串没有出现 在字符串中,那么则返回-1表示
字符串的判断:
字节数组与字符数组、字符串他们三者之间是可以互相转换。
public static void main(String[] args) {
String str = "Demo.java";
System.out.println("是否以指定 的字符串结束:"+ str.endsWith("ja"));
//str = "";
System.out.println("判断字符串是否为空内容:"+str.isEmpty());
System.out.println("判断字符串是否包含指定的内容:"+ str.contains("Demo"));
System.out.println("判断两个 字符串的内容是否一致:"+ "DEMO.JAVA".equals(str));
System.out.println("判断两个字符串的内容是否一致(忽略大小写比较):"+ "DEMO.JAVA".equalsIgnoreCase(str));
//转换的方法
char[] buf = str.toCharArray(); //把字符串转换字符数组
System.out.println("字符数组:"+ Arrays.toString(buf));
byte[] buf2 = str.getBytes(); //把字符串转字节数组
System.out.println("字节数组:"+ Arrays.toString(buf2));
}
字符串操作
String str = "今天晚上不考试";
System.out.println("指定新内容替换旧 的内容:"+ str.replace("不", "要好好"));
str = "大家-下-午-好";
String[] arr = str.split("-"); //根据指定的字符进行切割 。
System.out.println("字符串数组的内容:"+ Arrays.toString(arr));
str = "广州传智播客";
System.out.println("指定开始的索引值截取子串:"+ str.substring(2));
System.out.println("指定开始的索引值截取子串:"+ str.substring(2,6)); //包头不包尾 注意:截取的内容是包括开始的索引值,不包括结束的索引值, 截取的位置是结束的索引值-1.
str = "abC中国";
System.out.println("转大写:" + str.toUpperCase());
str = "AbdfSDD";
System.out.println("转小写:"+ str.toLowerCase());
str = " 大家最近 都非常努力 ";
System.out.println("去除字符串首尾的空格:"+ str.trim());
字符串的运用:
package cn.itcsat.string;
/*
需求1:自己实现trim的方法。
需求2: 获取上传文件名 "D:\\20120512\\day12\\Demo1.java"。
需求3: 将字符串对象中存储的字符反序。 新中国好 -----> 好国中新
需求4: 求一个子串在整串中出现的次数 。
public class Demo6 {
public static void main(String[] args) {
String str =" 大家 好嘛 ";
System.out.println(myTrim(str));
str = "D:\\20120512\\day12\\Demo1.java";
getFileName(str);
str = "新中国好";
System.out.println("翻转后的字符串:"+ reverse(str));
str = "abcjavaabcjavaphpjava"; //java
getCount(str, "java");
}
// 需求1:自己实现trim的方法。
public static String myTrim(String str){
//先转换成字符 数组
char[] arr = str.toCharArray();
//定义两个 变量记录开始与结束 的索引值
int startIndex = 0 ;
int endIndex = arr.length -1;
//确定开始 的索引值
while(true){
if(arr[startIndex]==' '){
startIndex++;
}else{
break;
}
}
//确定结束 的索引值:
while(true){
if(arr[endIndex]==' '){
endIndex--;
}else{
break;
}
}
//截取子串返回
return str.substring(startIndex,endIndex+1);
}
}
//需求2: 获取上传文件名 "D:\\20120512\\day12\\Demo1.java"。
public static void getFileName(String path){
int index = path.lastIndexOf("\\");
String fileName = path.substring(index+1);
System.out.println("文件名:"+ fileName);
}
//反转
public static String reverse(String str){
char[] arr = str.toCharArray();
for(int startIndex = 0 , endIndex=arr.length-1 ; startIndex<endIndex; startIndex++,endIndex--){
char temp = arr[startIndex];
arr[startIndex] = arr[endIndex];
arr[endIndex] = temp;
}
//使用字符数组构建一个字符串。
return new String(arr);
}
//统计子串出现 的次数
public static void getCount(String str,String target){
int count = 0 ; //用于记录出现的次数
int fromIndex = 0; // 记录从那个索引值开始寻找目标子串
while((fromIndex = str.indexOf(target, fromIndex))!=-1){
//如果indexof方法返回 的不是-1,那么就是已经找到了目标 元素。
count++;
fromIndex = fromIndex+target.length();
}
System.out.println("出现的次数:"+ count);
}
字符串还有个StringBuffer
如果需要频繁修改字符串 的内容,建议使用字符串缓冲 类(StringBuffer)。
笔试题目:使用Stringbuffer无 参的构造函数创建 一个对象时,默认的初始容量是多少? 如果长度不够使用了,自动增长多少倍?
StringBuffer 底层是依赖了一个字符数组才能存储字符数据 的,该字符串数组默认 的初始容量是16, 如果字符数组的长度不够使用 死,自动增长1倍。
容器的具备 的行为:增加 删除 修改 查看 判断
//先使用StringBuffer无参的构造函数创建一个字符串缓冲类。
StringBuffer sb = new StringBuffer();
sb.append("java");
sb.append("java");
sb.append("java");
sb.append("java");
sb.append("java");
StringBuffer对象和String对象之间的互转的代码如下:
String s = “abc”;
StringBuffer sb1 = new StringBuffer(“123”);
StringBuffer sb2 = new StringBuffer(s); //String转换为StringBuffer
String s1 = sb1.toString(); //StringBuffer转换为String
单行用加号拼接字符串是没有性能损失的,java编译器会隐式的替换成stringbuilder,
但在有循环的情况下,编译器没法做到足够智能的替换,仍然会有不必要的性能损耗,
因此,用循环拼接字符串的时候,还是老老实实的用stringbuilder吧。
String,StringBuffer与StringBuilder的区别??
注意:
1、String类型的字符串对象是不可变的,一旦String对象创建后,包含在这个对象中的字符系列是不可以改变的,直到这个对象被销毁。
2、StringBuilder和StringBuffer类型的字符串是可变的,不同的是StringBuffer类型的是线程安全的,而StringBuilder不是线程安全的
3、如果是多线程环境下涉及到共享变量的插入和删除操作,StringBuffer则是首选。如果是非多线程操作并且有大量的字符串拼接,插入,删除操作则StringBuilder是首选。毕竟String类是通过创建临时变量来实现字符串拼接的,耗内存还效率不高,怎么说StringBuilder是通过JNI方式实现终极操作的。
4、StringBuilder和StringBuffer的“可变”特性总结如下:
(1)append,insert,delete方法最根本上都是调用System.arraycopy()这个方法来达到目的
(2)substring(int, int)方法是通过重新new String(value, start, end -
start)的方式来达到目的。因此,在执行substring操作时,StringBuilder和String基本上没什么区别。单线程的时候基本上用StringBuild就对了主要有append和insert等方法
StringBuffer的方法
//先使用StringBuffer无参的构造函数创建一个字符串缓冲类。
StringBuffer sb = new StringBuffer();
sb.append(“abcjavaabc”);
/*
添加
sb.append(true);
sb.append(3.14f);
插入
sb.insert(2, "小明");
*/
/*
删除
sb.delete(2, 4); // 删除的时候也是包头不包尾
sb.deleteCharAt(3); //根据指定 的索引值删除一个字符
修改
sb.replace(2, 4, "陈小狗");
sb.reverse(); // 翻转字符串的内容
sb.setCharAt(3, '红');
String subString = sb.substring(2, 4);
System.out.println("子串的内容:"+ subString);
查看
int index = sb.indexOf("abc", 3);
System.out.println("索引值为:"+index);
sb.append("javajava");
System.out.println("查看字符数组的长度:"+ sb.capacity());
*/
System.out.println("存储的字符个数:"+sb.length());
System.out.println("索引指定的索引值查找字符:"+sb.charAt(2) );
System.out.println("字符串缓冲类的内容:"+ sb);
String content = sb.toString();
test(content);
String s1 = "abc";
String s2 = "a";
String s3 = "bc";
String s4 = s2 + s3;
System.out.println(s1 == s4);
结果为: false
原理是: 字符串相加是通过StringBuffer类的append()和toString()实现的, 而toString()返回的字符串是通过构造函数创建的.
toString()是转换为String类型
如果是引用对象那么就值就是完整类名@地址
如果是String就是输出结果
而且 System.out.println 会自动调用toString()
StringBuilder 可以实现字符串添加 没有创建新的字符串 toString返回的是字符串 是new出来的 在堆中