我想导航到对象的第N级,并以字符串格式序列化它的属性。例如:
class Animal {
public String name;
public int weight;
public Animal friend;
public Set<Animal> children = new HashSet<Animal>() ;
}应该像这样序列化:
{name:"Monkey",
weight:200,
friend:{name:"Monkey Friend",weight:300 ,children:{...if has children}},
children:{name:"MonkeyChild1",weight:100,children:{... recursively nested}}
}您可能会注意到,它类似于将对象序列化为json。我知道有很多歌词(Gson,Jackson…)可以做到这一点,你能给我一些关于如何自己写这篇文章的指导性意见吗?
发布于 2010-04-12 23:24:28
序列化基本上就是深度克隆。
您需要跟踪每个对象引用的重现情况(例如,通过使用IdentityHashMap)。无论你的最终实现方法是什么(如果不是外部库),记得检查对象的重现,否则你可能会陷入无限循环(当对象A引用了对象B,而对象B又引用了对象A或对象图中更复杂的循环)。
一种方法是使用类似DFS的算法遍历对象图,并从那里构建克隆(序列化字符串)。
这段伪代码有望解释如何:
visited = {}
function visit(node) {
if node in visited {
doStuffOnReoccurence(node)
return
}
visited.add(node)
doStuffBeforeOthers(node)
for each otherNode in node.expand() visit(otherNode)
doStuffAfterOthers(node)
}示例中的访问集是我将使用标识集(如果有)或IdentityHashMap的地方。
在查找反射字段时(这是node.expand()部分),请记住也要遍历超类字段。
反射不应该用在“正常”的开发案例中。反射将代码作为数据处理,您可以忽略所有正常的对象访问限制。我只在测试中使用了这个反射深度拷贝的东西:
发布于 2010-04-12 23:27:07
Google Gson可以在一行中完成此特定任务:
String json = new Gson().toJson(animal);顺便说一下,另一种方法也很简单:
Animal animal = new Gson().fromJson(json, Animal.class);我还没有看到另一个JSON序列化程序能够更好地支持泛型、集合/映射和(嵌套的) javabeans。
更新:说到这一点,你只需要了解反射。我建议您先完成Sun tutorial on the subject。简而言之,您可以使用Object#getClass()以及java.lang.Class、java.lang.reflect.Method等提供的所有方法来确定其中的哪一个。Google Gson是开源的,你也可以从中受益。
发布于 2010-04-12 23:32:24
一种简单的方法是使用访问者模式来,使您的编码实现与业务对象分离。有些人会争辩说,您可以简单地将Externalizable接口与readExternal / writeExternal一起实现,但这有以下问题:
示例
/**
* Our visitor definition. Includes a visit method for each
* object it is capable of encoding.
*/
public interface Encoder {
void visitAnimal(Animal a);
void visitVegetable(Vegetable v);
void visitMineral(Mineral m);
}
/**
* Interface to be implemented by each class that can be encoded.
*/
public interface Encodable {
void applyEncoder(Encoder e);
}
public class Animal implements Encodable {
public void applyEncoder(Encoder e) {
// Make call back to encoder to encode this particular Animal.
// Different encoder implementations can be passed to an Animal
// *without* it caring.
e.visitAnimal(this);
}
}通常,人们会定义一个有状态的Encoder实现,当OutputStream的visitXXX方法被调用时,它将把每个对象“推”到一个each中;
public class EncoderImpl implements Encoder {
private final DataOutputStream daos;
public EncoderImpl(File file) throws IOException {
this.daos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
}
public void visitAnimal(Animal a) {
daos.writeInt(a.getWeight());
daos.writeUTF(a.getName());
// Write the number of children followed by an encoding of each child animal.
// This allows for easy decoding.
daos.writeInt(a.getChildren().size());
for (Animal child : a.getChildren()) {
visitAnimal(child);
}
}
// TODO: Implement other visitXXX methods.
/**
* Called after visiting each object that requires serializing.
*/
public void done() {
daos.close();
}
}https://stackoverflow.com/questions/2623091
复制相似问题