大家先来看看一段奇怪的程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
这个程序真是简单啊!可是有什么问题呢?
1. 来自 String 的忧虑
上面这段程序中,到底有几个对象呢?
可能很多人脱口而出:两个,s1 和
s2
为什么?
String 是 final 类,它的值不可变。
看起来似乎很有道理,那么来检测一下吧,稍微改动一下程序
就可以看到结果了:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都会说已经不止两个对象了
编译并运行程序,输出:s1 == s2
啊!
为什么 s1 == s2 ?
== 分明是在说:s1 与
s2 引用同一个 String 对象
-- "Monday"!
2. 千变万化的 String
再稍微改动一下程序,会有更奇怪的发现:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
我们将 s2 用
new 操作符创建
程序输出:
s1 != s2
s1 equals s2
嗯,很明显嘛
s1 s2分别引用了两个"Monday"String对象
可是为什么两段程序不一样呢?
3. 在 String 的游泳池中游泳
哈哈,翻了翻书终于找到了答案:
原来,程序在运行的时候会创建一个字符串缓冲池
当使用 s2 = "Monday" 这样的表达是创建字符串的时候,程序首先会
在这个String缓冲池中寻找相同值的对象,在第一个程序中,s1先被
放到了池中,所以在s2被创建的时候,程序找到了具有相同值的
s1
将 s2 引用
s1 所引用的对象"Monday"
第二段程序中,使用了 new 操作符,他明白的告诉程序:
“我要一个新的!不要旧的!”与是一个新的"Monday"Sting对象被创
建在内存中。他们的值相同,但是位置不同,一个在池中游泳
一个在岸边休息。哎呀,真是资源浪费,明明是一样的非要分开做什么呢?
4. 继续潜水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
这次加入:s2 = s2.intern();
哇!程序输出:
s1 == s2
s1 equals s2
原来,程序新建了 s2 之后,又用intern()把他打翻在了池里
哈哈,这次 s2 和
s1 有引用了同样的对象了
我们成功的减少了内存的占用
5. == 与 equals() 的争斗
String 是个对象,要对比两个不同的String对象的值是否相同
明显的要用到 equals() 这个方法
可是如果程序里面有那么多的String对象,有那么多次的要用到
equals ,
哦,天哪,真慢啊
更好的办法:
把所有的String都intern()到缓冲池去吧
最好在用到new的时候就进行这个操作
String s2 = new String("Monday").intern();
嗯,大家都在水池里泡着了吗?哈哈
现在我可以无所顾忌的用 == 来比较
String 对象的值了
真是爽啊,又快又方便!
String 啊 String ,让我说你什么好呢?
你为我们 Java 程序员带来所有的困扰还不够吗?
看看 String 这一次又怎么闹事儿吧
1. 回顾一下坏脾气的
String 老弟
例程1:
class Str {
public static void main(String[] args) {
String s = "Hi!";
String t = "Hi!";
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
程序输出什么呢?
相信你很快会做出正确的判断:
程序输出:equals
2. 哦,天哪,它又在搅混水了
例程2:
class Str {
public static void main(String[] args) {
String s = "HELLO";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
那么这个程序有输出什么呢?
慎重!再慎重!不要被 String 这个迷乱的家伙所迷惑!
它输出:equals
WHY!!!
把程序简单的更改一下:
class Str2 {
public static void main(String[] args) {
String s = "Hello";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
你可能会说:不是一样吗?
不!千真万确的,不一样!这一次输出:not equals
Oh MyGOD!!!
谁来教训一下这个 String 啊!
3. 你了解你的马吗?
“要驯服脱缰的野马,就要了解它的秉性”牛仔们说道。
你了解 String 吗?
解读 String 的
API ,可以看到:
toUpperCase() 和 toLowerCase() 方法返回一个新的String对象,
它将原字符串表示字符串的大写或小写形势;
但是要注意:如果原字符串本身就是大写形式或小写形式,那么返回原始对象。
这就是为什么第二个程序中 s 和
t 纠缠不清的缘故
对待这个淘气的、屡教不改的 String ,似乎没有更好的办法了
让我们解剖它,看看它到底有什么结构吧:
(1) charAt(int n) 返回字符串内n位置的字符,第一个字符位置为0,
最后一个字符的位置为length()-1,访问错误的位置会扔出一块大砖头:
StringIndexOutOfBoundsException 真够大的
(2) concat(String str) 在原对象之后连接一个
str ,但是返回一个新的 String 对象
(3) EqualsIgnoreCase(String str) 忽略大小写的
equals 方法
这个方法的实质是首先调用静态字符方法toUpperCase() 或者
toLowerCase()
将对比的两个字符转换,然后进行 == 运算
(4) trim() 返回一个新的对象,它将原对象的开头和结尾的空白字符切掉
同样的,如果结果与原对象没有差别,则返回原对象
(5) toString() String 类也有
toString() 方法吗?
真是一个有趣的问题,可是如果没有它,你的 String 对象说不定真的不能用在
System.out.println() 里面啊
小心,它返回对象自己
String 类还有很多其他方法,掌握他们会带来很多方便
也会有很多困惑,所以坚持原则,是最关键的
4. 我想买一匹更好的马
来购买更驯服温和的 String 的小弟
StringBuffer 吧
这时候会有人反对:它很好用,它效率很高,它怎么能够是小弟呢?
很简单,它的交互功能要比 String 少,如果你要编辑字符串
它并不方便,你会对它失望
但这不意味着它不强大
public final class String implements Serializable,
Comparable, CharSequence
public final class StringBuffer implements Serializable,
CharSequence
很明显的,小弟少了一些东东,不过这不会干扰它的前途
StringBuffer 不是由 String 继承来的
不过要注意兄弟它也是 final 啊,本是同根生
看看他的方法吧,这么多稳定可靠的方法,用起来比顽皮的 String 要有效率的多
?nbsp;
Java 为需要改变的字符串对象提供了独立的
StringBuffer 类
它的实例不可变(final),之所以要把他们分开
是因为,字符串的修改要求系统的开销量增大,
占用更多的空间也更复杂,相信当有10000人挤在一个狭小的游泳池里游泳
而岸边又有10000人等待进入游泳池而焦急上火
又有10000人在旁边看热闹的时候,你这个
String 游泳池的管理员也会焦头烂额
在你无需改变字符串的情况下,简单的 String 类就足够你使唤的了,
而当要频繁的更改字符串的内容的时候,就要借助于宰相肚里能撑船的
StringBuffer 了
5. 宰相肚里能撑船
(1) length() 与 capacity()
String 中的 length() 返回字符串的长度
兄弟 StringBuffer 也是如此,他们都由对象包含的字符长度决定
capacity()呢?
public class TestCapacity {
public static void main(String[] args){
StringBuffer buf = new StringBuffer("it was the age
of wisdom,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " +
buf.length());
System.out.println("buf.capacity() = " +
buf.capacity());
String str = buf.toString();
System.out.println("str = " + str);
System.out.println("str.length() = " +
str.length());
buf.append(" " +
str.substring(0,18)).append("foolishness,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " +
buf.length());
System.out.println("buf.capacity() = " +
buf.capacity());
System.out.println("str = " + str);
}
}
程序输出:
buf = it was the age of wisdom.
buf.length() = 25
buf.capacity() = 41
str = it was the age of wisdom
str.length() = 25
buf = it was the age of wisdom, it was the age of
foolishness,
buf.length() = 56
buf.capacity() = 84
str = it was the age of wisdom,
可以看到,在内容更改之后,capacity也随之改变了
长度随着向字符串添加字符而增加
而容量只是在新的长度超过了现在的容量之后才增加
StringBuffer 的容量在操作系统需要的时候是自动改变的
程序员们对capacity所能够做的仅仅是可以在初始化
StringBuffer对象的时候
为它强行的分配一个固定的capacity,但是之后,它愿不愿以改变就完全看自己的了
capacity 会随着 length 超出而改变,总之,它总是要比
length 大
“哦亲爱的小马,快快启程吧,帮我把这84个箱子运到那边去。”
(!@#$$%% 这么多!)
“不过里面只有56个鸡蛋。”
(!@#$$%% 虐待啊)
6. 把好你的舵不要翻船
StringBuffer的胃口看起来很好啊
看起来似乎它可以随意的变成一艘航空母舰
不过请注意:
capacity 的每一次更改和变化,整个对象必须被重建并且移动到另外一个内存区
为了避免类似的溢出,最好在初始化的时候为他分配足够的容量
如果你是船长,在航行中突然下令:“我们准备弃船,换另外一艘大船去啦!”
你的水手们怎么想?“让我们自杀吗?”
所以出发前尽量准备一艘合适的船,不要超载,也不要太大
千万不要在中途翻船啊!
StringBuffer 还有一个炫耀的调皮方法:reverse()
它可以让它肚子里面的东西反一个个儿
7. 大马吃小马
哦,天哪,String 和
StringBuffer 用谁都会使性子
应该如何是好呢?
(1)如果你的 String 仅出现极少数次,随他们去吧,毕竟草原很辽阔
(2)如果他们数目惊人混乱不堪挤作一团到处破坏,
将他们 intern() ,学会游泳比淹死了强
另外配合着 StringBuffer 的使用,它很像这群乱马的头头
可以舒舒服服的调教哪些野性的 String ,把他们头接尾、尾接头的组合起来
形成一个团体,更容易控制和管理(不过令人沮丧的是它的编辑功能不太好)
不过要小心,虽然StringBuffer 的肚子很大,但是不要把它撑破了
适当的给它一个空间,它会发挥更好的作用
(3) 小心谨慎的对待
== 和 equals()
千万不要忘了本,他们都是对象
你可以用各种高效率的办法进行尝试(intern() 然后
==)
但是在最终的原则上要把握好
(4) String 和 StringBuffer不可以互相使用
equals()
不要忘了他们不是同类
小结:
好了,说了这么多
我想我们终于可以指挥着我们的千军万马驰骋在 Java 的大草原上了
String 还有 StringBuffer ,都可以成为我们手中的有力工具
Which two create an
instance of an array? (Choose two)
A. int[] ia = new int[15];
B. float fa = new
float[20];
C. char[] ca = “Some
String”;
D. Object oa = new
float[20];
E. int ia[][] = { 4, 5, 6,
}, { 1, 2, 3 };
[答案]:AD
Question No: 11
Which two demonstrate an “is a” relationship? (Choose
Two)
A. public interface Person { }
public class Employee extends Person { }
B. public interface Shape { }
public class Employee extends Shape { }
C. public interface Color { }
public class Employee extends Color { }
D. public class Species { }
public class Animal (private Species species;)
E. interface Component { }
Class Container implements Component (
Private Component[ ] children;
)
Answer: D, E
class Test{
public int aMethod (){
static int i = 0;
i++;
return I;
}
public static void main(String[] args){
test test = new test();
test.aMethod();
int j = test.aMethod();
System.out.println(j);
}
}
应该是compilation will fail
class Test{
static int i = 0;
public int aMethod (){
i++;
return i;
}
这样就对了!!!
class s extends Thread{
int j=0;
public void run() {
try{Thread.sleep(5000);}
catch(Exception e){}
j=100;
}
public static void main(String args[])
{
s t1=new s();
t1.start();
System.out.println(t1.j);
}
}
what you have to do to ensure that 'j' will print 100
A:you have make t1 as Daemon Thread
B:You have join the t1 to main
C:You have to suspend the main when the thread starts
and resume it after the value of 'j' is set to 100
D:You have to interrupt the main thread
选B,、
class S extends Thread{
int j=0;
public void run() {
try{Thread.sleep(1000);}
catch(Exception e){}
j=100;
System.err.println("S end");
}
public static void main(String args[])
{
S t1=new S();
t1.start();
try
{
t1.join();
}
catch(InterruptedException e)
{
}
System.err.println(t1.j);
System.err.println("main end");
}
}
73. which two cannot directly cause a thread to stop
executing?
A.calling the yield method
B.calling the wait method on an object
C.calling the notify method on an object
D.calling the notifyAll method on an object
E.calling the start method on another thread object
posted on 2005-09-16 10:44
我的java天地 阅读(383)
评论(0) 编辑 收藏 所属分类:
体会