StringBuffer与StringBulider
它们都继承自抽象类AbstractStringBuilder。
存储数据的字符数组没有被final修饰,说明值可以改变,抽象类AbstractStringBuilder内部都提供了一个自动扩容机制,当发现长度不够的时候(初始默认长度是16),会自动进行扩容工作,扩展为原数组长度的2倍加2,创建一个新的数组,并将数组的数据复制到新数组,所以对于拼接字符串效率要比String要高。
线程安全性:StringBuffer由于很多方法都被 synchronized 修饰了所以线程安全,但是当多线程访问时,加锁和释放锁的过程很平凡,所以效率相比StringBuilder要低。StringBuilder相反执行效率高,但是线程不安全。
执行速度:StringBuilder > StringBuffer > String。
0.StringBulider
1.StringBuffer(其对API的调用类似)
2.StringBuffer可以更改字符串,String不行
String不能更改:
3.StringBuffer常用方法
1.insert插入(索引,在字符串中追加的元素)
注意追加元素需要在选择时注意类型
2.replace(开始索引,结束索引,替换内容)
3.indexOf(为什么有时候用StringBuffer而不用String)
每次在字符串后面加上字符串,都会去开辟一个新的空间,如下:
4.reverse(反转字符串)
由于研究了关于字符串(String)的问题,今年就在这里总结一下,首先说一下有关于面试,我想的是,需要一定的技能,比方说,大家想到这个反转问题,肯定能说上了,只不过是你说的一般人都知道,要想在面试中更胜一筹,就必须比别人更多知道一点,更多地还是我们的积累,而不单单为了面试,好了,不说这些废话了,只有征服自己,才是更大的赢家。。。
直奔主题,说一下关于在别人问到这个问题的时候,该如何去回答,我们需要一点一点就说,这样子会感觉到我们更有条理,也不会更早的忘记。。。
从简单的开始(就是从简单的一句话开始)
注:old 为字符串变量
//return new StringBuffer(old).reverse().toString();
//return new StringBuilder(old).reverse().toString();
1
2
再来一个大气点的
我们要想到Collections类中有两个重要的方法,(sort()与reverse());而reverser()参数是集合,这个时候就需要转化为集合,代码如下:
String result = "";
List<String> olds = Arrays.asList(old.split(""));
Collections.reverse(olds);
for (String s : olds) {
result += s;
}
return result;
1
2
3
4
5
6
7
然后再说一下关于charAt() 的用法:返回指定索引处的 char 值。
利用下标倒序把字符取出来重组
String result = "";
for (int i = old.length() - 1; i >= 0; i--) {
result += String.valueOf(old.charAt(i));
}
return result;
1
2
3
4
5
这种方法是将先取出来的放在后取出来的后面
String result = "";
for (int i = 0; i < old.length(); i++) {
result = old.charAt(i) + result;
}
return result;
1
2
3
4
5
再说一下关于toCharArray()的用法:该方法的作用是返回一个字符数组,该字符数组中存放了当前字符串中的所有字符
利用栈,就是传说中的先进后出,如果不清楚,查看API即可,里面有:
Stack() 创建一个空堆栈。
empty() 测试堆栈是否为空;
push(E item) 把项压入堆栈顶部;
pop() 移除堆栈顶部的对象,并作为此函数的值返回该对象。
Character类为char的封装类
char[] chars = old.toCharArray();
Stack<Character> oldStack = new Stack<Character>();
for (Character c : chars) {
oldStack.push(c);
}
String result = "";
while (!oldStack.empty()) {
result += oldStack.pop();
}
return result;
1
2
3
4
5
6
7
8
9
10
来点刺激一点的,就是你的重点。。。要想说清楚就需要使用奇数偶数来测试 等等。。。
1
char[] chars = old.toCharArray();
int n = chars.length - 1;
for (int i = 0; i <= n / 2; i++) {
char temp = chars[i];
chars[i] = chars[n - i];
chars[n - i] = temp;
}
return new String(chars);
换为StringBuffer后(通过append追加字符在字符串中),速度很明显比String快很多:
Last:字符串连接,用+进行连接,其实内部也是通过StringBuilder的append来实现的。
一般情况进行字符串拼接用+就可以,系统内部会进行优化,但是如果是循环拼接,则需要用StringBuilder的append来实现。原因:因为如果是循环拼接,那么系统会在循环体内部创建StringBUilder,这样会造成空间浪费;而用StringBuilder进行显示拼接时,可以定义在外面,减少内存的消耗。
2.代码实现
String str1 = "love";
for(int i=0;i<10;i++)
{
//系统会在这里创建StringBuilder,然后进行append,这样会增加内存消耗
str1 += i;
}
//StringBuilder
StringBuilder str2 = new StringBuilder("love2");
for(int i=0;i<10;i++)
{
//这里的StringBuilder是在外部创建的,就一个,所以不会增加内存消耗
str2.append(i);
}
最后谈一下equals和== 的区别
Java当中所有的类,都继承于Object这个基类,Object中定义了一个equals方法,用来比较对象的内存地址,此时 == 的作用与 equals方法的作用是相同的。
但是,在一些类库(如:String、Integer、Date)中,equals方法被覆盖掉了,这些类库中的equals方法被用来比较对象的内容是否相同。
所以,对于Object基类,equals方法和 == 都是用来比较对象的内存地址是否相同的。
1、Java中的数据类型分为两类:
(1)基本数据类型(原始数据类型):byte、short、char、int、long、float、double、boolean
(2)引用数据类型:String,各种对象
2、==
(1)对于基本数据类型,比较的是值是否相同
(2)对于引用数据类型,比较的是内存地址是否相同
3、equals方法
(1)若未被重写,比较的是内存地址是否相同
(2)若已被重写,比较的是值或对象的内容是否相同
// 基本数据类型的比较,比较的是值是否相同
int num1 = 10;
int num2 = 10;
System.out.println(num1 == num2); //true
// 引用数据类型比较,比较的是内存地址是否相同
Student stu1 = new Student();
Student stu2 = new Student();
System.out.println(stu1 == stu2); //false
System.out.println(stu1.equals(stu2)); //false
// new出来了两个对象,内存地址一定不同
String a = "abc";
String b = "abc";
System.out.println(a == b); //true
// a代表的"abc"在常量池中,b代表的"abc"已经存在于常量池中,
// 所以b指向已存在的"abc",a和b的内存地址相同
System.out.println(a.equals(b)); //true
// String类库中,对equals方法进行了重写,此时equals方法比较的是两个字符串对象的内容是否相同
String a = new String("a");
String b = new String("a");
System.out.println(a == b); //false
// String是引用数据类型,此时 == 比较的是内存地址是否相同,new出来的两个对象,内存地址一定不同
System.out.println(a.equals(b)); //true
// a和b字符串的内容相同
String s1 = "Monday";
String s2 = new String("Monday");
System.out.println(s1 == s2); //false
// 比较内存地址是否相同,s1在常量池中,s2在堆(heap)内存中,内存地址不同
System.out.println(s1.equals(s2)); //true
// 两个字符串内容相同
String s1 = "ab";
String s2 = "cd";
String s3 = s1 + s2;
String s4 = "abcd";
System.out.println(s3.equals(s4)); //true
System.out.println(s3 == s4); //false
// s1、s2、s4 均在常量池当中,
// s3的执行过程是:JVM在堆中创建一个StringBuilder类,用s1指向的字符串完成初始化,
// 调用append()方法完成对s2所指向的字符串的合并操作,
// 调用StringBuilder的toString()方法在堆中创建一个String对象,
// 将生成的String对象的堆地址,存放在变量s3中,
// 因此s3和s4的内存地址不同