JavaFX保存扩展类变量

时间:2015-10-12 02:45:40

标签: javafx

在我不断增长的应用程序中,我有一个包含大约50个变量的BaseClass。还有10个其他类从BaseClass扩展。原因是这10个类有许多共同的变量,但也有一些属于类本身。现在我试图保存每个扩展类,所以我必须将BaseClass变量与ClassX变量结合起来。这是一张图片:

enter image description here

我可以在每个ClassX中使用类似的东西:

super.saveData();
saveLocalData();

这意味着我只需要在BaseClass中提供一个saveData,但实际上很多重复的saveLocalData() - 10。

在每个班级中,我都可以通过以下方式获得变量列表:

Field[] vars = DisplayField.class.getDeclaredFields();

我可以像这样编写变量名和值:

bw.write(f.getName() + "=" + f.get(this) + "\n");

我可以为所有ClassX类做同样的事情并构建一个类似的文本文件。

然后让我感到震惊的是,如果我可以从FileIOClass到达每个ClassX的BaseClass,我可以只有一个saveData()(由两部分组成)。我可以得到:

for (DisplayField field : fieldList) // Iterate all the CLassX's
field.getClass().getSuperclass().getDeclaredMethod("saveDisplayField").invoke(bw);

然后我被卡住了。任何人都可以解开'我或者我只是在这里咆哮错误的树?

2 个答案:

答案 0 :(得分:0)

您正在限制自己,并认为您只需要基本类型(目前),使您的应用程序无法扩展。

您的问题有各种解决方案。你可以。 G。使用JAXB来保存分层数据结构,它已经附带Java。

这是一个简单的例子:

BaseClass.java

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({
    Class1.class,
    Class2.class
})
@XmlRootElement(name = "Base")
public class BaseClass {

    @XmlAttribute(name = "var1", required = true)
    protected int var1;
    @XmlAttribute(name = "var2", required = true)
    protected int var2;
    @XmlAttribute(name = "var3", required = true)
    protected int var3;

    public String toString() {
        return "var1=" + var1 + ", " + "var2=" + var2 + ", " + "var3=" + var3;
    }
}

Class1.java

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Class1")
public class Class1 extends BaseClass {

    @XmlAttribute(name = "varX", required = false)
    protected int varX;
    @XmlAttribute(name = "varY", required = false)
    protected int varY;

    public String toString() {
        return "var1=" + var1 + ", " + "var2=" + var2 + ", " + "var3=" + var3 + ", varX=" + varX + ", varY=" + varY;
    }

}

Class2.java

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Class2")
public class Class2 extends BaseClass {

    @XmlAttribute(name = "varA", required = false)
    protected int varA;
    @XmlAttribute(name = "varB", required = false)
    protected int varB;

    public String toString() {
        return "var1=" + var1 + ", " + "var2=" + var2 + ", " + "var3=" + var3 + ", varA=" + varA + ", varB=" + varB;
    }

}

Main.java

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class XmlExample {
    public static void main(String[] args) {

        // marshal base
        BaseClass base = new BaseClass();
        base.var1=1;
        base.var2=2;
        base.var3=3;

        String baseXml = marshal( base);

        // marshal class1
        Class1 class1 = new Class1();
        class1.var1=1;
        class1.var2=2;
        class1.var3=3;
        class1.varX=10;
        class1.varY=20;

        String class1Xml = marshal( class1);

        // marshal class2
        Class2 class2 = new Class2();
        class2.var1=1;
        class2.var2=2;
        class2.var3=3;
        class2.varA=40;
        class2.varB=50;

        String class2Xml = marshal( class2);

        // unmarshal base
        unmarshal(baseXml);

        // unmarshal class1
        unmarshal(class1Xml);

        // unmarshal class2
        unmarshal(class2Xml);

        System.exit(0);
    }

    public static String marshal( BaseClass base) {

        try {

            JAXBContext jaxbContext = JAXBContext.newInstance(BaseClass.class);

            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            StringWriter stringWriter = new StringWriter();
            jaxbMarshaller.marshal(base, stringWriter);
            String xml = stringWriter.toString();

            System.out.println("XML:\n" + xml);

            return xml;

        } catch (Exception e) {
            throw new RuntimeException( e);
        }

    }

    public static void unmarshal( String xml) {

        try {

            JAXBContext jaxbContext = JAXBContext.newInstance(BaseClass.class);

            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            StringReader stringReader = new StringReader(xml);

            Object clazz = (Object) jaxbUnmarshaller.unmarshal(stringReader);

            // create/cast here whatever class you need
            if( clazz.getClass().isAssignableFrom( BaseClass.class)) {
                System.out.println( "BaseClass:");
            }
            else if( clazz.getClass().isAssignableFrom( Class1.class)) {
                System.out.println( "Class1:");
            }
            else if( clazz.getClass().isAssignableFrom( Class2.class)) {
                System.out.println( "Class2:");
            }

            System.out.println( clazz + "\n");

        } catch (Exception e) {
            throw new RuntimeException( e);
        }

    }
}

