java 出生日期查五行缺什么这块,怎么弄啊,一个一个打好麻烦,有没有简便点的

&&&&Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)
Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)
作者: 臧萌
出版社:清华大学出版社
上架时间:
出版日期:2010 年3月
开本:16开
其他详细信息查看:http://www./196571
Java编程老鸟潜心写作,奉献高效率的Java学习心得
完全站在没有编程经验读者的角度,手把手教会读者学习Java
配16小时多媒体教学视频,高效、直观
一一击破Java入门可能会遇到的难点和疑惑
抽丝剥茧,层层推进,让知识环环相扣,降低了学习的难度
通过大量的比喻、类比、对比和图示等多种讲解方式,学习效果好
对Java语言的每个语法都提供了一个或多个例程讲解
大量使用流程图表示程序的执行过程,使用结构图表示程序的内部状态
每章最后都给出了典型的练习题,让读者及时练习,巩固提高,并提供了参考答案
第1篇 Java语言基本语法
第1章 让自己的第一个Java程序跑起来 2
教学视频:19分钟
1.1 想要用Java改变这个世界吗? 2
1.1.1 Java有什么优势? 2
1.1.2 Java在哪儿? 3
1.2 准备好开始Java之旅 3
1.2.1 下载JDK 4
1.2.2 安装JDK 5
1.2.3 配置环境变量 6
1.2.4 测试环境是否安装成功 8
1.2.5 如果失败了怎么办? 9
1.3 让自己的第一个程序运行起来 10
1.3.1 编写自己的Hello World源程序 10
1.3.2 编译自己的HelloWorld程序 11
1.3.3 让代码运行起来 13
1.4 初探Hello World 14
1.4.1 类(Class):Java世界中一类物体 14
1.4.2 方法(Method):物体的功能 15
1.4.3 main()方法:所有Java程序执行的起点 15
.1.5 名词解释 16
1.5.1 JDK和Java平台 16
1.5.2 Java编译器(Java Compiler) 17
1.5.3 Java类库(Java Class Libraries) 17
1.5.4 Java虚拟机(Java Virtual Machine) 17
1.5.5 HelloWorld的整个流程 17
1.6 小结:我们学会了编译和运行一个Java程序! 18
1.7 习题 19
第2章 搭建自己的集成开发环境 20
教学视频:31分钟
2.1 安装集成开发环境 20
2.1.1 集成开发环境有哪些 20
2.1.2 安装Eclipse 21
2.2 Eclipse界面介绍 23
2.2.1 启动Eclipse 23
2.2.2 Eclipse的Perspective 24
2.2.3 Eclipse的菜单 25
2.2.4 Eclipse的工具条 25
2.2.5 Eclipse辅助视图区 25
2.2.6 Eclipse中Package Explorer 26
2.2.7 Eclipse中的源代码编辑器 26
2.2.8 Eclipse的设置窗口 26
2.2.9 Eclipse中的其他视图 27
2.3 如何使用Eclipse 28
2.3.1 在Eclipse中创建自己的第一个项目 28
2.3.2 在Eclipse中编写HelloWorld程序 29
2.3.3 通过Eclipse运行Hello World 31
2.4 小结:Eclipse——功能很强大 32
2.5 习题 32
第3章 Java中的基本数据类型和运算符 33
教学视频:1小时5分钟
3.1 Java中的基本数据类型 33
3.1.1 基本数据类型——编程语言中的数据原子 33
3.1.2 Java中的基本上数据类型介绍 34
3.1.3 基本数据类型值域 34
3.2 Java运算符 36
3.2.1 变量的概念 36
3.2.2 插曲:Java中的语句 37
3.2.3 创建一个变量和变量名的规范 37
3.2.4 Java中的基本运算符和表达式 39
3.2.5 Java中的布尔运算符 43
3.3 基本数据类型运算的难点 47
3.3.1 强制类型转换——小数哪里去了 48
3.3.2 类型的转换在运算中悄悄进行 50
3.3.3 强制类型转换最优先 52
3.3.4 等号其实不简单 52
3.3.5 小心使用浮点数进行比较 53
3.3.6 boolean和char 55
3.3.7 不要使用还没有创建出来的变量 57
3.3.8 String——char串起的项链 58
3.3.9 转义符——看不见写得出 61
3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63
3.5 习题 65
第4章 Java中的程序执行流程 67
教学视频:1小时57分钟
4.1 顺序执行 67
4.2 使用if-else让程序懂得判断 68
4.2.1 if语句 68
4.2.2 if语句的嵌套 71
4.2.3 if-else语句 73
4.2.4 if-else语句嵌套 75
4.3 使用while进行循环 76
4.3.1 使用while语句 76
4.3.2 使用do-while语句 79
4.4 使用for进行循环 80
4.4.1 自增和自减操作 80
4.4.2 for语句 82
4.4.3 for语句省略形式 84
4.5 语句中不能不说的事 84
4.5.1 小心复杂语句中创建的变量 85
4.5.2 别让循环次数给弄懵了 86
4.5.3 循环的嵌套 87
4.6 continue关键字与break关键字 88
4.6.1 continue关键字 88
4.6.2 break关键字 89
4.7 使用switch进行跳转 90
4.8 大例子 94
4.8.1 从控制台读取数据 94
4.8.2 结账程序中的循环 96
4.9 小结:Java不是一个直肠子 98
4.10 习题 99
第5章 数组 100
教学视频:35分钟
5.1 什么是数组 100
5.1.1 假设:如果需要逐个定义变量 100
5.1.2 数组初探 101
5.1.3 数组——物以类聚 104
5.1.4 数组元素的值内有乾坤 105
5.1.5 创建数组的简洁语法 106
5.2 数组的“名”与“实” 107
5.2.1 “名”与“实”分离的数组 107
5.2.2 一“实”多“名”的数组 109
5.2.3 一“实”多“名”带来的困惑 111
5.3 多维数组 114
5.3.1 什么是多维数组 114
5.3.2 多维数组的实质 115
5.4 数组大练兵 123
5.4.1 轻松查询全班成绩 123
5.4.2 轻松查询全校成绩不在话下 124
5.4.3 杨辉三角 125
5.5 小结:方便快速的数组 129
5.6 习题 129
第2篇 Java语言高级语法
第6章 Java的类(Class)和对象(Object) 132
教学视频:59分钟
6.1 驾驶汽车向类(Class)的世界进发 132
6.1.1 汽车带来的问题 132
6.1.1 类的组成 134
6.1.3 使用自定义的Car类 136
6.1.4 类和对象 139
6.1.5 源文件的存放 141
6.1.5 理解引用 143
6.1.7 null关键字 145
6.2 巧妙使用类中的属性 147
6.2.1 在类中给每个变量一个初始值 147
6.2.2 定义自己的引用 147
6.2.3 使用点操作符的技巧 148
6.2.4 类的数组 149
6.3 小结:Java其实是个类和对象的世界 152
6.4 习题 153
第7章 Java中的方法——给汽车丰富多彩的功能 154
教学视频:2小时55分钟
7.1 方法:让汽车动开动 154
7.1.1 引出问题:开动汽车 154
7.1.2 那么,方法到底是什么呢? 155
7.1.3 方法调用过程初探 156
7.2 Java普通方法的组成部分 157
7.2.1 访问控制符:public 158
7.2.2 返回值和关键字void 158
7.2.3 方法名(Method Name) 159
7.2.4 参数列表(Parameter List) 159
7.2.5 方法体(Method Body) 160
7.2.6 方法串串烧 160
7.3 方法的参数:让汽车加速 161
7.3.1 方法的参数:让汽车可以加速 161
7.3.2 带参数的方法有何不同? 162
7.3.3 让方法有多个参数 163
7.4 返回值:汽车超速了吗? 164
7.4.1 写一个有返回值的方法 164
7.4.2 调用有返回值的方法 165
7.4.3 发生了什么?如何使用方法的返回值? 166
7.4.4 使用return结束方法 166
7.5 方法重载(overload):给汽车加速添个限制 168
7.5.1 什么是方法的签名 168
7.5.2 什么是重载?为什么要重载? 168
7.5.3 给汽车加个重载的方法 169
7.5.4 测试一下 169
7.5.5 重载容易引发误解的两个地方——返回类型和形参名 170
7.5.6 重载中的最难点——参数匹配原则 171
7.6 使用类的实例作为方法参数 172
7.6.1 超车方法:使用类实例做参数 172
7.6.2 调用这个方法 173
7.6.3 发生了什么 174
7.7 加餐:局部变量和实例变量 175
7.7.1 什么是局部变量(Local Variable) 175
7.7.2 什么是实例变量(Instance Variable) 177
7.8 this关键字:指向对象自己的引用 177
7.8.1 发现问题:当实例变量和局部变量重名 177
7.8.2 经常深藏不露的this关键字 178
7.8.3 在方法中调用方法 179
7.9 构造方法(Constructor) 181
7.9.1 构造(Constructor)方法初探 181
7.9.2 如何使用构造方法 182
7.9.3 留个无参数的构造方法——给重要属性赋初始值 183
7.9.4 在构造方法中调用构造方法 184
7.10 方法大汇总 185
7.10.1 本例中用到的类 186
7.10.2 使用例程将本章的知识穿起来 189
7.11 小结:多方位理解Java方法 191
7.12 习题 192
第8章 Java中的包(Package)命名习惯和注释 193
教学视频:43分钟
8.1 Java中的包(Package) 193
8.1.1 Java中的包 193
8.1.2 在Eclipse中使用包 194
8.1.3 天上掉下个package 197
8.1.4 包带来了什么? 197
8.2 import语句:化繁为简 200
8.2.1 import语句 200
8.2.2 一网打尽包中所有类 201
8.2.3 import语句带来的小问题 202
8.2.4 默认引入的包 204
8.3 命名习惯大回顾 204
8.4 Java中的注释 205
8.4.1 使用双斜杠的单行注释 205
8.4.2 多行注释 206
8.4.3 Javadoc注释 206
8.5 小结:包让Java的类更清晰优雅 208
8.6 习题 209
第9章 再看数组、字符串和main()方法 210
教学视频:29分钟
9.1 数组也是类 210
9.1.1 得到数组的长度 210
9.1.2 加餐:不可改变的final变量 211
9.1.3 多维数组的长度 212
9.1.4 一维数组的clone()方法 212
9.1.5 当数组类型不再是基本数据类型 214
9.1.6 多维数组的clone()方法 217
9.2 老朋友String类 220
9.2.1 遍历String中的字符 220
9.2.2 获取字符串中的一部分 222
9.2.3 判断两个字符串是否相等 223
9.2.4 判断字符串的开头和结尾 225
9.2.5 分割字符串 225
9.2.6 在字符串中查找子字符串或字符 226
9.2.7 替换字符串中的内容 226
9.2.8 String对象——磐石刻字 227
9.3 String类的最佳拍档——StringBuffer类 227
9.3.1 StringBuffer:专业操纵字符 228
9.3.2 String和StringBuffer一个都不能少 229
9.4 最熟悉的陌生人:main()方法 229
9.4.1 main()方法的参数 229
9.4.2 static关键字 232
9.4.3 当方法遇到static关键字 233
9.5 小结:学会使用类中的方法 235
9.6 习题 236
第10章 继承和多态 237
教学视频:1小时55分钟
10.1 继承——最优的解决方案 237
10.1.1 饭前水果:实例变量的访问控制符 237
10.1.2 一切还是从汽车开始 238
10.1.3 一类车,一个类 241
10.1.4 分开也有麻烦 244
10.1.5 使用继承——问题迎刃而解 245
10.1.6 使用Bus类 248
10.1.7 Java中的单继承 248
10.1.8 Java中的类图 249
10.1.9 万类之祖——Object类 250
10.2 子类对象?父类对象? 251
10.2.1 父随子行 251
10.2.2 当构造方法遇到继承 254
10.2.3 记得给类一个无参数的构造方法 255
10.2.4 调用父类中的构造方法 256
10.2.5 对象也会“变脸” 258
10.2.6 遵守语法,正确“变脸” 262
10.3 覆盖——与继承如影随形 264
10.3.1 当方法不再通用 264
10.3.2 覆盖——让众口不再难调 265
10.3.3 覆盖——到底调用了哪个方法 270
10.3.4 覆盖的语法不简单 272
10.3.5 更复杂的使用覆盖的情况 274
10.3.6 覆盖——不得不打开的潘多拉魔盒 276
10.3.7 使用super调用父类中的方法和属性 278
10.4 多态(Polymorphism)以及其他 279
10.4.1 多态——运行方知结果 280
10.4.2 重载也不简单 280
10.4.3 使用多态构建车队 283
10.5 在多态的环境中拨开迷雾 284
10.5.1 神秘的Class类 284
10.5.2 覆盖不再神秘 285
10.5.3 instanceof运算符——让对象告诉你它的类是谁 286
10.6 小结:继承和多态让世界丰富多彩 287
10.7 习题 290
第11章 修饰符(Qualifier) 291
教学视频:26分钟
11.1 插曲:类的组成部分的名字 291
11.2 类中的修饰符 292
11.2.1 无修饰符类 292
11.2.2 类的可见性 293
11.2.3 final——让类不可被继承 295
11.2.4 理解final关键字 296
11.2.5 总结:类的修饰符 297
11.3 方法的修饰符 297
11.3.1 方法的访问控制符 298
11.3.2 public:没有限制的修饰符 299
11.3.3 protected:仅对子类和同包的类可见 300
11.3.4 默认控制符:仅在本包中可见 301
11.3.5 private:仅对本类可见 303
11.3.6 理解4个访问控制符 304
11.3.7 访问控制符可见性汇总 306
11.3.8 访问控制符带来的覆盖问题 306
11.3.9 final:不允许方法被覆盖 310
11.3.10 重温静态方法 311
11.3.11 静态方法——类范围里的概念 312
11.3.12 静态方法何以为“静态” 314
11.4 变量的修饰符 316
11.4.1 变量方法皆成员 317
11.4.2 变量的访问控制符 317
11.4.3 使用private修饰类的成员变量 318
11.4.4 使用private,然后呢? 320
11.4.5 变量的覆盖 322
11.4.6 使用final修饰成员变量 325
11.4.7 静态成员变量 326
11.4.8 局部变量的修饰符 326
11.4.9 当final遇到引用类型成员变量 327
11.5 小结:修饰符作用大 328
11.6 习题 330
第12章 接口 331
教学视频:29分钟
12.1 自行车带来的问题 331
12.1.1 记录马路上的车辆 331
12.1.2 引发问题的自行车 335
12.1.3 仔细分析recordTransport()方法 338
12.2 初用接口 339
12.2.1 准备好需要用到的类 339
12.2.2 认识接口的代码组成 340
12.2.3 什么是接口 341
12.2.4 使用接口仅需一步——实现接口 342
12.2.5 接口——让类集多重类型于一身 344
12.2.6 简化recordTransport()方法 347
12.3 再探接口 349
12.3.1 重温上节中的程序 349
12.3.2 面向接口编程 351
12.3.3 话说“抽象” 353
12.3.4 接口大瘦身 355
12.3.5 实现多个接口 355
12.3.6 接口中的变量 357
12.3.7 接口的继承 358
12.3.8 匹配抽象方法中的类型 359
12.3.9 空接口 361
12.4 小结:接口的难点在于何时使用 362
12.5 习题 364
第13章 抽象类和内部类 365
教学视频:26分钟
13.1 抽象类(Abstract Class) 365
13.1.1 不知道怎么打招呼的Person类 365
13.1.2 当类中有了抽象方法 367
13.1.3 抽象类语法详解 368
13.1.4 理解抽象类的作用 369
13.2 内部类的分类(Inner Class) 370
13.2.1 成员内部类 370
13.2.2 局部内部类 372
13.3 成员内部类 374
13.3.1 使用成员内部类 374
13.3.2 成员内部类的修饰符 375
13.3.3 在类外部使用内部类 376
13.3.4 非静态内部类的特性 378
13.3.5 外部类访问成员内部类中的属性 382
13.3.6 静态成员内部类 383
13.4 局部内部类 384
13.4.1 局部内部类之“局部” 385
13.4.2 局部内部类之“内部类” 386
13.4.3 使用局部内部类 388
13.5 匿名内部类(Anonymous inner classes) 389
13.5.1 准备工作 389
13.5.2 匿名内部类的语法 389
13.5.3 通过接口使用匿名类 390
13.5.4 通过抽象类使用匿名类 391
13.6 类,这样一路走来 391
13.7 小结:丰富多彩的类 395
13.8 习题 397
第14章 Java的异常处理机制 398
教学视频:36分钟
14.1 认识异常 398
14.1.1 异常什么时候发生 398
14.1.2 异常是什么 401
14.1.3 Java异常机制的流程 401
14.2 抛出异常 403
14.2.1 异常类的父类——Throwable 403
14.2.2 在代码中使用throw抛出一个异常 404
14.2.3 在方法声明中使用throws 407
14.2.4 构造自定义异常类 409
14.2.5 使用自定义异常类 410
14.3 异常的传递 411
14.3.1 抛出最确切的异常类型 411
14.3.2 Java异常的传递 412
14.3.3 图说Java异常的传递 414
14.4 异常的处理 418
14.4.1 把异常捉住 418
14.4.2 图说异常处理流程 421
14.4.3 多类异常,一并处理 424
14.4.4 try-catch-finally语句 426
14.4.5 try-finally语句 431
14.4.6 好好利用catch语句 432
14.5 异常的类型 433
14.5.1 3个类的继承关系 433
14.5.2 必须处理的Exception类 434
14.5.3 灵活掌握的RuntimeException类 434
14.5.4 不用处理的Error类 435
14.6 小结:终止错误的蔓延 435
14.7 习题 437
第15章 多线程编程 438
教学视频:1小时14分钟
15.1 线程——执行代码的机器 438
15.1.1 线程——执行代码的基本单位 438
15.1.2 演奏会模型 440
15.2 Java中的线程编程 443
15.2.1 线程类Thread 443
15.2.2 覆盖Thread类的run()方法 444
15.2.3 使用Runnable接口 446
15.2.4 两个线程 448
15.3 深入学习Thread类 449
15.3.1 线程的名字 449
15.3.2 得到当前的线程 451
15.3.3 让线程“沉睡” 453
15.4 多个线程的故事 457
15.4.1 一个有多个线程的程序 457
15.4.2 复印社模型 459
15.4.3 一个简单的复印社例程 461
15.5 多个线程的同步 463
15.5.1 线程同步之synchronized关键字 463
15.5.2 深入学习synchronized关键字 468
15.5.3 静态同步方法 469
15.5.4 非静态的同步方法 472
15.5.5 银行的麻烦——账户乱套了 474
15.5.6 多角度理解同步方法 481
15.5.7 闲话同步方法的使用 484
15.5.8 同步代码块 485
15.5.9 锁(Lock) 486
15.5.10 线程同步之wait()和notify()方法 488
15.5.11 wait和notify的顺序 491
15.6 小结:线程——代码执行器 494
15.7 习题 495
第3篇 Java语言编程进阶
第16章 如何学习本篇 498
教学视频:15分钟
16.1 多想多写多练 498
16.2 术业有专攻 498
16.3 拆分问题,逐个击破 500
16.4 阅读Javadoc 500
16.5 小结:大练兵马上开始 506
16.6 习题 507
第17章 编程常用知识 508
教学视频:18分钟
17.1 再谈对象的比较 508
17.1.1 hashcode()方法 508
17.1.2 equals()方法 509
17.1.3 对象的比较equals()方法 509
17.2 Java中的集合类框架 510
17.2.1 集合类框架中的接口 510
17.2.2 List接口 511
17.2.3 使用ArrayList 512
17.2.4 Set接口 516
17.2.5 使用HashSet类 517
17.2.6 List与Set 518
17.3 泛型简介 518
17.3.1 没有泛型时的程序 519
17.3.2 使用泛型——避免强制类型转 520
17.4 Map接口 522
17.4.1 认识Map 522
17.4.2 使用HashMap 523
17.5 字符集和编码 524
17.5.1 字符集 524
17.5.2 编码 525
17.5.3 关于字符集的小程序 526
17.6 小结:编程需要打好基础 529
17.7 习题 530
第18章 Java文件编程和Java文件I/O 531
教学视频:9分钟
18.1 Java中的文件编程 531
18.1.1 File类 531
18.1.2 创建和删除文件 532
18.1.3 列出文件和文件夹 533
18.1.4 重命名文件 535
18.2 Java的I/O编程 536
18.2.1 理解Java中的Stream 536
18.2.2 向文件中写入数据 538
18.2.3 从文件中读取数据 539
18.2.4 从控制台读取数据 541
18.2.5 使用输出流写入数据 543
18.2.6 使用输入流读取数据 545
18.3 小结:Java中的文件类和输入输出机制 546
18.4 习题 547
第19章 Java Socket编程 548
教学视频:8分钟
19.1 IP地址和端口号 548
19.1.1 IP地址——计算机的标识 548
19.1.2 端口号——通信的窗口 549
19.1.3 网络,IP地址和端口号 551
19.2 Java TCP编程 551
19.2.1 数据传输协议 552
19.2.2 TCP的数据传输模式 552
19.2.3 第一个TCP小程序 553
19.3 Java UDP编程 557
19.3.1 UDP的数据传输模式 557
19.3.2 使用UDP协议收发数据 558
19.3.3 TCP和UDP的区别 560
19.4 小结:让程序伸向整个网络 561
19.5 习题 561
第20章 Java Swing编程 562
教学视频:14分钟
20.1 Java Swing编程简介 562
20.1.1 图形用户界面编程简介 562
20.1.2 组件 563
20.1.3 布局管理器(Layout Manager) 563
20.1.4 事件处理(Event Handling) 564
20.2 Swing基本组件 565
20.2.1 窗口(JFrame) 565
20.2.2 Swing的线程 567
20.2.3 Swing组件的鼻祖——JComponent 567
20.2.4 Swing面板类 568
20.2.5 Swing中的标签 568
20.2.6 Swing中的文本框 570
20.2.7 Swing中的文本域 571
20.2.8 Swing中的组合框 572
20.2.9 Swing中的按钮 573
20.3 Swing的布局管理器 574
20.3.1 最简单的FlowLayout 574
20.3.2 东南西北中之BorderLayout 574
20.3.3 平均分割之——GridLayout 576
20.3.4 最强大的布局管理器——GridBagLayout 577
20.3.5 使用多个布局管理器 579
20.4 Swing的事件处理 581
20.4.1 事件的传递和封装 581
20.4.2 事件监听器——事件的处理者 582
20.4.3 Swing事件处理的机制 584
20.4.4 事件监听器的编写 586
20.4.5 如何学习更多的事件 588
20.5 小结:从此不再依赖控制台 588
20.6 习题 588
第21章 编程,需要的是想象力和恒心 589
教学视频:13分钟
21.1 编程的前奏 589
21.1.1 细数手中的积木 589
21.1.2 发挥想象力 590
21.1.3 确定程序的功能 591
21.2 聊天窗口程序 591
21.2.1 聊天程序设计 591
21.2.2 设计程序运行效果 593
21.2.3 UDP消息收发模块 595
21.2.4 图形用户界面模块 598
21.2.5 消息处理模块 600
21.2.6 一个更通用的聊天程序 601
21.3 小结:编程是必不可少的锻炼 602
21.4 习题 602
第22章 JDBC入门 603
教学视频:11分钟
22.1 JDBC的基本API 603
22.1.1 JDBC是什么 603
22.1.2 DriverManager——驱动管理器 605
22.1.3 Connection接口 606
22.1.4 Statement接口 606
22.1.5 PreparedStatement接口 606
22.1.6 ResultSet接口 607
22.1.7 JDBC-ODBC桥 607
22.2 一个操作数据库的简单程序 608
22.2.1 程序的执行结果 608
22.2.2 程序设计与模块划分 609
22.2.3 准备好数据源 610
22.2.4 数据库操作模块的实现 610
22.2.5 图形用户界面模块的实现 611
22.3 小结:强大的JDBC标准 613
22.4 习题 613
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
开发技术下载排行推荐这篇日记的豆列
······一个计算机专业学生几年的Java编程经验汇总(转)
想来学习Java也有两个年头了,永远不敢说多么精通,但也想谈谈自己的感受,写给软件学院的同仁们,帮助大家在技术的道路上少一点弯路。说得伟大一点是希望大家为软件学院争气,其实最主要的还是大家自身的进步提升??1. 关于动态加载机制??学习Java比C++更容易理解OOP的思想,毕竟C++还混合了不少面向过程的成分。很多人都能背出来Java语言的特点,所谓的动态加载机制等等。当然概念往往是先记住而后消化的,可有多少人真正去体会过动态加载的机制,试图去寻找过其中的细节呢? 提供大家一个方法:在命令行窗口运行Java程序的时候,加上这个很有用的参数:java -verbose *.class这样会清晰的打印出被加载的类文件,大部分是jdk自身运行需要的,最后几行会明显的看到自己用到的那几个类文件被加载进来的顺序。即使你声明了一个类对象,不实例化也不会加载,说明只有真正用到那个类的实例即对象的时候,才会执行加载。这样是不是大家稍微能明白一点动态加载了呢?^_^2. 关于寻找class文件原理??建议大家在入门的时候在命令行窗口编译和运行,不要借助JCreator或者Eclipse等IDE去帮助做那些事情。尝试自己这样做:javac -classpath yourpath *.javajava -classpath yourpath *.class也许很多人都能看懂,设置classpath的目的就是告诉编译器去哪里寻找你的class文件. 不过至少笔者今日才弄懂JVM去查询类的原理,编译器加载类要依靠classloader,而classloader有3个级别,从高到低分别是BootClassLoader(名字可能不准确) , ExtClassLoader, AppClassLoader.这3个加载器分别对应着编译器去寻找类文件的优先级别和不同的路径:BootClassLoader对应jre/classes路径,是编译器最优先寻找class的地方ExtClassLoader对应jre/lib/ext路径,是编译器次优先寻找class的地方AppClassLoader对应当前路径,所以也是编译器默认找class的地方其实大家可以自己写个程序简单的测试,对任何class,例如A, 调用new A().getClass().getClassLoader().toString() 打印出来就可以看到,把class文件放在不同的路径下再次执行,就会看到区别。特别注意的是如果打印出来是null就表示到了最高级 BootClassLoader, 因为它是C++编写的,不存在Java对应的类加载器的名字。寻找的顺序是一种向上迂回的思想,即如果本级别找不到,就只能去本级别之上的找,不会向下寻找。不过似乎从Jdk1.4到Jdk1.6这一特点又有改变,没有找到详细资料。所以就不举例子了。告诉大家设计这种体系的是Sun公司曾经的技术核心宫力先生,一个纯种华人哦!^_^这样希望大家不至于迷惑为什么总报错找不到类文件,不管是自己写的还是导入的第三方的jar文件(J2ee中经常需要导入的)。3. 关于jdk和jre??大家肯定在安装JDK的时候会有选择是否安装单独的jre,一般都会一起安装,我也建议大家这样做。因为这样更能帮助大家弄清楚它们的区别:Jre 是java runtime environment, 是java程序的运行环境。既然是运行,当然要包含jvm,也就是大家熟悉的虚拟机啦,还有所有java类库的class文件,都在lib目录下打包成了jar。大家可以自己验证。至于在windows上的虚拟机是哪个文件呢?学过MFC的都知道什么是dll文件吧,那么大家看看jre/bin/client里面是不是有一个jvm.dll呢?那就是虚拟机。Jdk 是java development kit,是java的开发工具包,里面包含了各种类库和工具。当然也包括了另外一个Jre. 那么为什么要包括另外一个Jre呢?而且jdk/jre/bin同时有client和server两个文件夹下都包含一个jvm.dll。说明是有两个虚拟机的。这一点不知道大家是否注意到了呢?相信大家都知道jdk的bin下有各种java程序需要用到的命令,与jre的bin目录最明显的区别就是jdk下才有javac,这一点很好理解,因为 jre只是一个运行环境而已。与开发无关,正因为如此,具备开发功能的jdk自己的jre下才会同时有client性质的jvm和server性质的 jvm, 而仅仅作为运行环境的jre下只需要client性质的jvm.dll就够了。记得在环境变量path中设置jdk/bin路径麽?这应该是大家学习Java的第一步吧,老师会告诉大家不设置的话javac和java是用不了的。确实jdk/bin目录下包含了所有的命令。可是有没有人想过我们用的java命令并不是 jdk/bin目录下的而是jre/bin目录下的呢?不信可以做一个实验,大家可以把jdk/bin目录下的java.exe剪切到别的地方再运行 java程序,发现了什么?一切OK!那么有人会问了?我明明没有设置jre/bin目录到环境变量中啊?试想一下如果java为了提供给大多数人使用,他们是不需要jdk做开发的,只需要jre能让java程序跑起来就可以了,那么每个客户还需要手动去设置环境变量多麻烦啊?所以安装jre的时候安装程序自动帮你把jre的java.exe添加到了系统变量中,验证的方法很简单,大家看到了系统环境变量的 path最前面有“%SystemRoot%/system32;%SystemRoot%;”这样的配置,那么再去Windows/system32下面去看看吧,发现了什么?有一个java.exe。如果强行能够把jdk/bin挪到system32变量前面,当然也可以迫使使用jdk/jre里面的java,不过除非有必要,我不建议大家这么做。使用单独的jre跑java程序也算是客户环境下的一种测试。这下大家应该更清楚jdk和jre内部的一些联系和区别了吧?PS: 其实还有满多感想可以总结的,一次写多了怕大家扔砖头砸死我,怪我太罗唆。大家应该更加踏实更加务实的去做一些研究并互相分享心得,大方向和太前沿的技术讨论是必要的但最好不要太多,毕竟自己基础都还没打好,什么都讲最新版本其实是进步的一大障碍!Java 学习杂谈(二)鉴于上回写的一点感想大家不嫌弃,都鼓励小弟继续写下去,好不容易等到国庆黄金周,实习总算有一个休息的阶段,于是这就开始写第二篇了。希望这次写的仍然对志同道合的朋友们有所帮助。上回讲了Java动态加载机制、classLoader原理和关于jdk和jre三个问题。这次延续着讲一些具体的类库??1. 关于集合框架类相信学过Java的各位对这个名词并不陌生,对 java.util.*这个package肯定也不陌生。不知道大家查询API的时候怎么去审视或者分析其中的一个package,每个包最重要的两个部分就是interfaces和classes,接口代表了它能做什么,实现类则代表了它如何去做。关注实现类之前,我们应该先理解清楚它的来源接口,不管在j2se还是j2ee中,都应该是这样。那么我们先看这三个接口:List、Set、Map。也许有些人不太熟悉这三个名字,但相信大部分人都熟悉ArrayList,LinkedList,TreeSet,HashSet,HashMap, Hashtable等实现类的名字。它们的区别也是满容易理解的,List放可以重复的对象集合,Set放不可重复的对象组合,而Map则放 &Key,Value & 这样的名值对, Key不可重复,Value可以。这里有几个容易混淆的问题:到底Vector和ArrayList,Hashtable和HashMap有什么区别?很多面试官喜欢问这个问题,其实更专业一点应该这样问:新集合框架和旧集合框架有哪些区别?新集合框架大家可以在这些包中找since jdk1.2的,之前的如vector和Hashtable都是旧的集合框架包括的类。那么区别是?a. 新集合框架的命名更加科学合理。例如List下的ArrayList和LinkedListb. 新集合框架下全部都是非线程安全的。建议去jdk里面包含的源代码里面自己去亲自看看vector和ArrayList的区别吧。当然如果是jdk5.0之后的会比较难看一点,因为又加入了泛型的语法,类似c++的template语法。那么大家是否想过为什么要从旧集合框架默认全部加锁防止多线程访问更新到新集合框架全部取消锁,默认方式支持多线程?(当然需要的时候可以使用collections的静态方法加锁达到线程安全)笔者的观点是任何技术的发展都未必是遵循它们的初衷的,很多重大改变是受到客观环境的影响的。大家知道Java的初衷是为什么而开发的麽?是为嵌入式程序开发的。记得上一篇讲到classLoader机制麽?那正是为了节约嵌入式开发环境下内存而设计的。而走到今天,Java成了人们心中为互联网诞生的语言。互联网意味着什么?多线程是必然的趋势。客观环境在变,Java技术也随着飞速发展,导致越来越脱离它的初衷。据说Sun公司其实主打的是J2se,结果又是由于客观环境影响,J2se几乎遗忘,留在大家谈论焦点的一直是j2ee。技术的细节这里就不多说了,只有用了才能真正理解。解释这些正是为了帮助大家理解正在学的和将要学的任何技术。之后讲j2ee的时候还会再讨论。多扯句题外话:几十年前的IT巨人是IBM,Mainframe市场无人可比。微软如何打败IBM?正是由于硬件飞速发展,对个人PC的需求这个客观环境,让微软通过OS称为了第二个巨人。下一个打败微软的呢?Google。如何做到的?如果微软并不和IBM争大型机,Google借着互联网飞速发展这个客观环境作为决定性因素,避开跟微软争OS,而是走搜索引擎这条路,称为第3个巨人。那么第4个巨人是谁呢?很多专家预言将在亚洲或者中国出现, Whatever,客观环境变化趋势才是决定大方向的关键。当然笔者也希望会出现在中国,^_^~~2. 关于Java设计模式身边的很多在看GOF的23种设计模式,似乎学习它无论在学校还是在职场,都成了一种流行风气。我不想列举解释这23种Design Pattern, 我写这些的初衷一直都是谈自己的经历和看法,希望能帮助大家理解。首先我觉得设计模式只是对一类问题的一种通用解决办法,只要是面向对象的编程预言都可以用得上这23种。理解它们最好的方法就是亲自去写每一种,哪怕是一个简单的应用就足够了。如果代码实现也记不住的话,记忆它们对应的UML图会是一个比较好的办法,当然前提是必须了解UML。同时最好能利用Java自身的类库帮助记忆,例如比较常用的观察者模式,在java.util.*有现成的Observer接口和Observable这个实现类,看看源代码相信就足够理解观察者模式了。再比如装饰器模式,大家只要写几个关于java.io.*的程序就可以完全理解什么是装饰器模式了。有很多人觉得刚入门的时候不该接触设计模式,比如图灵设计丛书系列很出名的那本《Java设计模式》,作者: Steven John Metsker,大部分例子老实说令现在的我也很迷惑。但我仍然不同意入门跟学习设计模式有任何冲突,只是我们需要知道每种模式的概念的和典型的应用,这样我们在第一次编写 FileOutputStream、BufferedReader、PrintWriter的时候就能感觉到原来设计模式离我们如此之近,而且并不是多么神秘的东西。另外,在学习某些模式的同时,反而更能帮助我们理解java类库的某些特点。例如当你编写原型(Prototype)模式的时候,你必须了解的是 java.lang.Cloneable这个接口和所有类的基类Object的clone()这个方法。即深copy和浅copy的区别:Object.clone()默认实现的是浅copy,也就是复制一份对象拷贝,但如果对象包含其他对象的引用,不会复制引用,所以原对象和拷贝共用那个引用的对象。深copy当然就是包括对象的引用都一起复制啦。这样原对象和拷贝对象,都分别拥有一份引用对象。如果要实现深copy就必须首先实现 java.lang.Cloneable接口,然后重写clone()方法。因为在Object中的clone()方法是protected签名的,而 Cloneable接口的作用就是把protected放大到public,这样clone()才能被重写。那么又有个问题了?如果引用的对象又引用了其他对象呢?这样一直判断并复制下去,是不是显得很麻烦?曾经有位前辈告诉我的方法是重写clone方法的时候直接把原对象序列化到磁盘上再反序列化回来,这样不用判断就可以得到一个深copy的结果。如果大家不了解序列化的作法建议看一看 ObjectOutputStream和ObjectInputStream归根结底,模式只是思想上的东西,把它当成前人总结的经验其实一点都不为过。鼓励大家动手自己去写,例如代理模式,可以简单的写一个Child类, Adult类。Child要买任何东西由Adult来代理实现。简单来说就是Adult里的buy()内部实际调用的是Child的buy(),可是暴露在main函数的却是Adult.buy()。这样一个简单的程序就足够理解代理模式的基本含义了。Java 杂谈(三)这已经笔者写的第三篇Java杂记了,庆幸前两篇一直得到论坛朋友们的支持鼓励,还望大家继续指正不足之处。笔者也一直渴望通过这样方式清醒的自审,来寻找自己技术上的不足之处,希望和共同爱好Java的同仁们一起提高。前两次分别讲述了关于jvm、jdk、jre、collection、classLoader和一些Design Pattern的自我理解。这次仍然不准备开始过渡到j2ee中,因为觉得还有一些琐碎的j2se的问题没有总结完毕。1. 关于Object类理解大家都知道Object是所有Java类的基类, 意味着所有的Java类都会继承了Object的11个方法。建议大家去看看Object的 11个成员函数的源代码,就会知道默认的实现方式。比如equals方法,默认实现就是用"=="来比较,即直接比较内存地址,返回true 或者 false。而toString()方法,返回的串组成方式是??"getClass().getName() + "@" + Integer.toHexString(hashCode())"其实不用我过多的解释,大家都能看懂这个串的组成。接下来再看看hashCode():public native int hashCode();由于是native方法,跟OS的处理方式相关,源代码里仅仅有一个声明罢了。我们有兴趣的话完全可以去深究它的hashCode到底是由OS怎么样产生的呢?但笔者建议最重要的还是先记住使用它的几条原则吧!首先如果equals()方法相同的对象具有相通的hashCode,但equals ()对象不相通的时候并不保证hashCode()方法返回不同的整数。而且下一次运行同一个程序,同一个对象未必还是当初的那个hashCode() 哦。其余的方法呢?nofigy()、notifyAll()、clone()、wait()都是native方法的,说明依赖于操作系统的实现。最后一个有趣的方法是finalize(),类似C++的析构函数,签名是protected,证明只有继承扩展了才能使用,方法体是空的,默示什么也不做。它的作用据笔者的了解仅仅是通知JVM此对象不再使用,随时可以被销毁,而实际的销毁权还是在于虚拟机手上。那么它真的什么也不做麽?未必,实际上如果是线程对象它会导致在一定范围内该线程的优先级别提高,导致更快的被销毁来节约内存提高性能。其实从常理来说,我们也可以大概这样猜测出jvm做法的目的。2. 关于重载hashCode()与Collection框架的关系笔者曾经听一位搞Java培训多年的前辈说在他看来hashCode方法没有任何意义,仅仅是为了配合证明具有同样的hashCode会导致equals 方法相等而存在的。连有的前辈都犯这样的错误,其实说明它还是满容易被忽略的。那么hashCode()方法到底做什么用?学过数据结构的课程大家都会知道有一种结构叫hash table,目的是通过给每个对象分配一个唯一的索引来提高查询的效率。那么Java也不会肆意扭曲改变这个概念,所以hashCode唯一的作用就是为支持数据结构中的哈希表结构而存在的,换句话说,也就是只有用到集合框架的 Hashtable、HashMap、HashSet的时候,才需要重载hashCode()方法,这样才能使得我们能人为的去控制在哈希结构中索引是否相等。笔者举一个例子:曾经为了写一个求解类程序,需要随机列出1,2,3,4组成的不同排列组合,所以笔者写了一个数组类用int[]来存组合结果,然后把随机产生的组合加入一个HashSet中,就是想利用HashSet不包括重复元素的特点。可是HashSet怎么判断是不是重复的元素呢?当然是通过 hashCode()返回的结果是否相等来判断啦,可做一下这个实验:int[] A = {1,2,3,4};int[] B = {1,2,3,4};System.out.println(A.hashCode());System.out.println(B.hashCode());这明明是同一种组合,却是不同的hashCode,加入Set的时候会被当成不同的对象。这个时候我们就需要自己来重写hashCode()方法了,如何写呢?其实也是基于原始的hashCode(),毕竟那是操作系统的实现, 找到相通对象唯一的标识,实现方式很多,笔者的实现方式是:首先重写了toString()方法:return A[0]“+” A[1]“+” A[2]“+” A[3]; //显示上比较直观然后利用toString()来计算hashCode():return this.toString().hashCode();这样上述A和B返回的就都是”1234”,在测试toString().hashCode(),由于String在内存中的副本是一样的,”1234”.hashCode()返回的一定是相同的结果。说到这,相信大家能理解得比我更好,今后千万不要再误解hashCode()方法的作用。3. 关于Class类的成员函数与Java反射机制很早刚接触Java就听很多老师说过Java的动态运行时机制、反射机制等。确实它们都是Java的显著特点,运行时加载笔者在第一篇介绍过了,现在想讲讲反射机制。在Java中,主要是通过java.lang包中的Class类和Method类来实现内存反射机制的。熟悉C++的人一定知道下面这样在C++中是做不到的:运行时以字符串参数传递一个类名,就可以得到这个类的所有信息,包括它所有的方法,和方法的详细信息。还可以实例化一个对象,并通过查到的方法名来调用该对象的任何方法。这是因为Java的类在内存中除了C++中也有的静态动态数据区之外,还包括一份对类自身的描述,也正是通过这描述中的信息,才能帮助我们才运行时读取里面的内容,得到需要加载目标类的所有信息,从而实现反射机制。大家有没有想过当我们需要得到一个JavaBean的实例的时候,怎么知道它有哪些属性呢?再明显简单不过的例子就是自己写一个JavaBean的解析器:a. 通过Class.forName(“Bean的类名”)得到Class对象,例如叫ABeanClassb. 通过ABeanClass的getMethods()方法,得到Method[]对象c. 按照规范所有get方法名后的单词就代表着该Bean的一个属性d. 当已经知道一个方法名,可以调用newInstance()得到一个实例,然后通过invoke()方法将方法的名字和方法需要用的参数传递进去,就可以动态调用此方法。当然还有更复杂的应用,这里就不赘述,大家可以参考Class类和Method类的方法。4. 坦言Synchronize的本质Synchronize大家都知道是同步、加锁的意思,其实它的本质远没有大家想得那么复杂。声明Synchronize的方法被调用的时候,锁其实是加载对象上,当然如果是静态类则是加在类上的锁,调用结束锁被解除。它的实现原理很简单,仅仅是不让第二把锁再次被加在同一个对象或类上,仅此而已。一个简单的例子足以说明问题:class A{synchronized void f(){}void g(){}}当A的一个对象a被第一个线程调用其f()方法的时候,第二个线程不能调用a的synchronized方法例如f(),因为那是在试图在对象上加第二把锁。但调用g()却是可以的,因为并没有在同一对象上加两把锁的行为产生。这样大家能理解了麽?明白它的原理能更好的帮助大家设计同步机制,不要滥用加锁。PS:下篇笔者计划开始对J2ee接触到的各个方面来进行总结,谈谈自己的经验和想法。希望大家还能一如既往的支持笔者写下去,指正不足之处。Java杂谈(四)不知不觉已经写到第四篇了,论坛里面不断的有朋友鼓励我写下去。坚持自己的作风,把一切迷惑不容易理清楚的知识讲出来,讲到大家都能听懂,那么自己就真的懂了。最近在公司实习的时候Trainer跟我讲了很多经典事迹,对还未毕业的我来说是笔不小的财富,我自己的信念是:人在逆境中成长的速度要远远快过顺境中,这样来看一切都能欣然接受了。好了,闲话不说了,第三篇讲的是反射机制集合框架之类的,这次打算讲讲自己对反序列化和多线程的理解。希望能对大家学习Java起到帮助??1.关于序列化和反序列化应该大家都大概知道Java中序列化和反序列化的意思,序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流的传输,反序列化的意思就是把这个接受到的二进制流重新组装成原来的对象逆过程。它们在Java中分别是通过ObjectInputStream和 ObjectInputStream这两个类来实现的(以下分别用ois和oos来简称)。oos的writeObject()方法用来执行序列化的过程,ois的readObject()用来执行反序列化的过程,在传输二进制流之前,需要讲这两个高层流对象连接到同一个Channel上,这个Channel可以是磁盘文件,也可以是socket底层流。所以无论用哪种方式,底层流对象都是以构造函数参数的形式传递进oos和ois这两个高层流,连接完毕了才可以进行二进制数据传输的。例子:可以是文件流通道file = new File(“C:/data.dat”);oos = new ObjectOutputStream(new FileOutputStream(file));ois = new ObjectInputStream(new FileInputStream(file));或者网络流通道oos = new ObjectOutputStream(socket.getOutputStream());ois = new ObjectInputStream(socket.getInputStream());不知道大家是否注意到oos总是在ois之前定义,这里不希望大家误解这个顺序是固定的么?回答是否定的,那么有顺序要求么?回答是肯定的。原则是什么呢?原则是互相对接的输入/输出流之间必须是output流先初始化然后再input流初始化,否则就会抛异常。大家肯定会问为什么?只要稍微看一看这两个类的源代码文件就大概知道了,output流的任务很简单,只要把对象转换成二进制往通道中写就可以了,但input流需要做很多准备工作来接受并最终重组这个Object,所以ObjectInputStream的构造函数中就需要用到output初始化发送过来的header信息,这个方法叫做 readStreamHeader(),它将会去读两个Short值用于决定用多大的缓存来存放通道发送过来的二进制流,这个缓存的size因jre的版本不同是不一样的。所以output如果不先初始化,input的构造函数首先就无法正确运行。对于上面两个例子,第一个顺序是严格的,第二个因为oos和ois连接的已经不是对方了,而是socket另外一端的流,需要严格按照另外一方对接的output流先于对接的input流打开才能顺利运行。这个writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以对象能一个一个接连不断的传过来,有很多人在运行的时候会碰到EOFException, 然后百思不得其解,去各种论坛问解决方案。其实笔者这里想说,这个异常不是必须声明的,也就是说它虽然是异常,但其实是正常运行结束的标志。EOF表示读到了文件尾,发送结束自然连接也就断开了。如果这影响到了你程序的正确性的话,请各位静下心来看看自己程序的业务逻辑,而不要把注意力狭隘的聚集在发送和接受的方法上。因为笔者也被这样的bug困扰了1整天,被很多论坛的帖子误解了很多次最后得出的教训。如果在while循环中去readObject,本质上是没有问题的,有对象数据来就会读,没有就自动阻塞。那么抛出EOFException一定是因为连接断了还在继续read,什么原因导致连接断了呢?一定是业务逻辑哪里存在错误,比如NullPoint、 ClassCaseException、ArrayOutofBound,即使程序较大也没关系,最多只要单步调适一次就能很快发现bug并且解决它。难怪一位程序大师说过:解决问题90%靠经验,5%靠技术,剩下5%靠运气!真是金玉良言,笔者大概查阅过不下30篇讨论在while循环中使用 readObject抛出EOFExceptionde 的帖子,大家都盲目的去关注解释这个名词、反序列化的行为或反对这样写而没有一个人认为EOF是正确的行为,它其实很老实的在做它的事情。为什么大家都忽略了真正出错误的地方呢?两个字,经验!2.关于Java的多线程编程关于Java的线程,初学或者接触不深的大概也能知道一些基本概念,同时又会很迷惑线程到底是怎么回事?如果有人认为自己已经懂了不妨来回答下面的问题:a. A对象实现Runnable接口,A.start()运行后所谓的线程对象是谁?是A么?b. 线程的wait()、notify()方法到底是做什么时候用的,什么时候用?c. 为什么线程的suspend方法会被标注过时,不推荐再使用,线程还能挂起么?d. 为了同步我们会对线程方法声明Synchronized来加锁在对象上,那么如果父类的f()方法加了Synchronized,子类重写f()方法必须也加Synchronized么?如果子类的f()方法重写时声明Synchronized并调用super.f(),那么子类对象上到底有几把锁呢?会因为竞争产生死锁么?呵呵,各位能回答上来几道呢?如果这些都能答上来,说明对线程的概念还是满清晰的,虽说还远远不能算精通。笔者这里一一做回答,碍于篇幅的原因,笔者尽量说得简介一点,如果大家有疑惑的欢迎一起讨论。首先第一点,线程跟对象完全是两回事,虽然我们也常说线程对象。但当你用run()和start()来启动一个线程之后,线程其实跟这个继承了 Thread或实现了Runnable的对象已经没有关系了,对象只能算内存中可用资源而对象的方法只能算内存正文区可以执行的代码段而已。既然是资源和代码段,另外一个线程当然也可以去访问,main函数执行就至少会启动两个线程,一个我们称之为主线程,还一个是垃圾收集器的线程,主线程结束就意味着程序结束,可垃圾收集器线程很可能正在工作。第二点,wait()和sleep()类似,都是让线程处于阻塞状态暂停一段时间,不同之处在于wait会释放当前线程占有的所有的锁,而 sleep不会。我们知道获得锁的唯一方法是进入了Synchronized保护代码段,所以大家会发现只有Synchronized方法中才会出现 wait,直接写会给警告没有获得当前对象的锁。所以notify跟wait配合使用,notify会重新把锁还给阻塞的线程重而使其继续执行,当有多个对象wait了,notify不能确定唤醒哪一个,必经锁只有一把,所以一般用notifyAll()来让它们自己根据优先级等竞争那唯一的一把锁,竞争到的线程执行,其他线程只要继续wait。从前Java允许在一个线程之外把线程挂起,即调用suspend方法,这样的操作是极不安全的。根据面向对象的思想每个对象必须对自己的行为负责,而对自己的权力进行封装。如果任何外步对象都能使线程被挂起而阻塞的话,程序往往会出现混乱导致崩溃,所以这样的方法自然是被毙掉了啦。最后一个问题比较有意思,首先回答的是子类重写f()方法可以加Synchronized也可以不加,如果加了而且还内部调用了super.f ()的话理论上是应该对同一对象加两把锁的,因为每次调用Synchronized方法都要加一把,调用子类的f首先就加了一把,进入方法内部调用父类的 f又要加一把,加两把不是互斥的么?那么调父类f加锁不就必须永远等待已经加的锁释放而造成死锁么?实际上是不会的,这个机制叫重进入,当父类的f方法试图在本对象上再加一把锁的时候,因为当前线程拥有这个对象的锁,也可以理解为开启它的钥匙,所以同一个线程在同一对象上还没释放之前加第二次锁是不会出问题的,这个锁其实根本就没有加,它有了钥匙,不管加几把还是可以进入锁保护的代码段,畅通无阻,所以叫重进入,我们可以简单认为第二把锁没有加上去。总而言之,Synchronized的本质是不让其他线程在同一对象上再加一把锁。Java杂谈(五)本来预计J2se只讲了第四篇就收尾了,可是版主厚爱把帖子置顶长期让大家浏览让小弟倍感责任重大,务必追求最到更好,所以关于J2se一些没有提到的部分,决定再写几篇把常用的部分经验全部写出来供大家讨论切磋。这一篇准备讲一讲Xml解析包和Java Swing,然后下一篇再讲java.security包关于Java沙箱安全机制和RMI机制,再进入J2ee的部分,暂时就做这样的计划了。如果由于实习繁忙更新稍微慢了一些,希望各位见谅!1. Java关于XML的解析 相信大家对XML都不陌生,含义是可扩展标记语言。本身它也就是一个数据的载体以树状表现形式出现。后来慢慢的数据变成了信息,区别是信息可以包括可变的状态从而针对程序硬编码的做法变革为针对统一接口硬编码而可变状态作为信息进入了XML中存储。这样改变状态实现扩展的唯一工作是在XML中添加一段文本信息就可以了,代码不需要改动也不需要重新编译。这个灵活性是XML诞生时候谁也没想到的。当然,如果接口要能提取XML中配置的信息就需要程序能解析规范的XML文件,Java中当然要提高包对这个行为进行有利支持。笔者打算讲到的两个包是 org.w3c.dom和javax.xml.parsers和。(大家可以浏览一下这些包中间的接口和类定义)Javax.xml.parsers包很简单,没有接口,两个工厂配两个解析器。显然解析XML是有两种方式的:DOM解析和SAX解析。本质上并没有谁好谁不好,只是实现的思想不一样罢了。给一个XML文件的例子: &?xml version=”1.0” encoding=”UTF-8” & &root & &child name=”Kitty” & A Cat &/child & &/root &所谓DOM解析的思路是把整个树状图存入内存中,需要那个节点只需要在树上搜索就可以读到节点的属性,内容等,这样的好处是所有节点皆在内存可以反复搜索重复使用,缺点是需要消耗相应的内存空间。自然SAX解析的思路就是为了克服DOM的缺点,以事件触发为基本思路,顺序的搜索下来,碰到了Element之前触发什么事件,碰到之后做什么动作。由于需要自己来写触发事件的处理方案,所以需要借助另外一个自定义的Handler,处于org.xml.sax.helpers包中。它的优点当然是不用整个包都读入内存,缺点也是只能顺序搜索,走完一遍就得重来。大家很容易就能猜到,接触到的J2ee框架用的是哪一种,显然是DOM。因为类似Struts,Hibernate框架配置文件毕竟是很小的一部分配置信息,而且需要频繁搜索来读取,当然会采用DOM方式(其实SAX内部也是用DOM采用的结构来存储节点信息的)。现在无论用什么框架,还真难发现使用 SAX来解析XML的技术了,如果哪位仁兄知道,请让笔者也学习学习。既然解析方式有了,那么就需要有解析的存储位置。不知道大家是否发现org.w3c.dom这个包是没有实现类全部都是接口的。这里笔者想说一下Java 如何对XML解析是Jdk应该考虑的事,是它的责任。而w3c组织是维护定义XML标准的组织,所以一个XML结构是怎么样的由w3c说了算,它不关心 Java如何去实现,于是乎规定了所有XML存储的结构应该遵循的规则,这就是org.w3c.dom里全部的接口目的所在。在笔者看来,简单理解接口的概念就是实现者必须遵守的原则。整个XML对应的结构叫Document、子元素对应的叫做Element、还有节点相关的Node、NodeList、Text、Entity、 CharacterData、CDATASection等接口,它们都可以在XML的语法中间找到相对应的含义。由于这里不是讲解XML基本语法,就不多介绍了。如果大家感兴趣,笔者也可以专门写一篇关于XML的语法规则帖与大家分享一下。2. Java Swing Swing是一个让人又爱又恨的东西,可爱之处在于上手很容易,较AWT比起来Swing提供的界面功能更加强大,可恨之处在于编复杂的界面工作量实在是巨大。笔者写过超过3000行的Swing界面,感觉用户体验还不是那么优秀。最近又写过超过6000行的,由于功能模块多了,整体效果还只是一般般。体会最深的就一个字:累! 所以大家现在都陆续不怎么用Swing在真正开发的项目上了,太多界面技术可以取代它了。笔者去写也是迫于无奈组里面大家都没写过,我不入地域谁入?尽管Swing慢慢的在被人忽略,特别是随着B/S慢慢的在淹没C/S,笔者倒是很愿意站出来为Swing正身。每一项技术的掌握绝不是为了流行时尚跟风。真正喜欢Java的朋友们还是应该好好体会一下Swing,相信在校的很多学生也很多在学习它。很可能从Jdk 1.1、1.2走过来的很多大学老师可能是最不熟悉它的。 Swing提供了一组轻组件统称为JComponent,它们与AWT组件的最大区别是JComponent全部都是Container,而 Container的特点是里面可以装载别的组件。在Swing组件中无论是JButton、JLabel、JPanel、JList等都可以再装入任何其他组件。好处是程序员可以对Swing组件实现“再开发”,针对特定需求构建自己的按钮、标签、画板、列表之类的特定组件。有轻自然就有重,那么轻组件和重组件区别是?重组件表现出来的形态因操作系统不同而异,轻组件是Swing自己提供GUI,在跨平台的时候最大程度的保持一致。 那么在编程的时候要注意一些什么呢?笔者谈谈自己的几点经验:a. 明确一个概念,只有Frame组件才可以单独显示的,也许有人会说JOptionPane里面的静态方法就实现了单独窗口出现,但追寻源代码会发现其实现实出来的Dialog也需要依托一个Frame窗体,如果没有指定就会默认产生一个然后装载这个Dialog显示出来。b. JFrame是由这么几部分组成: 最底下一层JRootPane,上面是glassPane (一个JPanel)和layeredPane (一个JLayeredPane),而layeredPane又由contentPane(一个JPanel)和menuBar构成。我们的组件都是加在 contentPane上,而背景图片只能加在layeredPane上面。至于glassPane是一个透明的覆盖了contentPane的一层,在特定效果中将被利用到来记录鼠标坐标或掩饰组件。c. 为了增强用户体验,我们会在一些按钮上添加快捷键,但Swing里面通常只能识别键盘的Alt键,要加入其他的快捷键,必须自己实现一个ActionListener。d. 通过setLayout(null)可以使得所有组件以setBounds()的四个参数来精确定位各自的大小、位置,但不推荐使用,因为好的编程风格不应该在Swing代码中硬编码具体数字,所有的数字应该以常数的形式统一存在一个静态无实例资源类文件中。这个静态无实例类统一负责Swing界面的风格,包括字体和颜色都应该包括进去。e. 好的界面设计有一条Golden Rule: 用户不用任何手册通过少数尝试就能学会使用软件。所以尽量把按钮以菜单的形式(不管是右键菜单还是窗体自带顶部菜单)呈现给顾客,除非是频繁点击的按钮才有必要直接呈现在界面中。其实Swing的功能是相当强大的,只是现在应用不广泛,专门去研究大概是要花不少时间的。笔者在各网站论坛浏览关于Swing的技巧文章还是比较可信的,自己所学非常有限,各人体会对Swing各个组件的掌握就是一个实践积累的过程。笔者只用到过以上这些,所以只能谈谈部分想法,还望大家见谅!Java杂谈(六)这篇是笔者打算写的J2se部分的最后一篇了,这篇结束之后,再写J2ee部分,不知道是否还合适写在这个版块?大家可以给点意见,谢谢大家对小弟这么鼓励一路写完前六篇Java杂谈的J2se部分。最后这篇打算谈一谈Java中的RMI机制和JVM沙箱安全框架。1. Java中的RMI机制 RMI的全称是远程方法调用,相信不少朋友都听说过,基本的思路可以用一个经典比方来解释:A计算机想要计算一个两个数的加法,但A自己做不了,于是叫另外一台计算机B帮忙,B有计算加法的功能,A调用它就像调用这个功能是自己的一样方便。这个就叫做远程方法调用了。远程方法调用是EJB实现的支柱,建立分布式应用的核心思想。这个很好理解,再拿上面的计算加法例子,A只知道去call计算机B的方法,自己并没有B的那些功能,所以A计算机端就无法看到B执行这段功能的过程和代码,因为看都看不到,所以既没有机会窃取也没有机会去改动方法代码。EJB正式基于这样的思想来完成它的任务的。当简单的加法变成复杂的数据库操作和电子商务交易应用的时候,这样的安全性和分布式应用的便利性就表现出来优势了。好了,回到细节上,要如何实现远程方法调用呢?我希望大家学习任何技术的时候可以试着依赖自己的下意识判断,只要你的想法是合理健壮的,那么很可能实际上它就是这么做的,毕竟真理都蕴藏在平凡的生活细节中。这样只要带着一些薄弱的Java基础来思考RMI,其实也可以想出个大概来。a) 需要有一个服务器角色,它拥有真正的功能代码方法。例如B,它提供加法服务 b) 如果想远程使用B的功能,需要知道B的IP地址 c) 如果想远程使用B的功能,还需要知道B中那个特定服务的名字我们很自然可以想到这些,虽然不完善,但已经很接近正确的做法了。实际上RMI要得以实现还得意于Java一个很重要的特性,就是Java反射机制。我们需要知道服务的名字,但又必须隐藏实现的代码,如何去做呢?答案就是:接口! 举个例子: public interface Person(){ public void sayHello(); }Public class PersonImplA implements Person{ public PersonImplA(){}public void sayHello(){ System.out.println(“Hello!”);} }Public class PersonImplB implements Person{ public PersonImplB(){}public void sayHello(){ System.out.println(“Nice to meet you!”);} }客户端:Person p = Naming.lookup(“PersonService”); p.sayHello();就这几段代码就包含了几乎所有的实现技术,大家相信么?客户端请求一个say hello服务,服务器运行时接到这个请求,利用Java反射机制的Class.newInstance()返回一个对象,但客户端不知道服务器返回的是 ImplA还是ImplB,它接受用的参数签名是Person,它知道实现了Person接口的对象一定有sayHello()方法,这就意味着客户端并不知道服务器真正如何去实现的,但它通过了解Person接口明确了它要用的服务方法名字叫做sayHello()。如此类推,服务器只需要暴露自己的接口出来供客户端,所有客户端就可以自己选择需要的服务。这就像餐馆只要拿出自己的菜单出来让客户选择,就可以在后台厨房一道道的按需做出来,它怎么做的通常是不让客户知道的!(祖传菜谱吧,^_^)最后一点是我调用lookup,查找一个叫PersonService名字的对象,服务器只要看到这个名字,在自己的目录(相当于电话簿)中找到对应的对象名字提供服务就可以了,这个目录就叫做JNDI (Java命名与目录接口),相信大家也听过的。有兴趣的朋友不妨自己做个RMI的应用,很多前辈的博客中有简单的例子。提示一下利用Jdk的bin目录中rmi.exe和 rmiregistry.exe两个命令就可以自己建起一个服务器,提供远程服务。因为例子很容易找,我就不自己举例子了!2. JVM沙箱&框架 RMI罗唆得太多了,实在是尽力想把它说清楚,希望对大家有帮助。最后的最后,给大家简单讲一下JVM框架,我们叫做Java沙箱。Java沙箱的基本组件如下: a) 类装载器结构 b) class文件检验器 c) 内置于Java虚拟机的安全特性 d) 安全管理器及Java API其中类装载器在3个方面对Java沙箱起作用: a. 它防止恶意代码去干涉善意的代码 b. 它守护了被信任的类库边界 c. 它将代码归入保护域,确定了代码可以进行哪些操作虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。我们常说的包(package)是在Java虚拟机第2版的规范第一次出现,正确定义是由同一个类装载器装载的、属于同一个包、多个类型的集合。类装载器采用的机制是双亲委派模式。具体的加载器框架我在Java杂谈(一)中已经解释过了,当时说最外层的加载器是AppClassLoader,其实算上网络层的话AppClassLoader也可以作为parent,还有更外层的加载器URLClassLoader。为了防止恶意攻击由URL加载进来的类文件我们当然需要分不同的访问命名空间,并且制定最安全的加载次序,简单来说就是两点:a. 从最内层JVM自带类加载器开始加载,外层恶意同名类得不到先加载而无法使用 b. 由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。附:关于Java的平台无关性,有一个例子可以很明显的说明这个特性: 一般来说,C或C++中的int占位宽度是根据目标平台的字长来决定的,这就意味着针对不同的平台编译同一个C++程序在运行时会有不同的行为。然而对于 Java中的int都是32位的二进制补码标识的有符号整数,而float都是遵守IEEE 754浮点标准的32位浮点数。PS: 这个小弟最近也没时间继续研究下去了,只是想抛砖引玉的提供给大家一个初步认识JVM的印象。有机会了解一下JVM的内部结构对今后做Java开发是很有好处的。本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lenhan12345/archive//4234333.aspx
最新教程周点击榜
微信扫一扫}

我要回帖

更多关于 出生日期 英文 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信