2

我正在为二进制文件格式编写解析器。我创建了类来表示我正在阅读的反序列化结构,我想在其中使用最终变量来保存提取的数据。

class MyObject {
    final int my_x;
    final int my_y;
    final int my_z;
}

我遇到的问题是某些字段的存在取决于设置的某些标志。例如:

MyObject(InputStream is) {
    my_x = in.read();
    if (my_x == 1) {
        my_y = in.read();
        if (my_y == 1) {
            my_z = in.read();
        }
    }
}

但是,这给了我一个错误,因为my_ymy_z可能没有被初始化。这些条件可以有 5-6 级深,我不想跟踪在分支树的每一级可能不会读取哪些字段。另一个复杂因素是,基于某些标志,我可能希望使用与顶级结构相同的模式来处理子对象。

class MyObject {
    final int my_x;
    final SubObject my_subobject;

    MyObject(InputStream is) {
        my_x = is.read();
        if (my_x == 1)
            my_subobject = new SubObject(is);
    }

    class SubObject {
        final int sub_x;
        final int sub_y;

        SubObject(InputStream is) {
            sub_x = is.read();
            if (sub_x == 1)
                sub_y = is.read();
        }
    }
}

有什么方法可以使我的字段最终化,而无需扭曲代码来处理每种可能的标志组合?

4

1 回答 1

4

使用局部变量并分配给final构造函数末尾的字段。

public MyObject(InputStream is) {
    int x = default_x_value;
    int y = default_y_value;
    int z = default_z_value;
    x = in.read();
    if (x == 1) {
        y = in.read();
        if (y == 1) {
            z = in.read();
        }
    }
    my_x = x;
    my_y = y;
    my_z = z;
}

或者(正如 Jon Skeet 在他的评论中建议的那样),使用静态工厂方法来计算非默认构造函数的适当值:

public static MyObject makeMyObject(InputStream is) {
    int x = default_x_value;
    int y = default_y_value;
    int z = default_z_value;
    x = in.read();
    if (x == 1) {
        y = in.read();
        if (y == 1) {
            z = in.read();
        }
    }
    return new MyObject(x, y, z);
}

第三种方法是定义一个初始化对象类:

public class MyObject {
    private static class MyObjectInitializer {
        int x = default_x_value;
        int y = default_y_value;
        int z = default_z_value;
        MyObjectInitializer(InputStream is) {
            x = in.read();
            if (x == 1) {
                y = in.read();
                if (y == 1) {
                    z = in.read();
                }
            }
        }
    }
    public MyObject(InputStream is) {
        this(new MyObjectInitializer(is));
    }
    private MyObject(MyObjectInitializer init) {
        my_x = init.x;
        my_y = init.y;
        my_z = init.z;
    }
}

初始化器类可能有自己的实用程序,在这种情况下,您可以将其(和相应的MyObject构造函数)公开。

于 2013-05-08T17:48:44.033 回答