mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签
所有文章 友链 关于我

mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签

Java学习笔记11

2017-12-28

day12

NIO

java.nio.ByteBuffer,这个类有写模式和读模式,区别在于我们对缓冲区写后,limit处于最大的分配长度,需要调用flip()用来改为读模式,这样limit就为我们写入的实际数据的长度,并且开始的位置归到0。

缓冲器有四个标志:

  • mark

  • position

  • limit

  • capacity

内存映射文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class LargeMappedFiles {
static int length=0x8FFFFFF;//128MB
public static void main(String[] main)throws Exception{
MappedByteBuffer out=new RandomAccessFile("test.dat", "rw")
.getChannel().map(FileChannel.MapMode.READ_WRITE,0, length);
for(int i=0;i<length;i++){
out.put((byte)'x');
}
for(int i=length/2;i<length/2+6;i++){
System.out.println((char)out.get(i));
}
}
}

通过调用getChannel返回一个通道,然后调用map方法,指定映射的范围,返回一个MappedByteBuffer类缓冲器,可以进行所有缓冲器的操作。

测试性能代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package io;
import java.util.*;
import javax.swing.event.TreeSelectionEvent;
import org.omg.CosNaming.NamingContextExtPackage.StringNameHelper;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class MappedIO {
private static int numOfInts=4000000;
private static int numOfUbuffInts=200000;
private static String filename="temp.tmp";
private abstract static class Tester{
private String name;
public Tester(String name){this.name=name;}
public abstract void test()throws IOException;
public void runTest(){
System.out.print(name+": ");
try{
long start=System.nanoTime();
test();
double time=(System.nanoTime()-start)/1.0e9;
System.out.println(time);
}catch (IOException e) {
throw new RuntimeException(e);// TODO: handle exception
}
}
}
private static Tester[] tests={new Tester("Stream Write"){
public void test()throws IOException{
DataOutputStream out=new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File(filename)
)
)
);
for(int i=0;i<numOfInts;i++)
out.writeInt(i);
out.close();
}
},
new Tester("Mapped Write"){
public void test()throws IOException{
FileChannel fc=new RandomAccessFile(filename,"rw")
.getChannel();
IntBuffer out=
fc.map(FileChannel.MapMode.READ_WRITE,0,fc.size()).asIntBuffer();
for(int i=0;i<numOfInts;i++){
out.put(i);
}
fc.close();
}
},
new Tester("Stream Read"){
public void test()throws IOException{
DataInputStream in=new DataInputStream(
new BufferedInputStream(
new FileInputStream(filename)
)
);
for(int i=0;i<numOfInts;i++){
in.readInt();
}
}
},
new Tester("Maped Read"){
public void test()throws IOException{
FileChannel fc=new RandomAccessFile(filename,"rw").getChannel();
IntBuffer ip=fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).asIntBuffer();
while(ip.hasRemaining()){
ip.get();
}
fc.close();
}
}
};
public static void main(String[] args){
for(Tester t:tests){
t.runTest();
}
}
}/*output
Stream Write: 0.935622322
Mapped Write: 0.20189704
Stream Read: 0.807558947
Maped Read: 0.048553753
*/

性能上来说,映射读写速度远大于缓冲io,不过容易频繁换页。

对象序列化

目的:对象在进程结束后自动销毁,为了让对象能继续存在使得下一次运行程序能直接使用。

用途:支持两种特性,一是Java的远程方法调用,使得存活于其他计算机上的对象使用起来就像是存活于本机上一样,当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。二是在JAVAbeans中的应用。

注意,对象序列化关注对象的“状态”,不会关注对象的静态变量。

下面是一个存储、恢复实例,用到了一个worm类能迭代引用多个worm,这个例子说明了恢复时不仅能恢复对象本身的状态,还能恢复对象引用的其他对象的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class Data implements Serializable{
private int n;
public Data(int n) {
this.n=n;
}
public String toString(){
return Integer.toString(n);
}
}
public class Worm implements Serializable {
private static Random rand=new Random(47);
private Data[] datas={
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10))
};
private Worm next;
private char c;
public Worm(int i,char x){
System.out.println("Worm constructor: "+i);
this.c=x;
if(--i>0)
next=new Worm(i, (char)(x+1));
else{
next=null;
}
}
public Worm(){
System.out.println("Default Constructor");
}
public String toString(){
StringBuilder result=new StringBuilder(":");
result.append(c);
result.append("(");
for(Data d:datas){
result.append(d+" ");
}
result.append(")");
if(this.next!=null){
result.append(this.next.toString());
}
return result.toString();
}
public static void main(String[] args)throws IOException,ClassNotFoundException{
Worm w=new Worm(6,'a');
System.out.println("w= "+w);
ObjectOutputStream out=new ObjectOutputStream(
new FileOutputStream("worm.out"));
out.writeObject("Worm storage\n");
out.writeObject(w);
out.close();
ObjectInputStream in=new ObjectInputStream(
new FileInputStream("worm.out"));
String s=(String)in.readObject();
Worm w2=(Worm)in.readObject();//没有调用任何构造器
System.out.println(s+"w= "+w2);
}
}/*output
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w= :a(8 5 3 ):b(1 1 9 ):c(8 0 2 ):d(7 8 8 ):e(1 9 9 ):f(8 8 1 )
Worm storage
w= :a(8 5 3 ):b(1 1 9 ):c(8 0 2 ):d(7 8 8 ):e(1 9 9 ):f(8 8 1 )
*/

