简体   繁体   English

使用更改的构造函数和“抽象”修饰符实例化相同 class 的不同版本

[英]Instantiate different versions of same class with changed constructor and "abstract" modifier

I am writing a Java program which uses external libraries.我正在编写一个使用外部库的 Java 程序。 I want to write my code so it is compatible with two different versions of one specific library.我想编写我的代码,以便它与一个特定库的两个不同版本兼容。

The problem is, they changed a class (called Configuration in my example) to abstract, added an abstract method and changed the constructor from a no-argument to parameterized constructor.问题是,他们将 class(在我的示例中称为Configuration )更改为抽象,添加了一个抽象方法并将构造函数从无参数更改为参数化构造函数。 I am not able to influence the external library and I have to work with what I got.我无法影响外部图书馆,我必须使用我得到的东西。

Old class example旧 class 示例

public class Configuration {

    public Configuration() {
        //Some code...
    }

    public static void main(String[] args) {
        Configuration conf = new Configuration();
        //Some code...
    }

}

New class example新 class 示例

public abstract class Configuration {

    public Configuration(boolean isCool, Map<String, String> entries, Object otherThing) {
        //Some code...
    }

    public abstract int doSomething();
    
    public static void main(String[] args) {
        Configuration conf = new MyConfiguration(false, null, new Object());
        //Some code...
    }

}

My implementation我的实现

public class MyConfiguration extends Configuration {
    
    public MyConfiguration(boolean isCool, Map<String, String> entries, Object otherThing) {
        super(isCool, entries, otherThing);
    }
    
    public MyConfiguration() {
        //needs super constructor call!?
    }

    public int doSomething() {
        //Some code...
        return -1;
    }

    public static void main(String[] args) {
        int version = 0;
        Configuration conf = version > 2 ? new MyConfiguration(false, null, new Object()) : new MyConfiguration();  
        //Some code...
    }

}

IDE错误

The no-argument constructor of my custom class MyConfiguration needs to call the constructor of the superclass in order to be compiled.我自定义的 class MyConfiguration的无参构造函数需要调用超类的构造函数才能编译。 However, the old class does not have a parameterized constructor, so I will run into an error if I do that.但是,旧的 class 没有参数化构造函数,所以如果我这样做会遇到错误。

  • Are there any tricks how I don't have to call the super constructor?有什么技巧可以让我不必调用超级构造函数吗?
  • Maybe there is a way using reflection to do what I want?也许有一种方法可以使用反射来做我想做的事?

Your example is a bit odd, as the new class example contains a reference to your MyConfiguration .您的示例有点奇怪,因为新的 class 示例包含对您的MyConfiguration的引用。

Generally, you're better off maintaining two versions of your MyConfiguration class or dropping support for the old version of that library.通常,您最好维护两个版本的MyConfiguration class 或放弃对该库旧版本的支持。 Or, consider not to use a library that makes such drastic changes.或者,考虑不要使用做出如此剧烈变化的库。

For completeness, there is a hack addressing your literal question.为了完整起见,有一个技巧可以解决您的字面问题。 Assuming that the class Configuration is not serializable as shown or at least, the old version isn't, you can utilize a specific Serialization behavior.假设 class Configuration不可序列化,或者至少旧版本不是,您可以利用特定的序列化行为。 When a serializable class extends a non-serializable class, deserializing an instance of it will cause the invocation of the superclass's default constructor.当可序列化的 class 扩展不可序列化的 class 时,反序列化它的实例将导致调用超类的默认构造函数。

So, the code utilizing it could look like:因此,使用它的代码可能如下所示:

public class MyConfiguration extends Configuration implements Serializable {
    public MyConfiguration(
        boolean isCool, Map<String, String> entries, Object otherThing) {
        super(isCool, entries, otherThing);
        // new version setup
    }
  
    private void readObject(java.io.ObjectInputStream in)
                                          throws IOException, ClassNotFoundException {
        // old version, Configuration's default constructor has been called
    }
  
    public static MyConfiguration create() {
        return new ByteArrayOutputStream() {
            MyConfiguration get() {
                final short numFields = 0;
                try {
                    Configuration.class.getConstructor(); // check for old version
                    DataOutputStream os = new DataOutputStream(this);
                    // using import static java.io.ObjectStreamConstants.*;
                    os.writeShort(STREAM_MAGIC);
                    os.writeShort(STREAM_VERSION);
                    os.write(TC_OBJECT);
                    os.write(TC_CLASSDESC);
                    os.writeUTF(MyConfiguration.class.getName());
                    os.writeLong(ObjectStreamClass.lookup(MyConfiguration.class)
                                                  .getSerialVersionUID());
                    os.write(SC_SERIALIZABLE);
                    os.writeShort(numFields);
                    os.write(TC_ENDBLOCKDATA);
                    os.write(TC_NULL);
                    os.flush();
                    return (MyConfiguration)new ObjectInputStream(
                           new ByteArrayInputStream(buf, 0, count)).readObject();
                }
                catch(NoSuchMethodException ex) {
                    // new version
                    return new MyConfiguration(false, Map.of(), null);
                }
                catch(IOException|ClassNotFoundException ex) {
                    throw new AssertionError(ex);
                }
            }
        }.get();
    }

    public int doSomething() {
        //Some code...
        return -1;
    }
}

This class can be compiled against the new version.这个 class 可以针对新版本进行编译。 The create() method first checks for the presence of the default constructor. create()方法首先检查是否存在默认构造函数。 When absent, ie running with the new version, the new constructor is called.如果不存在,即使用新版本运行,则调用新的构造函数。 Otherwise, it deserializes an instance with a stream having no data, so after the superclass's default constructor has been called, the readObject may perform the actual setup.否则,它使用没有数据的 stream 反序列化一个实例,因此在调用超类的默认构造函数之后, readObject可能会执行实际设置。

This all requires a lazy verifier that doesn't care for the incompatible constructors, as long as no-one tries to actually invoke the constructor.这一切都需要一个惰性验证器,它不关心不兼容的构造函数,只要没有人尝试实际调用构造函数。 As said at the beginning, you're likely better off with other solutions.如开头所说,您可能会使用其他解决方案更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM