mhcoderwl

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

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

mhcoderwl

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

  • 主页
  • 标签

Java学习笔记9

2017-12-28

day10

Class.newInstance和Constructor.newInstance()

首先来分析new和newInstance(),在使用new来创建一个对象时,我们必须知道这个对象的确切类型,而用newInstance()不知道知道确切类型,通过反射来创建实例。

我们知道newInstance()是通过类加载机制,也就是说,要加载过我们要创建的类型,才能创建对象实体。

  • Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;

  • Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。

  • Class.newInstance() 抛出所有由被调用构造函数抛出的异常。

  • Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;

  • Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。

队列

Queue

Queue在SE5中仅有的两个实现是LinkedList和PriorityList,其中,优先级队列的排列规则按照对象类型实现的Comparable控制。

使用方法如下:

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
package wangliang;
import java.util.*;
import java.util.concurrent.*;
public class QueueBeahavior {
private static int count=10;
static <T> void test(Queue<T> queue,Generator<T> gen){
for(int i=0;i<count;i++){
queue.offer(gen.next());//offer用来入队的方法,还有个add
}
while(queue.peek()!=null){
System.out.print(queue.remove()+" ");//remove返回队首元素并从队中删除。
}
System.out.println();
}
static class Gen implements Generator<String>{
String[] s=("one two three four five six seven eight nine ten").split(" ");
int i=0;
public String next(){return s[i++];}
}
public static void main(String[] args){
test(new LinkedList<String>(),new Gen());
test(new PriorityQueue<String>(), new Gen());
test(new ArrayBlockingQueue<String>(count),new Gen());
test(new PriorityBlockingQueue<>(), new Gen());
}
}

深入理解Map

Map里面总共6个实现:

  • HashMap

  • TreeMap

  • LinkedHashMap//LinkedHashMap可以使用最近最少算法,使得没有被访问的元素放在前面。

  • WeakHashMap

  • ConcurrentHashMap

  • IdentityHashMap

散列与散列码

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
package wangliang;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Random;
import java.util.*;
class Prediction{
private static Random rand=new Random(47);
private boolean shadow=rand.nextDouble()>0.5;
public String toString(){
if(shadow){
return "Six more weeks of Winter";
}else{
return "Early Spring";
}
}
}
public class SpringDetector {
public static <T extends Groundhog>void detectSpring(Class<T> type)
throws Exception{
Constructor<T> ghog=type.getConstructor(int.class);
Map<Groundhog, Prediction>map=new HashMap<Groundhog,Prediction>();
for(int i=0;i<10;i++){
map.put(ghog.newInstance(i), new Prediction());
}
System.out.println("map="+map);
Groundhog gh=ghog.newInstance(3);
System.out.println("Looking up for"+gh);
if(map.containsKey(gh)){
System.out.println(map.get(gh));
}else
System.out.println("Not Found"+gh);
}
public static void main(String[] args) throws Exception{
detectSpring(Groundhog.class);
}
}/*output
not found
*/

原因是因为我们的Groundhog类没有重写hashCode(),继承自Object的方法,Object中equals()用对象的内存地址来散列,因此我们用两个属性相同的对象散列后不想等。

创建equals()满足的条件:

  • 自反性。任意x,x.equals(x)must return true。

  • 对称性。任意x和y,如果x.equals(y)return true then y.equals(x)return true

  • 传递性。

  • 一致性。

  • 对任何不是null的x,x.equals(null)must return false。

容器选择

List