可以从结果看到,整个过程没有调用任何构造器,对象直接从数据中恢复过来。

另外,我们在用序列化文件还原某个对象时,一定要有该对象的.class文件能被虚拟机找到。

序列化控制

考虑安全问题,希望序列化的对象中一部分内容不进行序列化,需要用Externalizable接口,这个接口继承了Serializable接口并增加了两个方法,*而且不同与前者的是,这个接口读取序列化对象时一定调用默认构造器,如果构造器没有public的话会报异常。下面这个例子展示了如何序列化部分内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
class Blip3 implements Externalizable{
private int i;
private String s;
public Blip3(){
System.out.println("Blip3 Constructor");
}
public Blip3(String x,int a){
System.out.println("Blip3(String,int) Constructor");
this.i=a;
this.s=x;
}
public String toString(){
return s+i;
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println("Blip2.writeExternal");
out.writeInt(i);
out.writeObject(s);
}
public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException{
System.out.println("Blip2.readExternal");
this.i=in.readInt();
this.s=(String)in.readObject();
}
}
public class Blips {
public static void main(String[] args)throws IOException,ClassNotFoundException{
System.out.println("Constructing objects:");
//Blip1 b1=new Blip1();
//Blip2 b2=new Blip2();
Blip3 b3=new Blip3("A",7);
ByteArrayOutputStream bout=new ByteArrayOutputStream();
ObjectOutputStream out=new ObjectOutputStream(bout);
//out.writeObject(b1);
//out.writeObject(b2);
out.writeObject(b3);
out.close();
ObjectInputStream in=new ObjectInputStream(
new ByteArrayInputStream(bout.toByteArray()));
Object b4=in.readObject();
//b4=in.readObject();
//b4=in.readObject();
System.out.println(b4.toString());
}
}/*output
Constructing objects:
Blip3(String,int) Constructor
Blip3.writeExternal
Blip3 Constructor
Blip3.readExternal
A7
*/

可以看到,我们需要实现两个方法writeExternal(ObjectOutput)和inputExternal(ObjectInput),在这两个方法中自己来定义要序列的内容和读取的内容。

transient

如果对继承了Serializable接口的对象中部分内容不想序列化,就得使用transient(瞬时)关键字来指定内容不可序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*
* 假如某个Login对象保存某个特定的登录会话信息,登录的合法性通过校验之后,
* 我们想把数据保存下来,但不包括密码
*/
import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Logon implements Serializable{
private Date date=new Date();
private String username;
private transient String password;
public Logon(String name,String pwd){
username=name;
password=pwd;
}
public String toString(){
return "Logon info:\nusername: "+username+
"\nDate: "+date+"\npassword: "+password;
}
public static void main(String[] args)throws Exception{
Logon a= new Logon("Hulk", "myLittlePony");
System.out.println("logon a= "+a);
ObjectOutputStream out=new ObjectOutputStream(
new FileOutputStream("Login.out"));
out.writeObject(a);
out.close();
TimeUnit.SECONDS.sleep(1);
ObjectInputStream in=new ObjectInputStream(
new FileInputStream("Login.out"));
a=(Logon)in.readObject();
System.out.println(a);
}
}/*output
logon a= Logon info:
username: Hulk
Date: Tue Dec 26 22:04:51 CST 2017
password: myLittlePony
Logon info:
username: Hulk
Date: Tue Dec 26 22:04:51 CST 2017
password: null
*/

从结果发现,密码的引用是null,因为没有被存储,也不会被反序列化,对象引用如果是null,自动转成null字符串。

XML

赏

谢谢你请我吃糖果

  • JAVASE

扫一扫,分享到微信

微信分享二维码
仿c语言自制编程语言笔记1
Java学习笔记10
© 2018 mhcoderwl
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • unp
  • unix
  • socket
  • JAVASE
  • apue
  • muduo
  • c++
  • stl
  • c/c++
  • 编译器
  • C--
  • c
  • FakeCC
  • python
  • sql
  • web 开发
  • Flask框架
  • 算法
  • 面试
  • linux
  • 教程
  • hexo
  • 博客
  • sockets
  • 服务器

    缺失模块。
    1、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    2、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: true
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 昊师兄的博客
目前在东南大学读研
擅长c/c++,linux,shellscript
做一些3D人脸识别的研究
有兴趣一起交流学习!