java序列化list

Java中我有一个List的类对象要输出,类已序列化。打算用ObjetOutputStream,但是怎么用?

java.util

类 ArrayListE

java.lang.Object

java.util.AbstractCollectionE

java.util.AbstractListE

java.util.ArrayListE

所有已实现的接口:

Serializable, Cloneable, IterableE, CollectionE, ListE, RandomAccess

直接已知子类:

AttributeList, RoleList, RoleUnresolvedList

确实 这个类是可以序列化的 直接做IO操作啊

几种Java序列化 对比

在java中socket传输数据时,数据类型往往比较难选择。可能要考虑带宽、跨语言、版本的兼容等问题。比较常见的做法有两种:一是把对象包装成JSON字符串传输,二是采用java对象的序列化和反序列化。随着Google工具protoBuf的开源,protobuf也是个不错的选择。对JSON,Object Serialize,ProtoBuf 做个对比。

定义一个待传输的对象UserVo:

Java代码

public class User{

private String name;

private int age;

private long phone;

private ListUser friends;

}

初始化User的实例src:

Java代码

User user1 = new UserVo();

user1 .setName(“user1 “);

user1 .setAge(30);

user1 .setPhone(13789126278L);

UserVo f1 = new UserVo();

f1.setName(“tmac”);

f1.setAge(32);

f1.setPhone(123L);

User user2 = new User();

user2 .setName(“user2 “);

user2 .setAge(29);

user2 .setPhone(123L);

ListUser friends = new ArrayListUser();

friends.add(user1 );

friends.add(user2 );

user1 .setFriends(friends);

JSON格式

采用Google的gson-2.2.2.jar 进行转义

Java代码

Gson gson = new Gson();

String json = gson.toJson(src);

得到的字符串:

Js代码

{“name”:”user1 “,”age”:30,”phone”:123,”friends”:[{“name”:”user1 “,”age”:32,”phone”:123},{“name”:”user2 “,”age”:29,”phone”:123}]}

字节数为153

Json的优点:明文结构一目了然,可以跨语言,属性的增加减少对解析端影响较小。缺点:字节数过多,依赖于不同的第三方类库。

Object Serialize

UserVo实现Serializalbe接口,提供唯一的版本号:

Java代码