给出了两种容器的性能对比:

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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/*代码结构:首先有一个Test抽象类,主要用来实现各种方法的对象。有一个test()方法可以重写,根据具体实现方法用匿名内部类方法实现。
其次有一个Tester类,这个类含有一个指定的容器和存储各种参数下Test类的list,负责打印各种参数下test()的结果。
最后一个listPerformance类,用来添加具体测试的方法和参数。
//Tester.java
package wangliang;
import java.util.*;
public class Tester<C> {
public static int fieldWidth=8;//打印宽度
private static int sizeWidth=5;
private static String sizeField="%"+sizeWidth+"s";
private static String stringField(){
return "%"+fieldWidth+"s";
}
private static String numberField(){
return "%"+fieldWidth+"d";
}
public static TestParam[] defaultParams=TestParam.array(
10,5000,100,5000,1000,5000,10000,500);
protected C initialize(int size){
return container;
}
protected C container;
private String headline="";
private List<Test<C>>tests;
private TestParam[] paramList=defaultParams;
public Tester(C container,List<Test<C>>tests){
this.tests=tests;
this.container=container;
if(container!=null){
this.headline=container.getClass().getSimpleName();
}
}
public Tester(C container,List<Test<C>>tests,TestParam[] paramlist){
this(container,tests);
this.paramList=paramlist;
}
public void setHeadline(String head){
this.headline=head;
}
//一些通用的方法
public static <C> void run(C cntnr,List<Test<C>>tests){
new Tester<C>(cntnr,tests).timedTest();
}
public static <C> void run(C cntnr,List<Test<C>>tests,TestParam[] paramList){
new Tester<C>(cntnr,tests,paramList).timedTest();
}
private void displayHeader(){
int width=fieldWidth*tests.size()+sizeWidth;
int dashLength=width-headline.length()-1;
StringBuilder head=new StringBuilder(width);
for(int i=0;i<dashLength/2;i++){
head.append("-");
}
head.append(" "+headline+" ");
for(int i=0;i<dashLength/2;i++){
head.append("-");
}
System.out.println(head);
System.out.format(sizeField, "size");
for(Test test:tests){
System.out.format(stringField(), test.name);
}
System.out.println();
}
public void timedTest(){
displayHeader();
for(TestParam param:paramList){
System.out.format(sizeField, param.size);
C kontainer=initialize(param.size);
for(Test<C> test:tests){
long start=System.nanoTime();
int reps=test.test(kontainer,param);
long timePerRep=(System.nanoTime()-start)/reps;
System.out.format(numberField(), timePerRep);
}
System.out.println();
}
}
}
//ListPerformance.java
package wangliang;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
public class ListPerformance {
static Random rand=new Random(47);
static int reps=1000;
static List<Test<List<Integer>>>tests=new ArrayList<Test<List<Integer>>>();
static List<Test<LinkedList<Integer>>>qTests=new ArrayList<Test<LinkedList<Integer>>>();
static{
tests.add(new Test<List<Integer>>("add"){
int test(List<Integer> list,TestParam tp){
for(int i=0;i<tp.loops;i++){
list.clear();
for(int j=0;j<tp.size;j++)
list.add(j);
}
return tp.loops*tp.size;
}
});
tests.add(new Test<List<Integer>>("get"){
int test(List<Integer>list,TestParam tp){
int loop=tp.loops*reps;
for(int i=0;i<loop;i++){
list.get(rand.nextInt(list.size()));//就算是空也可以get()
}
return loop;
}
});
tests.add(new Test<List<Integer>>("set"){
int test(List<Integer>list,TestParam tp){
int loop=tp.loops*reps;
for(int i=0;i<loop;i++){
list.set(rand.nextInt(list.size()), 47);
}
return loop;
}
});
tests.add(new Test<List<Integer>>("iteradd"){
int test(List<Integer>list,TestParam tp){
final int LOOPS=100000;
int half=list.size()/2;
list.listIterator(half);
ListIterator<Integer>it=list.listIterator(half);
for(int i=0;i<LOOPS;i++){
it.add(47);//中间插入
}
return LOOPS;
}
});
tests.add(new Test<List<Integer>>("insert"){
int test(List<Integer>list,TestParam tp){
int LOOPS=tp.loops;
for(int i=0;i<LOOPS;i++){
list.add(5,47);//中间插入
}
return LOOPS;
}
});
tests.add(new Test<List<Integer>>("remove"){
int test(List<Integer>list,TestParam tp){
int loop=tp.loops;
int size=tp.size;
for(int i=0;i<loop;i++){
list.clear();
list.addAll(new CountingIntegerList(size));//先填满元素
while(list.size()>5){
list.remove(5);
}
}
return loop*size;
}
});
}
static class ListTester extends Tester<List<Integer>>{
public ListTester(List<Integer> container,List<Test<List<Integer>>>tests){
super(container,tests);
}
protected List<Integer>initialize(int size){
container.clear();
container.addAll(new CountingIntegerList(size));
return container;
}
public static void run(List<Integer>list,List<Test<List<Integer>>>tests){
new ListTester(list, tests).timedTest();
}
}
public static void main(String[] args){
if(args.length>0){
}
Tester<List<Integer>>arrayTest=new Tester<List<Integer>>(null,tests.subList(1,3)){
};
Tester.defaultParams=TestParam.array(10,5000,100,5000,1000,1000,10000,200);
//Tester.defaultParams
ListTester.run(new ArrayList<Integer>(), tests);
ListTester.run(new LinkedList<Integer>(), tests);
}
}/*output
--------------------- ArrayList ---------------------
size add get set iteradd insert remove
10 286 29 35 203 45567 381
100 41 31 33 68 45739 118
1000 31 26 31 181 46414 212
10000 15 30 28 1433 39079 1738
--------------------- LinkedList ---------------------
size add get set iteradd insert remove
10 311 64 65 209 516 289
100 32 84 90 19 206 44
1000 30 751 784 30 142 33
10000 25 12406 12659 42 161 51
*/

