场景一:

这个是经常出现的问题,因为我们经常误用String。
public class Test {

  public static void main(String[] args)
{ //参数"terrible"会创建一个对象
//然后,new String(),这个语句会创建一个对象
//所以,这个语句执行过程中,会创建两个对象
String s = new String("terrible."); //只创建一个对象,该对象的引用被赋值到变量 ok
String ok = "This is ok" ;
}
}
根据《Effective Java》一书的说法,对于 String ok = "This is ok" ,它可以保证,对于所有在同一台虚拟机中运行的代码,只要它们包含相同的字符串字面常量,该对象就会被重用。意思就是,我们在这里,创建了一个对象,它包含字符床字面值"This is ok",然后,如果在其它地方,再次出现字面值"This is ok",系统会使用重用当前已经创建完毕的,不会再创建一个新的对象。
这是重用不可变对象。包含字面值"This is ok"的对象,是不可变的。
 
场景二:
除了可以重用那些不可变对象之外,还可以重用那些在首次初始化之后,就不会改变的对象。这里的关键是要确定,该对象是否在首次初始化之后就不会被改变。
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone; public class Person {
private final Date birthDate ; public Person(Date birthDate) {
// Defensive copy - see Item 39
this. birthDate = new Date(birthDate.getTime());
} // Other fields, methods omitted // DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
Calendar gmtCal = Calendar. getInstance(TimeZone.getTimeZone("GMT" ));
gmtCal.set(1946, Calendar. JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar. JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
实例化Person之后,每次查询isBabyBoomer()方法,都会执行如下操作:1.创建一个Calendar实例。2.创建一个TimeZone实例。
3.创建两个Date实例。
而用户每次调用的时候,都是执行相同的操作,创建的对象也都是含义相同的,不会变化的。

所以,对于这种情况,可以将这些创建的对象定义为一个静态的类实例。修改为:

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone; class Person {
private final Date birthDate ; public Person(Date birthDate) {
// Defensive copy - see Item 39
this. birthDate = new Date(birthDate.getTime());
} // Other fields, methods /**
* The starting and ending dates of the baby boom.
*/
private static final Date BOOM_START;
private static final Date BOOM_END; static {
Calendar gmtCal = Calendar. getInstance(TimeZone.getTimeZone("GMT" ));
gmtCal.set(1946, Calendar. JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar. JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
} public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo( BOOM_END) < 0;
}
}
首次访问类Person时,会执行其中的静态语句块,创建一个Calendar实例,一个TimeZone实例,两个Date实例。
然后,客户端每次通过Person实例访问isBabyBoomer方法时,都是使用相同的Calendar实例,TimeZone实例,Date实例,而不用每次都创建一个局部实例。如此,相对于一个经常被访问的方法isBabyBoomer,程序的性能是提高了的。
 
场景三:
Java支持自动装箱技术(和对应的自动拆箱技术),装箱,就是把基本数据类型转换为对应的包装类实例。所以,会在无意间创建多个实例,比如:
敲错了一个字符,将l输入为大写的L,又由于自动装箱技术的存在,于是,就出现了下述的问题。
//一段运行缓慢的代码

public class Sum {
// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
Long sum = 0L;
for ( long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
}

实际运行的时候,java编译器,根据装箱技术,会将上述代码转换为:

  for ( long j = 0; j < Integer. MAX_VALUE; j++) {
sum += Long. valueOf(j);
}
System. out.println(sum);

这样会创建Integer.MAX_VALUE个Long个包装类的实例,从而影响了性能。

正确的代码是:

  long sum = 0L;
for ( long i = 0; i < Integer. MAX_VALUE; i++) {
sum += i;
}
System. out.println(sum);

这样就可以避免创建Integer.MAX_VALUE个Long包装类实例了。

Item 5 避免创建不必要的对象的更多相关文章

  1. 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间

    [源码下载] 速战速决 (5) - PHP: 动态地创建属性和方法, 对象的复制, 对象的比较, 加载指定的文件, 自动加载类文件, 命名空间 作者:webabcd 介绍速战速决 之 PHP 动态地创 ...

  2. Java避免创建不必要的对象

    小Alan最近看到了<Effective Java>这本书,这本书包含的内容非常丰富,这本书我就不多介绍了,只能默默的说一句,作为一名java开发错过了这本书难免会成为一个小遗憾,所以还是 ...

  3. 用类方法------>快速创建一个autorelease的对象,在封装的类方法内部

    在封装的类方法内部,也就是+ (id)personWithName:(NSString *)name andAge:(int)age内部: 创建了一个person对象,并且创建了一个person*类型 ...

  4. Effective Java之避免创建不必要的对象

    Effective Java中有很多值得注意的技巧,今天我刚开始看这本书,看到这一章的时候,我发现自己以前并没有理解什么是不必要的对象,所以拿出来跟大家探讨一下,避免以后犯不必要的错误! 首先书中对不 ...

  5. String,你到底创建了几个对象????

    String str=new String("aaa"); 这行代码究竟创建了几个String对象呢?答案是2个,而不是3个.由于 new String("aaa&quo ...

  6. JavaScript DOM高级程序设计2.1创建可重用的对象--我要坚持到底!

    1.对象中包含什么 在javascript中,从函数到字符串实际上都是对象 继承 //创建一个person对象的实例 var penson={}; person.getName=function(){ ...

  7. 面试题之String str = new String("abc"); 创建了几个对象

    今天去面试的时候碰到了这个问题:String str = new String("abc"); 创建了几个对象,回来自己研究并查阅资料才发现答错了..网上的争论不少,有的说是两个, ...

  8. String s = new String("aa") 创建了几个对象?

    1 最近几个同学面试的时候出现了这样一个问题 刚听到这个题目的时候的确是不知所措: 经过网上的查找和自己的理解来解释一下这个题目的答案 答案是: 为什么呢??? 1 实现我们都知道创建实例有两种方法 ...

  9. java中String s = new String("abc")创建了几个对象?

    答案是两个,现在我们具体的说一下: String s = new String("abc");一.我们要明白两个概念,引用变量和对象,对象一般通过new在堆中创建,s只是一个引用变 ...

随机推荐

  1. python学习笔记02:运行python程序

    1.启动cmd命令行,输入python后回车,运行python解释器: 输入python代码后回车: print('Hello World')

  2. LintCode-532.逆序对

    逆序对 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.给你一个数组,求出这个数组中逆序对的总数. 概括:如果a[i] > a[j] 且 i < j, a[i ...

  3. OnDraw和Opanit的区别

    OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中.  OnPaint() 是CWnd的类成员,负责响应WM_PA ...

  4. SVM之问题形式化

    >>>SVM之问题形式化 SVM之对偶问题 SVM之核函数 SVM之解决线性不可分 写在SVM之前——凸优化与对偶问题 SVM内容繁多,打算用五篇文章来记述.SVM之问题形式化描述给 ...

  5. C跟C++

    工作以来几乎就只写C,下周开始的新工作可能就要开始写C++啦~ C: C++: 1.template 2.多态.重载.继承 3.虚函数 C++内存布局 看两张耗子的图片就清楚了.其中虚函数表一般放在数 ...

  6. .NET环境下,通过LINQ操作SQLite数据库

    //对应数据库中的某个表 [Table(Name = "main.Student")]    public class Student    {        [Column(Na ...

  7. 【Python】PYTHON中STRIP()方法学习笔记

    Python strip() 方法用于移除字符串头尾指定的字符(默认为空格). 当使用strip('xxx'),只要字符串头尾有"xxx"中的一个,就会去掉,而不是符合字符串''x ...

  8. mac终端命令-----常规操作

    OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...

  9. Go语言【第十二篇】:Go数据结构之:切片(Slice)、范围(Range)、集合(Map)

    Go语言切片(Slice) Go语言切片是对数组的抽象,Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数 ...

  10. 未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出

    安装微软的windows补丁 KB2781514 ,补丁主要解决“在 .NET Framework 4.5 更新之后,Visual Studio 用户可能无法打开或创建 C++ 或 JavaScrip ...