首先,请原谅我,如果我的英语不完美,但我不是来自英语国家(西班牙),所以...
嗯,这是问题所在。在创建类时,¿是一个很好的做法,尽可能使用临时变量,或者最好将变量声明为类变量,只是为了保持清晰?
我将给你一个例子,使用一个简单的类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();
}
}
}
刚才意识到我真的不需要这个方法。一切都可以在构造函数中完成。
答案 0 :(得分:3)
或者最好将变量声明为类变量,只是为了保持清晰?
我认为你的意思是"属性" (实例变量),而不是静态(类)变量。将所有内容声明为实例变量会使事情变得非常不清楚。
简短回答:对于跨不同方法共享的数据,仅在严格必要时使用局部变量并创建属性。此外,局部变量的访问速度可能比属性稍快。
答案 1 :(得分:0)
创建类时,¿是一个很好的做法,尽可能使用临时变量,或者最好将变量声明为类变量,只是为了保持清晰?
如果信息仅与当前运行的方法相关,则将其存储在尽可能小的范围内的局部变量中。
如果有关对象的信息需要超过任何一个方法调用,并且无法从其他源派生,则将其存储在字段中。
如果有关该对象的信息可以从其他来源获得,但是继续导出它的效率低或不方便,那么记录它与其他数据的关系,可以将其标记为transient
并将其存储在字段中。
如果你找到一个包含许多字段的类,那么可能是时候把它分成更小的类了。 同样,如果一个方法有很多局部变量,那么可能是时候尝试将它分解成更小的方法了。
答案 2 :(得分:0)
假设您的意思是实例变量,而不是类/ static
变量。 (如果你确实意味着static
个变量,那么你还有很多其他问题需要处理......)
让我们从"优化"开始这个问题的一个方面。
首先要说的是两种方法之间的差异可能是微不足道的。很可能它不会对程序的性能产生明显的影响。在你的情况下,我想你在任何时候最多只有几十个该类的实例,所以内存使用的差异最多只有几千字节。
话虽如此,却有所不同。将字段声明为实例字段时,它们将在对象的生命周期内存在(并占用堆内存)。相反,当封闭方法调用结束时,局部变量不再存在。因此,使用局部变量可能会长期使用 less 内存。
但这里的重要问题是可读性,可维护性和正确性。
如果你转向本地"临时"变量到实例变量,然后有不同方法的范围......或对同一方法的不同调用......通过使用实例变量相互干扰。请注意,在某些用例中,干扰是不可避免的。例如,当两个不同的线程同时在同一个对象上调用相同的方法时,或者当一个方法直接或间接地调用自身时;即递归。
事实上可能发生这种事情会使代码难以阅读并且难以维护。 (除非您对代码非常熟悉,并且正在跟踪任何人对其做出的所有更改... ...您无法确定某些内容已经破坏了您的假设......并且您已经检查。)
相比之下,您不会遇到局部变量的这些问题。它们保证不可见到当前线程或其他方法上的任何其他方法调用。
简而言之,将变量声明为实例变量"只是为了保持清晰" 实际上将具有相反的效果。它会使事情明显不那么清晰。
最后,在程序员网站上有一个与此相关的有趣问题:
我在答案中得出的结论是,这并不能成为一种反模式"因为它不是一种设计模式。但是,它确实很糟糕。