可以看到,对于ArrayList,随机访问操作开销小,中间插入元素开销较大,对于LinkedList,恰恰相反。

Set的选择

测试代码如下:

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
package wangliang;
import java.util.*;
import org.omg.CORBA.PUBLIC_MEMBER;
public class SetPerformance {
static List<Test<Set<Integer>>>list=new ArrayList<Test<Set<Integer>>>();
static{
list.add(new Test<Set<Integer>>("add"){
int test(Set<Integer> list,TestParam tp){
for(int i=0;i<tp.loops;i++){
list.clear();
for(int j=0;j<tp.size;j++)
list.add(j);
}
return tp.loops*tp.size;
}
}
);
list.add(new Test<Set<Integer>>("contains"){
int test(Set<Integer> set,TestParam tp){
int loop=tp.loops;
int span=tp.size*2;
for(int i=0;i<loop;i++){
for(int j=0;j<span;j++)
set.contains(j);
}
return loop*span;
}
}
);
list.add(new Test<Set<Integer>>("iterate"){
int test(Set<Integer> set,TestParam tp){
int loop=tp.loops*10;
for(int i=0;i<loop;i++){
Iterator<Integer>it=set.iterator();
while(it.hasNext()){
it.next();
}
}
return loop;
}
}
);
}
public static void main(String[] args){
Tester.fieldWidth=10;
Tester.run(new TreeSet<Integer>(), list);
Tester.run(new HashSet<Integer>(), list);
Tester.run(new LinkedHashSet<Integer>(), list);
}
}/*output
------------- TreeSet -------------
size add contains iterate
10 801 444 855
100 176 64 1372
1000 130 120 9217
10000 167 152 99528
------------- HashSet -------------
size add contains iterate
10 444 226 1507
100 54 11 2099
1000 42 15 15652
10000 44 16 160976
---------- LinkedHashSet ----------
size add contains iterate
10 443 131 3978
100 56 37 1799
1000 66 29 15132
10000 53 31 155371
*/

HashSet的性能总是比TreeSet好,除了需要排序的Set外,都用HashSet。

###HashMap

  • 容量:表中的桶位数。

  • 初始容量:表在创建时所拥有的桶位数。HashMap和HashSet都具有允许你指定初始容量的构造器。

  • 尺寸:表中当前存储的项数。

  • 负载因子: 尺寸/容量。空表的负载因子是0,而半满表的负载因子是0.5,依次类推。负载轻的表产生的冲突的可能性小。因此对于插入和查找都是最理想的。可以人工指定负载因子,达到水平后扩大容量然后再散列。

Collection中的实用方法


max(Collection) 返回参数的Collection中最大或最小的元素,采用

min(Collection) Collection内置的自然比较法


max(Collection,Comparator) 同上,手动传入比较法。

min(Collection,Comparator)


reverse(list) 逆转所有元素次序


reverseOrder() 返回一个Comparator,逆转顺序

reverseOrder(Comparator)


shuffle(List) 随机顺序

shuffle(List,Random)


sort(List) 排序

sort(List.Comparator<?SuperT>c)


copy(Listdest,List<?extends T>src) 复制元素


swap(List,int i,int j) 交换两个位置元素,有优化


min()和max()只能作用于Collection对象。不用管排序。

WeakReference

先说说Java中的GC,当一个对象object被创建时,它被放在Heap里。当GC运行的时候,如果发现没有任何引用指向object,object就会被回收以腾出内存空间。或者换句话说,一个对象被回收,必须满足两个条件:1)没有任何引用指向它 2)GC被运行.

当我们声明了一个强引用时,比如:

StringBuilder buffer=new StringBuilder();

这个buffer就是个强引用,当程序不可访问到这个对象时,也就是没有引用标识符引用它了,GC会自动回收这个对象,但是强引用在某些情况会出问题,比如我们用一个HashMap存了一个控件和空间对应的感兴趣值得映射,如果某个控件的值我们不需要了,就必须手动在HashMap里删除,否则这个值就一直不会释放。

解决方案就是WeakReference,可以用WeakHashMap来存储。就是类似于c++里面的weak_ptr。

赏

谢谢你请我吃糖果

  • JAVASE

扫一扫,分享到微信

微信分享二维码
Java学习笔记10
Java学习笔记8
© 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人脸识别的研究
有兴趣一起交流学习!