1

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

好吧,这就是问题所在。在创建类时,尽可能使用临时变量是一种好习惯,或者最好将变量声明为类变量,只是为了保持清楚?

我会给你一个例子,使用一个简单的 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 迟早会处理它们,释放内存。- 将数组标记为最终数组,因为它将在运行时的其余部分保持不变。- 将 SIZE 常量拆分为宽度和高度,以防我决定使用一些非方形精灵表。- 声明 w 和 h 实际上是个好主意,因为在参数中调用方法通常不利于执行速度(或者这就是我在某些地方读到的)。- 由于 0 被多次使用,我相信将其声明为变量将有助于提高执行速度(只是一点点,可能无论如何都不会被注意到)。

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

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

¿ 我是改进了事情还是让事情变得更糟(实际上让事情变得更慢、可读性更差、将来更难维护、做编译器无论如何都会做的事情......)?

抱歉,如果我的问题太长太模糊,是我的第一个问题,对我来说很容易;)

提前致谢。

编辑:

我只是在稍作休息后才阅读它,它没有任何意义(您是否看到我正在将宽度和高度参数解析为 load() 并且从不使用它们?)

这是我认为应该的:

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();
}
}

}

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

4

3 回答 3

3

或者更好地将你的变量声明为类变量,只是为了保持清楚?

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

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

于 2014-03-30T01:45:12.963 回答
0

在创建类时,尽可能使用临时变量是一个好习惯,或者最好将变量声明为类变量,只是为了保持清楚?

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

如果有关对象的信息需要比任何一个方法调用更持久,并且不能从其他来源派生,则将其存储在字段中。

如果有关对象的信息可以从其他来源获得,但继续获得它效率低下或不方便,则记录其与其他数据的关系,可能会对其进行标记并将其transient存储在字段中。

如果你发现一个有很多领域的类,那么也许是时候把它分成更小的类了。同样,如果一个方法具有许多局部变量,那么也许是时候尝试将其分解为更小的方法了。

于 2014-03-30T02:30:38.073 回答
0

假设您根据示例表示实例变量,而不是类/static变量。(如果你真的是指static变量,那么你还有很多其他问题要处理......)


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

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

说了这么多,还是有区别的。当您将字段声明为实例字段时,它们将在对象的生命周期内存在(并占用堆内存)。相反,当封闭方法调用结束时,局部变量将不复存在。因此,从长远来看,使用局部变量可能会使用更少的内存。


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

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

而且这种事情可能发生的事实使代码更难阅读和更难维护。(除非你真的熟悉代码,并且正在跟踪任何人对其所做的所有更改......你不能确定有什么东西破坏了你的假设......你必须检查。)

相比之下,局部变量没有这些问题。它们保证在当前线程或另一个线程上对任何其他方法调用都不可见。

简而言之,将变量声明为实例变量“只是为了保持清晰”实际上会产生相反的效果。这将使事情变得不那么清楚


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

我在回答中的结论是,这并不真正符合“反模式”的条件,因为它不是设计模式。但无论如何,它真的很糟糕。

于 2014-03-30T02:33:26.807 回答