Java 在构造函数中调用虚方法-更好的设计
我用java声明了一个ISerializable接口 我基本上有两种方法:Java 在构造函数中调用虚方法-更好的设计,java,oop,design-patterns,Java,Oop,Design Patterns,我用java声明了一个ISerializable接口 我基本上有两种方法:serialize(),和反序列化(byte[]buffer) 下面是一个实现此接口的类的示例: public class MySerializableClass implements ISerializable{ byte[] serialize(){bla bla} deserialize(byte[] buffer){bla bla}; } 理想情况下,我希望对deserialize的调用是隐
serialize()
,和反序列化(byte[]buffer)
下面是一个实现此接口的类的示例:
public class MySerializableClass implements ISerializable{
byte[] serialize(){bla bla}
deserialize(byte[] buffer){bla bla};
}
理想情况下,我希望对deserialize
的调用是隐式的。i、 e.当调用构造函数MySerializableClass(byte[]buffer)
时,它将在传递缓冲区的情况下调用正确的反序列化。就像这样:
public abstract class AbstractSerializable {
public abstract byte[] serialize();
public abstract void deserialize(byte[] buffer);
public AbstractSerializable (){}
public AbstractSerializable (byte[] buffer){
deserialize();
}
}
public class MySerializableClass extends AbstractSerializable {
byte[] serialize(){bla bla}
deserialize(byte[] buffer){bla bla};
}
AFAIK在构造函数中调用虚拟方法是有问题的,这可能会导致未定义的行为。
因此,目前,我正在做以下工作:
MySerializableClass myClass = new MySerializableClass();
myClass.deserialize(buffer);
或者使用为扩展接口的每个类定义的专用静态方法(基本上只需执行上述两行代码):
我的问题是:有没有一种优雅的方法可以做到这一点,而不需要为每个实现ISerializable的类定义一个专用的静态方法?有没有解决这个问题的设计模式
注意:我的序列化是唯一的,因此我需要自己编写,而且出于技术原因,我只能使用Java的非常基本的功能。(无注释、模板元数据等),因此我需要一个非常基本的OOP解决方案。另一个解决方案是删除无参数构造函数
,因此您的具体类必须使用参数构造函数初始化 我觉得您的解决方案足够优雅,您所做的是一个,这是解决您的问题的优雅方式。您可以将构造函数保持私有,并始终通过工厂检索对象
public class MySerializableClass extends AbstractSerializable {
private MySerializableClass(){
}
public static MySerializableClass CreateMySerializableClass(final byte[] buffer){
MySerializableClass result = new MySerializableClass();
result.deserialize(buffer)
return result;
}
byte[] serialize(){bla bla}
deserialize(byte[] buffer){bla bla};
}
在进行序列化时,我不会传递字节数组,而是使用and。然后可以声明接口ISerializable
,例如:
public interface ISerializable{
void serialize(DataOutput out) throws IOException;
void deserialize(DataInput in) throws IOException;
}
然后,您可以提供静态实用程序方法,当提供一些DataOutput/DataInput时,这些方法能够序列化和反序列化ISerializable
的实例。静态反序列化方法还可以调用可能的构造函数,该构造函数接受DataInput作为其唯一参数
以下是此方法的完整示例代码,其中还包括用于测试序列化的主要方法:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class SerializableTest {
public interface ISerializable{
void serialize(DataOutput out) throws IOException;
void deserialize(DataInput in) throws IOException;
}
/**
* Writes the given ISerializable to the given DataOutput.
*/
public static void writeSerializable(ISerializable s, DataOutput out) throws IOException{
writeClass(out, s.getClass());
s.serialize(out);
}
/**
* Reads an ISerializable from the given DataInput.
*/
public static ISerializable readSerializable(DataInput in, ClassLoader cl) throws IOException{
ISerializable element = null;
Class<?> c;
try {
c = readClass(in, cl);
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
try {
try {
// see if the class has a constructor that accepts a DataInput
Constructor<?> constructor= c.getDeclaredConstructor(DataInput.class);
constructor.setAccessible(true);
return (ISerializable)constructor.newInstance(in);
} catch (NoSuchMethodException e) {
//ignore
}
element = (ISerializable) newInstance(c);
element.deserialize(in);
} catch (Exception e) {
throw new IOException("Could not deserialize the class" + c.getName());
}
return element;
}
private static <T> T newInstance(Class<T> c) throws IOException {
T element = null;
Constructor<T> constructor;
try {
constructor = c.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
element = constructor.newInstance();
} catch (NoSuchMethodException | InstantiationException |
IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
throw new IOException(e);
}
return element;
}
private static void writeClass(DataOutput out, Class<?> c) throws IOException {
out.writeUTF(c.getName());
}
private static Class<?> readClass(DataInput in, ClassLoader cl) throws IOException, ClassNotFoundException {
String name = in.readUTF();
return cl.loadClass(name);
}
// some test classes for testing serialization in the main method
public static class TestClass implements ISerializable{
private String data;
protected TestClass() {
// ISerializable no argument constructor
super();
}
public TestClass(String data) {
super();
this.data = data;
}
@Override
public void serialize(DataOutput out) throws IOException {
out.writeUTF(data);
}
@Override
public void deserialize(DataInput in) throws IOException {
this.data = in.readUTF();
}
}
public static class TestClass2 implements ISerializable{
private final String data;
protected TestClass2(DataInput in) throws IOException {
// ISerializable DataInput constructor
super();
this.data = in.readUTF();
}
public TestClass2(String data) {
super();
this.data = data;
}
@Override
public void serialize(DataOutput out) throws IOException {
out.writeUTF(data);
}
@Override
public void deserialize(DataInput in) throws IOException {
throw new UnsupportedOperationException();
}
}
// tests serialization and deserialization of two test classes
public static void main(String[] args) {
TestClass t1 = new TestClass("TestClass 1");
TestClass2 t2 = new TestClass2("TestClass 2");
File file = new File("testfile");
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return;
}
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
writeSerializable(t1, out);
writeSerializable(t2, out);
} catch (IOException e) {
e.printStackTrace();
return;
}finally{
if (out != null) {
try {
out.close();
} catch (IOException e) {}
}
}
DataInputStream in = null;
try {
in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
ClassLoader cl = SerializableTest.class.getClassLoader();
TestClass loadedClass1 = (TestClass) readSerializable(in, cl);
TestClass2 loadedClass2 = (TestClass2) readSerializable(in, cl);
System.out.println("loadedClass1.data: " + loadedClass1.data);
System.out.println("loadedClass2.data: " + loadedClass2.data);
} catch (IOException e) {
e.printStackTrace();
return;
} finally{
if (in != null) {
try {
in.close();
} catch (IOException e) {}
}
}
}
}
import java.io.BufferedInputStream;
导入java.io.BufferedOutputStream;
导入java.io.DataInput;
导入java.io.DataInputStream;
导入java.io.DataOutput;
导入java.io.DataOutputStream;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.lang.reflect.Constructor;
导入java.lang.reflect.InvocationTargetException;
公共类SerializableTest{
公共接口ISerializable{
void序列化(DataOutput out)抛出IOException;
void反序列化(DataInput-in)抛出IOException;
}
/**
*将给定的ISerializable写入给定的DataOutput。
*/
公共静态void writeSerializable(ISerializable s,DataOutput out)引发IOException{
writeClass(out,s.getClass());
s、 序列化(输出);
}
/**
*从给定的数据输入读取ISerializable。
*/
公共静态ISerializable readSerializable(DataInput in,ClassLoader cl)引发IOException{
ISerializable元素=null;
丙级;;
试一试{
c=读级(in,cl);
}catch(classnotfounde异常){
抛出新的IOException(e);
}
试一试{
试一试{
//查看类是否具有接受数据输入的构造函数
构造函数=c.getDeclaredConstructor(DataInput.class);
constructor.setAccessible(true);
返回(ISerializable)构造函数.newInstance(in);
}捕获(无此方法例外){
//忽略
}
元素=(ISerializable)newInstance(c);
元素。反序列化(在中);
}捕获(例外e){
抛出新IOException(“无法反序列化类”+c.getName());
}
返回元素;
}
私有静态T newInstance(类c)引发IOException{
T元素=null;
建造师;
试一试{
构造函数=c.getDeclaredConstructor();
如果(!constructor.isAccessible()){
constructor.setAccessible(true);
}
element=constructor.newInstance();
}catch(NoSuchMethodException |实例化异常|
IllegalAccessException | IllegalArgumentException |
调用目标异常(e){
抛出新的IOException(e);
}
返回元素;
}
私有静态void writeClass(DataOutput out,类c)引发IOException{
writeUTF(c.getName());
}
私有静态类readClass(DataInput in,ClassLoader cl)引发IOException,ClassNotFoundException{
字符串名称=in.readUTF();
返回cl.loadClass(名称);
}
//在main方法中测试序列化的一些测试类
公共静态类TestClass实现ISerializable{
私有字符串数据;
受保护的TestClass(){
//ISerializable无参数构造函数
超级();
}
公共测试类(字符串数据){
超级();
这个数据=数据;
}
@凌驾
public void serialize(DataOutput out)引发IOException{
out.writeUTF(数据);
}
@凌驾
public void反序列化(DataInput in)引发IOException{
this.data=in.readUTF();
}
}
公共静态类TestClass2实现ISerializable{
私有最终字符串数据;
受保护的TestClass2(DataInput in)引发IOException{
//ISerializable数据输入构造函数
超级();
this.data=in.readUTF();
}
聚氨基甲酸酯
public interface ISerializable{
void serialize(DataOutput out) throws IOException;
void deserialize(DataInput in) throws IOException;
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class SerializableTest {
public interface ISerializable{
void serialize(DataOutput out) throws IOException;
void deserialize(DataInput in) throws IOException;
}
/**
* Writes the given ISerializable to the given DataOutput.
*/
public static void writeSerializable(ISerializable s, DataOutput out) throws IOException{
writeClass(out, s.getClass());
s.serialize(out);
}
/**
* Reads an ISerializable from the given DataInput.
*/
public static ISerializable readSerializable(DataInput in, ClassLoader cl) throws IOException{
ISerializable element = null;
Class<?> c;
try {
c = readClass(in, cl);
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
try {
try {
// see if the class has a constructor that accepts a DataInput
Constructor<?> constructor= c.getDeclaredConstructor(DataInput.class);
constructor.setAccessible(true);
return (ISerializable)constructor.newInstance(in);
} catch (NoSuchMethodException e) {
//ignore
}
element = (ISerializable) newInstance(c);
element.deserialize(in);
} catch (Exception e) {
throw new IOException("Could not deserialize the class" + c.getName());
}
return element;
}
private static <T> T newInstance(Class<T> c) throws IOException {
T element = null;
Constructor<T> constructor;
try {
constructor = c.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
element = constructor.newInstance();
} catch (NoSuchMethodException | InstantiationException |
IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
throw new IOException(e);
}
return element;
}
private static void writeClass(DataOutput out, Class<?> c) throws IOException {
out.writeUTF(c.getName());
}
private static Class<?> readClass(DataInput in, ClassLoader cl) throws IOException, ClassNotFoundException {
String name = in.readUTF();
return cl.loadClass(name);
}
// some test classes for testing serialization in the main method
public static class TestClass implements ISerializable{
private String data;
protected TestClass() {
// ISerializable no argument constructor
super();
}
public TestClass(String data) {
super();
this.data = data;
}
@Override
public void serialize(DataOutput out) throws IOException {
out.writeUTF(data);
}
@Override
public void deserialize(DataInput in) throws IOException {
this.data = in.readUTF();
}
}
public static class TestClass2 implements ISerializable{
private final String data;
protected TestClass2(DataInput in) throws IOException {
// ISerializable DataInput constructor
super();
this.data = in.readUTF();
}
public TestClass2(String data) {
super();
this.data = data;
}
@Override
public void serialize(DataOutput out) throws IOException {
out.writeUTF(data);
}
@Override
public void deserialize(DataInput in) throws IOException {
throw new UnsupportedOperationException();
}
}
// tests serialization and deserialization of two test classes
public static void main(String[] args) {
TestClass t1 = new TestClass("TestClass 1");
TestClass2 t2 = new TestClass2("TestClass 2");
File file = new File("testfile");
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return;
}
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
writeSerializable(t1, out);
writeSerializable(t2, out);
} catch (IOException e) {
e.printStackTrace();
return;
}finally{
if (out != null) {
try {
out.close();
} catch (IOException e) {}
}
}
DataInputStream in = null;
try {
in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
ClassLoader cl = SerializableTest.class.getClassLoader();
TestClass loadedClass1 = (TestClass) readSerializable(in, cl);
TestClass2 loadedClass2 = (TestClass2) readSerializable(in, cl);
System.out.println("loadedClass1.data: " + loadedClass1.data);
System.out.println("loadedClass2.data: " + loadedClass2.data);
} catch (IOException e) {
e.printStackTrace();
return;
} finally{
if (in != null) {
try {
in.close();
} catch (IOException e) {}
}
}
}
}
interface ISerializer
{
byte[] serialize(ISerializable serializable);
ISerializable deserialize(byte[] buffer);
}