Java优化:使用临时变量声明类变量VS.

时间:2014-03-30 01:40:45

标签: java optimization class-variables code-readability temporary-objects

首先,请原谅我,如果我的英语不完美,但我不是来自英语国家(西班牙),所以...

嗯,这是问题所在。在创建类时,¿是一个很好的做法,尽可能使用临时变量,或者最好将变量声明为类变量,只是为了保持清晰?

我将给你一个例子,使用一个简单的类SpriteSheet。这是一个非常简短和流行的课程,几乎用于Java中的每个2D游戏。

以下代码就像我最初由我正在观看的教程的创建者计划的那样:

public class SpriteSheet {

private String path;
private final int SIZE;
public int[] spriteSheetPixels;

public SpriteSheet(String path, int size) {
this.path = path;
SIZE = size;

spriteSheetPixels = new int[SIZE * SIZE];

load();
}

private final void load() {
try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));
    int w = image.getWidth();
    int h = image.getHeight();
    image.getRGB(0, 0, w, h, spriteSheetPixels, 0, w);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

重点是,据我所知,他正在做一个普通的类,遵循所有Java约定。看了之后,我想我可以稍微改进一下。这是我同一个班级的版本:

public final class SpriteSheet {

public final int[] spriteSheetPixels;

public SpriteSheet(final String path, final int width, final int height) {
spriteSheetPixels = new int[width * height];

load(path, width, height);
}

private final void load(final String path, final int width, final int height) {
try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));

    final int w = image.getWidth();
    final int h = image.getHeight();
    final byte ZERO = 0;

    image.getRGB(ZERO, ZERO, w, h, spriteSheetPixels, ZERO, w);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

以防万一,如果你不想过多关注,我会尝试恢复我改变的内容以及原因: - 为类声明添加了“final”,因为我认为我不需要实例化它。 - 删除了除数组之外的所有类变量,因为这是我最终将从这个类中使用的唯一内容。我觉得将其余的变量声明为类变量只是浪费内存。如果它们是暂时的,如果我没有弄错的话,它们将被使用,然后GC迟早会照顾它们,释放记忆。 - 将数组标记为final,因为它将保持与其余运行时一样。 - 将SIZE常量拆分为宽度和高度,以防我决定使用一些非方形精灵表。 - 声明w和h实际上是一个很好的思考,因为调用参数中的方法通常不利于执行速度(或者这是我在某些地方读过的)。 - 由于多次使用0,我相信将其声明为变量将有助于提高执行速度(只需要一点点,无论如何都可能不会引人注意)。

这基本上就是全部。请注意我是一个有学问的人,可能我犯了一些非常错误的错误,这就是我想问这里的原因,因为我确信有很多经验丰富的程序员。

请记住,我并不关心SpriteSheet类,我对我的优化质量更加好奇。

¿我改进了什么或者让它们变得更糟(让事情变得更慢,更不易读,将来难以维护,做编译器会做的事情......)

对不起,如果我的问题太长而且太模糊,那么我的第一个问题就这么容易了;)

提前致谢。

编辑:

我只是稍微休息后阅读它,它没有任何意义(你看到我正在解析宽度和高度参数加载()并且从不使用它们吗?)

我认为这应该是:

public final class SpriteSheet {

public final int[] spriteSheetPixels;

public SpriteSheet(final String path, final int width, final int height) {
final byte ZERO = 0;
spriteSheetPixels = new int[width * height];

try {
    BufferedImage image = ImageIO.read(SpriteSheet.class
        .getResource(path));

    image.getRGB(ZERO, ZERO, width, height, spriteSheetPixels, ZERO,
        width);
} catch (IOException e) {
    e.printStackTrace();
}
}

}

刚才意识到我真的不需要这个方法。一切都可以在构造函数中完成。

3 个答案:

答案 0 :(得分:3)

  

或者最好将变量声明为类变量,只是为了保持清晰?

我认为你的意思是"属性" (实例变量),而不是静态(类)变量。将所有内容声明为实例变量会使事情变得非常不清楚。

简短回答:对于跨不同方法共享的数据,仅在严格必要时使用局部变量并创建属性。此外,局部变量的访问速度可能比属性稍快。

答案 1 :(得分:0)

  

创建类时,¿是一个很好的做法,尽可能使用临时变量,或者最好将变量声明为类变量,只是为了保持清晰?

如果信息仅与当前运行的方法相关,则将其存储在尽可能小的范围内的局部变量中。

如果有关对象的信息需要超过任何一个方法调用,并且无法从其他源派生,则将其存储在字段中。

如果有关该对象的信息可以从其他来源获得,但是继续导出它的效率低或不方便,那么记录它与其他数据的关系,可以将其标记为transient并将其存储在字段中。

如果你找到一个包含许多字段的类,那么可能是时候把它分成更小的类了。 同样,如果一个方法有很多局部变量,那么可能是时候尝试将它分解成更小的方法了。

答案 2 :(得分:0)

假设您的意思是实例变量,而不是类/ static变量。 (如果你确实意味着static个变量,那么你还有很多其他问题需要处理......)


让我们从"优化"开始这个问题的一个方面。

首先要说的是两种方法之间的差异可能是微不足道的。很可能它不会对程序的性能产生明显的影响。在你的情况下,我想你在任何时候最多只有几十个该类的实例,所以内存使用的差异最多只有几千字节。

话虽如此,却有所不同。将字段声明为实例字段时,它们将在对象的生命周期内存在(并占用堆内存)。相反,当封闭方法调用结束时,局部变量不再存在。因此,使用局部变量可能会长期使用 less 内存。


但这里的重要问题是可读性,可维护性和正确性。

如果你转向本地"临时"变量到实例变量,然后有不同方法的范围......或对同一方法的不同调用......通过使用实例变量相互干扰。请注意,在某些用例中,干扰是不可避免的。例如,当两个不同的线程同时在同一个对象上调用相同的方法时,或者当一个方法直接或间接地调用自身时;即递归。

事实上可能发生这种事情会使代码难以阅读并且难以维护。 (除非您对代码非常熟悉,并且正在跟踪任何人对其做出的所有更改... ...您无法确定某些内容已经破坏了您的假设......并且您已经检查。)

相比之下,您不会遇到局部变量的这些问题。它们保证不可见到当前线程或其他方法上的任何其他方法调用。

简而言之,将变量声明为实例变量"只是为了保持清晰" 实际上将具有相反的效果。它会使事情明显不那么清晰


最后,在程序员网站上有一个与此相关的有趣问题:

我在答案中得出的结论是,这并不能成为一种反模式"因为它不是一种设计模式。但是,它确实很糟糕。