public class User implements Serializable{

private static final long serialVersionUID = -5726374138698742258L;

private String name;

private int age;

private long phone;

private ListUser friends;

序列化方法:

Java代码

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream os = new ObjectOutputStream(bos);

os.writeObject(src);

os.flush();

os.close();

byte[] b = bos.toByteArray();

bos.close();

字节数是238

反序列化:

Java代码

ObjectInputStream ois = new ObjectInputStream(fis);

vo = (UserVo) ois.readObject();

ois.close();

fis.close();

Object Serializalbe 优点:java原生支持,不需要提供第三方的类库,使用比较简单。缺点:无法跨语言,字节数占用比较大,某些情况下对于对象属性的变化比较敏感。

对象在进行序列化和反序列化的时候,必须实现Serializable接口,但并不强制声明唯一的serialVersionUID

是否声明serialVersionUID对于对象序列化的向上向下的兼容性有很大的影响。我们来做个测试:

思路一

把User中的serialVersionUID去掉,序列化保存。反序列化的时候,增加或减少个字段,看是否成功。

Java代码

public class User implements Serializable{

private String name;

private int age;

private long phone;

private ListUserVo friends;

保存到文件中:

Java代码

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream os = new ObjectOutputStream(bos);

os.writeObject(src);

os.flush();

os.close();

byte[] b = bos.toByteArray();

bos.close();

FileOutputStream fos = new FileOutputStream(dataFile);

fos.write(b);

fos.close();

增加或者减少字段后,从文件中读出来,反序列化:

Java代码

FileInputStream fis = new FileInputStream(dataFile);

ObjectInputStream ois = new ObjectInputStream(fis);

vo = (User) ois.readObject();

ois.close();

fis.close();

结果:抛出异常信息

Java代码

Exception in thread “main” java.io.InvalidClassException: serialize.obj.UserVo; local class incompatible: stream classdesc serialVersionUID = 3305402508581390189, local class serialVersionUID = 7174371419787432394

at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)

at serialize.obj.ObjectSerialize.read(ObjectSerialize.java:74)

at serialize.obj.ObjectSerialize.main(ObjectSerialize.java:27)

思路二

eclipse指定生成一个serialVersionUID,序列化保存,修改字段后反序列化

略去代码

结果:反序列化成功

结论

如果没有明确指定serialVersionUID,序列化的时候会根据字段和特定的算法生成一个serialVersionUID,当属性有变化时这个id发生了变化,所以反序列化的时候就会失败。抛出“本地classd的唯一id和流中class的唯一id不匹配”。

jdk文档关于serialVersionUID的描述:

写道

如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 — serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

Google ProtoBuf

protocol buffers 是google内部得一种传输协议,目前项目已经开源()。它定义了一种紧凑得可扩展得二进制协议格式,适合网络传输,并且针对多个语言有不同得版本可供选择。

以protobuf-2.5.0rc1为例,准备工作:

下载源码,解压,编译,安装

Shell代码

tar zxvf protobuf-2.5.0rc1.tar.gz

./configure

./make

./make install

测试:

Shell代码

MacBook-Air:~ ming$ protoc –version

libprotoc 2.5.0

安装成功!进入源码得java目录,用mvn工具编译生成所需得jar包,protobuf-java-2.5.0rc1.jar

1、编写.proto文件,命名UserVo.proto

Text代码

package serialize;

option java_package = “serialize”;

option java_outer_classname=”UserVoProtos”;

message User{

optional string name = 1;

optional int32 age = 2;

optional int64 phone = 3;

repeated serialize.UserVo friends = 4;

}

2、在命令行利用protoc 工具生成builder类

Shell代码

protoc -IPATH=.proto文件所在得目录 –java_out=java文件的输出路径 .proto的名称

得到UserProtos类

3、编写序列化代码

Java代码

UserVoProtos.User.Builder builder = UserVoProtos.User.newBuilder();

builder.setName(“Yaoming”);

builder.setAge(30);

builder.setPhone(13789878978L);

UserVoProtos.UserVo.Builder builder1 = UserVoProtos.UserVo.newBuilder();

builder1.setName(“tmac”);

builder1.setAge(32);

builder1.setPhone(138999898989L);

UserVoProtos.UserVo.Builder builder2 = UserVoProtos.UserVo.newBuilder();

builder2.setName(“liuwei”);

builder2.setAge(29);

builder2.setPhone(138999899989L);

builder.addFriends(builder1);

builder.addFriends(builder2);

UserVoProtos.UserVo vo = builder.build();

byte[] v = vo.toByteArray();

字节数53

4、反序列化

Java代码

UserVoProtos.UserVo uvo = UserVoProtos.UserVo.parseFrom(dstb);

System.out.println(uvo.getFriends(0).getName());

结果:tmac,反序列化成功

google protobuf 优点:字节数很小,适合网络传输节省io,跨语言 。缺点:需要依赖于工具生成代码。

工作机制

proto文件是对数据的一个描述,包括字段名称,类型,字节中的位置。protoc工具读取proto文件生成对应builder代码的类库。protoc xxxxx –java_out=xxxxxx 生成java类库。builder类根据自己的算法把数据序列化成字节流,或者把字节流根据反射的原理反序列化成对象。官方的示例:。

proto文件中的字段类型和java中的对应关系:

详见:

.proto Type java Type c++ Type

double double double

float float float

int32 int int32

int64 long int64

uint32 int uint32

unint64 long uint64

sint32 int int32

sint64 long int64

fixed32 int uint32

fixed64 long uint64

sfixed32 int int32

sfixed64 long int64

bool boolean bool

string String string

bytes byte string

字段属性的描述:

写道

required: a well-formed message must have exactly one of this field.

optional: a well-formed message can have zero or one of this field (but not more than one).

repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.

protobuf 在序列化和反序列化的时候,是依赖于.proto文件生成的builder类完成,字段的变化如果不表现在.proto文件中就不会影响反序列化,比较适合字段变化的情况。做个测试:

把UserVo序列化到文件中:

Java代码

UserProtos.User vo = builder.build();

byte[] v = vo.toByteArray();

FileOutputStream fos = new FileOutputStream(dataFile);

fos.write(vo.toByteArray());

fos.close();

为User增加字段,对应的.proto文件:

Text代码

package serialize;

option java_package = “serialize”;

option java_outer_classname=”UserVoProtos”;

message User{

optional string name = 1;

optional int32 age = 2;

optional int64 phone = 3;

repeated serialize.UserVo friends = 4;

optional string address = 5;

}

从文件中反序列化回来:

Java代码

FileInputStream fis = new FileInputStream(dataFile);

byte[] dstb = new byte[fis.available()];

for(int i=0;idstb.length;i++){

dstb[i] = (byte)fis.read();

}

fis.close();

UserProtos.User uvo = UserProtos.User.parseFrom(dstb);

System.out.println(uvo.getFriends(0).getName());

成功得到结果。

三种方式对比传输同样的数据,google protobuf只有53个字节是最少的。结论:

方式 优点 缺点

JSON 跨语言、格式清晰一目了然

字节数比较大,需要第三方类库

Object Serialize java原生方法不依赖外部类库 字节数比较大,不能跨语言

Google protobuf 跨语言、字节数比较少

编写.proto配置用protoc工具生成对应的代码

怎么将java中list中的数据序列化到数据库中,方便存取

请注意看如下代码:

public List getObject(String sql, Object[] object) { //sql执行语句,object是你sql语句里面的参数

List list = new ArrayList();

Connection con = null;

PreparedStatement pre = null;

ResultSet rs = null;

try{

con = C3P0Util.getInstance().getConnection(); //这是你获得数据库连接,你把这里改成调用你自己写的jdbc方法

pre = con.prepareStatement(sql); //执行sql语句

if(object!=null){

for(int i=0;iobject.length;i++){

pre.setObject(i+1, object[i]); //给sql里面的参数进行赋值

}

}

rs = pre.executeQuery();

while(rs.next()){

Users u = new User();

u.setUserName(rs.getString(“UserName”));

u.setUserPas(rs.getString(“UserPas”)); list.add(u);

}

}catch(Exception e){

e.printStackTrace();

return null;

}finally{

C3P0Util.close(con, pre, rs); //关闭数据库资源

}

return list; //返回list集合

}

注意:list里面保存的是User对象的信息

你要获得User对象的信息,那么就要遍历list

for(int i=0;ilist.size;i++){

User u = (User)list.get(i); System.out.println(“UserName:”+u.getUserName());

System.out.println(“UserPas:”+u.getUserPas());

} 上面是针对list里面有很多个User对象,当然list里面只有一个User对象,也是可以的。

如果你的list里面只有一个User,那么可以直接:User u = (User)list.get(0);

System.out.println(“UserName:”+u.getUserName());

System.out.println(“UserPas:”+u.getUserPas());

希望对你有帮助!

java序列化list

java list能被序列化吗

实现了java.io.Serializable接口才能被序列化,而list本身是一个接口,也没继承java.io.Serializable,不存在序列化一说,但是它的子类ArrayList是可以被序列化的:

public class ArrayListE extends AbstractListE

implements ListE, RandomAccess, Cloneable, java.io.Serializable

本文来自投稿,不代表【】观点,发布者:【

本文地址: ,如若转载,请注明出处!

举报投诉邮箱:253000106@qq.com

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年3月25日 10:03:30
下一篇 2024年3月25日 10:09:44

相关推荐