控制台输出:

XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Base var1="1" var2="2" var3="3"/>

XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Class1 varX="10" varY="20" var1="1" var2="2" var3="3"/>

XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Class2 varA="40" varB="50" var1="1" var2="2" var3="3"/>

BaseClass:
var1=1, var2=2, var3=3

Class1:
var1=1, var2=2, var3=3, varX=10, varY=20

Class2:
var1=1, var2=2, var3=3, varA=40, varB=50

您可以使用这种非常方便的序列化任何类型的对象,甚至是需要像日期对象这样的对象的列表和格式。

即使你不打算这样做,我也绝不会将反射用于那种要求。而是在每个类中实现某种“serializeToFile”接口。

答案 1 :(得分:0)

除了我的第一个答案,这是另一种不同的解决方案,一种使用反射(如你所愿),因为这是你的问题。但正如我在另一个答案中所说的那样,你要限制自己。

我创建了一个自定义注释,这样你仍然可以在bean中做任何你喜欢的事情。

注释:Persist.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})  
public @interface Persist {
}

BaseClass.java

public class BaseClass {

    @Persist
    Integer var1;

    @Persist
    Integer var2;

    @Persist
    Integer var3;

}

Class1.java

public class Class1 extends BaseClass {

    @Persist
    Integer varX;

    @Persist
    Integer varY;

}

Class2.java

public class Class2 extends BaseClass {

    @Persist
    Integer varA;

    @Persist
    Integer varB;

}

这就是你如何使用这些类并序列化它们的值:

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class MainApp {

    public static void log(BaseClass base) {

        System.out.println( "\nClass: " + base.getClass().getName());

        Class parent = base.getClass().getSuperclass();
        while( parent != null) {
            logFields( base, parent);
            parent = parent.getSuperclass();
        }

        logFields( base, base.getClass());
    }

    public static void logFields(BaseClass obj, Class clazz) {

        try {

            for (Field field : clazz.getDeclaredFields()) {

                if (field.isAnnotationPresent(Persist.class)) {

                    Annotation annotation = field.getAnnotation(Persist.class);
                    Persist test = (Persist) annotation;

                    System.out.println(field.getName() + " = " + field.get(obj));

                }

            }

        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

    }

    public static void main(String[] args) throws Exception {

        BaseClass base = new BaseClass();
        base.var1 = 1;
        base.var2 = 2;
        base.var3 = 3;
        log(base);

        Class1 class1 = new Class1();
        class1.var1 = 4;
        class1.var2 = 5;
        class1.var3 = 6;
        class1.varX = 10;
        class1.varY = 20;
        log(class1);

        Class2 class2 = new Class2();
        class2.var1 = 7;
        class2.var2 = 8;
        class2.var3 = 9;
        class2.varA = 30;
        class2.varB = 40;
        log(class2);

        System.exit(0);
    }
}

控制台输出:

Class: BaseClass
var1 = 1
var2 = 2
var3 = 3

Class: Class1
var1 = 4
var2 = 5
var3 = 6
varX = 10
varY = 20

Class: Class2
var1 = 7
var2 = 8
var3 = 9
varA = 30
varB = 40

然后将数据序列化为您喜欢的任何类别的文件。