?!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Java中创建对象的常规方式有如?U:
1. 通过new调用构造器创徏Java对象Q?/p>
2. 通过Class对象的newInstance()Ҏ调用构造器创徏对象Q?/p>
3. 通过Java的反序列化机制从IO中恢复对象Q?/p>
4. 通过Java对象提供的cloneҎ复制一个对象;
5. 基本cd及StringcdQ可以直接赋予直接量?/p>
对于Java中的字符串直接量QJVM会用一个字W串池来保存它们Q当W一ơ用某个直接量ӞJVM会将它放入字W串池中~存Q在一般情况下Q字W串池中的字W串不会被Java回收器回Ӟ当程序再ơ用该直接量时Q无需重新创徏一个新的字W串Q而是直接让引用变量指向字W串池中已经存在的字W串?/p>
字符串池中的字符串是不会被回收的Q这是Java内存泄漏的一个原因?/p>
如果E序需要一个字W序列会改变的字W串Q那么应该考虑使用StringBuilder或StringBufferQ当Ӟ最好还是用StringBuilderQ因为对于线E安全的StringBufferQStringBuilder是线E不安全的,也就是说QStringBuffer中的l大部分代码都加了synchronized修饰W?/p>
如果你的代码所在的E序或进E是多个U程同时q行的,而这些线E会同时q行q段代码Q如果每ơ运行结果和单线E运行结果一P而且其他变量的g和预期的一P是U程安全的,或者说Q多个线E的切换不会D该接口的执行l果存在二义性,我们p该接口是U程安全的?/p>
Java是强cd语言Q所谓强cd语言Q通常h两个基本特征Q?/p>
1. 所有变更必d声明才能使用Q声明变量时必须指定该变量的数据cdQ?/p>
2. 一量某个变量的数据cd定下来Q那么该变量永远只能接受该类型的数据Q不能接受其他类型的数据?/p>
当一个算术表辑ּ中包含多个基本类型时Q整个算术表辑ּ的数据类型会自动提升Q这是我们已l知道的规定。在此之外有个特例,L以下代码Q?/p>
[java]
<span style="font-size:18px">short sv = 5;
sv = sv - 2;</span>
我们通常不能理解的一个问题是Q这D代码会报错。但l合数据cd的自动提升,我们可以q样理解Qsv - 2中,2是int型,所以sv - 2的结果是一个int型,所以不能赋值给sv?/p>
再看以下代码Q?/p>
[java]
<span style="font-size:18px">short sv = 5;
sv -= 2;</span>
如果你再用自动类型提升来理解的话Q你会解释ؓq一D代码结果也会报错,可惜QJava中还有另一规定Q复合赋D符包含了一个隐式的cd转换Qsv -= 2其实{h于sv = (short)(sv - 2)?/p>
昄q里又出C另外一个问题:巨大的int转化为short会出什么问题吗Q且看如下代码:
[java]
<span style="font-size:18px">short sv = 5;
sv += 9000;</span>
我们已知Qshortcd的数D围在-32768~32767之间Q所以当?005赋值给svӞ׃出现高位截断Qsv的最l结果ؓ24471?/p>
由此可见Q复合赋D符单、方便,而且h性能上的优势Q但复合赋D符可能有一定的危险Q它潜在的隐式类型{换可能会不知不觉中导致计结果的高位截断?/p>
且看以下代码Q?/p>
[java]
<span style="font-size:18px">List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
List<Integer> intList = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(intList.get(i));
}</span>
当我看到q段代码的时候,我理所当然的认D代码是错误的,因ؓlist里面包含的是StringQ不能赋值给List<Integer>Q而在Eclipse里面q行q段代码后,你会发现q段代码没有M错误Q可以编译,也可以运行,q就是泛型里面的陷阱。在使用泛型Ӟ要注意以下几点:
1. 当程序把一个原始类型的变量赋值给一个带泛型信息的变量时QL可以通过~译Q只是会提出一些警告,如上qC码中QList<Integer> intList = listq不会报错;
2. 当程序试图访问带泛型声明的集合的集合元素Ӟ~译器L把集合元素当成泛型类型处理——它q不兛_集合里集合元素的实际cdQ如上述代码中,intList.get(i)的结果是一个IntegercdQ?/p>
3. 当程序试图访问带泛型声明的集合的集合元素ӞJVM会遍历每个集合元素自动执行强制类型{换,如果集合元素的实际类型与集合所带的泛型信息不匹配,q行时将引发ClassCastException异常Q假讑֜上述代码的for循环中加上Integer in = intList.get(i)Q就会报此异常?/p>
上面讲的是把原始cd赋值给泛型cdQ假如反q来呢?且看以下代码Q?/p>
[java]
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
List li = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(li.get(i));
System.out.println(li.get(i).length()); // 1)
}
你会发现1)处的代码~译错误Q这是因为——把一个带泛型cd的Java变量赋值给一个不带泛型类型的变量ӞJavaE序会发生擦除,q种擦除不仅仅会擦除实际cd实参Q还会擦除所有泛型信息,如上qC码,li.get(i)是终被当成一个Object对象使用?/p>
Java泛型设计原则Q如果一D代码在~译时系l没有生“[unchecked]未经查的转换”警告,则程序在q行时不会引发ClassCastException异常?/p>
从JDK1.5开始,Java提供了三U方式来创徏、启动多U程Q?/p>
1. l承ThreadcL创徏U程c,重写run()Ҏ作ؓU程执行体;
2. 实现Runnable接口来创建线E类Q重写run()Ҏ作ؓU程执行体;
3. 实现Callable接口来创建线E类Q重写run()Ҏ作ؓU程执行体;
其中Q第一U方式效果最差,它有两点坏处Q?/p>
1. U程cȝ承了Threadc,无法再承其他父c;
2. 因ؓ每条U程都是一个Thread子类的实例,因此多个U程之间׃n数据比较ȝ?/p>
对于W二U和W三U,它们的本质是一LQ只是Callable接口里面包含的call()Ҏ既可以声明抛出异常,也可以拥有返回倹{?/p>
无论使用哪种方式Q都不要调用run()Ҏ来启动线E:启动U程应该使用start()ҎQ如果程序从未调用线E对象的start()Ҏ来启动它Q那么这个线E对象将一直处于新建状态?/p>