  • laravel调用java服务,laravel use

    amh不支持部署laravel框架么 它由两个主要部分组成:WEB服务器允许从一个原则的JavaScript跟着AJAX的Servlet(小应用程序)来获得,另一方面数据的JavaScript库,可以帮助Web开发人员能够轻松地采取收购优势。数据,以动态地改变网页的内容。 Composer安装完成后,下载最新版Laravel框架,把它解压缩到你服务器上的一个…

    2024年5月18日
    2900
  • java访问控制修饰符,java中访问控制修饰符

    java中类成员的访问修饰符有哪些 1、成员变量修饰符:(1)public(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问。(2)private(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。 2、一:访问修饰符:省略访问修饰符 具有默认的访问特性,即具有包访问特性,只能被同一个包中的类使用。…

    2024年5月18日
    3600
  • ios推送java,IOS推送服务

    Java服务器端如何接收IOS远程推送传递来的devicetoken 只要可以接受到推送消息就可以获取到deviceToken,那么就需要推送证书打包,并且uexWidget.setPushState(1),还要在应用提示“**想给您发送推送通知”时,点“好”。 iOS开发怎么实现消息推送机制,操作的方法如下:首先应用程序要注册好消息推送。IOS跟服务器设备…

    2024年5月18日
    3000
  • c语言listnode,c语言list用法

    C语言中,p=(ListNode*)malloc(sizeof(ListNode))具体什么意思, malloc自身的类型为void *.这里(ListNode *)就是强制转换为ListNode 指针类型。 通过malloc申请sizeof(listnode) 大小的一段连续内存空间,并将该空间地址首地址(指针)强制转换成listnode* 类型,并赋值给…

    2024年5月18日
    3100
  • java构造list,java构造领接表

    java中List的用法?尽量详细解释,包括例子。 1、采用循环的方法。通过循环第一个ArrayList,然后通过每循环一次的方式,将值赋值给另一个ArrayList。具体代码实现如下:采用ArrayList自带的addAll()方法。 2、LinkedListLei();这样list就只能add Lei 类型的对象,list.get(int i)获得的也是…

    2024年5月18日
    3200
  • java接口变量finall,JAVA变量

    java中Finally到底起的是什么作用??? 无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,finally代码块仍然会被执行。最后要说的是,finally代码块主要用来释放资源,比如:I/O缓冲区,数据库连接。 Finally是一个副词,表示最终或最后。常用于描述某件事物经过长时间或多次努力之后得到实…

    2024年5月18日
    4200
  • java异常继承图,JAVA继承的好处

    请问这两个java类图怎么看,里面的箭头哪个表示继承,哪个表示关联,关联… https:// 如果你需要有偿辅导服务的话,也可以私信我。 泛化/继承(Generalization):实线+三角形空心 相当于类继承,父参与者可以是抽象的,即不能创建一个父参与者的直接实例,这就要求属于抽象父参与者的外部对象一定能够属于其子参与者之一。 在Java中继…

    2024年5月18日
    3800
  • 关于上海5年java的信息

    java工资一般多少 1、以北京为例:北京的Java程序员的月平均工资为一万元左右,应届毕业生的月平均工资为五千元左右,工作年限越长,经验越多,能力越强,职位越高,工资也会越多。 2、初级java工程师:待遇一般在4000以上,8000以下。工作两年以内。中级java工程师:待遇一般是在8000-10000左右,工作5年以内 高级java工程师:待遇1000…

    2024年5月18日
    3500
  • 查看java安装路径linux,查看java安装路径命令

    linux查看java进程命令? 1、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。 pstack:Linux命令。 2、没有“应该显示几个”的规定,运行了几个就是几个。这一大堆内容是一个java进程,可执行文件是/jdk0_144/bin/ja…

    2024年5月18日
    3900
  • java日历框包,用java编写日历添加窗口

    用java做一个日历显示数据功能,在页面上显示日期数据。 主要功能包括显示当月的日历表,当日特殊显示。一定要用JAVA语言写。谢谢了eryaruoshui@12com… 主要功能包括显示当月的日历表 ,当日特殊显示。 一定要用JAVA语言写。 一个就是用了java.awt和javax.swing的,应该是叫JAVA桌面应用程序吧。日历是能做出来,…

    2024年5月18日
    3600

发表回复

登录后才能评论



关注微信