有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

安卓使用实用程序生成Java代码,使我的项目更加简洁。好主意

我正在从事的项目需要我编写大量重复的代码。例如,如果我想在代码中加载一个名为“logo.png”的图像文件,我会这样写: 位图图像

...
// Init
logoImage = load("logo.png")

...
// Usage
logoImage.draw(0, 0);

..
// Cleanup
logoImage.release();

必须编写此代码才能使用每个新图像是一件痛苦的事情,包括必须指定logoImage应加载文件“logo.png”

由于我正在开发一款Java Android游戏,而且图像在内部循环中被大量使用,所以我真的希望避免一些缓慢的事情,比如进行虚拟函数调用,以及在可以避免的情况下访问数组/地图/对象字段。从AndroidAPI(生成的R类)复制一个想法,我想我可以在编译之前运行一个实用程序,为我生成一些重复的代码。例如,项目文件中的实际代码将减少为:

logoImage.draw(0, 0);

使用一些命令行工具(例如grep、sed),我可以查找“Image.draw(…”的每个实例然后自动生成其他所需代码,即加载/释放文件的代码。png并在某处声明“位图logoImage”。可以将此代码添加到新类中,也可以在代码中添加占位符,告知代码生成器在何处插入生成的代码

要显示新图像,我只需将图像文件复制到正确的目录并添加一行代码。又好又简单。这避免了创建图像数组、定义带标签的int常量以引用数组以及必须指定要加载的文件名等方法

这真的是个坏主意吗?这似乎有点像黑客,但我看不到更简单的方法,它似乎彻底清理了我的代码。有没有标准的工具来完成这种简单的代码生成(即,该工具不需要理解代码的含义)?还有人这样做是为了弥补语言特性吗


共 (5) 个答案

  1. # 1 楼答案

    您将复杂性转移到代码生成上,而代码生成并不是微不足道的,而且可能有缺陷。 代码更难阅读和维护。一些清晰的设计和编码规则在这里更有用

  2. # 2 楼答案

    避免代码生成。它常常使代码难以维护

    在你的情况下,你为什么不:

    public class ImageUtils {
        public static void drawAndRelease(String name) {
            logoImage = load(name)
            logoImage.draw(0, 0);
            logoImage.release();
        }
    }
    

    然后打电话:

    ImageUtils.drawAndRelease("logo.png");
    

    如果这些方法之间有更多的代码,那么它们就是原子方法,在使用代码生成时,您将不知道将它们放在哪里

  3. # 3 楼答案

    有几种方法:

    EclipseCode2Code,您可以使用模板语言(如FreeMarker、groovy等)在模板中编写代码

    用于Android的eclipse sqLite插件自动生成sqLite代码

    MotoDevStudio4android有您可以使用的代码片段

  4. # 4 楼答案

    对这样的事情使用代码生成是个坏主意。(依我看,代码生成应该保留在需要生成大量代码的情况下,而这听起来不像那种情况。)

    如果您当前解决方案中的样板代码与您有关,那么更好的解决方案(比代码生成)是实现图像注册表抽象;e、 g

    public class ImageRegistry {
        private Map<String, Image> map = new HashMap<String, Image>();
    
        public synchronized Image getImage(String filename) {
            Image image = map.get(filename);
            if (image == null) {
                image = load(filename);
                map.put(filename, image);
            }
            return image;
        }
    
        public synchronized void shutdown() {
            for (Image image : map.valueSet()) {
                image.release();
            }
            map.clear();  // probably redundant ...
        }
    }
    

    logoImage.draw(0, 0)等替换为:

    registry.getImage("logo.png").draw(0, 0);
    

    删除所有load调用,并将所有release调用替换为对registry.shutdown()的单个调用

    编辑以回应OP的以下评论:

    ... but I mention that I'm writing a game for a phone. A HashMap lookup every time I'm drawing a sprite will kill performance.

    啊。。。我记得你从另一个线程

    1. 你(再一次)在没有任何实际绩效衡量依据的情况下对绩效做出假设。具体地说,您假设HashMap查找将过于昂贵。我的直觉是,查找所需的时间只占绘制图像所需时间的一小部分(<;10%)。在这一点上,它正接近一个用户无法察觉的水平

    2. 如果您的测量结果(或直觉)告诉您hashmap查找过于昂贵,那么编写以下内容是一个微不足道的修改

      Image=注册表。getImage(“logo.png”); 而(…){ ... 形象抽签(0,0); }


    For example, Google even go as far as to recommend you don't use iterators in inner loops because these cause the GC to fire when the Iterator objects are deallocated.

    这是不相关和不准确的

    1. 使用字符串键的HashMap查找不会生成垃圾。从来没有

    2. 在内部循环中使用迭代器不会“导致在迭代器对象被解除分配时触发GC”。在Java中,不释放对象。这就是C/C++思维

    3. 实例化内部循环中的迭代器不会new对象,但是只有当new操作达到内存阈值时,GC才会触发。这种情况只是偶尔发生


    Also, writing "file_that_does_not_exist.png" will not be picked up as a compile time error with your example.

    原始解决方案或代码生成方法都不能为丢失的文件提供编译时错误

  5. # 5 楼答案

    我赞同Bozho关于避免代码生成的回答,但是如果您必须编写可重复的代码片段,那么任何好的IDE通常都有一些内置的支持,可以使用变量和所有内容指定您自己的代码片段。IntelliJ IDEA具有此功能,称为实时模板。我猜Eclipse和NetBeans都有类似的功能