可变对象也存在临时对象问题
在RegExpMatcher中,当一个方法返回的数据类型为String类时,就有必要创建一个新的String类对象。在BadRegExpMatcher中存在的问题之一是match()返回的是一个对象而不是一个简单类型的数据━━因为一个方法返回一个对象,并不意味着一定会创建一个新的对象。考虑一下Point和Rectangle等
java.awt中的几何类,一个Rectangle只不过是由四个整数━━左上角点的X、Y坐标以及宽度和高度组成的,AWT
组件类存储了组件的位置并通过getBounds()方法将它作为一个Rectangle类对象返回:
public class Component {
...
public Rectangle getBounds();
}
在上面的例子中,getBounds()方法仅仅起一个辅助性作用,它只是声明一些组件内部的有关信息。getBounds()真的必须创建它返回的Rectangle对象吗?也许是这样的吧,我们来看一下getBounds()的编码:
public class Component {
...
PRotected Rectangle myBounds;
public Rectangle getBounds() { return myBounds; }
}
当有程序调用上面例子中的getBounds()时,并不会创建新的对象,因为组件已经知道它的位置,因此getBounds()是比较高效的。然而,Rectangle的可变性还引起了其他问题,当一个调用它的程序执行下面的代码时会出现什么样的情况呢?
Rectangle r = component.getBounds();
...
r.height *= 2;
因为Rectangle具有可变性,上面的代码将引起组件的改变,对于象AWT这样的GUI工具包而言,这将是灾难性的,因为当一个组件变化时,需要重新刷新屏幕,同时还需要通知事件监视程序。因此上面的Component.getBounds()的运行是相当危险的,下面所示的方式才是比较安全的:
public Rectangle getBounds() {
return new Rectangle(myBounds.x, myBounds.y,
myBounds.height, myBounds.width);
}
但是,就象RegExpMatcher那样,每次调用getBounds()都会创建一个新的对象,下面的代码将会创建四个临时对象:
int x = component.getBounds().x;
int y = component.getBounds().y;
int h = component.getBounds().height;
int w = component.getBounds().width;
对于String类而言,创建对象是必要的,因为String是不可变的。但是在这个例子中,创建临时对象似乎也是必需的,因为Rectangle具有可变性,我们可以通过不在接口中使用任何对象来避免象String引起的那样的问题。尽管在与RegExpMatcher类似的场合中,这一方案并非总是可行的或理想的,然而,幸运的是,在设计类时可以采用一些技术,既能使用小一些的对象又不会碰到使用太多的小对象所引起的问题。
进入讨论组讨论。