javaSE27天复习总结

2023-05-24,

JAVA学习总结    2

第一天    2

1:计算机概述(了解)    2

(1)计算机    2

(2)计算机硬件    2

(3)计算机软件    2

(4)软件开发(理解)    2

(5)语言    2

(6)人机交换    2

2:键盘功能键的认识和快捷键(掌握)    2

(1)功能键的认识    2

(2)快捷键    3

3:常见的DOS命令(掌握)    3

(1)常见的如下    3

(2)其他的几个(了解)    3

4:Java语言概述(了解)    4

(1)Java语言的发展史    4

(2)Java语言的特点    4

(3)Java语言是跨平台的,请问是如何保证的呢?(理解)    4

(4)Java语言的平台    4

5:JDK,JRE,JVM的作用及关系(掌握)    4

(1)作用    4

(2)关系    4

6:JDK的下载,安装,卸载(掌握)    4

(1)下载到官网。    4

(2)安装    5

(3)卸载    5

7:第一个程序:HelloWorld案例(掌握)    5

(1)程序解释:    5

(2)Java程序的开发执行流程:    5

8:常见的问题(掌握)    6

(1)扩展名被隐藏    6

(2)我要求文件名称和类名一致。    6

(3)Java语言严格区分大小写,请注意。    6

(4)见到非法字符: \65307肯定是中文问题。    6

(5)括号的配对问题。    6

(6)遇到    6

9:path环境变量(掌握)    6

(1)path环境变量的作用    6

(2)path配置的两种方案:    6

10:classpath环境变量(理解)    7

(1)classpath环境变量的作用    7

(2)classpath环境变量的配置    7

第二天    7

1:关键字(掌握)    7

2:标识符(掌握)    7

(1)就是给类,接口,方法,变量等起名字的字符序列    7

(2)组成规则:    7

(3)注意事项:    8

(4)常见的命名规则(见名知意)    8

3:注释(掌握)    8

(1)就是对程序进行解释说明的文字    8

(2)分类:    8

(3)把HelloWorld案例写了一个带注释的版本。    8

(4)注释的作用    9

4:常量(掌握)    9

5:进制转换(了解)    9

(1)其他进制到十进制    9

(2)十进制到其他进制    9

(3)进制转换的快速转换法    9

6:变量(掌握)    10

7:数据类型(掌握)    10

(1)Java是一种强类型语言,针对每种数据都提供了对应的数据类型。    10

(2)分类:    10

(3)基本数据类型    10

8:数据类型转换(掌握)    11

(1)boolean类型不参与转换    11

(2)默认转换    11

(3)强制转换    11

(4)思考题和面试题:    11

A:下面两种方式有区别吗?    11

B:下面的程序有问题吗,如果有,在哪里呢?    11

C:下面的操作结果是什么呢?    11

D:字符参与运算    11

E:字符串参与运算    11

第三天    12

1:运算符(掌握)    12

(1)算术运算符    12

(2)赋值运算符    12

(3)比较运算符    13

(4)逻辑运算符    13

(5)位运算符(了解)    13

(6)三元运算符    14

2:键盘录入(掌握)    14

3:流程控制语句    14

4:if语句(掌握)    14

(1)三种格式    15

(2)注意事项    16

(3)案例:    16

(4)三元运算符和if语句第二种格式的关系    16

第四天    16

1:switch语句(掌握)    16

(1)格式:    17

(2)面试题    17

(3)执行流程:    17

(4)注意事项:    17

(5)案例:    18

(6)if语句和switch语句各自的场景    18

2:循环语句(掌握)    18

(1)有三种:for,while,do...while    18

(2)for循环语句    18

(3)while循环    19

(4)do...while循环    20

(5)循环使用的注意事项(死循环)    20

3:控制跳转语句(掌握)    20

(1)break:中断的意思    20

(2)continue:继续    20

(3)return:返回    21

第五天    21

1:方法(掌握)    21

(1)方法:就是完成特定功能的代码块。    21

(2)格式:    21

(3)两个明确:    22

(4)方法调用    22

(5)案例:    22

(6)方法的注意事项    22

(7)方法重载    22

(8)方法重载案例    22

2:数组(掌握)    22

(1)数组定义:    23

(2)特点:    23

(3)定义格式    23

(4)数组的初始化    23

A:动态初始化    23

B:静态初始化    23

(5)Java的内存分配    23

(6)数组内存图    24

(7)数组操作的两个常见小问题    24

(8)数组的常见操作    24

A:遍历    24

B:最值    24

最大值:    25

最小值:    25

C:逆序    25

D:查表    26

E:基本查找    26

第六天    26

1:二维数组(理解)    26

(1)元素是一维数组的数组。    27

(2)格式:    27

(3)案例(掌握):    27

2:两个思考题(理解)    27

(1)Java中的参数传递问题    27

(2)数据加密问题    27

3:面向对象(掌握)    27

(1)面向对象    27

(2)面向对象的思想特点    27

(3)把大象装进冰箱(理解)    28

(4)类与对象    28

(5)类的定义及使用    28

(6)案例:    28

(7)内存图    29

(8)Java程序的开发,设计和特征    29

第七天    29

1:成员变量和局部变量的区别(理解)    29

(1)在类中的位置不同    29

(2)在内存中的位置不同    29

(3)生命周期不同    29

(4)初始化值不同    29

2:类作为形式参数的问题?(理解)    30

3:匿名对象(理解)    30

4:封装(理解)    30

5:private关键字(掌握)    30

6:this关键字(掌握)    31

7:构造方法(掌握)    31

(1)作用:    31

(2)格式:    31

(3)构造方法的注意事项    31

(4)给成员变量赋值的方式    31

(5)标准案例    31

8:代码:Student s = new Student();做了哪些事情?(理解)    32

9:面向对象的练习题(掌握)    33

第八天    33

1:如何制作帮助文档(了解)    33

2:通过JDK提供的API学习了Math类(掌握)    33

(1)API(Application Programming Interface)    33

(2)如何使用呢?    33

(3)Math类    33

3:代码块(理解)    34

4:继承(掌握)    34

(1)继承的定义    34

(2)Java中如何表示继承呢?格式是什么呢?    34

(3)继承的好处:    34

(4)继承的弊端:    34

(5)Java中继承的特点    35

(6)继承的注意事项:    35

(7)什么时候使用继承呢?    35

(8)Java继承中的成员关系    35

A:成员变量    35

B:构造方法    35

C:成员方法    35

(9)两个面试题:    36

(10)数据初始化的面试题    36

(11)案例:    36

第九天    36

1:final关键字(掌握)    36

(1)定义:    36

(2)特点:    36

(3)面试相关:    36

A:局部变量    37

B:初始化时机    37

2:多态(掌握)    37

(1)多态的定义:    37

(2)多态的前提:    37

(3)多态中的成员访问特点    37

(4)多态的好处:    38

(5)多态的弊端:    38

(6)多态中的转型    38

A:向上转型    38

B:向下转型    38

(7)孔子装爹的案例帮助大家理解多态    38

(8)多态的练习    38

3:抽象类(掌握)    38

(1)定义:    39

(2)抽象类的特点    39

(3)抽象类的成员特点:    39

(4)抽象类的练习    39

(5)抽象类的几个小问题    39

4:接口(掌握)    39

(1)回顾猫狗案例,它们仅仅提供一些基本功能。    40

(2)接口的特点:    40

(3)接口的成员特点:    40

(4)类与类,类与接口,接口与接口    40

(5)抽象类和接口的区别(自己补齐)?    40

(6)练习:    41

第十天    41

1:形式参数和返回值的问题(理解)    41

(1)形式参数:    41

(2)返回值类型:    41

(3)链式编程    41

2:包(理解)    41

(1)其实就是文件夹    41

(2)作用:    42

(3)包的定义(掌握)    42

(4)注意事项:(掌握)    42

(5)带包的编译和运行    42

3:导包(掌握)    42

4:权限修饰符(掌握)    42

5:常见的修饰符(理解)    43

6:内部类(理解)    43

(1)定义:    44

(2)内部类的访问规则    44

(3)内部类的分类    44

(4)成员内部类    44

(5)成员内部类的面试题(填空)    44

(6)局部内部类    44

(7)匿名内部类(掌握)    45

(8)匿名内部类在开发中的使用    45

(9)匿名内部类的面试题(补齐代码)    46

第十一天    46

1:Eclipse的概述使用(掌握)    46

2:API的概述(了解)    47

3:Object类(掌握)    47

第十二天    48

1:Scanner的使用(了解)    48

(1)在JDK5以后出现的用于键盘录入数据的类。    48

(2)构造方法:    48

(3)基本方法格式:    48

(4)要掌握的两个方法    48

(5)需要注意的小问题    48

2:String类的概述和使用(掌握)    48

(1)多个字符组成的一串数据。    49

(2)构造方法:    49

(3)字符串的特点    49

(4)字符串的面试题(看程序写结果)    49

(5)字符串的功能(自己补齐方法中文意思)    50

(6)字符串的案例    50

第十三天    51

1:StringBuffer(掌握)    51

(1)说明:    51

(2)StringBuffer的构造方法    51

(3)StringBuffer的常见功能(自己补齐方法的声明和方法的解释)    51

(4)StringBuffer的练习(做一遍)    52

(5)面试题    52

(6)注意的问题:    52

2:数组高级以及Arrays(掌握)    52

(1)排序    52

A:冒泡排序    52

B:选择排序    53

(2)查找    53

A:基本查找    53

B:二分查找(折半查找)    54

(3)Arrays工具类    54

3:Integer(掌握)    54

(1)说明:    55

(2)Integer的构造方法    55

(3)String和int的相互转换    55

(4)其他的功能(了解)    55

(5)JDK5的新特性    55

(6)面试题    55

4:Character(了解)47    55

(1)Character构造方法    56

(2)要掌握的方法:(自己补齐)    56

(3)案例:    56

第十四天    56

1:正则表达式(理解)    56

(1)定义:    56

(2)常见规则    56

A:字符    56

B:字符类    56

C:预定义字符类    57

D:边界匹配器    57

E:Greedy 数量词    57

(3)常见功能:(分别用的是谁呢?)    57

(4)案例    57

2:Math(掌握)    58

3:Random(理解)    58

4:System(掌握)    58

5:BigInteger(理解)    59

6:BigDecimal(理解)    59

7:Date/DateFormat(掌握)    59

8:Calendar(掌握)    60

第十五天    60

1:对象数组(掌握)    60

2:集合(Collection)(掌握)    60

(1)集合的由来?    61

(2)集合和数组的区别?    61

A:长度区别    61

B:内容区别    61

C:元素内容    61

(3)集合的继承体系结构?    61

(4)Collection的功能概述(自己补齐)    61

(5)Collection集合的遍历    62

(6)迭代器    62

(7)Collection集合的案例(遍历方式 迭代器)    62

A:存储字符串并遍历    62

B:存储自定义对象并遍历    63

3:集合(List)(掌握)    64

(1)List是Collection的子接口    64

(2)List的特有功能:(自己补齐)    64

(3)List集合的特有遍历功能    64

(4)列表迭代器的特有功能;(了解)    65

(5)并发修改异常    65

(6)常见数据结构    65

(7)List的子类特点(面试题)    65

(8)List集合的案例(遍历方式 迭代器和普通for)    66

第十六天    66

1:List的子类(掌握)    66

(1)List的子类特点    66

(2)ArrayList    66

(3)Vector    66

(4)LinkedList    67

(5)案例:    67

2:泛型(掌握)    67

(1)泛型概述    67

(2)格式:    67

(3)好处:    68

(4)泛型的前世今生    68

(5)我们在哪里使用呢?    68

3:增强for循环(掌握)    68

4:静态导入(了解)    68

5:可变参数(掌握)    69

6:练习(掌握)    69

7:要掌握的代码    69

第十七天    69

1:登录注册案例(理解)    69

2:Set集合(理解)    70

(1)Set集合的特点    70

(2)HashSet集合(掌握)    70

(3)TreeSet集合    70

(4)案例:    70

3:Collection集合总结(掌握)    70

4:针对Collection集合我们到底使用谁呢?(掌握)    71

5:在集合中常见的数据结构(掌握)    72

第十八天    72

1:Map(掌握)    72

(1)定义:    72

(2)Map和Collection的区别?    72

(3)Map接口功能概述(自己补齐)    72

(4)Map集合的遍历    72

(5)HashMap集合的练习    73

(6)TreeMap集合的练习    73

(7)案例    73

2:Collections(理解)    74

(1)是针对集合进行操作的工具类    74

(2)面试题:Collection和Collections的区别    74

(3)常见的几个小方法:    74

(4)案例    74

第十九天    74

1:异常(理解)    74

(1)程序出现的不正常的情况。    75

(2)异常的体系    75

(3)异常的处理:    75

(4)面试题    75

(5)finally关键字及其面试题    75

(6)自定义异常    76

(7)异常的注意实现    76

2:File(掌握)    76

(1)说明:    76

(2)构造方法    76

(3)File类的功能(自己补齐)    76

(4)案例:    77

第二十天    77

1:递归(理解)    77

2:IO流(掌握)    77

(1)IO用于在设备间进行数据传输的操作    77

(2)分类:    77

(3)FileOutputStream写出数据    78

(4)FileInputStream读取数据    78

(5)案例:2种实现    79

(6)字节缓冲区流    79

(7)案例:4种实现    79

3:自学字符流    79

第二十一天    80

1:字符流(掌握)    80

(1)字节流操作中文数据不是特别的方便,所以就出现了转换流。    80

(2)转换流其实是一个字符流    80

(3)编码表    80

(4)IO流中的编码问题    80

(5)字符流    81

(6)复制文本文件(5种方式)    81

2:IO流小结(掌握)    81

3:案例(理解 练习一遍)    82

第二十二天    82

1:登录注册IO版本案例(掌握)    82

2:数据操作流(操作基本类型数据的流)(理解)    83

3:内存操作流(理解)    83

4:打印流(掌握)    83

(1)字节打印流,字符打印流    84

(2)特点:    84

(3)复制文本文件    84

5:标准输入输出流(理解)    84

6:随机访问流(理解)    85

7:合并流(理解)    85

8:序列化流(理解)    85

9:Properties(理解)    85

10:NIO(了解)    86

第二十三天    86

1:多线程(理解)    86

(1)多线程:一个应用程序有多条执行路径    87

(2)Java程序的运行原理及JVM的启动是多线程的吗?    87

(3)多线程的实现方案(自己补齐步骤及代码    掌握)    87

(4)线程的调度和优先级问题    87

(5)线程的控制(常见方法)    87

(6)线程的生命周期(参照    线程生命周期图解.bmp)    87

(7)电影院卖票程序的实现    88

(8)电影院卖票程序出问题    88

(9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题    88

(10)同步解决线程安全问题    88

(11)回顾以前的线程安全的类    88

第二十四天    89

1:多线程(理解)    89

2:设计模式(理解)    89

(1)面试对象的常见设计原则    90

(2)设计模式概述和分类    90

(3)改进的设计模式    90

(4)Runtime    90

第二十五天    90

1:如何让Netbeans的东西Eclipse能访问。    90

2:GUI(了解)    90

(1)用户图形界面    91

(2)两个包:    91

(3)GUI的继承体系    91

(4)事件监听机制(理解)    91

(5)适配器模式(理解)    91

(6)案例:    91

(7)Netbeans的概述和使用    91

第二十六天    92

1:网络编程(理解)    92

(1)网络编程:用Java语言实现计算机间数据的信息传递和资源共享    92

(2)网络编程模型    92

(3)网络编程的三要素    92

(3)Socket机制    92

(4)UDP协议发送和接收数据(掌握 自己补齐代码)    92

(5)TCP协议发送和接收数据(掌握 自己补齐代码)    93

(6)案例:    93

第二十七天    93

1:反射(理解)    93

(1)类的加载及类加载器    94

(2)反射:    94

(3)反射的使用    94

(4)反射案例    94

(5)动态代理    94

2:设计模式    94

(1)装饰设计模式    94

(2)模版设计模式    94

3:JDK新特性    94

(1)JDK5(掌握)    94

(2)JDK6(了解)    95

(3)JDK7(理解)    95

(4)JDK8(了解)    95

 

 

第一天

1:计算机概述(了解)2

2:键盘功能键的认识和快捷键(掌握)2

3:常见的DOS命令(掌握)3

4:Java语言概述(了解)3

5:JDK,JRE,JVM的作用及关系(掌握)    3

6:JDK的下载,安装,卸载(掌握)4

7:第一个程序:HelloWorld案例(掌握)4

8:常见的问题(掌握)5

9:path环境变量(掌握)5

10:classpath环境变量(理解)5

第二天

1:关键字(掌握)6

2:标识符(掌握)6

3:注释(掌握)7

4:常量(掌握)7

5:进制转换(了解)7

6:变量(掌握)8

7:数据类型(掌握)8

8:数据类型转换(掌握)8

第三天

1:运算符(掌握)10

2:键盘录入(掌握)11

3:流程控制语句12

4:if语句(掌握)12

第四天

1:switch语句(掌握)14

2:循环语句(掌握)15

3:控制跳转语句(掌握)17

第五天

1:方法(掌握)18

2:数组(掌握)19

第六天

1:二维数组(理解)23

2:两个思考题(理解)23

3:面向对象(掌握)23

第七天

1:成员变量和局部变量的区别(理解)25

2:类作为形式参数的问题?(理解)25

3:匿名对象(理解)25

4:封装(理解)25

5:private关键字(掌握)25

6:this关键字(掌握)26

7:构造方法(掌握)26

8:代码:Student s = new Student();做了哪些事情?(理解)27

9:面向对象的练习题(掌握)27

第八天

1:如何制作帮助文档(了解)28

2:通过JDK提供的API学习了Math类(掌握)28

3:代码块(理解)28

4:继承(掌握)28

第九天

1:final关键字(掌握)30

2:多态(掌握)30

3:抽象类(掌握)32

4:接口(掌握)33

第十天

1:形式参数和返回值的问题(理解)35

2:包(理解)35

3:导包(掌握)35

4:权限修饰符(掌握)36

5:常见的修饰符(理解)36

6:内部类(理解)37

第十一天

1:Eclipse的概述使用(掌握)40

2:API的概述(了解)40

3:Object类(掌握)40

第十二天

1:Scanner的使用(了解)41

2:String类的概述和使用(掌握)41

 

 

第十三天

1:StringBuffer(掌握)44

2:数组高级以及Arrays(掌握)44

3:Integer(掌握)46

4:Character(了解)47

第十四天

1:正则表达式(理解)47

2:Math(掌握)49

3:Random(理解)49

4:System(掌握)49

5:BigInteger(理解)50

6:BigDecimal(理解)50

7:Date/DateFormat(掌握)50

8:Calendar(掌握)51

第十五天

1:对象数组(掌握)52

2:集合(Collection)(掌握)52

3:集合(List)(掌握)55

第十六天

1:List的子类(掌握)57

2:泛型(掌握)58

3:增强for循环(掌握)58

4:静态导入(了解)58

5:可变参数(掌握)59

6:练习(掌握)59

7:要掌握的代码59

第十七天

1:登录注册案例(理解)60

2:Set集合(理解)60

3:Collection集合总结(掌握)60

4:针对Collection集合我们到底使用谁呢?(掌握)61

5:在集合中常见的数据结构(掌握)61

第十八天

1:Map(掌握)62

2:Collections(理解)63

第十九天

1:异常(理解)64

2:File(掌握)65

第二十天

 

1:递归(理解)66

2:IO流(掌握)66

3:自学字符流

 

第二十一天

1:字符流(掌握)69

第二十一天

1:字符流(掌握)69

2:IO流小结(掌握)70

3:案例(理解 练习一遍)71

第二十二天

1:登录注册IO版本案例(掌握)72

2:数据操作流(操作基本类型数据的流)(理解)72

3:内存操作流(理解)72

4:打印流(掌握)72

5:标准输入输出流(理解)73

6:随机访问流(理解)73

7:合并流(理解)73

8:序列化流(理解)73

9:Properties(理解)74

10:NIO(了解)74

第二十三天

1:多线程(理解)75

第二十四天

1:多线程(理解)77

2:设计模式(理解)77

第二十五天

1:如何让Netbeans的东西Eclipse能访问79

2:GUI(了解)79

第二十六天

1:网络编程(理解)80

第二十七天

1:反射(理解)82

2:设计模式82

3:JDK新特性82

 

 

JAVA学习总结

第一天

1. 计算机概述(了解)
    (1)计算机
    (2)计算机硬件
    (3)计算机软件

        系统软件:window,linux,mac

        应用软件:qq,yy,飞秋

    (4)软件开发(理解)

        软件:是由数据和指令组成的。(计算器)

        开发:就是把软件做出来。

        如何实现软件开发呢?

            就是使用开发工具和计算机语言做出东西来

    (5)语言

        自然语言:人与人交流沟通的

        计算机语言:人与计算机交流沟通的

            C,C++,C#,Java

    (6)人机交换

        图形界面:操作方便只管

        DOS命令:需要记忆一些常见的命令

 

2. 键盘功能键的认识和快捷键(掌握)
    (1)功能键的认识

        tab

        shift

        ctrl

        alt

        windos

        空格

        上下左右

        回车

        截图

    (2)快捷键

        全选    Ctrl+A

        复制    Ctrl+C

        粘贴    Ctrl+V

        剪切    Ctrl+X

        撤销    Ctrl+Z

        保存    Ctrl+S

 

3. 常见的DOS命令(掌握)
    (1)常见的如下

        盘符的切换

            d:回车

        目录的进入

            cd javase

            cd javase\day01\code

        目录的回退

            cd..

            cd\

        清屏

            cls

        退出

            exit

    (2)其他的几个(了解)

        创建目录

        删除目录

        创建文件

        删除文件

        显示目录下的内容

        删除带内容的目录

 

4. Java语言概述(了解)
    (1)Java语言的发展史

        Java之父

        

        JDK1.4.2

        JDK5

        JDK7

    (2)Java语言的特点

        有很多小特点,重点有两个开源,跨平台

    (3)Java语言是跨平台的,请问是如何保证的呢?(理解)

        我们是通过翻译的案例讲解的。

        

        针对不同的操作系统,提高不同的jvm来实现的。

    (4)Java语言的平台

        JavaSE

        JavaME--Android

        JavaEE

 

5. JDK,JRE,JVM的作用及关系(掌握)
    (1)作用

        JVM:保证Java语言跨平台

        JRE:Java程序的运行环境

        JDK:Java程序的开发环境

    (2)关系

        JDK:JRE+工具

        JRE:JVM+类库

 

6. JDK的下载,安装,卸载(掌握)
    (1)下载到官网。

        A:也可以到百度搜索即可。

        B:我给你。

    (2)安装

        A:绿色版    解压就可以使用

        B:安装版    必须一步一步的安装,一般只要会点击下一步即可

        

        注意:

            建议所有跟开发相关的软件都不要安装在有中文或者空格的目录下。

    (3)卸载

        A:绿色版    直接删除文件夹

        B:安装版    

            a:控制面板 -- 添加删除程序

            b:通过专业的软件卸载工具。(比如360的软件管家卸载)

 

7. 第一个程序:HelloWorld案例(掌握)

    

class HelloWorld {

    public static void main(String[] args) {

        System.out.println("HelloWorld");

    }

}

 

    (1)程序解释:

        A:Java程序的最基本单位是类,所以我们要定义一个类。

            格式:class 类名

            举例:class HelloWorld

        B:在类中写内容的时候,用大括号括起来。

        C:Java程序要想执行,必须有main方法。

            格式:public
static
void main(String[] args)

        D:要指向那些东西呢,也用大括号括起来。

        E:你要做什么呢?今天我们仅仅做了一个简单的输出

            格式:System.out.println("HelloWorld");

            注意:""里面的内容是可以改动的。

    

    (2)Java程序的开发执行流程:

        A:编写java源程序(.java)

        B:通过javac命令编译生成.class文件

        C:通过java命令运行.class文件

    

8. 常见的问题(掌握)
    (1)扩展名被隐藏

        如何找到:工具--文件夹选项--查看--去除隐藏扩展名的那个勾勾

    (2)我要求文件名称和类名一致。

        实际上不这样做也是可以的。

        但是,注意:

            javac后面跟的是文件名+扩展名

            java后面跟的类名不带扩展名

    (3)Java语言严格区分大小写,请注意。

         还有就是单词不要写错了。

    (4)见到非法字符: \65307肯定是中文问题。

        我们写程序要求标点符号必须全部是英文状态。

    (5)括号的配对问题。

        一般来说,括号都是成对出现的。

    (6)遇到

        在类 HelloWorld 中找不到主方法, 请将主方法定义为

        肯定是主方法的格式问题。

 

9. path环境变量(掌握)
    (1)path环境变量的作用

        保证javac命令可以在任意目录下运行。

        同理可以配置qq等

    (2)path配置的两种方案:

        A:方案1(了解)

        B:方案2

            找到环境变量的位置,在系统变量里面

            新建:

                变量名:JAVA_HOME

                变量值:D:\develop\Java\jdk1.7.0_60

            修改:

                变量名:Path

                变量值:%JAVA_HOME%\bin;以前的内容

 

10. classpath环境变量(理解)
    (1)classpath环境变量的作用

        保证class文件可以在任意目录下运行

    (2)classpath环境变量的配置

        找到环境变量的位置,在系统变量里面

        新建:

            变量名:classpath

            变量值:E:\JavaSE\day01\code\HelloWorld案例

 

 

第二天

1. 关键字(掌握)

    (1)被Java语言赋予特定含义的单词

    (2)特点:

        全部小写。

    (3)注意事项:

        A:goto和const作为保留字存在。

        B:类似于Notepad++这样的高级记事本会对关键字有特殊颜色标记

2.反码、原码、补码

3. 标识符(掌握)
    (1)就是给类,接口,方法,变量等起名字的字符序列
    (2)组成规则:

        A:英文大小写字母

        B:数字

        C:$和_

    (3)注意事项:

        A:不能以数字开头

        B:不能是java中的关键字

        C:区分大小写

    (4)常见的命名规则(见名知意)

        A:包    全部小写

            单级包:小写

                举例:liuyi,com

            多级包:小写,并用.隔开

                举例:cn.itcast,com.baidu                

        B:类或者接口

            一个单词:首字母大写

                举例:Student,Demo

            多个单词:每个单词首字母大写

                举例:HelloWorld,StudentName

        C:方法或者变量

            一个单词:首字母小写

                举例:name,main

            多个单词:从第二个单词开始,每个单词首字母大写

                举例:studentAge,showAllNames()

        D:常量

            全部大写

            一个单词:大写

                举例:PI

            多个单词:大写,并用_隔开

                举例:STUDENT_MAX_AGE

 

4. 注释(掌握)
    (1)就是对程序进行解释说明的文字
    (2)分类:

        A:单行注释    //

        B:多行注释    /**/

        C:文档注释(后面讲) /** */

    (3)把HelloWorld案例写了一个带注释的版本。

        后面我们要写一个程序的过程。

        需求:

        分析:

        实现:

        代码体现:

    (4)注释的作用

        A:解释说明程序,提高了代码的阅读性。

        B:可以帮助我们调试程序。

            后面我们会讲解一个更高端的一个调试工具

 

5. 常量(掌握)

    (1)在程序执行的过程中,其值不发生改变的量

    (2)分类:

        A:字面值常量

        B:自定义常量(后面讲)

    (3)字面值常量

        A:字符串常量 "hello"

        B:整数常量    12,23

        C:小数常量    12.345

        D:字符常量    'a','A','0'

        E:布尔常量    true,false

        F:空常量    null(后面讲)

    (4)在Java中针对整数常量提供了四种表现形式

        A:二进制    由0,1组成。以0b开头。

        B:八进制    由0,1,...7组成。以0开头。

        C:十进制    由0,1,...9组成。整数默认是十进制。

        D:十六进制    由0,1,...9,a,b,c,d,e,f(大小写均可)组成。以0x开头。

 

6. 进制转换(了解)
    (1)其他进制到十进制

        系数:就是每一个位上的数值

        基数:x进制的基数就是x

        权:对每一个位上的数据,从右,并且从0开始编号,对应的编号就是该数据的权。

        

        结果:系数*基数^权次幂之和。

    (2)十进制到其他进制

        除基取余,直到商为0,余数反转。

    (3)进制转换的快速转换法

        A:十进制和二进制间的转换

            8421码。

        B:二进制到八进制,十六进制的转换


7. 变量(掌握)

    (1)在程序的执行过程中,其值在某个范围内可以发生改变的量

    (2)变量的定义格式:

        A:数据类型 变量名 = 初始化值;

        B:数据类型 变量名;

         变量名 = 初始化值;

 

8. 数据类型(掌握)
    (1)Java是一种强类型语言,针对每种数据都提供了对应的数据类型。
    (2)分类:

        A:基本数据类型:4类8种

        B:引用数据类型:类,接口,数组。

    (3)基本数据类型

        A:整数            占用字节数

            byte            1

            short            2

            int             4

            long            8

        B:浮点数

            float            4

            double            8

        C:字符

            char            2

        D:布尔

            boolean            1

            

        注意:

            整数默认是int类型,浮点数默认是double。

            

            长整数要加L或者l。

            单精度的浮点数要加F或者f。

 

9. 数据类型转换(掌握)
    (1)boolean类型不参与转换
    (2)默认转换

        A:从小到大

        B:byte,short,char -- int -- long -- float -- double

        C:byte,short,char之间不相互转换,直接转成int类型参与运算。

    (3)强制转换

        A:从大到小

        B:可能会有精度的损失,一般不建议这样使用。

        C:格式:

            目标数据类型 变量名 = (目标数据类型) (被转换的数据);

    (4)思考题和面试题:

        A:下面两种方式有区别吗?

            float
f1 = 12.345f;

            float
f2 = (float)12.345;

        B:下面的程序有问题吗,如果有,在哪里呢?

            byte
b1 = 3;

            byte
b2 = 4;

            byte
b3 = b1 + b2;(这个是有问题的,类型提升)

            byte
b4 = 3 + 4;

        C:下面的操作结果是什么呢?

            byte
b = (byte)130;(-126)

        D:字符参与运算

            是查找ASCII里面的值

            'a'        97

            'A'        65

            '0'        48

            

            System.out.println('a');

            System.out.println('a' + 1);

        E:字符串参与运算

            这里其实是字符串的连接

            

            System.out.println("hello"+'a'+1);

            System.out.println('a'+1+"hello");

            System.out.println("5+5="+5+5);

            System.out.println(5+5+"=5+5");

 

 

 

 

 

 

第三天

1. 运算符(掌握)
    (1)算术运算符

        A:+,-,*,/,%,++,--

        B:+的用法

            a:加法

            b:正号

            c:字符串连接符

        C:/和%的区别

            数据做除法操作的时候,/取得是商,%取得是余数

        D:++和--的用法

            a:他们的作用是自增或者自减

            b:使用

                **单独使用

                    放在操作数据的前面和后面效果一样。

                    a++或者++a效果一样。

                **参与操作使用

                    放在操作数的前面:先自增或者自减,再参与操作

                        int a = 10;

                        int b = ++a;

                    放在操作数的后面:先参与操作,再自增或者自减

                        int a = 10;

                        int b = a++;

    (2)赋值运算符

        A:=,+=,-=,*=,/=,%=等

        B:=叫做赋值运算符,也是最基本的赋值运算符

            int x = 10; 把10赋值给int类型的变量x。

        C:扩展的赋值运算符的特点

            隐含了自动强制转换。

            

            面试题:

                short s = 1;

                s = s + 1;(这个会保错,会丢失精度)

                

                short s = 1;

                s += 1;(隐含了自动类型转换,没有问题)

                请问上面的代码哪个有问题?

    (3)比较运算符

        A:==,!=,>,>=,<,<=

        B:无论运算符两端简单还是复杂最终结果是boolean类型。

        C:千万不要把==写成了=

    (4)逻辑运算符

        A:&,|,^,!,&&,||

        B:逻辑运算符用于连接boolean类型的式子

        C:结论

            &:有false则false

            |:有true则true

            ^:相同则false,不同则true。

                情侣关系。

            !:非true则false,非false则true

            

            &&:结果和&是一样的,只不过有短路效果。左边是false,右边不执行。

            ||:结果和|是一样的,只不过有短路效果。左边是true,右边不执行。

    (5)位运算符(了解)

        A:^的特殊用法

            一个数据针对另一个数据位异或两次,该数不变

        B:面试题

            a:请实现两个变量的交换

                **采用第三方变量

                **用位异或运算符

                    左边a,b,a

                    右边a^b

            b:请用最有效率的方式计算出2乘以8的结果

                2<<3

    (6)三元运算符

        A:格式

            比较表达式?表达式1:表达式2;

        B:执行流程:

            首先计算比较表达式的值,看是true还是false。

            如果是true,表达式1就是结果。

            如果是false,表达式2就是结果。

        C:案例:

            a:比较两个数据是否相等

            b:获取两个数据中的最大值

            c:获取三个数据中的最大值

            

2:键盘录入(掌握)

    (1)实际开发中,数据是变化的,为了提高程序的灵活性,我们加入键盘录入数据。

    (2)如何实现呢?目前就记住

        A:导包

            import java.util.Scanner;

            位置:在class的上边

        B:创建对象

            Scanner sc = new Scanner(System.in);

        C:获取数据

            int
i = sc.nextInt();

    (3)把三元运算符的案例加入键盘录入改进。

 

3:流程控制语句

    (1)顺序结构 从上往下,依次执行

    (2)选择结构    按照不同的选择,执行不同的代码

    (3)循环结构 做一些重复的代码

 

4. if语句(掌握)
    (1)三种格式

        A:格式1

            if(比较表达式) {

                语句体;

            }

            

            执行流程:

                判断比较表达式的值,看是true还是false

                如果是true,就执行语句体

                如果是false,就不执行语句体

        

        B:格式2

            if(比较表达式) {

                语句体1;

            }else {

                语句体2;

            }

            

            执行流程:

                判断比较表达式的值,看是true还是false

                如果是true,就执行语句体1

                如果是false,就执行语句体2

                

        C:格式3

            if(比较表达式1) {

                语句体1;

            }else if(比较表达式2){

                语句体2;

            }

            ...

            else {

                语句体n+1;

            }

            

            执行流程:

                判断比较表达式1的值,看是true还是false

                如果是true,就执行语句体1

                如果是false,就继续判断比较表达式2的值,看是true还是false

                如果是true,就执行语句体2

                如果是false,就继续判断比较表达式3的值,看是true还是false

                ...

                如果都不满足,就执行语句体n+1

    (2)注意事项

        A:比较表达式无论简单还是复杂,结果是boolean类型

        B:if语句控制的语句体如果是一条语句,是可以省略大括号的;如果是多条,不能省略。

            建议:永远不要省略。

        C:一般来说,有左大括号,就没有分号,有分号,就没有左大括号。

        D:else后面如果没有if,是不会出现比较表达式的。

        E:三种if语句其实都是一个语句,只要有一个执行,其他的就不再执行。

    (3)案例:

        A:比较两个数是否相等

        B:获取两个数中的最大值

        C:获取三个数中的最大值(if语句的嵌套)

        D:根据成绩输出对应的等级

        E:根据月份,输出对应的季节

        F:根据x计算对应y的值并输出

    (4)三元运算符和if语句第二种格式的关系

        所有的三元运算符能够实现的,if语句的第二种格式都能实现。

        反之不成立。

        

        如果if语句第二种格式控制的语句体是输出语句,就不可以。

        因为三元运算符是一个运算符,必须要有一个结果返回,不能是一个输出语句。

 

 

第四天

 

1. switch语句(掌握)
    (1)格式:

        switch(表达式) {

            case 值1:

                语句体1;

                break;

            case 值2:

                语句体2;

                break;

            ...

            default:

                语句体n+1;

                break;

        }

        格式解释说明:

            switch:说明这是switch语句。

            表达式:可以是byte,short,int,char

                JDK5以后可以是枚举

                JDK7以后可以是字符串

            case:后面的值就是要和表达式进行比较的值

            break:表示程序到这里中断,跳出switch语句

            default:如果所有的情况都不匹配,就执行这里,相当于if语句中的else

    (2)面试题

        switch语句的表达式可以是byte吗?可以是long吗?可以是String吗?

            可以,不可以,JDK7以后可以

    (3)执行流程:

        A:首先计算表达式的值

        B:和每一个case进行匹配,如果有就执行对应的语句体,看到break就结束。

        C:如果没有匹配,就执行default的语句体n+1。

    (4)注意事项:

        A:case后面只能是常量,不能是变量,而且,多个case后面的值不能出现相同的

        B:default可以省略吗?

            可以省略,但是不建议,因为它的作用是对不正确的情况给出提示。

            特殊情况:

                case就可以把值固定。

                A,B,C,D

        C:break可以省略吗?

            可以省略,但是结果可能不是我们想要的。

            会出现一个现象:case穿透。

            最终我们建议不要省略

        D:default一定要在最后吗?

            不是,可以在任意位置。但是建议在最后。

        E:switch语句的结束条件

            a:遇到break就结束了

            b:执行到末尾就结束了

    (5)案例:

        A:键盘录入一个数字(1-7),输出对应的星期几。

        B:单项选择题

        C:键盘录入一个字符串的问题

            String s = sc.nextLine();

        D:根据给定的月份,输出对应的季节

    (6)if语句和switch语句各自的场景

        A:if

            针对boolean类型的判断

            针对一个范围的判断

            针对几个常量的判断

        B:switch

            针对几个常量的判断

 

2. 循环语句(掌握)
    (1)有三种:for,while,do...while
    (2)for循环语句

        A:格式

            for(初始化语句;判断条件语句;控制条件语句){

                循环体语句;

            }

            

            执行流程:

                a:执行初始化语句

                b:执行判断条件语句

                    如果这里是true,就继续

                    如果这里是false,循环就结束

                c:执行循环体语句

                d:执行控制条件语句

                e:回到b

        B:注意事项

            a:判断条件语句无论简单还是复杂,结果是boolean类型

            b:循环体语句如果是一条,可以省略大括号,但是不建议

            c:有分号就没有左大括号,有左大括号就没有分号

        C:案例

            a:输出10次HelloWorld

            b:输出1-10的数据

            c:输出10-1的数据

            d:求1-10的和

            e:求1-100的和,求1-100的偶数和,求1-100的奇数和

            f:求5的阶乘

            g:在控制台打印水仙花数

            h:统计水仙花个数

            i:改进版的回文数

                一个五位数

                个位 = 万位

                十位 = 千位

                个位 + 十位 + 千位 + 万位 = 百位

            j:统计1-1000之间同时满足如下条件的数据有多少个

                x%3==2

                x%5==3

                x%7==2

    (3)while循环

        A:基本格式

            while(判断条件语句) {

                循环体语句;

            }

            

            扩展格式:

            初始化语句;

            while(判断条件语句){

                循环体语句;

                控制条件语句;

            }

            

            通过查看这个格式,我们就知道while循环可以和for循环等价转换。

        B:while的练习

            把for语句的练习用while改进

        C:for和while的区别

            a:使用上的区别

                for语句的那个控制条件变量,在循环结束后不能在使用了。

                而while的可以继续使用。

            b:理解上的区别

                for适合于一个范围的判断

                while适合次数不明确的

                    举例:吃葡萄

        D:案例:

            a:珠穆朗玛峰问题

            b:小芳存钱问题(break以后才能做)

    (4)do...while循环

        A:基本格式

            do {

                循环体语句;

            }while(判断条件语句);

            

            扩展格式:

            初始化语句;

            do {

                循环体语句;

                控制条件语句;

            }while(判断条件语句);

            

            通过查看格式,我们就可以看出其实三种循环的格式可以是统一的。

        B:三种循环的区别

            a:do...while循环至少执行一次循环体

            b:for和while必须先判断条件是否是true,然后后才能决定是否执行循环体

    (5)循环使用的注意事项(死循环)

        A:一定要注意修改控制条件,否则容易出现死循环。

        B:最简单的死循环格式

            a:while(true){...}

            b:for(;;){}

3. 控制跳转语句(掌握)
    (1)break:中断的意思

        A:用在循环和switch语句中,离开此应用场景无意义。

        B:作用

            a:跳出单层循环

            b:跳出多层循环,需要标签语句的配合

    (2)continue:继续

        A:用在循环中,离开此应用场景无意义。

        B:作用

            a:跳出单层循环的一次,可以继续下一次

        C:填空题

            for(int x=1; x<=10; x++) {

                if(x%3 == 0) {

                    //补齐代码

                }

                System.out.println("Java基础班");

            }

            如何让控制台输出2次:Java基础班

            如何让控制台输出7次:Java基础班

            如何让控制台输出13次:Java基础班

    (3)return:返回

        A:用于结束方法的,后面还会在继续讲解和使用。

        B:一旦遇到return,程序就不会在继续往后执行。

第五天

1. 方法(掌握)
    (1)方法:就是完成特定功能的代码块。

        注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法。

    (2)格式:

        修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...) {

            方法体语句;

            return 返回值;

        }

 

        修饰符:目前就用 public static。后面再详细讲解其他修饰符

        返回值类型:就是功能结果的数据类型

        方法名:就是起了一个名字,方便我们调用该方法。

        参数类型:就是参数的数据类型

        参数名:就是变量

        参数分类:

            实参:实际参与运算的数据

            形参:方法上定义的,用于接收实际参数的变量

        方法体语句:就是完成功能的代码块

        return:结束方法

        返回值:就是功能的结果,由return带给调用者。

    (3)两个明确:

        返回值类型:结果的数据类型

        参数列表:参数的个数及对应的数据类型

    (4)方法调用

        A:有明确返回值的方法

            a:单独调用,没有意义

            b:输出调用,不是很好,因为我可能需要不结果进行进一步的操作。但是讲课一般我就用了。

            c:赋值调用,推荐方案

        B:void类型修饰的方法

            a:单独调用

    (5)案例:

        A:求和方案

        B:获取两个数中的较大值

        C:比较两个数据是否相同

        D:获取三个数中的最大值

        E:输出m行n列的星形

        F:输出nn乘法表

    (6)方法的注意事项

        A:方法不调用不执行

        B:方法之间是平级关系,不能嵌套定义

        C:方法定义的时候,参数是用,隔开的

        D:方法在调用的时候,不用在传递数据类型

        E:如果方法有明确的返回值类型,就必须有return语句返回。

    (7)方法重载

        在同一个类中,方法名相同,参数列表不同。与返回值无关。

        

        参数列表不同:

            参数的个数不同。

            参数的对应的数据类型不同。

    (8)方法重载案例

        不同的类型的多个同名方法的比较。

        

2. 数组(掌握)
    (1)数组定义:

存储同一种数据类型的多个元素的容器。

    (2)特点:

每一个元素都有编号,从0开始,最大编号是长度-1。

     编号的专业叫法:索引

    (3)定义格式

        A:数据类型[] 数组名;如: int[] a;//定义一个int类型的数组a变量

        B:数据类型 数组名[]; 如:int a[];//定义一个int类型的a数组变量

        

        推荐是用A方式,B方法就忘了吧。

        但是要能看懂(两者的效果是一样的,都是定义一个数组)

    (4)数组的初始化

*定义:初始化就是为数组开辟内存空间,并未每个数组元素赋以初值

        A:动态初始化

            只给长度,由系统给出默认值

            

            举例:int[] arr = new int[3];

        B:静态初始化

            给出值,系统决定长度

            

            举例:int[] arr = new
int[]{1,2,3};

            简化版:int[] arr = {1,2,3};//其实也隐含的进行了new操作

    (5)Java的内存分配

        A:栈 存储局部变量

        B:堆 存储所有new出来的

        C:方法区(面向对象部分详细讲解)

        D:本地方法区(系统相关)

        E:寄存器(CPU使用)

        

        注意:

            a:局部变量 在方法定义中或者方法声明上定义的变量。

            b:栈内存和堆内存的区别

                栈:数据使用完毕,就消失(前提是脱离该变量的作用域之后,                    就会被自动释放掉)。

                堆:每一个new出来的东西都有地址

                 每一个变量都有默认值

                        byte,short,int,long 0

                        float,double 0.0

                        char '\u0000' 代表空字符

                        boolean false

                        引用类型 null

                 数据使用完毕后,在垃圾回收器空闲的时候回收。

    (6)数组内存图

        A:一个数组

        B:二个数组

        C:三个数组(两个栈变量指向同一个堆内存)

(7)数组操作的两个常见小问题

1. ArrayIndexOutOfBoundsException :数组下标越界异常

原因分析:你访问了不存在的索引

2. NullPointerException:空指针异常

原因分析:数组已经不再指向堆内存,而你还用数组名去访问元素

    (8)数组的常见操作

        A:遍历

            方式1:

                

public static void printArray(int[] arr) {

        for (int x = 0; x < arr.length; x++) {

            System.out.println(arr[x]);

        }

    }

 

                

            方式2:

                

public static void printArray(int[] arr) {

        System.out.print("[");

        for (int x = 0; x < arr.length; x++) {

            if (x == arr.length - 1) {

                System.out.println(arr[x] + "]");

            } else {

                System.out.println(arr[x] + ", ");

            }

        }

    }

 

        B:最值

            最大值:

                

public static int getMax(int[] arr) {

        int max = arr[0];

        for (int x = 1; x < arr.length; x++) {

            if (arr[x] > max) {

                max = arr[x];

            }

        }

        return max;

    }

 

            最小值:

                

public static int getMin(int[] arr) {

        int min = arr[0];

        for (int x = 1; x < arr.length; x++) {

            if (arr[x] < min) {

                min = arr[x];

            }

        }

 

        return min;

    }

 

        C:逆序

            方式1:

                

public static void reverse(int[] arr) {

        for (int x = 0; x < arr.length / 2; x++) {

            int temp = arr[x];

            arr[x] = arr[arr.length - 1 - x];

            arr[arr.length - 1 - x] = temp;

        }

    }

 

                

            方式2:(较简单)

                

public static void reverse(int[] arr) {

        for (int start = 0, end = arr.length - 1; start <= end; start++, end--) {

            int temp = arr[start];

            arr[start] = arr[end];

            arr[end] = temp;

        }

    }

 

        D:查表

                

public static String getString(String[] strArray, int index) {

        return strArray[index];

    }

 

        E:基本查找

            方式1:

                

public static int getIndex(int[] arr, int value) {

        for (int x = 0; x < arr.length; x++) {

            if (arr[x] == value) {

                return x;

            }

        }

        return -1;

    }

 

                

            方式2:(较简单)

                

public static int getIndex(int[] arr, int value) {

        int index = -1;

 

for (int x = 0; x < arr.length; x++) {

            if (arr[x] == value) {

                index = x;

                break;

            }

        }

 

        return index;

    }

 

        

 

 

第六天

1. 二维数组(理解)
    (1)就是元素为一维数组的一个数组。
    (2)格式:

        A:数据类型[][] 数组名 = new 数据类型[m][n];

        B:数据类型[][] 数组名 = new 数据类型[m][];

        C:数据类型[][] 数组名 = new 数据类型[][]{{...},{...},{...}};

        D:数据类型[][] 数组名 = {{...},{...},{...}};

参数:m : 表示这个二维数组有多少个一维数组

n : 表示每一个一维数组的元素有多少个

    (3)案例(掌握):

        A:二维数组的遍历

说明:二维数组外循环控制的是二维数组的长度,其实就是一维数组的个数。

内循环控制的是一维数组的长度

 

代码:

public static void printArray2(int[][] arr) {

        for (int x = 0; x < arr.length; x++) {

            for (int y = 0; y < arr[x].length; y++) {

                System.out.print(arr[x][y] + " ");

            }

            System.out.println();

        }

    }

 

        B:二维数组的求和

/*

* 需求:二维数组求和

*/

class Array2Test2 {

    public static void main(String[] args) {

        // 把题目的数据用二维数组来表示

        int[][] arr = { { 22, 66, 44 }, { 77, 33, 88 }, { 25, 45, 65 }, { 11, 66, 99 } };

 

        int sum = 0;

 

        // 通过遍历就可以得到每一个二维数组的元素。

        for (int x = 0; x < arr.length; x++) {

            for (int y = 0; y < arr[x].length; y++) {

                // 把元素累加即可。

                sum += arr[x][y];

            }

        }

 

        // 最后输出sum,就是结果。

        System.out.println("总和为:" + sum );

    }

}

 

        C:杨辉三角形

(不要想着一个循环就可以搞定,应该分为多个循环一步一步的处理)

/*

 

    需求:打印杨辉三角形(行数可以键盘录入)

    

    1

    1 1    

    1 2 1

    1 3 3 1

    1 4 6 4 1

    1 5 10 10 5 1

 

    分析:看这种图像的规律

        B:从第三行开始,每一个数据是它上一行的前一列和它上一行的本列之和。

    

    步骤:

        A:首先定义一个二维数组。行数如果是n,我们把列数也先定义为n。

         这个n的数据来自于键盘录入。

        C:按照规律给其他元素赋值

            从第三行开始,每一个数据是它上一行的前一列和它上一行的本列之和。

        D:遍历这个二维数组。

*/

import java.util.Scanner;

 

class Array2Test3 {

    public static void main(String[] args) {

        //创建键盘录入对象

        Scanner sc = new Scanner(System.in);

        

        //这个n的数据来自于键盘录入。

        System.out.println("请输入一个数据:");

        int n = sc.nextInt();

        

        //定义二维数组

        int[][] arr = new int[n][n];

        

        for(int x=0; x<arr.length; x++) {

        }

        

        //按照规律给其他元素赋值

        //从第三行开始,每一个数据是它上一行的前一列和它上一行的本列之和。

        for(int x=2; x<arr.length; x++) {

            //这里如果y<=x是有个小问题的,就是最后一列的问题

开始,因为第一列也是有值了

            for(int y=1; y<=x-1; y++) {

                //每一个数据是它上一行的前一列和它上一行的本列之和。

                arr[x][y] = arr[x-1][y-1] + arr[x-1][y];

            }

        }

        

        //这个时候,要注意了,内循环的变化必须和曾经讲过的九九乘法表类似

        for(int x=0; x<arr.length; x++) {

            for(int y=0; y<=x; y++) {

                System.out.print(arr[x][y]+"\t");

            }

            System.out.println();

        }

    }

}

 

 

2. 两个思考题(理解)
    (1)Java中的参数传递问题

        Java中只有值传递。

        基本类型:形式参数的改变不影响实际参数

        引用类型:形式参数的改变直接影响实际参数

    (2)数据加密问题

        综合的小案例。(我没有做出来,是一个比较好的综合练习)

    

/*

位的整数,为了确保安全,

    在传递过程中需要加密,加密规则如下:

,再用和除以10的余数代替该数字,

        最后将第一位和最后一位数字交换。
请任意给定一个小于8位的整数,

        然后,把加密后的结果在控制台打印出来。

        

    题目要求:

位的整数

            定义一个int类型的数据

            int number = 123456;

        B:加密规则

            a:首先将数据倒序

,再用和除以10的余数代替该数字

            c:最后将第一位和最后一位数字交换

        C:把加密后的结果输出在控制台

        

        通过简单的分析,我们知道如果我们有办法把这个数据变成数组就好了。

        不是直接写成这个样子的:

            int[] arr = {1,2,3,4,5,6};

            

        如何把数据转成数组呢?

            A:定义一个数据

                int number = 123456;

            B:定义一个数组,这个时候问题就来了,数组的长度是多少呢?

                在赋值的时候,我用一个变量记录索引的变化。

                int index = 0;

            C:获取每一个数据

                int ge = number%10

                int shi = number/10%10

                int bai = number/10/10%10

                

                arr[index] = ge;

                index++;

                arr[index] = shi;

                index++;

                arr[index] = bai;

                ...

*/

class JiaMiDemo {

    public static void main(String[] args) {

        //定义一个数据

        int number = 123456;

        

        //定义一个数组

        int[] arr = new int[8];

        

        //把数据中每一位上的数据获取到后存储到数组中

        /*

        int index = 0;

        arr[index] = number%10; //arr[0]=6;

        index++;

        arr[index] = number/10%10; //arr[1]=5;

        index++;

        arr[index] = mumber/10/10%10; //arr[2]=4;

        */

        

        //通过观察这个代码,我们发现应该是可以通过循环改进的

        int index = 0;

        

        while(number > 0) { //number=123456,number=12345,number=1234,number=123,number=12,number=1,number=0

            arr[index] = number%10; //arr[0]=6,arr[1]=5,arr[2]=4,arr[3]=3,arr[4]=2,arr[5]=1

            index++;//index=1,index=2,index=3,index=4,index=5,index=6

            number/=10;//number=12345,number=1234,number=123,number=12,number=1,number=0

        }

        

,再用和除以10的余数代替该数字

        for(int x=0; x<index; x++) {

            arr[x] += 5;

            arr[x] %= 10;

        }

        

        //最后将第一位和最后一位数字交换

        int temp = arr[0];

        arr[0] = arr[index-1];

        arr[index-1] = temp;

        

        //输出数据

        for(int x=0; x<index; x++) {

            System.out.print(arr[x]);

        }

        System.out.println();

    }

}

 

3. 面向对象(掌握)
    (1)面向对象

        面向对象是基于面向过程的编程思想

    (2)面向对象的思想特点

        A:是一种更符合我们思考习惯的思想

        B:把复杂的事情简单化

        C:让我们从执行者变成了指挥者

        

        举例:

            买电脑

            洗衣服

            做饭

            ...

            万事万物皆对象

    (3)把大象装进冰箱(理解)

        A:面向过程实现

        B:面向对象实现

        

        注意:如何让我们的操作更符合面向对象思想呢?

        A:有哪些类

        B:每个类有哪些成员

        C:类与类的关系

    (4)类与对象

        A:现实世界的事物

            属性    事物的基本描述

            行为    事物的功能

        B:Java语言中最基本的单位是类。所以,我们要用类来体现事物

        C:类

            成员变量    事物属性

            成员方法    事物行为

        D:类:是一组相关的属性和行为的集合。是一个抽象的概念。

         对象:是该类事物的具体存在,是一个具体的实例。(对象)

        

         举例:

            学生:类

            班长:对象

    (5)类的定义及使用

        A:类的定义

            成员变量    定义格式和以前一样,就是位置不同,在类中,方法外。

            成员方法    定义格式和以前一样,就是去掉了static。

        B:使用类的内容

            a:创建对象? 格式

                类名 对象名 = new 类名();

            b:如何使用成员变量和成员方法呢

                对象名.成员变量

                对象名.成员方法()

    (6)案例:

        A:学生类的定义和使用

        B:手机类的定义和使用

    (7)内存图

        A:一个对象的内存图

        

        B:二个对象的内存图

        

        C:三个对象的内存图

        

    (8)Java程序的开发,设计和特征

        A:开发:就是不断的创建对象,通过对象调用功能

        B:设计:就是管理和维护对象间的关系

        C:特征

            a:封装(encapsulation)

            b:继承(inheritance)

            c:多态(polymorphism)

 

 

 

 

 

 

第七天

 

1. 成员变量和局部变量的区别(理解)
    (1)在类中的位置不同

        成员变量:类中方法外

        局部变量:方法定义中或者方法声明上

    (2)在内存中的位置不同

        成员变量:在堆内存中

        局部变量:在栈内存中

    (3)生命周期不同

        成员变量:随着对象的创建而存在,随着对象的消失而消失

        局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

    (4)初始化值不同

        成员变量:有默认值

        局部变量:没有默认值,必须定义,赋值,然后才能使用

    注意事项:

             局部变量名称可以和成员变量名称一样,在方法中使用的时候,采    用的是就近原则。

2. 形式参数的问题?(理解)

    (1)形式参数是类:

如果你看到一个方法需要的参数是一个类名,就应该知道这里实际需要的是一个具体的对象。

    形式参数是基本类型:

    基本类型:形式参数的改变不影响实际参数

    引用类型:形式参数的改变直接影响实际参数的值

    3. 匿名对象(理解)

        (1)没有名字的对象

        (2)应用场景

            A:调用方法,仅仅只调用一次的时候。(注意:不适合调用多次)

            b:可以作为实际参数传递。

        (3)匿名调用有什么好处?

    答:有,匿名对象在调用完毕之后就是垃圾,可以被垃圾回收器回收

    4. 封装(理解)

        (1)隐藏实现细节,提供公共的访问方式

        (2)好处:

            A:隐藏实现细节,提供公共的访问方式

            B:提高代码的复用性

            C:提高代码的安全性

        (3)设计原则

            把不想让外界知道的实现细节给隐藏起来,提供公共的访问方式

        (4)private是封装的一种体现。

            封装:类,方法,private修饰成员变量

     

    5. private关键字(掌握)

        (1)私有的意义,可以修饰成员变量和成员方法

        (2)特点:

            被private修饰的后的成员只能在本类中被访问

        (3)private的应用:

            以后再写一个类的时候:

                把所有的成员变量给private了

                提供对应的getXxx()/setXxx()方法

     

    6. this关键字(掌握)

        (1)代表当前类的引用对象

            记住:哪个对象调用方法,该方法内部的this就代表那个对象

        (2)this的应用场景:

            A:解决了局部变量隐藏成员变量的问题

            B:其实this还有其他的应用,明天讲解。

     

    7. 构造方法(掌握)

        (1)作用:

    用于给对象的数据进行初始化

        (2)格式:

            A:方法名和类名相同

            B:没有返回值类型,连void都不能有

            C:没有返回值

            

            思考题:构造方法中可不可以有return语句呢?

            可以。而是我们写成这个样子就OK了:return;

            其实,在任何的void类型的方法的最后你都可以写上:return;

        (3)构造方法的注意事项

            A:如果我们没写构造方法,系统将提供一个默认的无参构造方法

            B:如果我们给出了构造方法,系统将不再提供默认的无参构造方法

                如果这个时候,我们要使用无参构造方法,就必须自己给出。

                推荐:永远手动自己给出无参构造方法。

        (4)给成员变量赋值的方式

            A:setXxx()

            B:带参构造方法

        (5)标准案例

            

    class Student {

        private String name;

        private int age;

     

        public Student() {

        }

     

        public Student(String name, int age) {

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

    }

     

            测试:

            

    class StudentDemo {

        public static void main(String[] args) {

            Student s1 = new Student();

            s1.setName("林青霞");

            s1.setAge(27);

            System.out.println(s1.getName() + "---" + s1.getAge());

     

            Student s2 = new Student("刘意", 30);

            System.out.println(s2.getName() + "---" + s2.getAge());

        }

    }

     

    8. 成员方法的分类及使用

    .根据返回值分类:

      Void类型

      非void类型

     

    .根据形式参数分类:

      空参方法

      非空参方法

    .代码举例:

     

    class Student {

        public String getString() {

            return "helloworld";

        }

     

        public void show() {

            System.out.println("show");

        }

     

        public void method(String name) {

            System.out.println(name);

        }

     

        public String function(String s1, String s2) {

            return s1 + s2;

        }

    }

     

    class StudentDemo {

        public static void main(String[] args) {

            // 创建对象

            Student s = new Student();

     

            // 调用无参无返回值方法

            s.show();

     

            // 调用无参有返回值方法

            String result = s.getString();

            System.out.println(result);

     

            // 调用带参无返回值的方法

            s.method("林青霞");

     

            // 调用带参带返回值的方法

            String result2 = s.function("hello", "world");

            System.out.println(result2);

        }

    }

     

     

    9. 代码:Student s = new Student();做了哪些事情?(理解)

        (1)把Student.class文件加载到内存

        (2)在栈内存为s开辟空间

        (3)在堆内存为学生对象申请空间

        (4)给学生的成员变量进行默认初始化。null,0

        (5)给学生的成员变量进行显示初始化。林青霞,27

        (6)通过构造方法给成员变量进行初始化。刘意,30

        (7)对象构造完毕后,把堆内存的地址赋值给栈内存的s变量

            

    10. 面向对象的练习题(掌握)

        (1)标准的手机类的定义和测试

        (2)Demo类有求和方法,Test类进行测试。

            A) 变量什么时候定义为成员变量?

    答:如果这个变量是用来描述这个类的信息时,那么,该变量就应该定义为成员变量。

    B) 变量到底定义在哪里比较好?

    答:变量的范围是越小越好,因为能及时的被回收。

            

        (3)长方形案例

        (4)员工案例

        (5)MyMath案例(自己提供加减乘除并测试)

     

     

    11. 关键字static 引入和应用

    (1). static 的特点:(它可以修饰成员变量,还可以修饰成员方法)

    A:随着类的加载而加载

    B:优先于对象存在

    C:被类的所有对象所共享

            举例:班级的学生应该共用同一个班级编号

    其实这个特点也是在告诉我们什么时候使用静态?

    答:如果某个成员变量是被所有对象共享的,那么它就应该被定义为静态的

    D:可以通过类名调用

    其实他本身也可以通过对象调用

    推荐使用类名调用

    静态修饰的内容一般我们称其为:与类相关的,类成员

    (2). Static 关键字的内存图解

    (3).static 的注意事项

        A:在静态方法中是没有this关键字的

            如何理解呢?

                静态是随着类的加载而加载,this是随着对象的创建而存在。

                静态比对象先存在。

        B:静态方法只能访问静态的成员变量和静态的成员方法

                a: 静态方法:

                    a). 成员变量:只能访问静态变量

                    b). 成员方法:只能访问静态成员方法

                b: 非静态方法:

                    a). 成员变量:可以是静态方法,也可以是非静态方法

                    b). 成员方法:可是是静态的成员方法,也可以是非静态的                                    成员方法。

                简单记:

                    A)静态只能访问静态。

    B) 非静态的:既可以访问非静态的,也可以访问静态的

     

     

    12. 静态变量和成员变量的区别(理解)

      所属不同

        静态变量属于类,所有也称为类变量

        成员变量属于对象,所以也称为实例变量(对象变量)

      在内存中的位置不同

        静态变量存储于方法区的静态区

        成员变量存储于堆内存

      内存中出现的时间不同

        静态变量随着类的加载而加载,随着类的消失而消失

        成员变量随着对象的创建而存在,随着对象的消失而消失

      调用不同

        静态变量可以通过类名调用,也可以通过对象调用

        成员变量只能通过对象调用

    13. main 方法的格式讲解

    public static void main(String[] args) {...}

    Public: 公共的,访问权限是最大的,由于main方法是被jvm调用,所以权限要够大

    Static:静态的,不需要创建对象,通过类名就可以调用,方便jvm直接调用

    void :因为我们曾经说过,方法的返回值是返回非调用者的,而main方法是被jvm调用,所以你返回内容给 jvm 是没有意义的

    main :是一个常见的方法入口,我见过的语言都是以 main 作为方法入口的

    String[] args : 这是一个字符串数组,值去哪里呢?

    这个东西到底有什么用啊?怎么给值呢?

    答:这个东西早期是为了接受键盘录入的数据的

    格式为: java MainDemo hello world java

     

    class MainDemo {

        public static void main(String[] args) {

            // System.out.println(args); //[Ljava.lang.String;@175078b

            // System.out.println(args.length); //0

            // System.out.println(args[0]); //ArrayIndexOutOfBoundsException

     

            // 接收数据后

            System.out.println(args);

            System.out.println(args.length);

            // System.out.println(args[0]);

            for (int x = 0; x < args.length; x++) {

                System.out.println(args[x]);

            }

        }

    }

     

     

    第八天

    1. 如何制作帮助文档(了解)

        (1)写一个类

        (2)加入文档注释

    怎么加呢?

    加些什么东西呢?

        (3)通过javadoc工具生成即可

            javadoc -d 目录 -author -version ArrayTool.java

    目录:直接写目录的名称,表示在当前文件的这个位置,新建这个目录

    例如: javadoc -d doc -author -version ArrayTool.java

    (doc 表示在当前文件位置新建一个名为 doc 的目录)

    注意:找不到可以文档化的公共或者收保护的类:这告诉我们类的权限不够

     

    2. 通过JDK提供的API学习了Math类(掌握)

        (1)API(Application Programming Interface)

            应用程序编程接口(帮助文档)

     

        (2)如何使用呢?

            请参照

                day08\code\02_如何使用JDK提供的帮助文档\如何使用帮助文档.txt

     

        (3)Math类

            A:是针对数学进行操作的类

            B:没有构造方法,因为它的成员都是静态的

            C:产生随机数

                public
    static
    double random(): [0.0,1.0)

            D:如何产生一个1-100之间的随机数

                int
    number = (int)(Math.random()*100)+1;

            E:猜数字小游戏

    注意:java.lang包下的所有类都不需要导入,其他的全部需要导入。

    /*

        猜数字小游戏(数据在1-100之间)

        

        分析:

            A:程序产生一个随机数。(被猜的)

            B:键盘录入数据。(你猜的)

            C:把你猜的和被猜的进行比较

                a:大了

                b:小了

                c:猜中了

            D:给出多次猜的机会,猜中就结束。

                while()循环,猜中就break

    */

    import java.util.Scanner;

     

    class GuessNumber {

        public static void main(String[] args) {

            //程序产生一个随机数。(被猜的)

            int number = (int)(Math.random()*100)+1;

            //System.out.println(number);

            

            //给出多次猜的机会,猜中就结束。

            while(true) {

                //键盘录入数据。(你猜的)

                Scanner sc = new Scanner(System.in);

                System.out.println("请输入你要猜的数据(1-100):");

                int guessNumber = sc.nextInt();

                

                //把你猜的和被猜的进行比较

                if(guessNumber > number) {

                    System.out.println("你猜的数据"+guessNumber+"大了");

                }else if(guessNumber < number) {

                    System.out.println("你猜的数据"+guessNumber+"小了");

                }else {

                    System.out.println("恭喜你,猜中了");

                    break;

                }

            }

        }

    }

     

    3. 代码块(理解)

        (1)用{}括起来的代码。

     

        (2)分类:

            A:局部代码块

                在方法中出现,用于限定变量的生命周期,及早释放,提高内存利用率。

            B:构造代码块

                A)定义:

    在类中的成员变量位置处,用{}括起来的代码,每次调用构造方法执行前,首先会执行构造代码块。

    B)作用:可以把多个构造方法中的共同代码放到该代码块中,对                        对象进行初始化

            C:静态代码块

                 A)定义:

    在类中的成员位置,用{} 括起来的代码,只不过它static修饰了

    B)作用:

    一般对类进行初始化,仅仅只执行一次。

        (3)静态代码块,构造代码块,构造方法的顺序问题?

            静态代码块 > 构造代码块 > 构造方法

    静态代码块:只执行一次

    构造代码块:每次调用构造方法都会执行

        (4)对应代码示例:

     

    /*

    * 代码块:在Java中,使用{}括起来的代码被称为代码块。
    根据其位置和声明的不同,可以分为
    局部代码块:局部位置,用于限定变量的生命周期。

    * 构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。

    * 作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。
    静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了。

    * 作用:一般是对类进行初始化。

    *

    * 面试题? 静态代码块,构造代码块,构造方法的执行顺序? 静态代码块 -- 构造代码块 -- 构造方法
    静态代码块:只执行一次

    * 构造代码块:每次调用构造方法都执行

    */

    class Code {

        static {

            int a = 1000;

            System.out.println(a);

        }

     

        // 构造代码块

        {

            int x = 100;

            System.out.println(x);

        }

     

        // 构造方法

        public Code() {

            System.out.println("code");

        }

     

        // 构造方法

        public Code(int a) {

            System.out.println("code");

        }

     

        // 构造代码块

        {

            int y = 200;

            System.out.println(y);

        }

     

        // 静态代码块

        static {

            int b = 2000;

            System.out.println(b);

        }

    }

     

    class CodeDemo {

        public static void main(String[] args) {

            // 局部代码块

            {

                int x = 10;

                System.out.println(x);

            }

            // 找不到符号

            // System.out.println(x);

            {

                int y = 20;

                System.out.println(y);

            }

            System.out.println("---------------");

     

            Code c = new Code();

            System.out.println("---------------");

            Code c2 = new Code();

            System.out.println("---------------");

            Code c3 = new Code(1);

        }

    }

     

    4. 继承(掌握)

        (1)继承的定义

    把多个类中相同的成员给提取出来定义到一个独立的类中。然后让这多    个类和该独立的类产生一个关系,

    这多个类就具备了这些内容。这个关系叫继承。

     

        (2)Java中如何表示继承呢?格式是什么呢?

            A:用关键字extends表示

            B:格式:

                class 子类名 extends 父类名 {}

        (3)继承的好处:

            A:提高了代码的复用性

            B:提高了代码的维护性

            C:让类与类产生了一个关系,是多态的前提

        (4)继承的弊端:

            A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。

                原则:低耦合,高内聚。

                耦合:类与类的关系

                内聚:自己完成某件事情的能力

            B:打破了封装性

        (5)Java中继承的特点

            A:Java中类只支持单继承

            B:Java中可以多层(重)继承(继承体系)

        (6)继承的注意事项:

            A:子类只能继承父类所有非私有的成员(成员方法和成员变量)

            B:子类不能继承父类的构造方法,但是可以通过super去访问父类的构造方法

            C:不要为了部分功能而去继承

        (7)什么时候使用继承呢?

            A:继承体现的是:is a的关系。

            B:采用假设法

        (8)Java继承中的成员关系

            A:继承中成员变量的关系

                a:子类的成员变量名称和父类中的成员变量名称不一样,这个太简单

                b:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢?

                    子类的方法访问变量的查找顺序:

                        在子类方法的局部范围找,有就使用。

                        在子类的成员范围找,有就使用。

                        在父类的成员范围找,有就使用。

                        找不到,就报错。

            B:继承中构造方法的关系

                a:子类中所有的构造方法默认都会访问父类中空参数的构造方法

                    为什么呢?

    答:因为子类继承父类中的数据,可能还会使用父类的数据,

    所以子类初始化之前,一定要先完成父类数据的初始化

    注意:子类的每一个构造方法里面第一条语句默认都是:super()

                b:父类中如果没有无参构造方法,怎么办?

    解决方案:

                    A:在父类中加一个无参构造方法

    B:通过使用super关键字去显式的调用父类的带参构造方法

    C:子类通过this去调用本类中的其他构造方法(但前提是:子类    中一定要有一个构造方法去访问了父类的构造方法,否则父类数据就没有初始化)

     

    注意事项:this(...)或者super(...)语句必须出现在第一条语句上,如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

     

            C:继承中成员方法的关系

                A:子类的成员方法和父类中的成员方法名称不一样,这个太简单

                B:子类的成员方法和父类中的成员方法名称一样,这个怎么访问呢?

                    通过子类对象访问一个方法的查找顺序:

                        a:先在子类中找,有就使用

                        b:再在父类中找,有就使用

                        c:找不到,就报错

        (9)两个面试题:

            A:Override和Overload的区别?Overload是否可以改变返回值类型?

    a.方法重写( override ):

    在子类中,出现和父类中一模一样的方法声明的现象

    b.方法重载( overload ):

    同一个类中,出现的方法名相同,参数列表不同的现象

    c..方法重载能改变返回值类型,因为他和返回值类型无关

                                        

            B:this和super的区别和各自的作用?

      分别是什么呢?

      This:代表当前类对象的引用

      Super:代表父类存储空间的标识(可以理解为父类引用,通过他可以操作父类成员)

    2)怎么用呢?

      调用成员变量

      this.成员变量 表示调用本类的成员变量

      super.成员变量 表示调用父类的成员变量

      调用构造方法

      This(....)        表示调用本类的构造方法

      Super(...) 表示调用父类的构造方法

      调用成员方法

      this.成员方法        表示调用本类的成员方法

      super.成员方法        表示调用父类的成员方法

        (10)数据初始化的面试题

            A:一个类的初始化过程

    成员变量进行初始化

    默认初始化

    显式初始化

    构造方法初始化

     

            B:子父类的构造执行过程

    先进行父类初始化,然后进行子类的初始化

            C:分层初始化

    Super仅仅表示要先进行父类初始化,然后进行子类的初始化

    (11)方法重写的概述和应用


    1. 定义:子类中出现了和父类中方法声明一模一样的方法

    2. 方法重写的应用:

    当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,有定义了子类特有的内容

    3. 方法重写的注意事项:

    A: 父类中私有方法不能被重写

    因为父类的私有方法,子类根本就无法继承

    B: 子类重写父类方法时,访问权限不能更低

    C: 父类静态方法,子类也必须通过静态方法进行重写

    D: 子类重写父类方法,两者的声明最好一模一样

        (12)案例:

            A:学生和老师案例

                继承前

                继承后

            B:猫狗案例的分析和实现

     

     

    第九天

    1. final关键字(掌握)

        (1)定义:

    是最终的意思,可以修饰类,方法,变量。

        (2)特点:

            A:它修饰的类,不能被继承。

            B:它修饰的方法,不能被重写。

            C:它修饰的变量,是一个常量。

        (3)面试相关:

            A:final修饰的局部变量

                a:基本类型 值不能发生改变

                b:引用类型 地址值不能发生改变,但是对象的内容是可以改变的

            B:final修饰变量的初始化时机

                a:被final修饰的变量只能被赋值一次。

                b:在构造方法执行完毕之前(前提为:非静态变量)                        

    c:赋值时机:1.在定义的时候就进行赋值。(推荐)

                     2.在构造方法中进行赋值。

        

    2. 多态(掌握)

        (1)多态的定义:

    同一个对象在不同时刻体现出来的不同状态。

        (2)多态的前提:

            A:有继承或者实现关系。

            B:有方法重写。

            C:有父类或者父接口引用指向子类对象。

            

            多态的分类:

                a:具体类多态

                    class Fu {}

                    class Zi extends Fu {}

                    

                    Fu f = new Zi();

                b:抽象类多态

                    abstract class Fu {}

                    class Zi extends Fu {}

                    

                    Fu f = new Zi();

                c:接口多态

                    interface Fu {}

                    class Zi implements Fu {}

                    

                    Fu f = new Zi();

        (3)多态中的成员访问特点

            A:成员变量

                编译看左边,运行看左边

            B:构造方法

                创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化

            C:成员方法

                编译看左边,运行看右边

            D:静态方法

                编译看左边,运行看左边

                

            为什么?

                由于成员方法存在方法重写,所以它运行看右边

        (4)多态的好处:

            A:提高代码的维护性(继承体现)

            B:提高代码的扩展性(多态体现)

        (5)多态的弊端:

            父不能使用子的特有功能。

            

            现象:

                子可以当作父使用,父不能当作子使用。

        (6)多态中的转型

            A:向上转型

                从子到父(Fu f = new Zi())

            B:向下转型

                把父类的引用强制转换为子类的引用(从父到子)(Zi z = (Zi)f )

        (7)孔子装爹的案例帮助大家理解多态

    // 多态的问题理解:

    class
    孔子爹 {

        public int age = 40;

     

        public void teach() {

            System.out.println("讲解JavaSE");

        }

    }

     

    class
    孔子
    extends
    孔子爹 {

        public int age = 20;

     

        public void teach() {

            System.out.println("讲解论语");

        }

     

        public void playGame() {

            System.out.println("英雄联盟");

        }

    }

     

    class MainDemo {

        public static void main(String[] args) {

            // Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了

            // 但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?

            // 然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹

            // 向上转型

            孔子爹
    k爹 = new
    孔子();

            // 到人家那里去了

            System.out.println(k爹.age); // 40

            k爹.teach(); // 讲解论语

            // k爹.playGame(); //这是儿子才能做的

     

            // 讲完了,下班回家了

            // 脱下爹的装备,换上自己的装备

            // 向下转型

            孔子
    k = (孔子) k爹;

            System.out.println(k.age); // 20

            k.teach(); // 讲解论语

            k.playGame(); // 英雄联盟

     

        }

    }    

     

    (8)多态继承中的内存图解

     

    .多态中的对象变化内存图解

        (10)多态的练习

            A:猫狗案例

            B:老师和学生案例

     

    3. 抽象类(掌握)

        (1)定义:

    把多个共性的东西提取到一个类中,这是继承的做法。

         但是呢,这多个共性的东西,在有些时候,方法声明一样,但是方法体。

         也就是说,方法声明一样,但是每个具体的对象在具体实现的时候内容不一样。

         所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。

         而一个没有具体的方法体的方法是抽象的方法。

         在一个类中如果有抽象方法,该类必须定义为抽象类。

        (2)抽象类的特点

            A:抽象类和抽象方法必须用关键字abstract修饰

            B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类

            C:抽象类不能实例化

    因为它不是具体的

    抽象类有构造方法,但是不能实例化,构造方法的作用是什么呢?

    用于子类访问父类数据的初始化

            D:抽象类的子类

                a:如果不想重写抽象方法,该子类则是一个抽象类。

                b:是一个具体类。这个类必须重写抽象类中的所有抽象方法。

        (3)抽象类的成员特点:

            A:成员变量

                既可以是变量,也可以是常量

    B:构造方法

                有构造方法,用于子类访问父类数据的初始化

            C:成员方法

                既可以是抽象的,也可以是非抽象的

    抽象类的成员方法特性:

    A: 抽象方法:强制要求子类做的事情

    B: 非抽象方法:子类继承的事情,提高代码复用性

        (4)抽象类的练习

            A:猫狗案例练习

            B:老师案例练习

            C:学生案例练习

            D:员工案例练习

        (5)抽象类的几个小问题

            A:抽象类有构造方法,不能实例化,那么构造方法有什么用?

                用于子类访问父类数据的初始化

            B:一个类如果没有抽象方法,却定义为了抽象类,有什么用?

                为了不让创建对象

            C:abstract不能和哪些关键字共存

                a:final    冲突

                b:private 冲突

                c:static 无意义

     

    4. 接口(掌握)

        (1)回顾猫狗案例,它们仅仅提供一些基本功能。

         比如:猫钻火圈,狗跳高等功能,不是动物本身就具备的,

         是在后面的培养中训练出来的,这种额外的功能,java提供了接口表示。

        (2)接口的特点:

            A:接口用关键字interface修饰

                interface 接口名 {}

            B:类实现接口用implements修饰

                class 类名 implements 接口名 {}

            C:接口不能实例化

    那么,接口如何实例化呢?

    按照多态的方式来实例化

    多态类实例化方式?

    a: 具体类多态(几乎没有)

    b: 抽象类多态(常用)

    c: 接口多态(最常用)

            D:接口的实现类

                a可以是抽象类。但是意义不大

                b:也可以是具体类,这个类必须重写接口中的所有抽象方法。(推荐方案)

        (3)接口的成员特点:

            A:成员变量

                只能是常量,并且是静态的

                默认修饰符:public static final

    建议:自己手动给出

            B:构造方法

                没有构造方法

            C:成员方法

                只能是抽象的

                默认修饰符:public abstract

        (4)类与类,类与接口,接口与接口

            A:类与类

                继承关系,只能单继承,可以多层继承

            B:类与接口

                实现关系,可以单实现,也可以多实现。

                还可以在继承一个类的同时,实现多个接口

            C:接口与接口

                继承关系,可以单继承,也可以多继承

        (5)抽象类和接口的区别?

            A:成员区别

                抽象类:

    成员变量:既可以是变量,也可以是常量

    构造方法:有

    成员方法:既可以是抽象方法,也可以是非抽象方法

                接口:

    成员变量:只可以是常量

    成员方法:只可以是抽象方法

            B:关系区别:

                类与类:

    继承,单继承

                类与接口:

    实现,单实现,多实现

                接口与接口:

    继承,单继承,多继承

            C:设计理念不同

                抽象类:is a,抽象类中定义的是共性功能。

                接口:like a,接口中定义的是扩展功能。

        (6)练习:

            A:猫狗案例,加入跳高功能

            B:老师和学生案例,加入抽烟功能

     

     

     

    第十天

    1. 形式参数和返回值的问题(理解)

        (1)形式参数:

            类名:需要的是该类的对象

            抽象类名:需要该类的子类对象

            接口名:需要该接口的实现类对象

        (2)返回值类型:

            类名:返回的是该类的对象

            抽象类名:返回的是该类的子类对象

            接口名:返回的是该接口的实现类的对象

        (3)链式编程

            对象.方法1().方法2().......方法n();

            

            这种用法:其实在方法1()调用完毕后,应该一个对象;

                 方法2()调用完毕后,应该返回一个对象。

                     方法n()调用完毕后,可能是对象,也可以不是对象。

     

    2. 包(理解)

        (1)其实就是文件夹

        (2)作用:

            A:区分同名的类

            B:对类进行分类管理

                a:按照功能分

                b:按照模块分

        (3)包的定义(掌握)

            package 包名;

            

            多级包用.分开。

        (4)注意事项:(掌握)

            A:package语句必须在文件中的第一条有效语句

            B:在一个java文件中,只能有一个package

            C:如果没有package,默认就是无包名

        (5)带包的编译和运行

            A:手动式

    a: 编写一个带包的 java 文件

    b: 通过javac 命令编译该java文件

    c: 手动创建包名

    d: 把b步骤的class文件放到c步骤的最底层包

    e: 回到和包根目录在同一目录的地方,然后运行

            B:自动式(掌握)

    a: 编写一个带包的 java 文件

    b: javac编译的时候带上 -d 即可

    c: 回到和包根目录在同一目录的地方,然后运行

     

                javac -d . HelloWorld.java

                

    3. 导包(掌握)

        (1)我们多次使用一个带包的类,非常的麻烦,这个时候,Java就提供了一个关键字import。

        (2)格式:

            import 包名...类名;

            另一种:

            import 包名...*;(不建议)

        (3)package,import,class的顺序

            package > import > class

    Package:只能有一个

    Import:可以有多个

    Class:可以有多个,但是建议是一个

        

    4. 权限修饰符(掌握)

        (1)权限修饰符

                        本类    同一个包下    不同包下的子类    不同包下的无关类

            private        Y

            默认        Y        Y

            protected    Y        Y            Y

            public        Y        Y            Y                Y

        (2)这四种权限修饰符在任意时刻只能出现一种。

            public class Demo {}        

     

    5. 常见的修饰符(理解)

        (1)分类:

            权限修饰符:private,默认,protected,public

            状态修饰符:static,final

            抽象修饰符:abstract

        (2)常见的类及其组成的修饰

            类:

                权限修饰符:默认修饰符、public

    状态修饰符:final

    抽象修饰符:abstract

     

    用的最多的是:public

                    

            成员变量:

                权限修饰符:private,默认,protected,public            

                状态修饰符:static 、 final

     

    用的最多的是:private

                

            构造方法:

                权限修饰符:private,默认,protected,public

                

                常用的:public

            

            成员方法:

                权限修饰符:private,默认,protected,public,

                状态修饰符:static,final

    抽象修饰符:abstract

                常用的:public

     

        (3)另外比较常见的:

            成员变量:public
    static
    final
    int
    X = 10;

            成员方法:public
    static
    void show() {}

                        public
    final
    void show() {}

             public
    abstract
    void
    show();

     

    6. 内部类(理解)

        (1)定义:

    把类定义在另一个类的内部,该类就被称为内部类。

            举例:把类B定义在类A中,类B就被称为内部类。

        (2)内部类的访问规则

            A:内部类可以直接访问外部类的成员,包括私有

            B:外部类要想访问内部类成员,必须创建对象

        (3)内部类的分类

            A:在成员位置定义的类,被称之为成员内部类

            B:在局部位置定义的类,被称之为局部内部类

        (4)成员内部类

            A:private 为了数据的安全性

            B:static 为了访问的方便性

            

            成员内部类是非静态的:

                外部类名.内部类名 对象名 = new 外部类名.new 内部类名();

            成员内部类是静态的:

                外部类名.内部类名 对象名 = new 外部类名.内部类名();

        (5)成员内部类的面试题(填空)

            面试题:按照要求天空输出30,20,10

            注意:

      内部类和外部类之间没有继承关系

      通过外部类名限定this对象

      Outer.this

            

    class Outer {

        public int num = 10;

     

        class Inner {

            public int num = 20;

     

            public void show() {

                int num = 30;

     

                System.out.println(num);// 30

                System.out.println(this.num);// 20

                System.out.println(Outer.this.num);// 10

            }

        }

    }

     

        (6)局部内部类

    局部内部类特点:

      可以直接访问外部类的成员

      在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能

    面试题:

    局部内部类访问局部变量的注意事项?

            A:局部内部类访问局部变量必须加final修饰。

            B:为什么呢?

                因为局部变量使用完毕就消失,而堆内存的数据并不会立即消失。

                所以,堆内存还是用该变量,而改变量已经没有了。

                为了让该值还存在,就加final修饰。

                通过反编译工具我们看到了,加入final后,堆内存直接存储的是值,而不是变量名。

        (7)匿名内部类(掌握)

            A:是局部内部类的简化形式

            B:前提

                存在一个类或者接口

    这里的类可以是具体类也可以是抽象类

            C:格式:

                new 类名或者接口名() {

                    重写方法;

                }

            D:本质:

                其实是继承该类或者实现该接口的子类匿名对象

        (8)匿名内部类在开发中的使用

            我们在开发的时候,会看到抽象类,或者接口作为参数。

            而这个时候,我们知道实际需要的是一个子类对象。

            如果该方法仅仅调用一次,我们就可以使用匿名内部类的格式简化。

            

            

    interface Person {

        public abstract void study();

    }

     

    class PersonDemo {

        public void method(Person p) {

            p.study();

        }

    }

     

    class PersonTest {

        public static void main(String[] args) {

            PersonDemo pd = new PersonDemo();

            pd.method(new Person() {

                public void study() {

                    System.out.println("好好学习,天天向上");

                }

            });

        }

    }

     

            

        (9)匿名内部类的面试题

            

    interface Inter {

        void show();

    }

     

    class Outer {

        // 补齐代码

        public static Inter method() {

            return new Inter() {

                public void show() {

                    System.out.println("HelloWorld");

                }

            };

        }

    }

     

    class OuterDemo {

        public static void main(String[] args) {

            Outer.method().show(); // "HelloWorld"

            /*

             * 分析: 1. Outer.method() 可以看出method() 应该是 Outer 类中的一个 静态方法 2.

             * Outer.method().show() 可以看出 method() 方法的返回值是一 个对象,又由于接口Inter
    中有一个

             * show() 方法,所以我认 为 method() 方法的返回值类型是一个Inter
    接口

             *

             */

        }

    }

     

     

     

     

     

     

    第十一天

    1:Eclipse的概述使用(掌握)

        请参照ppt和课堂练习.txt

        

    2:API的概述(了解)

        (1)应用程序编程接口。

        (2)就是JDK提供给我们的一些提高编程效率的java类。

     

    3:Object类(掌握)

        (1)Object是类层次结构的根类,所有的类都直接或者间接的继承自Object类。

        (2)Object类的构造方法有一个,并且是无参构造

            这其实就是理解当时我们说过,子类构造方法默认访问父类的构造是无参构造

        (3)要掌握的方法:

            A: public String toString()

                返回对象的字符串表示,默认是由类的全路径+'@'+哈希值的十六进制表示。

                这个表示其实是没有意义的,一般子类都会重写该方法。

                如何重写呢?过程我也讲解过了,基本上就是要求信息简单明了。

                但是最终还是自动生成。

            B: public
    boolean equals(Object obj)

                比较两个对象是否相同。默认情况下,比较的是地址值是否相同。

                而比较地址值是没有意义的,所以,一般子类也会重写该方法。

                重写过程,我也详细的讲解和分析了。

                但是最终还是自动生成。

        (4)要了解的方法:

            A: public
    int hashCode()

    返回对象的哈希值。不是实际地址值(逻辑值),可以理解为地址值。

            B: public
    final Class<?> getClass() :

    返回对象的字节码文件对象,反射中我们会详细讲解    

            C: protected
    void finalize()
    :用于垃圾回收,但不确定的时间

    D: protected Object clone()
    :可以实现对象的克隆,包括成员变量的数据复制,但是它和两个引用指向同一个对象是有区别的。

        (5)两个注意问题;

            A:直接输出一个对象名称,其实默认调用了该对象的toString()方法。

            B:面试题

                ==和equals()的区别?

                A:==

                    基本类型:比较的是值是否相同

                    引用类型:比较的是地址值是否相同

                B:equals()

                    只能比较引用类型。默认情况下,比较的是地址值是否相同。

                    但是,我们可以根据自己的需要重写该方法。

     

    第十二天

     

    1. Scanner的使用(了解)

        (1)在JDK5以后出现的用于键盘录入数据的类。

        (2)构造方法:

    System类下有一个静态的字段:

    public
    static
    final InputStream in; //标准的输入流,对应着键盘录入

    InputStream is = System.in;

            A:讲解了System.in这个东西。

                它其实是标准的输入流,对应于键盘录入

            B:构造方法

                InputStream is = System.in;            

                public Scanner(InputStream source)

            C:常用的格式

                Scanner sc = new Scanner(System.in);

        (3)基本方法格式:

            A:hasNextXxx() 判断是否是某种类型的

    格式:public boolean hasNextXxx()

            B:nextXxx()    返回某种类型的元素

    格式:public Xxx nextXxx()

     

    举例:用int 类型的方法举例

    public
    boolean hasNext()

    public int nextInt()

        (4)要掌握的两个方法

    A: public int nextInt():获取一个int类型的数据

            B: public String nextLine()
    :获取一个String类型的值

        (5)需要注意的小问题

            A:同一个Scanner对象,先获取数值,再获取字符串会出现一个小问题。

            B:解决方案:

                a:重新定义一个Scanner对象

                b:把所有的数据都用字符串获取,然后再进行相应的转换

                

    2. String类的概述和使用(掌握)

        (1)多个字符组成的一串数据。

            其实它可以和字符数组进行相互转换。

        (2)构造方法:

            A: public String():空构造

            B: public String(byte
    bytes[]):把字节数组转成字符串

    C: public String(byte
    bytes[], int
    offset, int
    length):把字节数组的一部分转成字符串

            D:
    public String(char
    value[])
    :把字符数组转成字符串

    E: public String(char
    value[], int
    offset, int
    count)
    :把字符数组的一部分转成字符串

            F: public String(String original)
    :把字符串常量值转成字符串

            下面的这一个虽然不是构造方法,但是结果也是一个字符串对象

            G: String s = "hello";

        (3)字符串的特点

            A:字符串一旦被赋值,就不能改变(因为字符串为常量)。

                注意:这里指的是字符串的内容不能改变,而不是引用不能改变(也                    就是说引用可以被改变)。

            B:字面值作为字符串对象和通过构造方法创建对象的不同

     

    面试题?

                String s = new String("hello");和String s = "hello";的区别?

    答:前者会创建2个或者1对象,后者创建1个或者0个对象

        (4)字符串的面试题(看程序写结果)

            A:==和equals()

                

    String s1 = new String("hello");

            String s2 = new String("hello");

            System.out.println(s1 == s2);// false

            System.out.println(s1.equals(s2));// true

     

            String s3 = new String("hello");

            String s4 = "hello";

            System.out.println(s3 == s4);// false

            System.out.println(s3.equals(s4));// true

     

            String s5 = "hello";

            String s6 = "hello";

            System.out.println(s5 == s6);// true

            System.out.println(s5.equals(s6));// true

     

            B:字符串的拼接

    说明:

      字符串如果是变量相加,先开空间,在进行拼接

      字符串如果是常量相加,是先加,然后在常量池中找,如果找到就直    接返回,否则,就     创建并返回

     

    String s1 = "hello";

            String s2 = "world";

            String s3 = "helloworld";

            System.out.println(s3 == s1 + s2);// false

            System.out.println(s3.equals((s1 + s2)));// true

     

            System.out.println(s3 == "hello" + "world");// false 这个我们错了,应该是true

            System.out.println(s3.equals("hello" + "world"));// true

     

     

        (5)字符串的功能(自己补齐方法中文意思)

            A:判断功能

    1:public
    boolean equals(Object anObject)
    :比较字符串的内容是否相同(区分大小写)

    2:public
    boolean equalsIgnoreCase(String anotherString)
    :比较字符串内容是否相同(忽略大小写)

                3:public
    boolean contains(String str)
    :判断大字符串中是否包含小字符串

    4:public
    boolean startsWith(String str)
    :判断字符串是否以某个指定的字符串开头

    5:public
    boolean endsWith(String str)
    :判断字符串是否以某个指定的字符串结尾

                6:public
    boolean isEmpty()
    :判断字符串是否为空

    注意:

    字符串内容为空和字符串对象为空的区别?

    a: 字符串内容为空:表示字符串对象存在,但是没有数据

    如:String str = "";

    b: 字符串对象为空:表示字符串对象不存在

    如:String str = null;

     

            B:获取功能

            1:public
    int length()
    :获取字符串的长度

            2:public
    char charAt(int
    index)
    :获取指定索引位置的字符

            3:public
    int indexOf(int
    ch):返回指定字符在此字符串中第一次出现处的索引

    为什么这里是int 类型,而不是 char 类型?

    原因是:'a' 和 97 其实都可以代表'a'

    4:public
    int indexOf(String str)返回指定字符串在此字符串中第一次出现处的索引

    5:public
    int indexOf(int
    ch,int
    fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引

    6:public
    int indexOf(String str,int
    fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引

    7:public String substring(int
    start):从指定位置开始截取字符串,默认截取到末尾

    8:public String substring(int
    start,int
    end)
    :从指定位置开始到指定位置结束截取字符串,包头不包                                                尾

     

            C:转换功能

                1:public
    byte[] getBytes()
    :把字符串转换为字节数组

                2:public
    char[] toCharArray()
    :把字符串转换为字符数组

                3:public
    static String valueOf(char[] chs)
    :把字符数组转换成字符串

                4:public
    static String valueOf(int
    i)
    :把int类型的数据转换成字符串

    注意:String 类的 valueOf() 方法可以把任意类型的数据转成字符串

                5:public String toLowerCase()
    :把字符串转成小写(原串不变)

                6:public String toUpperCase()
    :把字符串转成大写(原串不变)

                7:public String concat(String str)
    :把字符串进行拼接

     

            D:其他功能

                a:替换功能

                1:public String replace(char
    old,char
    newChar)

                2:public String replace(String oldString, String newString)

                b:去空格功能

                    public String trim()

                c:按字典比较功能

                    public
    int compareTo(String str)

                    public
    int compareToIgnoreCase(String str)

     

        (6)字符串的案例

            A:模拟用户登录

    import java.util.Scanner;

    /*

    * 模拟登录,给三次机会,并提示还有几次。

    *

    * 分析:

    *         A:定义用户名和密码。已存在的。

    *         B:键盘录入用户名和密码。

    *         C:比较用户名和密码。

    *             如果都相同,则登录成功

    *             如果有一个不同,则登录失败

    *         D:给三次机会,用循环改进,最好用for循环。

    */

    class StringTest {

        public static void main(String[] args) {

            // 定义用户名和密码。已存在的。

            String username = "admin";

            String password = "admin";

     

            // 给三次机会,用循环改进,最好用for循环。

            for (int x = 0; x < 3; x++) {

                // x=0,1,2

                // 键盘录入用户名和密码。

                Scanner sc = new Scanner(System.in);

                System.out.println("请输入用户名:");

                String name = sc.nextLine();

                System.out.println("请输入密码:");

                String pwd = sc.nextLine();

     

                // 比较用户名和密码。

                if (name.equals(username) && pwd.equals(password)) {

                    // 如果都相同,则登录成功

                    System.out.println("登录成功");

                    break;

                } else {

                    // 如果有一个不同,则登录失败

                    // 2,1,0

    次,应该换一种提示

                    if ((2 - x) == 0) {

                        System.out.println("帐号被锁定,请与班长联系");

                    } else {

                        System.out.println("登录失败,你还有" + (2 - x) + "次机会");

                    }

                }

            }

        }

    }

     

            B:字符串遍历

    /*

    * 需求:遍历获取字符串中的每一个字符

    *

    * 分析:

    *         A:如何能够拿到每一个字符呢?

    *             char charAt(int index)

    *         B:我怎么知道字符到底有多少个呢?

    *             int length()

    */

    class StringTest {

        public static void main(String[] args) {

            // 定义字符串

            String s = "helloworld";

     

            // 原始版本

            // System.out.println(s.charAt(0));

            // System.out.println(s.charAt(1));

            // System.out.println(s.charAt(2));

            // System.out.println(s.charAt(3));

            // System.out.println(s.charAt(4));

            // System.out.println(s.charAt(5));

            // System.out.println(s.charAt(6));

            // System.out.println(s.charAt(7));

            // System.out.println(s.charAt(8));

            // System.out.println(s.charAt(9));

     

    取到9

            // for (int x = 0; x < 10; x++) {

            // System.out.println(s.charAt(x));

            // }

     

            // 如果长度特别长,我不可能去数,所以我们要用长度功能

            for (int x = 0; x < s.length(); x++) {

                // char ch = s.charAt(x);

                // System.out.println(ch);

                // 仅仅是输出,我就直接输出了

                System.out.println(s.charAt(x));

            }

        }

    }

     

            C:统计字符串中大写,小写及数字字符的个数

    /*

    * 需求:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。(不考虑其他字符)

    * 举例:

    *         "Hello123World"

    * 结果:

    *

    * 分析:

    *         前提:字符串要存在

    *         A:定义三个统计变量

    *             bigCount=0

    *             smallCount=0

    *             numberCount=0

    *         B:遍历字符串,得到每一个字符。

    *             length()和charAt()结合

    *         C:判断该字符到底是属于那种类型的

    *             大:bigCount++

    *             小:smallCount++

    *             数字:numberCount++

    *

    *             这道题目的难点就是如何判断某个字符是大的,还是小的,还是数字的。

    *             ASCII码表:

    *                 0    48

    *                 A    65

    *                 a    97

    *             虽然,我们按照数字的这种比较是可以的,但是想多了,有比这还简单的

    *                 char ch = s.charAt(x);

    *

    *                 if(ch>='0' && ch<='9') numberCount++

    *                 if(ch>='a' && ch<='z') smallCount++

    *                 if(ch>='A' && ch<='Z') bigCount++

    *        D:输出结果。

    *

    * 练习:把给定字符串的方式,改进为键盘录入字符串的方式。

    */

    class StringTest2 {

        public static void main(String[] args) {

            // 定义一个字符串

            String s = "Hello123World";

     

            // 定义三个统计变量

            int bigCount = 0;

            int smallCount = 0;

            int numberCount = 0;

     

            // 遍历字符串,得到每一个字符。

            for (int x = 0; x < s.length(); x++) {

                char ch = s.charAt(x);

     

                // 判断该字符到底是属于那种类型的

                if (ch >= 'a' && ch <= 'z') {

                    smallCount++;

                } else if (ch >= 'A' && ch <= 'Z') {

                    bigCount++;

                } else if (ch >= '0' && ch <= '9') {

                    numberCount++;

                }

            }

     

            // 输出结果。

            System.out.println("大写字母" + bigCount + "个");

            System.out.println("小写字母" + smallCount + "个");

            System.out.println("数字" + numberCount + "个");

        }

    }

     

            D:把字符串的首字母转成大写,其他小写

    /*

    * 需求:把一个字符串的首字母转成大写,其余为小写。(只考虑英文大小写字母字符)

    * 举例:

    *         helloWORLD

    * 结果:

    *         Helloworld

    *

    * 分析:

    *         A:先获取第一个字符

    *         B:获取除了第一个字符以外的字符

    *         C:把A转成大写

    *         D:把B转成小写

    *         E:C拼接D

    */

    class StringTest {

        public static void main(String[] args) {

            // 定义一个字符串

            String s = "helloWORLD";

     

            // 先获取第一个字符

            String s1 = s.substring(0, 1);

            // 获取除了第一个字符以外的字符

            String s2 = s.substring(1);

            // 把A转成大写

            String s3 = s1.toUpperCase();

            // 把B转成小写

            String s4 = s2.toLowerCase();

            // C拼接D

            String s5 = s3.concat(s4);

            System.out.println(s5);

     

            // 优化后的代码

            // 链式编程

            String result = s.substring(0, 1).toUpperCase().concat(s.substring(1).toLowerCase());

            System.out.println(result);

        }

    }

     

            E:把int数组拼接成一个指定格式的字符串

    /*

    * 需求:把数组中的数据按照指定个格式拼接成一个字符串

    * 举例:

    *         int[] arr = {1,2,3};    

    * 输出结果:

    *        "[1, 2, 3]"

    * 分析:

    *         A:定义一个字符串对象,只不过内容为空

    *         B:先把字符串拼接一个"["

    *         C:遍历int数组,得到每一个元素

    *         D:先判断该元素是否为最后一个

    *             是:就直接拼接元素和"]"

    *             不是:就拼接元素和逗号以及空格

    *         E:输出拼接后的字符串

    *

    * 把代码用功能实现。

    */

    class StringTest2 {

        public static void main(String[] args) {

            // 前提是数组已经存在

            int[] arr = { 1, 2, 3 };

     

            // 写一个功能,实现结果

            String result = arrayToString(arr);

            System.out.println("最终结果是:" + result);

        }

     

        /*

         * 两个明确: 返回值类型:String 参数列表:int[] arr

         */

        public static String arrayToString(int[] arr) {

            // 定义一个字符串

            String s = "";

     

            // 先把字符串拼接一个"["

            s += "[";

     

            // 遍历int数组,得到每一个元素

            for (int x = 0; x < arr.length; x++) {

                // 先判断该元素是否为最后一个

                if (x == arr.length - 1) {

                    // 就直接拼接元素和"]"

                    s += arr[x];

                    s += "]";

                } else {

                    // 就拼接元素和逗号以及空格

                    s += arr[x];

                    s += ", ";

                }

            }

     

            return s;

        }

    }

     

            F:字符串反转

    import java.util.Scanner;

     

    /*

    * 字符串反转

    * 举例:键盘录入"abc"        

    * 输出结果:"cba"

    *

    * 分析:

    *         A:键盘录入一个字符串

    *         B:定义一个新字符串

    *         C:倒着遍历字符串,得到每一个字符

    *             a:length()和charAt()结合

    *             b:把字符串转成字符数组

    *         D:用新字符串把每一个字符拼接起来

    *         E:输出新串

    */

    class StringTest3 {

        public static void main(String[] args) {

            // 键盘录入一个字符串

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入一个字符串:");

            String line = sc.nextLine();

     

            /*

             * // 定义一个新字符串 String result = "";

             *

             * // 把字符串转成字符数组 char[] chs = line.toCharArray();

             *

             * // 倒着遍历字符串,得到每一个字符 for (int x = chs.length - 1; x >= 0; x--) { //

             * 用新字符串把每一个字符拼接起来 result += chs[x]; }

             *

             * // 输出新串 System.out.println("反转后的结果是:" + result);

             */

     

            // 改进为功能实现

            String s = myReverse(line);

            System.out.println("实现功能后的结果是:" + s);

        }

     

        /*

         * 两个明确: 返回值类型:String 参数列表:String

         */

        public static String myReverse(String s) {

            // 定义一个新字符串

            String result = "";

     

            // 把字符串转成字符数组

            char[] chs = s.toCharArray();

     

            // 倒着遍历字符串,得到每一个字符

            for (int x = chs.length - 1; x >= 0; x--) {

                // 用新字符串把每一个字符拼接起来

                result += chs[x];

            }

            return result;

        }

    }

     

            G:统计大串中小串出现的次数

    /*

    * 统计大串中小串出现的次数

    * 举例:

    *         在字符串"woaijavawozhenaijavawozhendeaijavawozhendehenaijavaxinbuxinwoaijavagun"

    * 结果:

    *

    * 分析:

    *         前提:是已经知道了大串和小串。

    *

    *         B:先在大串中查找一次小串第一次出现的位置

    *             a:索引是-1,说明不存在了,就返回统计变量

    *             b:索引不是-1,说明存在,统计变量++

    *         C:把刚才的索引+小串的长度作为开始位置截取上一次的大串,

                    返回一个新的字符串,并把该字符串的值重新赋值给大串

    *         D:回到B

    */

    class StringTest5 {

        public static void main(String[] args) {

            // 定义大串

            String maxString = "woaijavawozhenaijavawozhendeaijavawozhendehenaijavaxinbuxinwoaijavagun";

            // 定义小串

            String minString = "java";

     

            // 写功能实现

            int count = getCount(maxString, minString);

            System.out.println("Java在大串中出现了:" + count + "次");

        }

     

        /*

         * 两个明确: 返回值类型:int
    参数列表:两个字符串

         */

        public static int getCount(String maxString, String minString) {

            int count = 0;

     

            /*

             * // 先在大串中查找一次小串第一次出现的位置 int index = maxString.indexOf(minString); //

             * 索引不是-1,说明存在,统计变量++ while (index != -1) { count++; //

             * 把刚才的索引+小串的长度作为开始位置截取上一次的大串, 返回一个新的字符串,并把该字符串的值重新赋值给大串 // int

             * startIndex = index + minString.length(); // maxString =

             * maxString.substring(startIndex); maxString =

             * maxString.substring(index + minString.length()); // 继续查 index =

             * maxString.indexOf(minString); }

             */

     

            int index;

            // 先查,赋值,判断

            while ((index = maxString.indexOf(minString)) != -1) {

                count++;

                maxString = maxString.substring(index + minString.length());

            }

     

            return count;

        }

    }

     

     

     

    第十三天

    1. StringBuffer(掌握)

        (1)说明:

    用字符串做拼接,比较耗时并且也耗内存,而这种拼接操作又是比较常见的,为了解决这个问题,Java就提供了

         一个字符串缓冲区类。StringBuffer供我们使用。

    为线程安全的可变字符序列

        (2)StringBuffer的构造方法

            A: public
    StringBuffer()
    :无参构造方法(默认容量16个字符)

            B: public
    StringBuffer(int capacity)
    :指定容量的字符串缓冲区对象

            C: public
    StringBuffer(String str)
    :指定字符串内容的字符串缓冲区对象

    (理论容量 = 字符串长度 + 默认容量16个字符)

        (3)StringBuffer的常见功能

            A:添加功能

    public StringBuffer append(String str) :可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身

    public StringBuffer insert(int
    offset, String str) : 在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身

            B:删除功能

    public StringBuffer deleteCharAt(int
    index): 删除指定位置的字符(只删除一个字符),并返回缓冲区本身

    public StringBuffer delete(int
    start, int
    end)
    :删除从指定位置开始到到指定结束位置的内容,并返回缓冲区本身

            C:替换功能

    public StringBuffer replace(int
    start, int
    end, String str):从start 开始到end用 str 进行替换

            D:反转功能

                public StringBuffer reverse():字符串反转

            E:截取功能(注意这个返回值)

    注意:截取的子串返回给一个新串,原串没有被改变

                public String substring(int
    start)

    public String substring(int
    start, int
    end)

    F:其他方法:

    public
    int capacity() : 返回当前容量。理论值

    public
    int length(): 返回长度(字符数)。实际值

        (4)StringBuffer的练习(做一遍)

            A:String和StringBuffer相互转换?

                String -- > StringBuffer

                    方式1:通过构造方法

    方式2:通过append方法

                StringBuffer --> String

                    方式1:通过构造方法

    方式2:通过 toString() 方法

    /*

    * 为什么我们要讲解类之间的转换:

    * A -- B的转换

    * 我们把A转换为B,其实是为了使用B的功能。

    * B -- A的转换

    * 我们可能要的结果是A类型,所以还得转回来。

    *

    * String和StringBuffer的相互转换?

    */

    public class MainDemo {

        public static void main(String[] args) {

            // String --- StringBuffer

            String s = "hello";

            // 注意:不能把字符串的值直接赋值给StringBuffer

            // StringBuffer sb = "hello";

            // StringBuffer sb = s;

            // 方式1:通过构造方法

            StringBuffer sb = new StringBuffer(s);

    :通过append()方法

            StringBuffer sb2 = new StringBuffer();

            sb2.append(s);

            System.out.println("sb:" + sb);

            System.out.println("sb2:" + sb2);

            System.out.println("---------------");

     

            // StringBuffer --- String

            StringBuffer buffer = new StringBuffer("java");

            // String(StringBuffer buffer)

            // 方式1:通过构造方法

            String str = new String(buffer);

    :通过toString()方法

            String str2 = buffer.toString();

            System.out.println("str:" + str);

            System.out.println("str2:" + str2);

        }

    }

     

            B:字符串的拼接

                

    /*

    * 需求:把数组拼接成一个字符串

    */

    public class MainDemo {

        public static void main(String[] args) {

            // 定义一个数组

            int[] arr = { 44, 33, 55, 11, 22 };

     

            // 定义功能

    :用String做拼接的方式

            String s1 = arrayToString(arr);

            System.out.println("s1:" + s1);

     

            // 方式2:用StringBuffer做拼接的方式

            String s2 = arrayToString2(arr);

            System.out.println("s2:" + s2);

        }

     

        // 用StringBuffer做拼接的方式

        public static String arrayToString2(int[] arr) {

            StringBuffer sb = new StringBuffer();

     

            sb.append("[");

            for (int x = 0; x < arr.length; x++) {

                if (x == arr.length - 1) {

                    sb.append(arr[x]);

                } else {

                    sb.append(arr[x]).append(", ");

                }

            }

            sb.append("]");

     

            return sb.toString();

        }

     

        // 用String做拼接的方式

        public static String arrayToString(int[] arr) {

            String s = "";

     

            s += "[";

            for (int x = 0; x < arr.length; x++) {

                if (x == arr.length - 1) {

                    s += arr[x];

                } else {

                    s += arr[x];

                    s += ", ";

                }

            }

            s += "]";

     

            return s;

        }

    }

     

            C:把字符串反转

    package cn.itcast01;

     

    import java.util.Scanner;

    /*

    * 需求:把字符串反转

    */

    public class MainDemo {

        public static void main(String[] args) {

            // 键盘录入数据

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入数据:");

            String s = sc.nextLine();

     

    :用String做拼接

            String s1 = myReverse(s);

            System.out.println("s1:" + s1);

    :用StringBuffer的reverse()功能

            String s2 = myReverse2(s);

            System.out.println("s2:" + s2);

        }

     

        // 用StringBuffer的reverse()功能

        public static String myReverse2(String s) {

            // StringBuffer sb = new StringBuffer();

            // sb.append(s);

     

            // StringBuffer sb = new StringBuffer(s);

            // sb.reverse();

            // return sb.toString();

     

            // 简易版

            return new StringBuffer(s).reverse().toString();

        }

     

        // 用String做拼接

        public static String myReverse(String s) {

            String result = "";

     

            char[] chs = s.toCharArray();

            for (int x = chs.length - 1; x >= 0; x--) {

                // char ch = chs[x];

                // result += ch;

                result += chs[x];

            }

     

            return result;

        }

    }

     

            D:判断一个字符串是否对称

    import java.util.Scanner;

    /*

    * 需求:判断一个字符串是否是对称字符串

    * 例如"abc"不是对称字符串,"aba"、"abba"、"aaa"、"mnanm"是对称字符串

    *

    * 分析:

    *         判断一个字符串是否是对称的字符串,我只需要把

    *             第一个和最后一个比较

    *             第二个和倒数第二个比较

    *             ...

    */

    public class MainDemo {

        public static void main(String[] args) {

            // 创建键盘录入对象

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入一个字符串:");

            String s = sc.nextLine();

     

            // 一个一个的比较

            boolean b = isSame(s);

            System.out.println("b:" + b);

     

            // 用字符串缓冲区的反转功能

            boolean b2 = isSame2(s);

            System.out.println("b2:" + b2);

        }

     

        // 用字符串缓冲区的反转功能

        public static boolean isSame2(String s) {

            return new StringBuffer(s).reverse().toString().equals(s);

        }

     

        // public static boolean isSame(String s) {

        // // 把字符串转成字符数组

        // char[] chs = s.toCharArray();

        //

        // for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {

        // if (chs[start] != chs[end]) {

        // return false;

        // }

        // }

        //

        // return true;

        // }

     

        // 一个一个的比较

        public static boolean isSame(String s) {

            boolean flag = true;

     

            // 把字符串转成字符数组

            char[] chs = s.toCharArray();

     

            for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {

                if (chs[start] != chs[end]) {

                    flag = false;

                    break;

                }

            }

     

            return flag;

        }

    }

     

        (5)面试题

            小细节:

                StringBuffer:同步的,线程安全的、数据安全,效率低。

                StringBuilder:不同步的,数据不安全,效率高。

            A:String,StringBuffer,StringBuilder的区别?

    答:

    1. String:长度和内容不可变

    2. StringBuffer 和 StringBuilder 都是长度和内容可变的

    3.String Buffer 是同步的,数据安全,效率低,;而StringBuilder是不同步的,数据不                 安全,效率搞

            B:StringBuffer和数组的区别?

    答:

    二者都可以看着是一个容器,都可以装其他的数据

    但是呢,StringBuffer 的数据最终是一个字符串数据,

    而数据可以放置多种数据,但必须都是同一种数据类型

        (6)注意的问题:

            1. String作为形式参数,效果和基本类型作为形式参数传递是一样的

    形式参数的改变不影响实际参数

      StringBuffer作为形式参数。赋值不改变实际值,但是调用其方法进行的值更改,则

      会改变实际值

        

    2. 数组高级以及Arrays(掌握)

        (1)排序

            A:冒泡排序

                相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处。同理,其            他的元素就可以排好。

                注意:第一次比较完之后,下一次比较的时候,就会减少一个元素的比较

                

    public static void bubbleSort(int[] arr) {

            for (int x = 0; x < arr.length - 1; x++) {

                for (int y = 0; y < arr.length - 1 - x; y++) {

                    if (arr[y] > arr[y + 1]) {

                        int temp = arr[y];

                        arr[y] = arr[y + 1];

                        arr[y + 1] = temp;

                    }

                }

            }

        }

     

                

            B:选择排序

                把0索引的元素,和索引1以后的元素都进行比较,第一次完毕,最小值出现在了0索            引。同理,其他的元素就可以排好。

                

                

    public static void selectSort(int[] arr) {

            for (int x = 0; x < arr.length - 1; x++) {

                for (int y = x + 1; y < arr.length; y++) {

                    if (arr[y] < arr[x]) {

                        int temp = arr[x];

                        arr[x] = arr[y];

                        arr[y] = temp;

                    }

                }

            }

        }

     

        (2)查找

            A:基本查找

                使用场景:针对数组无序的情况(从头找到尾)

                

                

    public static int getIndex(int[] arr, int value) {

            int index = -1;

     

            for (int x = 0; x < arr.length; x++) {

                if (arr[x] == value) {

                    index = x;

                    break;

                }

            }

            return index;

        }

     

            B:二分查找(折半查找)

                应用场景:针对数组有序的情况

                注意事项:针对无序的数组,进行先排序,后查找,是有问题的?

    答:因为数组本身是无序的,所以这种情况下不能使用二分查找

    所以你先排序了,但是你排序的时候已经改变了该数组最初是的元素索引

                

    public static int binarySearch(int[] arr, int value) {

            // 定义最小索引

            int min = 0;

            // 定义最大索引

            int max = arr.length - 1;

            // 计算中间索引

            int mid = (min + max) / 2;

            // 拿中间索引的值和被查找的值进行比较

            while (arr[mid] != value) {

                // 如果中间索引的值 比 被查找的值大了

                // 则最大索引
    = 原中间索引 - 1

                if (arr[mid] > value) {

                    max = mid - 1;

                    // 如果中间索引的值 比 被查找的值小了

                    // 则最小索引
    = 中间索引 + 1

                } else if (arr[mid] < value) {

                    min = mid + 1;

                }

                // 加入判断(如果没有该值的处理)

                if (min > max) {

                    return -1;

                }

     

                mid = (min + max) / 2;

            }

     

            return mid;

        }

     

        (3)Arrays工具类

            A:是针对数组进行操作的工具类。包括排序和查找等功能。

            B:要掌握的方法(自己补齐方法)

                1:public
    static String toString(int[] a) : 把数组转成字符串

                2:public
    static
    void sort(int[] a) : 对数组进行排序

    3:public
    static
    int binarySearch(int[] a, int
    key):二分查找,返回查找值的索引    

    Arrays工具类的源码解析

    Public static String toString(int[] a) 的源码分析

    public static int binarySearch(int[] a, int key)源码分析

     

    public static String toString(int[] a)源码分析

    public static void sort(int[] a)
    底层是快速排序,知道就可以了。有空看,有问题再问我

    public static int binarySearch(int[] a,int key)

    开发原则:

        只要是对象,我们就要判断该对象是否为null。

     

    int[] arr = { 24, 69, 80, 57, 13 };

    System.out.println("排序前:" + Arrays.toString(arr));

    // 这是源码

        public static String toString(int[] a) {

            // a -- arr -- { 24, 69, 80, 57, 13 }

     

            if (a == null)

                return "null"; // 说明数组对象不存在

            int iMax = a.length - 1; // iMax=4;

            if (iMax == -1)

                return "[]"; // 说明数组存在,但是没有元素。

     

            StringBuilder b = new StringBuilder();

            b.append('['); // "["

            for (int i = 0;; i++) {

                b.append(a[i]); // "[24, 69, 80, 57, 13"

                if (i == iMax)

                    // "[24, 69, 80, 57, 13]"

                    return b.append(']').toString();

                b.append(", "); // "[24, 69, 80, 57, "

            }

        }

    public static int binarySearch(int[] a, int key)源码分析

     

    int[] arr = {13, 24, 57, 69, 80};

    System.out.println("binarySearch:" + Arrays.binarySearch(arr, 577));

     

    // 源码

        public static int binarySearch(int[] a, int key) {

            // a -- arr -- {13, 24, 57, 69, 80}

            // key -- 577

            return binarySearch0(a, 0, a.length, key);

        }

    private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) {

            // a -- arr -- {13, 24, 57, 69, 80}

            // fromIndex -- 0

            // toIndex -- 5

            // key -- 577

     

            int low = fromIndex; // low=0

            int high = toIndex - 1; // high=4

     

            while (low <= high) {

                int mid = (low + high) >>> 1; // mid=2,mid=3,mid=4

                int midVal = a[mid]; // midVal=57,midVal=69,midVal=80

     

                if (midVal < key)

                    low = mid + 1; // low=3,low=4,low=5

                else if (midVal > key)

                    high = mid - 1;

                else

                    return mid; // key found

            }

            return -(low + 1); // key not found.

        }

     

        (5)把字符串中的字符进行排序

            举例:

                "edacbgf"

                得到结果

                "abcdefg"

     

    3. Integer(掌握)

        (1)说明:

    为了让基本类型的数据进行更多的操作,Java就为每种基本类型提供了对应的包装类类型

            byte         Byte

            short        Short

            int            Integer

            long        Long

            float        Float

            double        Double

            char        Character

            boolean        Boolean

        (2)Integer的构造方法

            A: Integer i = new Integer(100);

            B: Integer i = new Integer("100");

                注意:这里的字符串必须是由数字字符组成

        (3)String和int的相互转换

            A:String --> int

                Integer.parseInt("100");

            B:int --> String

                String.valueOf(100);

        (4)其他的功能(了解)

            一、进制转换

    1:public
    static String toBinaryString(int
    i) :二进制

    2:public
    static String toOctalString(int
    i)
    :八进制

    3:public
    static String toHexString(int
    i)
    : 十六进制

      进制数的范围:

      范围:2 - 36

      因为:只有 0 -9 和 a - z 共 36个数字和字母

      三、十进制 到 其他进制

      1: public static String toString(int i, int radix):

      参数说明:i :表示10进制值

      Radix:表示进制

      例如:Integer.toString(100, 8);    表示把 10进制的100 转成 8进制

    Integer.toString(100, 16); 表示把 10进制的100 转成16进制

      其他进制 到 十进制

      1:public
      static
      int parseInt(String s, int
      radix)

      例如: Integer.parseInt("100", 2);
      表示把二进制的100转成10进制

      Integer.parseInt("67", 8);
      表示把8进制的67转成10进制

        (5)JDK5的新特性

            自动装箱    基本类型--包装类型

            自动拆箱    包装类型--基本类型

    注意一个小问题:

    在使用,Integer x = null; 代码会出现 NullPointException异常

    建议:先判断是否为 null, 然后再使用

            

            把下面的这个代码理解即可:

                

    Integer i = 100;

            i += 200;

            // 通过反编译后的代码

            // Integer ii = Integer.valueOf(100); //自动装箱

            // ii = Integer.valueOf(ii.intValue() + 200); //自动拆箱,再自动装箱

            // System.out.println((new StringBuilder("ii:")).append(ii).toString());

     

        (6)面试题

            结论:对Integer类型的数据直接赋值的时候,如果在-128 到 127 之间的,

    会直接从缓冲池里面获取数据,否则重新创建一个Integer对象并返回

    /*

             * 看程序写结果

             *

    之间,会直接从缓冲池里获取数据

             */

            Integer i1 = new Integer(127);

            Integer i2 = new Integer(127);

            System.out.println(i1 == i2);//false

            System.out.println(i1.equals(i2));//true

            System.out.println("-----------");

     

            Integer i3 = new Integer(128);

            Integer i4 = new Integer(128);

            System.out.println(i3 == i4);//false

            System.out.println(i3.equals(i4));//true

            System.out.println("-----------");

     

            Integer i5 = 128;

            Integer i6 = 128;

            System.out.println(i5 == i6);//false

            System.out.println(i5.equals(i6));//true

            System.out.println("-----------");

     

            Integer i7 = 127;

            Integer i8 = 127;

            System.out.println(i7 == i8);//true 关键点

            System.out.println(i7.equals(i8));//false

     

    之间的数据,做了一个数据缓冲池,如果数据是该范围内的,每次并不创建新的空间

            // Integer ii = Integer.valueOf(127);

     

    4. Character(了解)

        (1)Character构造方法    

            Character ch = new Character('a');

        (2)要掌握的方法:(自己补齐)

            A:判断给定的字符是否是大写字符    

                public
    static
    boolean isUpperCase(char ch)

            B:判断给定的字符是否是小写字符

                public
    static
    boolean isLowerCase(char ch)

            C:判断给定的字符是否是数字字符

                public
    static
    boolean isDigit(char ch)

            D:把给定的字符转成大写字符

                public
    static
    char toUpperCase(char ch)

            E:把给定的字符转成小写字符

                public
    static
    char toLowerCase(char ch)

        (3)案例:

            统计字符串中大写,小写及数字字符出现的次数

            

    import java.util.Scanner;

    /*

    * 统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。

    (不考虑其他字符)

    *

    * 分析:

    *         A:定义三个统计变量。

    *             int bigCont=0;

    *             int smalCount=0;

    *             int numberCount=0;

    *         B:键盘录入一个字符串。

    *         C:把字符串转换为字符数组。

    *         D:遍历字符数组获取到每一个字符

    *         E:判断该字符是

    *             大写    bigCount++;

    *             小写    smalCount++;

    *             数字    numberCount++;

    *         F:输出结果即可

    */

    public class MainDemo {

        public static void main(String[] args) {

            // 定义三个统计变量。

            int bigCount = 0;

            int smallCount = 0;

            int numberCount = 0;

     

            // 键盘录入一个字符串。

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入一个字符串:");

            String line = sc.nextLine();

     

            // 把字符串转换为字符数组。

            char[] chs = line.toCharArray();

     

            // 历字符数组获取到每一个字符

            for (int x = 0; x < chs.length; x++) {

                char ch = chs[x];

     

                // 判断该字符

                if (Character.isUpperCase(ch)) {

                    bigCount++;

                } else if (Character.isLowerCase(ch)) {

                    smallCount++;

                } else if (Character.isDigit(ch)) {

                    numberCount++;

                }

            }

     

            // 输出结果即可

            System.out.println("大写字母:" + bigCount + "个");

            System.out.println("小写字母:" + smallCount + "个");

            System.out.println("数字字符:" + numberCount + "个");

        }

    }

     

     

     

     

     

     

    第十四天

    1. 正则表达式(理解)

        (1)定义:

    就是符合一定规则的字符串

        (2)常见规则

            A:字符

                x 字符 x。举例:'a'表示字符a

                \\ 反斜线字符。

                \n 新行(换行)符 ('\u000A')

                \r 回车符 ('\u000D')

                

            B:字符类

                [abc] a、b 或 c(简单类)(只能同时匹配单个字符)

                [^abc] 任何字符,除了 a、b 或 c(否定)

                [a-zA-Z] a到 z 或 A到 Z,两头的字母包括在内(范围)

                [0-9] 0到9的字符都包括

                

            C:预定义字符类

                . 任何字符。我的就是.字符本身,怎么表示呢? \.

                \d 数字:[0-9]

                \w 单词字符:[a-zA-Z_0-9]

                    在正则表达式里面组成单词的东西必须由这些东西组成

     

            D:边界匹配器

                ^ 行的开头

                $ 行的结尾

                \b 单词边界

                    就是不是单词字符的地方。

                    举例:hello world?haha;xixi

                

            E:Greedy 数量词

                X? X,一次或一次也没有 ,也就是0次或者1次

                X* X,零次或多次

                X+ X,一次或多次

                X{n} X,恰好 n 次

                X{n,} X,至少 n 次

                X{n,m} X,至少 n 次,但是不超过 m 次

        (3)常见功能:(分别用的是谁呢?)

            A:判断功能

                String类的public
    boolean matches(String regex)

            B:分割功能

                String类的public String[] split(String regex)

            C:替换功能

                String类的public String replaceAll(String regex,String replacement)

                说明:使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串

            D:获取功能

                Pattern和Matcher

                    //把规则编译成模式对象

                    Pattern p = Pattern.compile("a*b");

                    //利用模式对象来生成匹配器对象

                    Matcher m = p.matcher("aaaaab");

                    

                    find():查找是否存在下一个匹配的元素

                    group():获取刚才匹配成功的数据

                注意事项:调用group() 方法之前,必须先调用find() 方法

        (4)案例

            A:判断电话号码和邮箱

        

    import java.util.Scanner;

    /*

    * 需求:校验邮箱

    *

    * 分析:

    *         A:键盘录入邮箱

    *         B:定义邮箱的规则

    *             1517806580@qq.com

    *             liuyi@163.com

    *             linqingxia@126.com

    *             fengqingyang@sina.com.cn

    *             fqy@itcast.cn

    *         C:调用功能,判断即可

    *         D:输出结果

    */

    public class RegexTest {

        public static void main(String[] args) {

            //键盘录入邮箱

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入邮箱:");

            String email = sc.nextLine();

            

            //定义邮箱的规则

            //String regex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,6}(\\.[a-zA-Z_0-9]{2,3})+";

            String regex = "\\w+@\\w{2,6}(\\.\\w{2,3})+";

            

            //调用功能,判断即可

            boolean flag = email.matches(regex);

            

            //输出结果

            System.out.println("flag:"+flag);

        }

    }

     

            B:按照不同的规则分割数据

                

    import java.util.Arrays;

    /*

    * 需求:我有如下一个字符串:"91 27 46 38 50"

    * 请写代码实现最终输出结果是:"27 38 46 50 91"

    *

    * 分析:

    *         A:定义一个字符串

    *         B:把字符串进行分割,得到一个字符串数组

    *         C:把字符串数组变换成int数组

    *         D:对int数组排序

    *         E:把排序后的int数组在组装成一个字符串

    *         F:输出字符串

    */

    public class RegexTest {

        public static void main(String[] args) {

            // 定义一个字符串

            String s = "91 27 46 38 50";

     

            // 把字符串进行分割,得到一个字符串数组

            String[] strArray = s.split(" ");

     

            // 把字符串数组变换成int数组

            int[] arr = new int[strArray.length];

     

            for (int x = 0; x < arr.length; x++) {

                arr[x] = Integer.parseInt(strArray[x]);

            }

     

            // 对int数组排序

            Arrays.sort(arr);

     

            // 把排序后的int数组在组装成一个字符串

            StringBuilder sb = new StringBuilder();

            for (int x = 0; x < arr.length; x++) {

                sb.append(arr[x]).append(" ");

            }

            //转化为字符串

            String result = sb.toString().trim();

            

            //输出字符串

            System.out.println("result:"+result);

        }

    }

     

            C:把论坛中的数字替换为*

    /*

    * 替换功能 String类的public String replaceAll(String regex,String replacement) 使用给定的

    * replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

    */

    class RegexDemo {

        public static void main(String[] args) {

            // 定义一个字符串

            String s = "helloqq12345worldkh622112345678java";

     

            // 我要去除所有的数字,用*给替换掉

            // String regex = "\\d+";

            // String regex = "\\d";

            // String ss = "*";

     

            // 直接把数字干掉

            String regex = "\\d+";

            String ss = "";

     

            String result = s.replaceAll(regex, ss);

            System.out.println(result);

        }

    }

     

            D:获取字符串中由3个字符组成的单词

    import java.util.regex.Matcher;

    import java.util.regex.Pattern;

     

    /*

    * 获取功能:

    * 获取下面这个字符串中由三个字符组成的单词

    * da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?

    */

    class RegexDemo2 {

        public static void main(String[] args) {

            // 定义字符串

            String s = "da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?";

            // 规则

            String regex = "\\b\\w{3}\\b";

     

            // 把规则编译成模式对象

            Pattern p = Pattern.compile(regex);

            // 通过模式对象得到匹配器对象

            Matcher m = p.matcher(s);

            // 调用匹配器对象的功能

            // 通过find方法就是查找有没有满足条件的子串

            // public boolean find()

            // boolean flag = m.find();

            // System.out.println(flag);

            // // 如何得到值呢?

            // // public String group()

            // String ss = m.group();

            // System.out.println(ss);

            //

            // // 再来一次

            // flag = m.find();

            // System.out.println(flag);

            // ss = m.group();

            // System.out.println(ss);

            

            //如果匹配到值,就返回
    true

            while (m.find()) {

                System.out.println(m.group());

            }

     

            // 注意:一定要先find(),然后才能group()

            // IllegalStateException: No match found

            // String ss = m.group();

            // System.out.println(ss);

        }

    }

     

        

    2. Math(掌握)

        (1)定义:

    用于数学运算的类

        (2)常见方法

            A:绝对值:public
    static
    int abs(int
    a)

                    

            B:向上取整:public
    static
    double ceil(double
    a)

                    

            C:向下取整:public
    static
    double floor(double
    a)

                    

            D:两个数据中的大值:public
    static
    int max(int
    a, int
    b)

                    

            E:a的b次幂:public
    static
    double pow(double
    a, double
    b)

                    

            F:随机数:public
    static
    double random()

     

            G:四舍五入:public
    static
    int round(float
    a)

            H:正平方根:public
    static
    double sqrt(double
    a)

    (3)成员变量

            public
    static
    final
    double
    E = 2.7182818284590452354;

            public
    static
    final
    double
    PI = 3.14159265358979323846;

         (4)案例:

            A:猜数字小游戏

    import java.util.Random;

    import java.util.Scanner;

     

    /*

    * 动态产生一个 1 - 100 之间的数字,记录猜中结果的次数

    */

    public class GuessGame {

     

        

        public static void startGame() {

            Random ran = new Random();

            

            //获取到的随机数

            int num = ran.nextInt(100) + 1;

            //定义一个统计变量

            int count = 0;

            

            while(true) {

                Scanner sc = new Scanner(System.in);

                System.out.println("你输入你猜中的数字:");

                int n = sc.nextInt();

                count++;

                //比较数字

                if (num == n) {

                    System.out.println("恭喜你," + count + "次就猜中啦,好厉害呀!");

                    break;

                } else if (num > n) {

                    System.out.println("你猜的数字小了!继续加油吧...");

                } else if (num < n) {

                    

                    System.out.println("你猜的数字大了!还差一点喔..come on baby.");

                }

                

            }

        }

        

    }

     

            B:获取任意范围的随机数

                

    import java.util.Scanner;

     

    /*

    * 需求:请设计一个方法,可以实现获取任意范围内的随机数。

    *

    * 分析:

    *         A:键盘录入两个数据。

    *             int strat;

    *             int end;

    *         B:想办法获取在start到end之间的随机数

    *             我写一个功能实现这个效果,得到一个随机数。(int)

    *         C:输出这个随机数

    */

    public class MathDemo {

        public static void main(String[] args) {

            //

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入开始数:");

            int start = sc.nextInt();

            System.out.println("请输入结束数:");

            int end = sc.nextInt();

     

            for (int x = 0; x < 100; x++) {

                // 调用功能

                int num = getRandom(start, end);

                // 输出结果

                System.out.println(num);

            }

        }

     

        /*

         * 写一个功能 两个明确: 返回值类型:int
    参数列表:int start,int end 分析:比如两个数为:200 - 300 之间的随机数

         * 1、 1 - 100 之间随机数的获取: (int)(Math.random() * 100) + 1; 2、同理: 200 -

         * 300之间随机数为:(int)(Math.random() * 300) + 200; 这真的正确吗? 现在的范围就变为了:[0,300)

    、如果更改为: (int)(Math.random() * (300 -

         * 200 + 1)) + 200; 呢? 现在的范围为:[0,100] 然后 加上 200 ------》 变为了

         * [200,300],这是我们想要的

         */

        public static int getRandom(int start, int end) {

            // 回想我们讲过的1-100之间的随机数

            // int number = (int) (Math.random() * 100) + 1;

            // int number = (int) (Math.random() * end) + start;

            // 发现有问题了,怎么办呢?

            int number = (int) (Math.random() * (end - start + 1)) + start;

            return number;

        }

    }

     

        

    3. Random(理解)

        (1)定义:

    用于产生随机数的类

        (2)构造方法:

            A: public Random():

    没有给出种子,用的是默认种子(当前时间的毫秒值),每次产生的随机数不同

            B: public Random(long
    seed)

    指定种子,给定种子后,每次得到的随机数是相同的

        (3)成员方法:

            A: public
    int nextInt()
    :返回int类型范围内的随机数

            B: public
    int nextInt(int
    n) : 返回[0,n)范围内的随机数

    (4)代码演示

            

    import java.util.Random;

    /*

    * Random:产生随机数的类

    *

    * 构造方法:

    *         public Random():没有给种子,用的是默认种子,是当前时间的毫秒值

    *        public Random(long seed):给出指定的种子

    *        给定种子后,每次得到的随机数是相同的。

    *

    * 成员方法:

    *         public int nextInt():返回的是int类型范围内的随机数

    *        public int nextInt(int n):返回的是[0,n)范围内随机数

    */

    class RandomDemo {

        public static void main(String[] args) {

            // 创建对象

            // Random r = new Random();

            Random r = new Random(1111);

     

            for (int x = 0; x < 10; x++) {

                // int num = r.nextInt();

                int num = r.nextInt(100) + 1;

                System.out.println(num);

            }

        }

    }

     

    4. System(掌握)

        (1)定义:

    系统类,提供了一些有用的字段和方法

        (2)成员方法

         A:运行垃圾回收器:

    public
    static
    void gc()

    执行System.gc()前,系统会自动调用finalize()方法清除对象占有的资源    

    B:退出jvm:

    public
    static
    void exit(int
    status)

    终止当前正在运行的 Java 虚拟机。参数用作状态码;根据惯例,非 0 的状态码表示异常终止。

     


    演示:

    /*

    * System类包含一些有用的类字段和方法。它不能被实例化。

    * 方法:

    *        public static void exit(int status):终止当前正在运行的 Java 虚拟机。

    * 参数用作状态码;根据惯例,非 0 的状态码表示异常终止。

    */

    class SystemDemo {

        public static void main(String[] args) {

            System.out.println("我们喜欢林青霞(东方不败)");

            System.exit(0);

            System.out.println("我们也喜欢赵雅芝(白娘子)");

        }

    }

     

            C:获取当前时间的毫秒值:

                    public
    static
    long currentTimeMillis()

                演示:

            

    /*

    * System类包含一些有用的类字段和方法。它不能被实例化。

    *

    * 方法:

    *        public static long currentTimeMillis():返回以毫秒为单位的当前时间

    */

    class SystemDemo {

        public static void main(String[] args) {

            // System.out.println(System.currentTimeMillis());

     

            // 单独得到这样的实际目前对我们来说意义不大

            // 那么,它到底有什么作用呢?

            // 要求:请大家给我统计这段程序的运行时间

            long start = System.currentTimeMillis();

            for (int x = 0; x < 100000; x++) {

                System.out.println("hello" + x);

            }

            long end = System.currentTimeMillis();

            System.out.println("共耗时:" + (end - start) + "毫秒");

        }

    }

     

    D:数组复制:

    public
    static
    void arraycopy(Object src, int
    srcPos,

                     Object dest, int
    destPos, int
    length)

     

    从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。

                    并复制几个元素

                演示:

    import java.util.Arrays;

     

    /*

    * System类包含一些有用的类字段和方法。它不能被实例化。

    * 方法:

    *        public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)

    *                从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。

    */

    class SystemDemo {

        public static void main(String[] args) {

            // 定义数组

            int[] arr = { 11, 22, 33, 44, 55 };

            int[] arr2 = { 6, 7, 8, 9, 10 };

     

            // 请大家看这个代码的意思

            System.arraycopy(arr, 1, arr2, 2, 2);

            //结果:[ 11, 22, 33, 44, 55 ]

            System.out.println(Arrays.toString(arr));

            //结果:[6, 7, 22, 33, 10]

            System.out.println(Arrays.toString(arr2));

        }

    }

     

    5. BigInteger(理解)

        (1)说明:

    针对大整数的运算

        (2)构造方法    

            A: public BigInteger(String s)

        (3)成员方法

            A:加

                    public BigInteger add(BigInteger val)

            B:减

                    public BigInteger subtract(BigInteger val)

            C:乘

                    public BigInteger multiply(BigInteger val)

            D:除

                    public BigInteger divide(BigInteger val)

            E:返回商和余数的数组:也就是Biginter[0] = 商 Biginter[1] = 余数

                    public BigInteger[] divideAndRemainder(BigInteger val)

    (4)代码演示:

            

    import java.math.BigInteger;

     

    class BigIntegerDemo {

        public static void main(String[] args) {

            BigInteger bi1 = new BigInteger("100");

            BigInteger bi2 = new BigInteger("50");

     

            // public BigInteger add(BigInteger val):加

            System.out.println("add:" + bi1.add(bi2));

            // public BigInteger subtract(BigInteger val):加

            System.out.println("subtract:" + bi1.subtract(bi2));

            // public BigInteger multiply(BigInteger val):加

            System.out.println("multiply:" + bi1.multiply(bi2));

            // public BigInteger divide(BigInteger val):加

            System.out.println("divide:" + bi1.divide(bi2));

     

            // public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组

            BigInteger[] bis = bi1.divideAndRemainder(bi2);

            System.out.println("商:" + bis[0]);

            System.out.println("余数:" + bis[1]);

        }

    }

     

    6. BigDecimal(理解)

        (1)定义:

    (float、double)浮点数据做运算,会丢失精度。所以,针对浮点数据的操作建议采用BigDecimal。(金融相关的项目)

        (2)构造方法

            A: public BigDecimal(String s)

        (3)成员方法:

            A:加

                public BigDecimal add(BigDecimal augend)

            B:减

                public BigDecimal subtract(BigDecimal subtrahend)

            C:乘

                public BigDecimal multiply(BigDecimal multiplicand)

            D:除

                public BigDecimal divide(BigDecimal divisor)

            E:自己保留小数几位

    public BigDecimal divide(BigDecimal divisor, int
    scale, RoundingMode roundingMode)

    参数列表说明:divisor:商

    Scale:保留几位小数

                                roundingMode:取舍模式(一般为BigDecimal.ROUND_HALF_UP

    (4)代码演示

    import java.math.BigDecimal;

     

    class BigDecimalDemo {

        public static void main(String[] args) {

            /*

             *

             * 看程序写结果:结果和我们想的有一点点不一样,这是因为float类型的数据存储和整数不一样导致的。它们大部分的时候,都是带有有效数字位。

             *

             * 由于在运算的时候,float类型和double很容易丢失精度,演示案例。所以,为了能精确的表示、计算浮点数,Java提供了BigDecimal

             *

             * BigDecimal类:不可变的、任意精度的有符号十进制数,可以解决数据丢失问题。

             */

    //        System.out.println(0.09 + 0.01); //0.09999999999999999

    //        System.out.println(1.0 - 0.32);//0.6799999999999999

    //        System.out.println(1.015 * 100);//101.49999999999999

    //        System.out.println(1.301 / 100);// 0.013009999999999999

            

            //为了解决上面丢失精度的问题,需要使用
    BigDecimal

            BigDecimal bd1 = new BigDecimal("0.09");

            BigDecimal bd2 = new BigDecimal("0.01");

            //相加运算

            System.out.println("add:" + bd1.add(bd2));

            System.out.println("-------------------");

     

            BigDecimal bd3 = new BigDecimal("1.0");

            BigDecimal bd4 = new BigDecimal("0.32");

            //想减运算

            System.out.println("subtract:" + bd3.subtract(bd4));

            System.out.println("-------------------");

     

            BigDecimal bd5 = new BigDecimal("1.015");

            BigDecimal bd6 = new BigDecimal("100");

            //相乘运算

            System.out.println("multiply:" + bd5.multiply(bd6));

            System.out.println("-------------------");

     

            BigDecimal bd7 = new BigDecimal("1.301");

            BigDecimal bd8 = new BigDecimal("100");

            //相除运算

            System.out.println("divide:" + bd7.divide(bd8));

            //自己指定保留几位小数,和取舍模式

            System.out.println("divide:" + bd7.divide(bd8, 3, BigDecimal.ROUND_HALF_UP));

            System.out.println("divide:" + bd7.divide(bd8, 8, BigDecimal.ROUND_HALF_UP));

        }

    }

     

    7. Date/DateFormat(掌握)

        (1)Date 类的定义:

    Date是日期类,可以精确到毫秒。

            A:构造方法

                public Date() :根据当前的默认(系统)毫秒值创建日期对象

                public Date(long
    date) :根据给定的毫秒值创建日期对象

                代码演示:

                

    import java.util.Date;

     

    /*

    * Date:表示特定的瞬间,精确到毫秒。

    *

    * 构造方法:

    *         Date():根据当前的默认毫秒值创建日期对象

    *         Date(long date):根据给定的毫秒值创建日期对象

    */

    class DateDemo {

        public static void main(String[] args) {

            // 用无参构造方法创建对象

            Date d = new Date();

            System.out.println("d:" + d);

     

            // 用给定的毫秒值创建对象

            // long time = System.currentTimeMillis();

            long time = 1000 * 60 * 60; // 1小时

            Date d2 = new Date(time);

            System.out.println("d2:" + d2);

        }

    }

     

            B:成员方法

                public
    long getTime() :获取当前系统时间的毫秒值,以毫秒为单位

                public
    void setTime(long
    time) :用毫秒值设置时间

                代码演示:

                

    import java.util.Date;

     

    /*

    * public long getTime():获取时间,以毫秒为单位

    * public void setTime(long time):设置时间

    *                         注意事项:需要注意全球时区的不同,造成的时差

    *

    * 从Date得到一个毫秒值

    *         getTime()

    * 把一个毫秒值转换为Date

    *         构造方法

    *         setTime(long time)

    */

    class DateDemo {

        public static void main(String[] args) {

            // 创建对象

            Date d = new Date();

     

            // 获取时间

            long time = d.getTime();

            System.out.println(time);

            // System.out.println(System.currentTimeMillis());

     

            System.out.println("d:" + d);

            // 设置时间,这里需要注意时区的问题

            d.setTime(1000);

            System.out.println("d:" + d);

        }

    }

     

            C:日期和毫秒值的相互转换

                    

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * Date     --     String(格式化)

    *         public final String format(Date date)

    *

    * String -- Date(解析)

    *         public Date parse(String source)

    *

    * DateForamt:可以进行日期和字符串的格式化和解析,但是由于是抽象类,所以使用具体子类SimpleDateFormat。

    *

    * SimpleDateFormat的构造方法:

    *         SimpleDateFormat():默认模式

    *         SimpleDateFormat(String pattern):给定的模式

    *             这个模式字符串该如何写呢?

    *             通过查看API,我们就找到了对应的模式

    *             年 y

    *             月 M    

    *             日 d

    *             时 H

    *             分 m

    *             秒 s

    *

    月12日 12:12:12

    */

    public class DateTest3 {

     

        public static void main(String[] args) {

     

            // 创建日期对象

            Date date = new Date();

            // Date ----> String

            dateToString(date);

     

            // String ----> Date

            String nowtime = "2016-12-09 15:36:25";

            stringToDate(nowtime);

     

        }

     

        /**

         * 将具有指定格式的字符串解析为 Date对象

         *

         * @param time

         */

        public static void stringToDate(String time) {

            // 创建格式化对象

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

     

            // 将字符串解析为Date

            Date date = null;

            try {

                date = sdf.parse(time);

            } catch (ParseException e) {

     

                e.printStackTrace();

            }

            System.out.println(date);

        }

     

        /**

         * Date对象 格式化为 String对象(可以方便读取的时间字符串)

         *

         * @param date

         */

        public static void dateToString(Date date) {

     

            // 创建格式化对象

            // SimpleDateFormat()

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

     

            // 将日期对象进行格式化

            // public final String format(Date date)

            String nowTime = sdf.format(date);

            // 输出格式化后的字符串

            System.out.println(nowTime);

     

        }

    }

     

            D:案例:你来到这个世界多少天了?

        

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.Scanner;

     

    /*

    * 案例:算一下你来到这个世界多少天?

    *

    * 分析:

    *         A:键盘录入你的出生的年月日

    *         B:把该字符串转换为一个日期

    *         C:通过该日期得到一个毫秒值

    *         D:获取当前时间的毫秒值

    *         E:用D-C得到一个毫秒值

    *         F:把E的毫秒值转换为年

    *             /1000/60/60/24

    */

    class MyYearOldDemo {

        public static void main(String[] args) throws ParseException {

            // 键盘录入你的出生的年月日

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入你的出生年月日:");

            String line = sc.nextLine();

     

            // 把该字符串转换(解析)为一个日期

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            Date d = sdf.parse(line);

     

            // 通过该日期得到一个毫秒值

            long myTime = d.getTime();

     

            // 获取当前时间的毫秒值

            long nowTime = System.currentTimeMillis();

     

            // 用D-C得到一个毫秒值

            long time = nowTime - myTime;

     

            // 把E的毫秒值转换为年

            long day = time / 1000 / 60 / 60 / 24;

     

            System.out.println("你来到这个世界:" + day + "天");

        }

    }

     

    (2)DateFormat类的定义:

    DateFormat针对日期进行格式化和针对字符串进行解析的类,但是是抽象类,所以使用其子类SimpleDateFormat

            A:构造方法

                    public SimpleDateFormat():默认模式

                    public SimpleDateFormat(String pattern):给定模式

                
    常用模式:yyyy-MM-dd HH:mm:ss

            B:日期和字符串的转换(SimpleDateFormat类)

                a:Date

    -
    String

                    public
    final String format(Date date)

                    

                b:String
    --

    Date

                    public Date parse(String source)

    c:代码演示:

                

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * Date     --> String(格式化)

    *         public final String format(Date date)

    *

    * String --> Date(解析)

    *         public Date parse(String source)

    *

    * DateForamt:可以进行日期和字符串的格式化和解析,但是由于是抽象类,

    *              所以使用具体子类SimpleDateFormat。

    *

    * SimpleDateFormat的构造方法:

    *         SimpleDateFormat():默认模式

    *         SimpleDateFormat(String pattern):给定的模式

    *             这个模式字符串该如何写呢?

    *             通过查看API,我们就找到了对应的模式

    *             年 y

    *             月 M    

    *             日 d

    *             时 H

    *             分 m

    *             秒 s

    *

    月12日 12:12:12

    */

    class DateFormatDemo {

        public static void main(String[] args) throws ParseException {

            // Date -- String

            // 创建日期对象

            Date d = new Date();

            // 创建格式化对象(无参),没有给定模式

            // SimpleDateFormat sdf = new SimpleDateFormat();

            // 给定模式

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

            // public final String format(Date date)

            String s = sdf.format(d);

            System.out.println(s);

     

            // String -- Date

            String str = "2008-08-08 12:12:12";

            // 在把一个字符串解析为日期的时候,请注意格式必须和给定的字符串格式匹配

            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Date dd = sdf2.parse(str);

            System.out.println(dd);

        }

    }

     

            C:案例:

                制作了一个针对日期操作的工具类。

        

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /**

    * 这是日期和字符串相互转换的工具类

    *

    * @author
    风清扬

    */

    class DateUtil {

        private DateUtil() {

        }

     

        /**

         * 这个方法的作用就是把日期转成一个字符串

         *

         * @param d

         * 被转换的日期对象

         * @param format

         * 传递过来的要被转换的格式

         * @return
    格式化后的字符串

         */

        public static String dateToString(Date d, String format) {

            // SimpleDateFormat sdf = new SimpleDateFormat(format);

            // return sdf.format(d);

            return new SimpleDateFormat(format).format(d);

        }

     

        /**

         * 这个方法的作用就是把一个字符串解析成一个日期对象

         *

         * @param s

         * 被解析的字符串

         * @param format

         * 传递过来的要被转换的格式

         * @return
    解析后的日期对象

         * @throws ParseException

         */

        public static Date stringToDate(String s, String format) throws ParseException {

            return new SimpleDateFormat(format).parse(s);

        }

    }

     

    8. Calendar(掌握)

        (1)定义:

    日历类,封装了所有的日历字段值,通过统一的方法根据传入不同的日历字段可以获取值。

        (2)如何得到一个日历对象呢?

            Calendar rightNow = Calendar.getInstance();

            本质返回的是子类对象

        (3)成员方法

            A:根据日历字段得到对应的值

                    public
    int get(int
    field)

                    常用的日历字段:

    年:Calendar.YEAR

    月:Calendar.MONTH

    日:Calendar.DATE

     

                代码演示:

     

    import java.util.Calendar;

     

    /*

    * Calendar:它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等

    *             日历字段之间的转换提供了一些方法,

    *             并为操作日历字段(例如获得下星期的日期)提供了一些方法。

    *

    * public int get(int field):返回给定日历字段的值。日历类中的每个日历字段都是静态的成员变量,并且是int类型。

    */

    class CalendarDemo {

        public static void main(String[] args) {

            // 其日历字段已由当前日期和时间初始化:

            Calendar rightNow = Calendar.getInstance(); // 子类对象

     

            // 获取年

            int year = rightNow.get(Calendar.YEAR);

            // 获取月

            int month = rightNow.get(Calendar.MONTH);

            // 获取日

            int date = rightNow.get(Calendar.DATE);

     

            System.out.println(year + "年" + (month + 1) + "月" + date + "日");

        }

    }

     

    /*Calendar.getInstance(); 返回的对象是子类对象的解释

    * abstract class Person {

    *         public static Person getPerson() {

    *             return new Student();

    * }

    * }

    * class Student extends Person {

    *

    * }

    */

     

     

     

            B:根据日历字段和一个正负数确定是添加还是减去对应日历字段的值

                    public
    void add(int
    field, int
    amount)

            C:设置日历对象的年月日

                    public
    final
    void set(int
    year, int
    month, int
    date)

    (4)方法演示:

        

    import java.util.Calendar;

     

    /*

    * public void add(int field,int amount):根据给定的日历字段和对应的时间,

                                                来对当前的日历进行操作。

    * public final void set(int year,int month,int date):设置当前日历的年月日

    */

    class CalendarDemo {

        public static void main(String[] args) {

            // 获取当前的日历时间

            Calendar c = Calendar.getInstance();

     

            // 获取年

            int year = c.get(Calendar.YEAR);

            // 获取月

            int month = c.get(Calendar.MONTH);

            // 获取日

            int date = c.get(Calendar.DATE);

            System.out.println(year + "年" + (month + 1) + "月" + date + "日");

     

            // // 三年前的今天

            // c.add(Calendar.YEAR, -3);

            // // 获取年

            // year = c.get(Calendar.YEAR);

            // // 获取月

            // month = c.get(Calendar.MONTH);

            // // 获取日

            // date = c.get(Calendar.DATE);

            // System.out.println(year + "年" + (month + 1) + "月" + date + "日");

     

    天前

            c.add(Calendar.YEAR, 5);

            c.add(Calendar.DATE, -10);

            // 获取年

            year = c.get(Calendar.YEAR);

            // 获取月

            month = c.get(Calendar.MONTH);

            // 获取日

            date = c.get(Calendar.DATE);

            System.out.println(year + "年" + (month + 1) + "月" + date + "日");

            System.out.println("--------------");

            //设置当前日历的时间(包含年月日)

            c.set(2011, 11, 11);

            // 获取年

            year = c.get(Calendar.YEAR);

            // 获取月

            month = c.get(Calendar.MONTH);

            // 获取日

            date = c.get(Calendar.DATE);

            System.out.println(year + "年" + (month + 1) + "月" + date + "日");

        }

    }

     

            

    (5)案例:

            计算任意一年的2月份有多少天?

     

    import java.util.Calendar;

    import java.util.Scanner;

     

    /*

    * 案例:获取任意一年的二月有多少天

    *         (所用的方法很巧妙)

    *

    * 分析:

    *         A:键盘录入任意的年份

    *         B:设置日历对象的年月日

    *             年就是A输入的数据

    月的最后一天

    *         D:获取这一天输出即可

    */

    class CalendarTest {

        public static void main(String[] args) {

            // 键盘录入任意的年份

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入年份:");

            int year = sc.nextInt();

     

            // 设置日历对象的年月日

            Calendar c = Calendar.getInstance();

    月1日

    月的最后一天

            c.add(Calendar.DATE, -1);

     

            // 获取这一天输出即可

            System.out.println(c.get(Calendar.DATE));

        }

    }

     

    第十五天

    1. 对象数组(掌握)

    (1)定义:

    数组既可以存储基本数据类型,也可以存储引用类型。它存储引用类型的时候的数组就叫对象数组。

    (2)对象数组的内存图解

    (3)案例:

            用数组存储5个学生对象,并遍历数组。

    import java.util.ArrayList;

    import java.util.Collection;

     

    /*

    个学生对象,并把学生对象进行遍历。

    *

    * 分析:

    * A:创建学生类

    * B:创建集合对象

    * C:创建学生对象

    * D:把学生添加到集合

    * E:把集合转成数组

    * F:遍历数组

    */

    class StudentDemo {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 创建学生对象

            Student s1 = new Student("林青霞", 27);

            Student s2 = new Student("风清扬", 30);

            Student s3 = new Student("令狐冲", 33);

            Student s4 = new Student("武鑫", 25);

            Student s5 = new Student("刘晓曲", 22);

     

            // 把学生添加到集合

            c.add(s1);

            c.add(s2);

            c.add(s3);

            c.add(s4);

            c.add(s5);

     

            // 把集合转成数组

            Object[] objs = c.toArray();

            // 遍历数组

            for (int x = 0; x < objs.length; x++) {

                // System.out.println(objs[x]);

     

                Student s = (Student) objs[x];

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

     

    2. 集合(Collection)(掌握)

        (1)集合的由来?

            我们学习的是Java -- 面向对象 -- 操作很多对象 -- 存储 -- 容器(数组和StringBuffer) -- 数组

            而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们使用。

        (2)集合和数组的区别?

            A:长度区别

                数组固定

                集合可变

            B:内容区别

                数组可以是基本类型,也可以是引用类型

                集合只能是引用类型

            C:元素内容

                数组只能存储同一种类型

                集合可以存储不同类型(其实集合一般存储的也是同一种类型)

        (3)集合的继承体系结构?

            由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,

            我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。

            

            Collection

                |--List

                    |--ArrayList

                    |--Vector

                    |--LinkedList

                |--Set

                    |--HashSet

                    |--TreeSet

        (4)Collection的功能概述

            A:添加功能

                boolean add(E e):在集合的末尾添加一个元素

    boolean addAll(Collection<? extends E> c):添加一个集合的元素,也就是在原集合中的后面追加一个集合

            B:删除功能

                void clear():移除集合中所有元素

                boolean remove(Object o):移除一个指定的元素

    boolean removeAll(Collection<?> c):移除一个集合的元素,(只要有一个元素被删除,就返回true)

            C:判断功能

                boolean contains(Object o):判断集合中是否包含指定的元素

    boolean containsAll(Collection<?> c):判断集合中是否包含指定集合中的所有元素(如果全部包含,就返回 true,否则返回false)

                boolean isEmpty():判断集合是否为空

            D:获取功能

                Iterator<E> iterator():迭代器遍历集合元素

            E:长度功能

                int size():返回集合中元素的个数

            F:交集(了解)

                boolean retainAll(Collection<?> c):获取两个集合的交集,

                说明:假如有两个集合 A和B,

                     A对B做交集,最终的结果保存在A中,B不变

                     返回值:表示A集合是否发生过改变,如果改变,返回true

            G:把集合转数组(了解)

                Object[] toArray():把集合转为数组

        (5)Collection集合的遍历

            A:把集合转数组(了解)(toArray()方法的使用)

    import java.util.ArrayList;

    import java.util.Collection;

     

    /*

    * 集合的遍历。其实就是依次获取集合中的每一个元素。

    *

    * Object[] toArray():把集合转成数组,可以实现集合的遍历

    */

    CollectionDemo3 {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 添加元素

            c.add("hello"); // Object obj = "hello"; 向上转型

            c.add("world");

            c.add("java");

     

            // 遍历

            // Object[] toArray():把集合转成数组,可以实现集合的遍历

            Object[] objs = c.toArray();

            for (int x = 0; x < objs.length; x++) {

                // System.out.println(objs[x]);

                // 我知道元素是字符串,我在获取到元素的的同时,还想知道元素的长度。

                // System.out.println(objs[x] + "---" + objs[x].length());

                // 上面的实现不了,原因是Object中没有length()方法

                // 我们要想使用字符串的方法,就必须把元素还原成字符串

                // 向下转型

                String s = (String) objs[x];

                System.out.println(s + "---" + s.length());

            }

        }

    }

     

     

            B:迭代器(集合专用方式)

    import java.util.ArrayList;

    import java.util.Collection;

    import java.util.Iterator;

     

    /*

    * Iterator iterator():迭代器,集合的专用遍历方式

    *         Object next():获取元素,并移动到下一个位置。

    *             NoSuchElementException:报错,表示没有这样的元素,因为你已经找到最后了。

    *         boolean hasNext():如果仍有元素下一个元素可以迭代,则返回 true。

    */

    class IteratorDemo {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 创建并添加元素

            // String s = "hello";

            // c.add(s);

            c.add("hello");

            c.add("world");

            c.add("java");

     

            // Iterator iterator():迭代器,集合的专用遍历方式

            Iterator it = c.iterator(); // 实际返回的肯定是子类对象,这里是多态

     

            // Object obj = it.next();

            // System.out.println(obj);

            // System.out.println(it.next());

            // System.out.println(it.next());

            // System.out.println(it.next());

            // System.out.println(it.next());

            // 最后一个不应该写,所以,我们应该在每次获取前,如果有一个判断就好了

            // 判断是否有下一个元素,有就获取,没有就不搭理它

     

            // if (it.hasNext()) {

            // System.out.println(it.next());

            // }

            // if (it.hasNext()) {

            // System.out.println(it.next());

            // }

            // if (it.hasNext()) {

            // System.out.println(it.next());

            // }

            // if (it.hasNext()) {

            // System.out.println(it.next());

            // }

            // if (it.hasNext()) {

            // System.out.println(it.next());

            // }

     

            // 最终版代码

            while (it.hasNext()) {

                // System.out.println(it.next());

                String s = (String) it.next();

                System.out.println(s);

            }

        }

    }

     

    C:for循环也可以遍历集合元素(不推荐)

    import java.util.ArrayList;

    import java.util.Collection;

    import java.util.Iterator;

     

    /*

    * 问题1:能用while循环写这个程序,我能不能用for循环呢?

    * 问题2:不要多次使用it.next()方法,因为每次使用都是访问一个对象。

    */

    class IteratorTest2 {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 创建学生对象

            Student s1 = new Student("林青霞", 27);

            Student s2 = new Student("风清扬", 30);

            Student s3 = new Student("令狐冲", 33);

            Student s4 = new Student("武鑫", 25);

            Student s5 = new Student("刘晓曲", 22);

     

            // 把学生添加到集合中

            c.add(s1);

            c.add(s2);

            c.add(s3);

            c.add(s4);

            c.add(s5);

     

            // 遍历//while循环写,层次清楚

            Iterator it = c.iterator();

            while (it.hasNext()) {

                Student s = (Student) it.next();

                System.out.println(s.getName() + "---" + s.getAge());

     

                // NoSuchElementException 不要多次使用it.next()方法

                //next()方法返回的是下一对象。

                // System.out.println(((Student) it.next()).getName() + "---"

                // + ((Student) it.next()).getAge());

     

            }

            // System.out.println("----------------------------------");

     

            // for循环改写//效率高//层次不清楚

            // for(Iterator it = c.iterator();it.hasNext();){

            // Student s = (Student) it.next();

            // System.out.println(s.getName() + "---" + s.getAge());

            // }

        }

    }

     

        (6)迭代器

            A:是集合的获取元素的方式。

            B:是依赖于集合而存在的。

            C:迭代器的原理和源码。

                a:为什么定义为了一个接口而不是实现类?

                b:看了看迭代器的内部类实现。

            

    //interator
    的源码解析

    //接口 ,该接口中定义了两个抽象方法

    public interface Inteator {

        boolean hasNext();

        Object next();

    }

     

    //接口

    public interface Iterable {

    Iterator iterator();

    }

     

    //顶层集合接口Collection 继承 Iterable
    接口

    public interface Collection extends Iterable {

        Iterator iterator();

    }

     

    public interface List extends Collection {

        Iterator iterator();

    }

     

    //ArrayList子类 实现 List接口

    public class ArrayList implements List {

    //同时也实现了
    Iterator() 方法

        public Iterator iterator() {

    return new Itr();

    }

     

    //内部类实现了
    Iterator 接口,并且私有,只允许外部类调用

    private class Itr implements Iterator {

        public boolean hasNext() {}

            public Object next(){}

    }

    }

     

    //案例:

    Collection c = new ArrayList();

    c.add("hello");

    c.add("world");

    c.add("java");

    Iterator it = c.iterator();     //new Itr();

    while(it.hasNext()) {

        String s = (String)it.next();

        System.out.println(s);

    }

     

    D:迭代器的原理图解

        (7)Collection集合的案例(遍历方式
    迭代器)

            集合的操作步骤:

                A:创建集合对象

                B:创建元素对象

                C:把元素添加到集合

                D:遍历集合

        
     

            A:存储字符串并遍历

                

    import java.util.ArrayList;

    import java.util.Collection;

    import java.util.Iterator;

     

    /*

    * 需求:存储字符串并遍历。

    *

    * 分析:

    *         A:创建集合对象

    *         B:创建字符串对象

    *         C:把字符串对象添加到集合中

    *         D:遍历集合

    */

    class CollectionTest {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 创建字符串对象

            // 把字符串对象添加到集合中

            c.add("林青霞");

            c.add("风清扬");

            c.add("刘意");

            c.add("武鑫");

            c.add("刘晓曲");

     

            // 遍历集合

            // 通过集合对象获取迭代器对象

            Iterator it = c.iterator();

            // 通过迭代器对象的hasNext()方法判断有没有元素

            while (it.hasNext()) {

                // 通过迭代器对象的next()方法获取元素

                String s = (String) it.next();

                System.out.println(s);

            }

        }

    }

     

            

            B:存储自定义对象并遍历

                

    import java.util.ArrayList;

    import java.util.Collection;

    import java.util.Iterator;

     

    /*

    * 需求:存储自定义对象并遍历Student(name,age)

    *

    * 分析:

    *         A:创建学生类

    *         B:创建集合对象

    *         C:创建学生对象

    *         D:把学生对象添加到集合对象中

    *         E:遍历集合

    */

    class CollectionTest2 {

        public static void main(String[] args) {

            // 创建集合对象

            Collection c = new ArrayList();

     

            // 创建学生对象

            Student s1 = new Student("貂蝉", 25);

            Student s2 = new Student("小乔", 16);

            Student s3 = new Student("黄月英", 20);

            Student s4 = new Student();

            s4.setName("大乔");

            s4.setAge(26);

     

            // 把学生对象添加到集合对象中.

     

            c.add(s1);

            c.add(s2);

            c.add(s3);

            c.add(s4);

            c.add(new Student("孙尚香", 18)); // 匿名对象

     

            // 遍历集合

            Iterator it = c.iterator();

            while (it.hasNext()) {

                Student s = (Student) it.next();

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

    (8)Collection功能的代码演示

            A)所有方法中,方法名后缀不带All的方法测试

                

    import java.util.ArrayList;

    import java.util.Collection;

     

    /*

    * 集合的由来:

    *         我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。

    *         而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?

    *         数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。

    *         而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。

    *

    * 数组和集合的区别?

    *         A:长度区别

    *             数组的长度固定

    *             集合长度可变

    *         B:内容不同

    *             数组存储的是同一种类型的元素

    *             而集合可以存储不同类型的元素

    *         C:元素的数据类型问题    

    *             数组可以存储基本数据类型,也可以存储引用数据类型

    *             集合只能存储引用类型

    *

    * 刚说过集合是存储多个元的,但是呢,存储多个元素我们也是有不同需求的:比如说,我要这多个元素中不能有相同的元素,

    * 再比如说,我要这多个元素按照某种规则排序一下。针对不同的需求,Java就提供了不同的集合类,这样呢,Java就提供了很多个集合类。

    * 这多个集合类的数据结构不同,结构不同不重要的,重要的是你要能够存储东西,并且还要能够使用这些东西,比如说判断,获取等。

    * 既然这样,那么,这多个集合类是有共性的内容的,我们把这些集合类的共性内容不断的向上提取,最终就能形成集合的继承体系结构。

    *

    * 数据结构:数据的存储方式。

    *

    * Collection:是集合的顶层接口,它的子体系有重复的,有唯一的,有有序的,有无序的。(后面会慢慢的讲解)

    *

    * Collection的功能概述:

    * 1:添加功能

    *         boolean add(Object obj):添加一个元素

    *         boolean addAll(Collection c):添加一个集合的元素

    * 2:删除功能

    *         void clear():移除所有元素

    *         boolean remove(Object o):移除一个元素

    *         boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

    * 3:判断功能

    *         boolean contains(Object o):判断集合中是否包含指定的元素

    *         boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)

    *         boolean isEmpty():判断集合是否为空

    * 4:获取功能

    *         Iterator<E> iterator()(重点)

    * 5:长度功能

    *         int size():元素的个数

    *         面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?

    * 6:交集功能

    *         boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

    * 7:把集合转换为数组

    *         Object[] toArray()

    */

    class CollectionDemo {

        public static void main(String[] args) {

            // 测试不带All的方法

     

            // 创建集合对象

            // Collection c = new Collection(); //错误,因为接口不能实例化

            Collection c = new ArrayList();

     

            // boolean add(Object obj):添加一个元素

            // System.out.println("add:"+c.add("hello"));

            c.add("hello");

            c.add("world");

            c.add("java");

     

            // void clear():移除所有元素

            // c.clear();

     

            // boolean remove(Object o):移除一个元素

            // System.out.println("remove:" + c.remove("hello"));

            // System.out.println("remove:" + c.remove("javaee"));

     

            // boolean contains(Object o):判断集合中是否包含指定的元素

            // System.out.println("contains:"+c.contains("hello"));

            // System.out.println("contains:"+c.contains("android"));

     

            // boolean isEmpty():判断集合是否为空

            // System.out.println("isEmpty:"+c.isEmpty());

     

            // int size():元素的个数

            System.out.println("size:" + c.size());

     

            System.out.println("c:" + c);

        }

    }

            B)所有方法中,方法名后缀带All的方法测试

                

    import java.util.ArrayList;

    import java.util.Collection;

     

    /*

    * boolean addAll(Collection c):添加一个集合的元素

    * boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

    * boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)

    * boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

    */

    class CollectionDemo2 {

        public static void main(String[] args) {

            Collection c1 = new ArrayList();

            c1.add("abc1");

            c1.add("abc2");

            c1.add("abc3");

            c1.add("abc4");

     

            Collection c2 = new ArrayList();

            // c2.add("abc1");

            // c2.add("abc2");

            // c2.add("abc3");

            // c2.add("abc4");

            c2.add("abc5");

            c2.add("abc6");

            c2.add("abc7");

     

            // boolean addAll(Collection c):添加一个集合的元素

            // System.out.println("addAll:" + c1.addAll(c2));

     

            // boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

            // 只要有一个元素被移除了,就返回true。

            // System.out.println("removeAll:"+c1.removeAll(c2));

     

            // boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)

            // 只有包含所有的元素,才叫包含

            // System.out.println("containsAll:"+c1.containsAll(c2));

     

            // boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

            // 假设有两个集合A,B。

            // A对B做交集,最终的结果保存在A中,B不变。

            // 返回值表示的是A是否发生过改变。

            System.out.println("retainAll:" + c1.retainAll(c2));

     

            System.out.println("c1:" + c1);

            System.out.println("c2:" + c2);

        }

    }

                

     

     

     

    3. 集合(List)(掌握)

        (1)List是Collection的子接口

            特点:有序(存储顺序和取出顺序一致),可重复。

            

    /*

    * List集合的特点:

    *         有序(存储和取出的元素一致),可重复的。

    */

    class ListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            List list = new ArrayList();

     

            // 存储元素

            list.add("hello");

            list.add("world");

            list.add("java");

            list.add("javaee");

            list.add("android");

            list.add("javaee");

            list.add("android");

     

            // 遍历集合

            Iterator it = list.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

                System.out.println(s);

            }

        }

    }

     

        (2)List的特有功能:

            A:添加功能

                public
    void add(int
    index, E element):在指定的位置添加元素

            B:删除功能

                public E remove(int
    index):根据索引删除元素,返回被删除的元素

            C:获取功能

                public E get(int
    index):获取指定位置的元素

            D:迭代器功能

                public ListIterator<E> listIterator(int
    index):List集合特有的迭代器

            E:修改功能

                public E set(int
    index, E element):根据索引修改元素,返回被修改的元素

     

            F:各功能方法演示

    import java.util.ArrayList;

    import java.util.List;

     

    /*

    * List集合的特有功能:

    * A:添加功能

    *         void add(int index,Object element):在指定位置添加元素

    * B:获取功能

    *         Object get(int index):获取指定位置的元素

    * C:列表迭代器

    *         ListIterator listIterator():List集合特有的迭代器

    * D:删除功能

    *         Object remove(int index):根据索引删除元素,返回被删除的元素

    * E:修改功能

    *         Object set(int index,Object element):根据索引修改元素,返回被修改的元素

    */

    class ListDemo {

        public static void main(String[] args) {

            // 创建集合对象

            List list = new ArrayList();

     

            // 添加元素

            list.add("hello");

            list.add("world");

            list.add("java");

     

            // void add(int index,Object element):在指定位置添加元素

            // list.add(1, "android");//没有问题

            // IndexOutOfBoundsException

            // list.add(11, "javaee");//有问题

            // list.add(3, "javaee"); //没有问题

            // list.add(4, "javaee"); //有问题

     

            // Object get(int index):获取指定位置的元素

            // System.out.println("get:" + list.get(1));

            // IndexOutOfBoundsException

            // System.out.println("get:" + list.get(11));

     

            // Object remove(int index):根据索引删除元素,返回被删除的元素

            // System.out.println("remove:" + list.remove(1));

            // IndexOutOfBoundsException

            // System.out.println("remove:" + list.remove(11));

     

            // Object set(int index,Object element):根据索引修改元素,返回被修改的元素

            System.out.println("set:" + list.set(1, "javaee"));

     

            System.out.println("list:" + list);

        }

    }

     

        (3)List集合的特有遍历功能

            A:由size()和get()结合。

            B:代码演示

                        

    import java.util.ArrayList;

    import java.util.List;

     

    /*

    * List集合的特有遍历功能:

    *         size()和get()方法结合使用

    */

    class ListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            List list = new ArrayList();

     

            // 添加元素

            list.add("hello");

            list.add("world");

            list.add("java");

     

            // Object get(int index):获取指定位置的元素

            // System.out.println(list.get(0));

            // System.out.println(list.get(1));

            // System.out.println(list.get(2));

            // IndexOutOfBoundsException

            // System.out.println(list.get(3));

     

            // 用循环改进

            // for (int x = 0; x < 3; x++) {

            // System.out.println(list.get(x));

            // }

            // 如果元素过多,数起来就比较麻烦,所以我们使用集合的一个长度功能:size()

            // 最终的遍历方式就是:size()和get()

            for (int x = 0; x < list.size(); x++) {

                // System.out.println(list.get(x));

     

                String s = (String) list.get(x);

                System.out.println(s);

            }

        }

    }

     

        (4)列表迭代器listIterator的特有功能;(了解)

            可以逆向遍历,但是要先正向遍历,所以无意义,基本不使用。

    import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

    import java.util.ListIterator;

     

    /*

    * 列表迭代器:

    *         ListIterator listIterator():List集合特有的迭代器

    *         该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。

    *

    * 特有功能:

    *         Object previous():获取上一个元素

    *         boolean hasPrevious():判断是否有元素

    *

    *         注意:ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义,不使用。

    */

    class ListIteratorDemo {

        public static void main(String[] args) {

            // 创建List集合对象

            List list = new ArrayList();

            list.add("hello");

            list.add("world");

            list.add("java");

     

            // ListIterator listIterator()

            ListIterator lit = list.listIterator(); // 子类对象

            

             while (lit.hasNext()) {

                 String s = (String) lit.next();

                 System.out.println(s);

                }

             System.out.println("-----------------");

            

            while (lit.hasPrevious()) {

                String s = (String) lit.previous();

                System.out.println(s);

            }

            System.out.println("-----------------");

     

            // 迭代器

            Iterator it = list.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

                System.out.println(s);

            }

            System.out.println("-----------------");

     

        }

    }

     

        (5)并发修改异常(ConcurrentModificationException)

            A:出现的现象

                迭代器遍历集合,集合修改集合元素

            B:原因

                迭代器是依赖于集合的,而集合的改变,迭代器并不知道。

            C:解决方案

                a:迭代器遍历,迭代器修改(ListIterator)

                    元素添加在刚才迭代的位置

                b:集合遍历,集合修改(size()和get())

                    元素添加在集合的末尾

    D:代码演示

     

    import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

    import java.util.ListIterator;

     

    /*

    * 问题?

    *         我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。

    *

    * ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

    * 产生的原因:

    *         迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。

    *         其实这个问题描述的是:迭代器遍历元素的时候,通过集合是不能修改元素的。

    * 如何解决呢?

    *         A:迭代器迭代元素,迭代器修改元素

    *             元素是跟在刚才迭代的元素后面的。

    *         B:集合遍历元素,集合修改元素(普通for)

    *             元素在最后添加的。

    */

    class ListIteratorDemo2 {

        public static void main(String[] args) {

            // 创建List集合对象

            List list = new ArrayList();

            // 添加元素

            list.add("hello");

            list.add("world");

            list.add("java");

     

            // 迭代器遍历

            // Iterator it = list.iterator();

            // while (it.hasNext()) {

            // String s = (String) it.next();

            // if ("world".equals(s)) {

            // list.add("javaee");

            // }

            // }

     

    :迭代器迭代元素,迭代器修改元素

            // 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator

            // ListIterator lit = list.listIterator();

            // while (lit.hasNext()) {

            // String s = (String) lit.next();

            // if ("world".equals(s)) {

            // lit.add("javaee");

            // }

            // }

     

    :集合遍历元素,集合修改元素(普通for)

            for (int x = 0; x < list.size(); x++) {

                String s = (String) list.get(x);

                if ("world".equals(s)) {

                    list.add("javaee");

                }

            }

     

            System.out.println("list:" + list);

        }

    }

     

        (6)常见数据结构

            A:栈 先进后出

            B:队列 先进先出

            C:数组 查询快,增删慢

            D:链表 查询慢,增删快

    E:数据结构之数组和链表结构图解

     

    F:数据结构之栈和队列结构图解

        (7)List的子类特点(面试题)

            

    /*

    List:(面试题List的子类特点)

    ArrayList:

        底层数据结构是数组,查询快,增删慢。

        线程不安全,效率高。

    Vector:

        底层数据结构是数组,查询快,增删慢。

        线程安全,效率低。

    LinkedList:

        底层数据结构是链表,查询慢,增删快。

        线程不安全,效率高。

        

    List有三个儿子,我们到底使用谁呢?

        看需求(情况)。

        

    要安全吗?

        要:Vector(即使要安全,也不用这个了,后面有替代的)

        不要:ArrayList或者LinkedList

            查询多:ArrayList

            增删多:LinkedList

            

    如果你什么都不懂,就用ArrayList。

     

    */

     

        (8)List集合的案例(遍历方式
    迭代器和普通for)

            A:存储字符串并遍历

    import java.util.ArrayList;

    import java.util.List;

     

    /*

    * List集合的特有遍历功能:

    *         size()和get()方法结合使用

    */

    class ListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            List list = new ArrayList();

     

            // 添加元素

            list.add("hello");

            list.add("world");

            list.add("java");

     

            // 最终的遍历方式就是:size()和get()

            for (int x = 0; x < list.size(); x++) {

                // System.out.println(list.get(x));

     

                String s = (String) list.get(x);

                System.out.println(s);

            }

        }

    }

     

            B:存储自定义对象并遍历

    import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

     

    /*

    * List集合的特有遍历功能:         

            size()和get()方法结合使用

    *

    * 存储自定义对象并遍历,用普通for循环。(size()和get()结合)

    */

    class ListDemo3 {

        public static void main(String[] args) {

            // 创建集合对象

            List list = new ArrayList();

     

            // 创建学生对象

            Student s1 = new Student("林黛玉", 18);

            Student s2 = new Student("刘姥姥", 88);

            Student s3 = new Student("王熙凤", 38);

     

            // 把学生添加到集合中

            list.add(s1);

            list.add(s2);

            list.add(s3);

     

            // 遍历

            // 迭代器遍历

            Iterator it = list.iterator();

            while (it.hasNext()) {

                Student s = (Student) it.next();

                System.out.println(s.getName() + "---" + s.getAge());

            }

            System.out.println("--------");

     

            // 普通for循环

            for (int x = 0; x < list.size(); x++) {

                Student s = (Student) list.get(x);

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

     

     

     

     

    第十六天

    1:List的子类(掌握)

        (1)List的子类特点

            ArrayList:

                底层数据结构是数组,查询快,增删慢

                线程不安全,效率高,允许添加null值

            Vector:

                底层数据结构是数组,查询快,增删慢

                线程安全,效率低

            LinkedList:

                底层数据结构是链表,查询慢,增删快

                线程不安全,效率高,允许添加null值

        (2)ArrayList

            A:没有特有功能需要学习

    说明:ArrayList中允许插入null值,而且可以插入多个,最终集合中存储着所有

                    你插入的null

            B:案例

                a:ArrayList存储字符串并遍历

                

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * List的子类特点:

    *         ArrayList:

    *             底层数据结构是数组,查询快,增删慢

    *             线程不安全,效率高

    *         Vector:

    *             底层数据结构是数组,查询快,增删慢

    *             线程安全,效率低

    *         LinkedList:

    *              底层数据结构是链表,查询慢,增删快

    *             线程不安全,效率高

    *

    * 案例:

    *         使用List的任何子类存储字符串或者存储自定义对象并遍历。

    *

    * ArrayList的使用。    

    *         存储字符串并遍历

    */

    class ArrayListDemo {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList array = new ArrayList();

     

            // 创建元素对象,并添加元素

            array.add("hello");

            array.add("world");

            array.add("java");

     

            // 遍历

            Iterator it = array.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

                System.out.println(s);

            }

     

            System.out.println("-----------");

     

            for (int x = 0; x < array.size(); x++) {

                String s = (String) array.get(x);

                System.out.println(s);

            }

        }

    }

     

                b:ArrayList存储自定义对象并遍历

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * ArrayList存储自定义对象并遍历

    */

    class ArrayListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList array = new ArrayList();

     

            // 创建学生对象

            Student s1 = new Student("武松", 30);

            Student s2 = new Student("鲁智深", 40);

            Student s3 = new Student("林冲", 36);

            Student s4 = new Student("杨志", 38);

     

            // 添加元素

            array.add(s1);

            array.add(s2);

            array.add(s3);

            array.add(s4);

     

            // 遍历

            Iterator it = array.iterator();

            while (it.hasNext()) {

                Student s = (Student) it.next();

                System.out.println(s.getName() + "---" + s.getAge());

            }

     

            System.out.println("----------------");

     

            for (int x = 0; x < array.size(); x++) {

                // ClassCastException 注意,千万要搞清楚类型

                // String s = (String) array.get(x);

                // System.out.println(s);

     

                Student s = (Student) array.get(x);

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

        (3)Vector

            A:有特有功能

                a:添加

                    public
    synchronized
    void addElement(E obj)        --    被add()替代

    向集合中添加一个元素

                b:获取

                    public
    synchronized E elementAt(int
    index)        --    被get()替代

                    获取指定位置的元素

                    public Enumeration<E> elements()    -- 被iterator()替代

                    返回集合中所有的元素

            B:案例

                a:Vector存储字符串并遍历(与ArrayList案例代码相似)

                b:Vector存储自定义对象并遍历(与ArrayList案例代码相似)

    c:Vector的方法演示

    import java.util.Enumeration;

    import java.util.Vector;

     

    /*

    * Vector的特有功能:

    * 1:添加功能

    *         public void addElement(Object obj)        --    add()

    * 2:获取功能

    *         public Object elementAt(int index)        -- get()

    *         public Enumeration elements()            --    Iterator iterator()

    *                 boolean hasMoreElements()                hasNext()

    *                 Object nextElement()                    next()

    *

    * JDK升级的原因:

    *         A:安全

    *         B:效率

    *         C:简化书写

    */

    class VectorDemo {

        public static void main(String[] args) {

            // 创建集合对象

            Vector v = new Vector();

     

            // 添加功能

            v.addElement("hello");

            v.addElement("world");

            v.addElement("java");

     

            // 遍历

            for (int x = 0; x < v.size(); x++) {

                String s = (String) v.elementAt(x);

                System.out.println(s);

            }

     

            System.out.println("------------------");

     

            Enumeration en = v.elements(); // 返回的是实现类的对象

            while (en.hasMoreElements()) {

                String s = (String) en.nextElement();

                System.out.println(s);

            }

        }

    }

     

        (4)LinkedList

            说明:LinkedList允许插入null值,而且可以插入多个null值,最终集合中存储着你插入的所有null值

            A:有特有功能    

                a:添加

                    public
    void addFirst(E e):在集合的头部添加一个元素

                    public
    void addLast(E e):在集合的尾部添加一个元素

                b:删除

                    public E removeFirst():删除集合中第一个元素,并返回被删除的元素

                    public E removeLast():删除集合中最后一个元素,并返回被删除的元素

                c:获取

                    public E getFirst():获取集合中的第一个元素

                    public E getLast():获取集合中的最后一个元素

            B:案例

                a:LinkedList存储字符串并遍历(与ArrayList案例代码相似)

                b:LinkedList存储自定义对象并遍历(与ArrayList案例代码相似)

    c:LinkedList方法演示

    import java.util.LinkedList;

     

    /*

    * LinkedList的特有功能:

    *         A:添加功能

    *             public void addFirst(Object e) :在集合的头部添加一个元素

    *             public void addLast(Object e) :在集合的末尾添加一个元素

    *         B:获取功能

    *             public Object getFirst() :获取集合中的第一个元素

    *             public Obejct getLast() :获取集合中的最后一个元素

    *         C:删除功能

    *             public Object removeFirst():删除集合中的第一个元素,并返回被删除的元素

    *             public Object removeLast():删除集合中的最后一个元素,并返回被删除的元素

    */

    class LinkedListDemo {

        public static void main(String[] args) {

            // 创建集合对象

            LinkedList link = new LinkedList();

     

            // 添加元素

            link.add("hello");

            link.add("world");

            link.add("java");

     

            // public void addFirst(Object e) :在集合的头部添加一个元素

            // link.addFirst("javaee");

            // public void addLast(Object e) :在集合的末尾添加一个元素

            // link.addLast("android");

     

            // public Object getFirst() :获取集合中的第一个元素

            // System.out.println("getFirst:" + link.getFirst());

            // public Obejct getLast() :获取集合中的最后一个元素

            // System.out.println("getLast:" + link.getLast());

     

            // public Object removeFirst():删除集合中的第一个元素,并返回被删除的元素

            System.out.println("removeFirst:" + link.removeFirst());

            // public Object removeLast():删除集合中的最后一个元素,并返回被删除的元素

            System.out.println("removeLast:" + link.removeLast());

     

            // 输出对象名

            System.out.println("link:" + link);

        }

    }

     

        (5)案例:

            A:去除集合中的多个字符串的重复元素

                如果字符串的内容相同,即为重复元素

                方式一:用新集合存储未重复元素

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * 案例:ArrayList去除集合中字符串的重复值(字符串的内容相同)

    *

    * 分析:

    *         A:创建集合对象

    *         B:添加多个字符串元素(包含内容相同的)

    *         C:创建新集合

    *         D:遍历旧集合,获取得到每一个元素

    *         E:拿这个元素到新集合去找,看有没有

    *             有:不搭理它

    *             没有:就添加到新集合

    *         F:遍历新集合

    */

    class ArrayListDemo {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList array = new ArrayList();

     

            // 添加多个字符串元素(包含内容相同的)

            array.add("hello");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("java");

            array.add("world");

     

            // 创建新集合

            ArrayList newArray = new ArrayList();

     

            // 遍历旧集合,获取得到每一个元素

            Iterator it = array.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

     

                // 拿这个元素到新集合去找,看有没有

                if (!newArray.contains(s)) {

                    newArray.add(s);

                }

            }

     

            // 遍历新集合

            for (int x = 0; x < newArray.size(); x++) {

                String s = (String) newArray.get(x);

                System.out.println(s);

            }

        }

    }

        
     

    方式二:在老集合上面进行重复元素的删除

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)

    * 要求:不能创建新的集合,就在以前的集合上做。

    */

    class ArrayListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList array = new ArrayList();

     

            // 添加多个字符串元素(包含内容相同的)

            array.add("hello");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("java");

            array.add("world");

     

            // 由选择排序思想引入,我们就可以通过这种思想做这个题目

    索引的依次和后面的比较,有就把后的干掉

    索引...

            for (int x = 0; x < array.size() - 1; x++) {

                for (int y = x + 1; y < array.size(); y++) {

                    if (array.get(x).equals(array.get(y))) {

                        array.remove(y);

                        //说明:因为如果一个字符串相连重复出现的话,就会造成,

                        //初始字符串与后续相同的字符串进行比较时,相同就删除,

                        //该元素被删除之后,后一个相同的元素,就会顶替被删除元素,

                        //并占有它的索引,所以会导致出现漏网之鱼的情况

                        y--;// 这里是关键点

                    }

                }

            }

     

            // 遍历集合

            Iterator it = array.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

                System.out.println(s);

            }

        }

    }

     

            B:去除集合中的多个自定义对象的重复元素

                如果自定义对象的成员变量值都相同,即为重复元素

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)

    * 要求:不能创建新的集合,就在以前的集合上做。

    */

    class ArrayListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList array = new ArrayList();

     

            // 添加多个字符串元素(包含内容相同的)

            array.add("hello");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("java");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("world");

            array.add("java");

            array.add("world");

     

            // 由选择排序思想引入,我们就可以通过这种思想做这个题目

    索引的依次和后面的比较,有就把后的干掉

    索引...

            for (int x = 0; x < array.size() - 1; x++) {

                for (int y = x + 1; y < array.size(); y++) {

                    if (array.get(x).equals(array.get(y))) {

                        array.remove(y);

                        //说明:因为如果一个字符串相连重复出现的话,就会造成,

                        //初始字符串与后续相同的字符串进行比较时,相同就删除,

                        //该元素被删除之后,后一个相同的元素,就会顶替被删除元素,

                        //并占有它的索引,所以会导致出现漏网之鱼的情况

                        y--;// 这里是关键点

                    }

                }

            }

     

            // 遍历集合

            Iterator it = array.iterator();

            while (it.hasNext()) {

                String s = (String) it.next();

                System.out.println(s);

            }

        }

    }

     

            C:用LinkedList模拟一个栈数据结构的集合类,并测试。(重点理解)

                你要定义一个集合类,只不过内部可以使用LinkedList来实现。

    import java.util.LinkedList;

     

    /*

    *请用LinkedList模拟栈数据结构的集合,并测试

    *题目的意思是:

    *        你自己的定义一个集合类,在这个集合类内部可以使用LinkedList模拟。

    */

     

    /*

    * MyStack的测试

    */

    class MyStackDemo {

        public static void main(String[] args) {

            // 创建集合对象

            MyStack ms = new MyStack();

     

            // 添加元素

            ms.add("hello");

            ms.add("world");

            ms.add("java");

     

            // System.out.println(ms.get());

            // System.out.println(ms.get());

            // System.out.println(ms.get());

            // NoSuchElementException

            // System.out.println(ms.get());

     

            while (!ms.isEmpty()) {

                System.out.println(ms.get());

            }

        }

    }

     

    /**

    * 自定义的栈集合 模拟了栈先进后出的特点,但是底层任然是调用 LinkedList类的方法

    *

    * @author
    风清扬

    * @version V1.0

    */

    class MyStack {

        private LinkedList link;

     

        public MyStack() {

            link = new LinkedList();

        }

     

        public void add(Object obj) {

            link.addFirst(obj);

        }

     

        public Object get() {

            // return link.getFirst();

            return link.removeFirst();

        }

     

        public boolean isEmpty() {

            return link.isEmpty();

        }

    }

     

    2:泛型(掌握)

        (1)泛型概述

            是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。

        (2)格式:

            <数据类型>

            注意:该数据类型只能是引用类型。

        (3)好处:

            A:把运行时期的问题提前到了编译期间

            B:避免了强制类型转换

            C:优化了程序设计,解决了黄色警告线问题,让程序更安全

    (4)泛型介绍的代码演示

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * ArrayList存储字符串并遍历

    *

    * 我们按照正常的写法来写这个程序, 结果确出错了。

    * 为什么呢?

    *         因为我们开始存储的时候,存储了String和Integer两种类型的数据。

    *         而在遍历的时候,我们把它们都当作String类型处理的,做了转换,所以就报错了。

    * 但是呢,它在编译期间却没有告诉我们。

    * 所以,我就觉得这个设计的不好。

    * 回想一下,我们的数组

    *         String[] strArray = new String[3];

    *         strArray[0] = "hello";

    *         strArray[1] = "world";

    *         strArray[2] = 10;

    * 集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。

    * 而这种技术被称为:泛型。

    *

    * 泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。

    参数化类型,把类型当作参数一样的传递。

    * 格式:

    *         <数据类型>

    *         此处的数据类型只能是引用类型。

    * 好处:

    *         A:把运行时期的问题提前到了编译期间

    *         B:避免了强制类型转换

    *         C:优化了程序设计,解决了黄色警告线

    */

    class GenericDemo {

        public static void main(String[] args) {

            // 创建

            ArrayList<String> array = new ArrayList<String>();

     

            // 添加元素

            array.add("hello");

            array.add("world");

            array.add("java");

            // array.add(new Integer(100));

            // array.add(10); // JDK5以后的自动装箱

            // 等价于:array.add(Integer.valueOf(10));

     

            // 遍历

            Iterator<String> it = array.iterator();

            while (it.hasNext()) {

                // ClassCastException

                // String s = (String) it.next();

                String s = it.next();

                System.out.println(s);

            }

     

            // 看下面这个代码

            // String[] strArray = new String[3];

            // strArray[0] = "hello";

            // strArray[1] = "world";

            // strArray[2] = 10;

        }

    }

     

        (5)泛型的前世今生

            A:泛型的由来

                Object类型作为任意类型的时候,在向下转型的时候,会隐含一个转型问题

            B:泛型类

                泛型定义在类上面

     

    /*

    * 泛型类:把泛型定义在类上

    */

    class ObjectTool<T> {

        private T obj;

     

        public T getObj() {

            return obj;

        }

     

        public void setObj(T obj) {

            this.obj = obj;

        }

    }

     

    /*

    * 泛型类的测试

    */

    class ObjectToolDemo {

        public static void main(String[] args) {

     

            ObjectTool<String> ot = new ObjectTool<String>();

            // ot.setObj(new Integer(27)); //这个时候编译期间就过不去

            ot.setObj(new String("林青霞"));

            String s = ot.getObj();

            System.out.println("姓名是:" + s);

     

            ObjectTool<Integer> ot2 = new ObjectTool<Integer>();

            // ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去

            ot2.setObj(new Integer(27));

            Integer i = ot2.getObj();

            System.out.println("年龄是:" + i);

        }

    }

     

            C:泛型方法

    /*

    * 泛型方法:把泛型定义在方法上

    */

    class ObjectTool {

        public <T> void show(T t) {

            System.out.println(t);

        }

    }

     

    /*

    * 泛型方法的测试

    */

    class ObjectToolDemo {

        public static void main(String[] args) {

            // ObjectTool ot = new ObjectTool();

            // ot.show("hello");

            // ot.show(100);

            // ot.show(true);

     

            // ObjectTool<String> ot = new ObjectTool<String>();

            // ot.show("hello");

            //

            // ObjectTool<Integer> ot2 = new ObjectTool<Integer>();

            // ot2.show(100);

            //

            // ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();

            // ot3.show(true);

     

            // 如果还听得懂,那就说明泛型类是没有问题的

            // 但是呢,谁说了我的方法一定要和类的类型的一致呢?

            // 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢?

     

            // 定义泛型方法后

            ObjectTool ot = new ObjectTool();

            ot.show("hello");

            ot.show(100);

            ot.show(true);

        }

    }

     

            D:泛型接口

    /*

    * 泛型接口:把泛型定义在接口上

    */

    interface Inter<T> {

        public abstract void show(T t);

    }

     

    //实现类在实现接口的时候

    //第一种情况:已经知道是什么类型的了(说明;这种情况很罕见)

     

    //public class InterImpl implements Inter<String> {

    //

    //    @Override

    //    public void show(String t) {

    //        System.out.println(t);

    //    }

    //}

     

    //第二种情况:还不知道是什么类型的(说明:这种情况比较常见)

    class InterImpl<T> implements Inter<T> {

     

        @Override

        public void show(T t) {

            System.out.println(t);

        }

    }

     

    class InterDemo {

        public static void main(String[] args) {

            // 第一种情况的测试

            // Inter<String> i = new InterImpl();

            // i.show("hello");

     

            // 第二种情况的测试

            Inter<String> i = new InterImpl<String>();

            i.show("hello");

     

            Inter<Integer> ii = new InterImpl<Integer>();

            ii.show(100);

        }

    }

     

            E:泛型高级通配符

                ?:任意类型,如果没有明确,那么就是Object以及任意的java类

                ? extends E
    :向下限定,E及其子类

                ? super E
    :向上限定,E及其父类

    import java.util.ArrayList;

    import java.util.Collection;

     

    /*

    * 泛型高级(通配符)

    * ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了

    * ? extends E:向下限定,E及其子类

    * ? super E:向上限定,E及其父类

    */

    class GenericDemo {

        public static void main(String[] args) {

            // 泛型如果明确的写的时候,前后必须一致

            Collection<Object> c1 = new ArrayList<Object>();

            // Collection<Object> c2 = new ArrayList<Animal>();

            // Collection<Object> c3 = new ArrayList<Dog>();

            // Collection<Object> c4 = new ArrayList<Cat>();

     

            // ?表示任意的类型都是可以的

            Collection<?> c5 = new ArrayList<Object>();

            Collection<?> c6 = new ArrayList<Animal>();

            Collection<?> c7 = new ArrayList<Dog>();

            Collection<?> c8 = new ArrayList<Cat>();

     

            // ? extends E:向下限定,E及其子类

            //Collection<? extends Animal> c9 = new ArrayList<Object>();//它不行,编译报错

            Collection<? extends Animal> c10 = new ArrayList<Animal>();

            Collection<? extends Animal> c11 = new ArrayList<Dog>();

            Collection<? extends Animal> c12 = new ArrayList<Cat>();

     

            // ? super E:向上限定,E极其父类

            Collection<? super Animal> c13 = new ArrayList<Object>();

            Collection<? super Animal> c14 = new ArrayList<Animal>();

            // Collection<? super Animal> c15 = new ArrayList<Dog>();//它不行,编译报错

            // Collection<? super Animal> c16 = new ArrayList<Cat>();//它不行,编译报错

        }

    }

     

    class Animal {

    }

     

    class Dog extends Animal {

    }

     

    class Cat extends Animal {

    }

     

    F:案例

    1集合存储自定义对象,遍历,要求使用泛型

                        

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * 需求:存储自定义对象并遍历。

    *

    * A:创建学生类

    * B:创建集合对象

    * C:创建元素对象

    * D:把元素添加到集合

    * E:遍历集合

    */

    class ArrayListDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            // JDK7的新特性:泛型推断。

    // 但是我不建议这样使用。

            // ArrayList<Student> array = new ArrayList<>();

            

            ArrayList<Student> array = new ArrayList<Student>();

     

            // 创建元素对象

            Student s1 = new Student("曹操", 40); // 后知后觉

            Student s2 = new Student("蒋干", 30); // 不知不觉

            Student s3 = new Student("诸葛亮", 26);// 先知先觉

     

            // 添加元素

            array.add(s1);

            array.add(s2);

            array.add(s3);

     

            // 遍历

            Iterator<Student> it = array.iterator();

            while (it.hasNext()) {

                Student s = it.next();

                System.out.println(s.getName() + "---" + s.getAge());

            }

            System.out.println("------------------");

     

            for (int x = 0; x < array.size(); x++) {

                Student s = array.get(x);

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

        (6)泛型的应用场景

            一般是在集合中使用。

    import java.util.ArrayList;

    import java.util.Iterator;

     

    /*

    * 泛型在哪些地方使用呢?

    *         看API,如果类,接口,抽象类后面跟的有<E>就说要使用泛型。

            一般来说就是在集合中使用。

    */

    class ArrayListDemo {

        public static void main(String[] args) {

            // 用ArrayList存储字符串元素,并遍历。用泛型改进代码

            ArrayList<String> array = new ArrayList<String>();

     

            array.add("hello");

            array.add("world");

            array.add("java");

     

            Iterator<String> it = array.iterator();

            while (it.hasNext()) {

                String s = it.next();

                System.out.println(s);

            }

            System.out.println("-----------------");

     

            for (int x = 0; x < array.size(); x++) {

                String s = array.get(x);

                System.out.println(s);

            }

        }

    }

     

        

    3:增强for循环(掌握)

        (1)是for循环的一种

        (2)格式:

            for(元素的数据类型 变量名 : 数组或者Collection集合的对象) {

                使用该变量即可,该变量其实就是数组或者集合中的元素。

            }

        (3)好处:

            简化了数组和集合的遍历

        (4)弊端

            增强for循环的目标不能为null。建议在使用前,先判断是否为null。

    (5)增强for代码演示

        

    import java.util.ArrayList;

    import java.util.List;

     

    /*

    * JDK5的新特性:自动拆装箱,泛型,增强for,静态导入,可变参数,枚举

    *

    * 增强for:是for循环的一种。

    *

    * 格式:

    *         for(元素数据类型 变量 : 数组或者Collection集合) {

    *            使用变量即可,该变量就是元素

    *     }

    *

    * 好处:简化了数组和集合的遍历。

    *

    * 弊端: 增强for的目标不能为null。

    * 如何解决呢?对增强for的目标先进行不为null的判断,然后在使用。

    */

    class ForDemo {

        public static void main(String[] args) {

            // 定义一个int数组

            int[] arr = { 1, 2, 3, 4, 5 };

            for (int x = 0; x < arr.length; x++) {

                System.out.println(arr[x]);

            }

            System.out.println("---------------");

            // 增强for

            for (int x : arr) {

                System.out.println(x);

            }

            System.out.println("---------------");

            // 定义一个字符串数组

            String[] strArray = { "林青霞", "风清扬", "东方不败", "刘意" };

            // 增强for

            for (String s : strArray) {

                System.out.println(s);

            }

            System.out.println("---------------");

            // 定义一个集合

            ArrayList<String> array = new ArrayList<String>();

            array.add("hello");

            array.add("world");

            array.add("java");

            // 增强for

            for (String s : array) {

                System.out.println(s);

            }

            System.out.println("---------------");

     

            List<String> list = null;

            // NullPointerException

            // 这个s是我们从list里面获取出来的,在获取前,它肯定还好做一个判断

            // 说白了,这就是迭代器的功能

            if (list != null) {

                for (String s : list) {

                    System.out.println(s);

                }

            }

     

            // 增强for其实是用来替代迭代器的

            //ConcurrentModificationException

            // for (String s : array) {

            // if ("world".equals(s)) {

            // array.add("javaee");

            // }

            // }

            // System.out.println("array:" + array);

        }

    }

     

     

     

    4:静态导入(了解)

        (1)可以导入到方法级别的导入

        (2)格式:

            import static 包名....类名.方法名;

        (3)注意事项:

            A:方法必须是静态的

            B:如果多个类下有同名的方法,就不好区分了,还得加上前缀。

                所以一般我们并不使用静态导入,但是一定要能够看懂。

        

    /*

    * 静态导入:

    * 格式:import static 包名….类名.方法名;

    * 可以直接导入到方法的级别

    *

    * 静态导入的注意事项:

    *         A:方法必须是静态的

    *         B:如果有多个同名的静态方法,容易不知道使用谁?这个时候要使用,必须加前缀。

                由此可见,意义不大,所以一般不用,但是要能看懂。

    */

    import static java.lang.Math.abs;

    import static java.lang.Math.pow;

    import static java.lang.Math.max;

     

    //错误

    //import static java.util.ArrayList.add;

     

    class StaticImportDemo {

        public static void main(String[] args) {

            // System.out.println(java.lang.Math.abs(-100));

            // System.out.println(java.lang.Math.pow(2, 3));

            // System.out.println(java.lang.Math.max(20, 30));

            // 太复杂,我们就引入到import

     

            // System.out.println(Math.abs(-100));

            // System.out.println(Math.pow(2, 3));

            // System.out.println(Math.max(20, 30));

            // 太复杂,有更简单

     

    //        System.out.println(abs(-100));

            System.out.println(java.lang.Math.abs(-100));

            System.out.println(pow(2, 3));

            System.out.println(max(20, 30));

        }

        

        public static void abs(String s){

            System.out.println(s);

        }

    }

     

    5:可变参数(掌握)

    (1)应用场景

    如果我们在写方法的时候,参数个数不明确,就应该定义可变参数。

    (2)格式

            修饰符 返回值类型 方法名(数据类型... 变量) {}

            

            注意:

                A:该变量其实是一个数组名

                B:如果一个方法有多个参数,并且有可变参数,可变参数必须在最后

    (3)Arrays工具类的一个方法

            asList()把数组转成集合

            注意:这个集合的长度不能改变。

    import java.util.Arrays;

    import java.util.List;

     

    /*

    * 把数组转化成集合,转化之后的集合的长度不能改变。

    * public static <T> List<T> asList(T... a):把数组转成集合

    *

    * 注意事项:

    *         虽然可以把数组转成集合,但是集合的长度不能改变。

    */

    class ArraysDemo {

        public static void main(String[] args) {

            // 定义一个数组

            // String[] strArray = { "hello", "world", "java" };

            // List<String> list = Arrays.asList(strArray);

     

            List<String> list = Arrays.asList("hello", "world", "java");

            

            //不支持增加和删除,但可以修改

            // list.add("javaee");// UnsupportedOperationException

            // list.remove(1);// UnsupportedOperationException

            list.set(1, "javaee");

     

            for (String s : list) {

                System.out.println(s);

            }

        }

    }

     

    (4)代码演示

    /*

    * 可变参数:定义方法的时候不知道该定义多少个参数

    * 格式:

    *         修饰符
    返回值类型
    方法名(数据类型… 变量名){

    *

    *         }

    *

    *         注意:

    *             这里的变量其实是一个数组

    *             如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

    */                

    class ArgsDemo {

        public static void main(String[] args) {

            // 2个数据求和

            int a = 10;

            int b = 20;

            int result = sum(a, b);

            System.out.println("result:" + result);

     

            // 3个数据的求和

            int c = 30;

            result = sum(a, b, c);

            System.out.println("result:" + result);

     

            // 4个数据的求和

            int d = 30;

            result = sum(a, b, c, d);

            System.out.println("result:" + result);

     

            // 需求:我要写一个求和的功能,到底是几个数据求和呢,

            //我不太清楚,但是我知道在调用的时候我肯定就知道了

            // 为了解决这个问题,Java就提供了一个东西:可变参数

            result = sum(a, b, c, d, 40);

            System.out.println("result:" + result);

     

            result = sum(a, b, c, d, 40, 50);

            System.out.println("result:" + result);

        }

     

        public static int sum(int... a) {

            // System.out.println(a);

            //return 0;

     

            int s = 0;

            

            for(int x : a){

                s +=x;

            }

            

            return s;

        }

     

        // public static int sum(int a, int b, int c, int d) {

        // return a + b + c + d;

        // }

        //

        // public static int sum(int a, int b, int c) {

        // return a + b + c;

        // }

        //

        // public static int sum(int a, int b) {

        // return a + b;

        // }

    }

     

    6:练习(掌握)

        A:集合的嵌套遍历

    import java.util.ArrayList;

     

    /*

    * 集合的嵌套遍历

    * 需求:

    *         我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>

    *         但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList<Student>。

    *         而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢?

    *         就是这个样子的:ArrayList<ArrayList<Student>>

    */

    class ArrayListDemo {

        public static void main(String[] args) {

            // 创建大集合

            ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();

     

            // 创建第一个班级的学生集合

            ArrayList<Student> firstArrayList = new ArrayList<Student>();

            // 创建学生

            Student s1 = new Student("唐僧", 30);

            Student s2 = new Student("孙悟空", 29);

            Student s3 = new Student("猪八戒", 28);

            Student s4 = new Student("沙僧", 27);

            Student s5 = new Student("白龙马", 26);

            // 学生进班

            firstArrayList.add(s1);

            firstArrayList.add(s2);

            firstArrayList.add(s3);

            firstArrayList.add(s4);

            firstArrayList.add(s5);

            // 把第一个班级存储到学生系统中

            bigArrayList.add(firstArrayList);

     

            // 创建第二个班级的学生集合

            ArrayList<Student> secondArrayList = new ArrayList<Student>();

            // 创建学生

            Student s11 = new Student("诸葛亮", 30);

            Student s22 = new Student("司马懿", 28);

            Student s33 = new Student("周瑜", 26);

            // 学生进班

            secondArrayList.add(s11);

            secondArrayList.add(s22);

            secondArrayList.add(s33);

            // 把第二个班级存储到学生系统中

            bigArrayList.add(secondArrayList);

     

            // 创建第三个班级的学生集合

            ArrayList<Student> thirdArrayList = new ArrayList<Student>();

            // 创建学生

            Student s111 = new Student("宋江", 40);

            Student s222 = new Student("吴用", 35);

            Student s333 = new Student("高俅", 30);

            Student s444 = new Student("李师师", 22);

            // 学生进班

            thirdArrayList.add(s111);

            thirdArrayList.add(s222);

            thirdArrayList.add(s333);

            thirdArrayList.add(s444);

            // 把第三个班级存储到学生系统中

            bigArrayList.add(thirdArrayList);

     

            // 遍历集合

            for (ArrayList<Student> array : bigArrayList) {

                for (Student s : array) {

                    System.out.println(s.getName() + "---" + s.getAge());

                }

            }

        }

    }

     

        B:产生10个1-20之间的随机数,要求随机数不能重复

    import java.util.ArrayList;

    import java.util.Random;

     

    /*

    个1-20之间的随机数,要求不能重复

    *

    * 用数组实现,但是数组的长度是固定的,长度不好确定。

    * 所以我们使用集合实现。

    *

    * 分析:

    *         A:创建产生随机数的对象

    *         B:创建一个存储随机数的集合。

    开始。

    *             是:先产生一个随机数,判断该随机数在集合中是否存在。

    *                     如果不存在:就添加,统计变量++。

    *                     如果存在:就不搭理它。

    *             否:不搭理它

    *         E:遍历集合

    */

    class RandomDemo {

        public static void main(String[] args) {

            // 创建产生随机数的对象

            Random r = new Random();

     

            // 创建一个存储随机数的集合。

            ArrayList<Integer> array = new ArrayList<Integer>();

     

    开始。

            int count = 0;

     

            while (count < 10) {

                //先产生一个随机数

                int number = r.nextInt(20) + 1;

                

                //判断该随机数在集合中是否存在。

                if(!array.contains(number)){

                    //如果不存在:就添加,统计变量++。

                    array.add(number);

                    count++;

                }

            }

            

            //遍历集合

            for(Integer i : array){

                System.out.println(i);

            }

        }

    }

     

        C:键盘录入多个数据,以0结束,并在控制台输出最大值

    import java.util.ArrayList;

    import java.util.Arrays;

    import java.util.Scanner;

     

    /*

    结束,要求在控制台输出这多个数据中的最大值

    *

    * 分析:

    *         A:创建键盘录入数据对象

    *         B:键盘录入多个数据,我们不知道多少个,所以用集合存储

    结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了

    *         D:把集合转成数组

    *         E:对数组排序

    *         F:获取该数组中的最大索引的值

    */

    class ArrayListDemo {

        public static void main(String[] args) {

            // 创建键盘录入数据对象

            Scanner sc = new Scanner(System.in);

     

            // 键盘录入多个数据,我们不知道多少个,所以用集合存储

            ArrayList<Integer> array = new ArrayList<Integer>();

     

    结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了

            while (true) {

                System.out.println("请输入数据:");

                int number = sc.nextInt();

                if (number != 0) {

                    array.add(number);

                } else {

                    break;

                }

            }

     

            // 把集合转成数组

            // public <T> T[] toArray(T[] a)

            Integer[] i = new Integer[array.size()];

            // Integer[] ii = array.toArray(i);

            array.toArray(i);

            // System.out.println(i);

            // System.out.println(ii);

     

            // 对数组排序

            // public static void sort(Object[] a)

            Arrays.sort(i);

     

            // 获取该数组中的最大索引的值

            System.out.println("数组是:" + arrayToString(i) + "最大值是:"

                    + i[i.length - 1]);

        }

     

        public static String arrayToString(Integer[] i) {

            StringBuilder sb = new StringBuilder();

     

            sb.append("[");

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

                if (x == i.length - 1) {

                    sb.append(i[x]);

                } else {

                    sb.append(i[x]).append(", ");

                }

            }

            sb.append("]");

     

            return sb.toString();

        }

    }

     

        

    7:要掌握的代码

        集合存储元素,加入泛型,并可以使用增强for遍历。

     

     

    第十七天

    1:登录注册案例(理解)

        A:用户注册案例的分析

    /*

    需求:用户登录注册案例。

     

    按照如下的操作,可以让我们更符号面向对象思想

        A:有哪些类呢?

        B:每个类有哪些东西呢?

        C:类与类之间的关系是什么呢?

        

    分析:

        A:有哪些类呢?

            用户类

            测试类

        B:每个类有哪些东西呢?

            用户类:

                成员变量:用户名,密码

                构造方法:无参构造

                成员方法:getXxx()/setXxx()

                     登录,注册

                    

                假如用户类的内容比较对,将来维护起来就比较麻烦,为了更清晰的分类,我们就把用户又划分成了两类

                    用户基本描述类

                        成员变量:用户名,密码

                        构造方法:无参构造

                        成员方法:getXxx()/setXxx()

                    用户操作类

                        登录,注册

            测试类:

                main方法。

        C:类与类之间的关系是什么呢?

            在测试类中创建用户操作类和用户基本描述类的对象,并使用其功能。

            

    分包:

        A:功能划分

        B:模块划分

        C:先按模块划分,再按功能划分

        

    今天我们选择按照功能划分:

        用户基本描述类包 cn.itcast.pojo

        用户操作接口 cn.itcast.dao

        用户操作类包 cn.itcast.dao.impl

            今天是集合实现,过几天是IO实现,再过几天是GUI实现,就业班我们就是数据库实现

        用户测试类 cn.itcast.test

     

    */

     

        B:用户注册案例的源码


    1: cn.itcast.pojo.User.java

    /**

    * 这是用户基本描述类

    *

    * @author
    风清扬

    * @version V1.0

    *

    */

    class User {

        // 用户名

        private String username;

        // 密码

        private String password;

     

        public User() {

        }

     

        public String getUsername() {

            return username;

        }

     

        public void setUsername(String username) {

            this.username = username;

        }

     

        public String getPassword() {

            return password;

        }

     

        public void setPassword(String password) {

            this.password = password;

        }

    }

     

    2:cn.itcast.dao.UserDao.java

    import cn.itcast.pojo.User;

     

    /**

    * 这是针对用户进行操作的接口

    *

    * @author
    风清扬

    * @version V1.0

    *

    */

    interface UserDao {

        /**

         * 这是用户登录功能

         *

         * @param username

         * 用户名

         * @param password

         * 密码

         * @return
    返回登录是否成功

         */

        public abstract boolean isLogin(String username, String password);

     

        /**

         * 这是用户注册功能

         *

         * @param user

         * 要注册的用户信息

         */

        public abstract void regist(User user);

    }

     

         3:cn.itcast.dao.impl.UserDaoImpl.java

    import java.util.ArrayList;

     

    import cn.itcast.dao.UserDao;

    import cn.itcast.pojo.User;

     

    /**

    * 这是用户操作的具体实现类(集合版)

    *

    * @author
    风清扬

    * @version V1.0

    *

    */

    public class UserDaoImpl implements UserDao {

        // 为了让多个方法能够使用同一个集合,就把集合定义为成员变量

        // 为了不让外人看到,用private

        // 为了让多个对象共享同一个成员变量,用static

        private static ArrayList<User> array = new ArrayList<User>();

     

        @Override

        public boolean isLogin(String username, String password) {

            // 遍历集合,获取每一个用户,并判断该用户的用户名和密码是否和传递过来的匹配

            boolean flag = false;

     

            for (User u : array) {

                if (u.getUsername().equals(username)

                        && u.getPassword().equals(password)) {

                    flag = true;

                    break;

                }

            }

     

            return flag;

        }

     

        @Override

        public void regist(User user) {

            // 把用户信息存储集合

            // ArrayList<User> array = new ArrayList<User>();

            array.add(user);

        }

    }

     

            4:cn.itcast.test.UserTest.java

    import java.util.Scanner;

     

    import cn.itcast.dao.UserDao;

    import cn.itcast.dao.impl.UserDaoImpl;

    import cn.itcast.game.GuessNumber;

    import cn.itcast.pojo.User;

     

    /**

    * 用户测试类

    *

    * @author
    风清扬

    * @version V1.0

    *

    * 新增加了两个小问题 A:多个对象共享同一个成员变量,用静态

    * B:循环里面如果有switch,并且在switch里面有break,那么结束的不是循环,而是switch语句

    *

    */

    class UserTest {

        public static void main(String[] args) {

            // 为了能够回来

            while (true) {

                // 欢迎界面,给出选择项

                System.out.println("--------------欢迎光临--------------");

                System.out.println("1 登录");

                System.out.println("2 注册");

                System.out.println("3 退出");

                System.out.println("请输入你的选择:");

                // 键盘录入选择,根据选择做不同的操作

                Scanner sc = new Scanner(System.in);

                // 为了后面的录入信息的方便,我所有的数据录入全部用字符接收

                String choiceString = sc.nextLine();

     

                // switch语句的多个地方要使用,我就定义到外面

                UserDao ud = new UserDaoImpl();

     

                // 经过简单的思考,我选择了switch

                switch (choiceString) {

                case "1":

                    // 登录界面,请输入用户名和密码

                    System.out.println("--------------登录界面--------------");

                    System.out.println("请输入用户名:");

                    String username = sc.nextLine();

                    System.out.println("请输入密码:");

                    String password = sc.nextLine();

     

                    // 调用登录功能

                    // UserDao ud = new UserDaomImpl();

     

                    boolean flag = ud.isLogin(username, password);

                    if (flag) {

                        System.out.println("登录成功,可以开始玩游戏了");

     

                        System.out.println("你玩吗?y/n");

                        while (true) {

                            String resultString = sc.nextLine();

                            if (resultString.equalsIgnoreCase("y")) {

                                // 玩游戏

                                GuessNumber.start();

                                System.out.println("你还玩吗?y/n");

                            } else {

                                break;

                            }

                        }

                        System.out.println("谢谢使用,欢迎下次再来");

                        System.exit(0);

                        // break; //这里写break,结束的是switch

                    } else {

                        System.out.println("用户名或者密码有误,登录失败");

                    }

                    break;

                case "2":

                    // 欢迎界面,请输入用户名和密码

                    System.out.println("--------------注册界面--------------");

                    System.out.println("请输入用户名:");

                    String newUsername = sc.nextLine();

                    System.out.println("请输入密码:");

                    String newPassword = sc.nextLine();

     

                    // 把用户名和密码封装到一个对象中

                    User user = new User();

                    user.setUsername(newUsername);

                    user.setPassword(newPassword);

     

                    // 调用注册功能

                    // 多态

                    // UserDao ud = new UserDaoImpl();

                    // 具体类使用

                    // UserDaoImpl udi = new UserDaoImpl();

     

                    ud.regist(user);

                    System.out.println("注册成功");

                    break;

                case "3":

                default:

                    System.out.println("谢谢使用,欢迎下次再来");

                    System.exit(0);

                    break;

                }

            }

        }

    }

     

            5:cn.itcast.game.GuessNumber.java

    import java.util.Scanner;

     

    /**

    * 这是猜数字小游戏

    *

    * @author
    风清扬

    * @version V1.0

    *

    */

    class GuessNumber {

        private GuessNumber() {

        }

     

        public static void start() {

            // 产生一个随机数

            int number = (int) (Math.random() * 100) + 1;

     

            // 定义一个统计变量

            int count = 0;

     

            while (true) {

                // 键盘录入一个数据

                Scanner sc = new Scanner(System.in);

                System.out.println("请输入数据(1-100):");

                int guessNumber = sc.nextInt();

     

                count++;

     

                // 判断

                if (guessNumber > number) {

                    System.out.println("你猜的数据" + guessNumber + "大了");

                } else if (guessNumber < number) {

                    System.out.println("你猜的数据" + guessNumber + "小了");

                } else {

                    System.out.println("恭喜你," + count + "次就猜中了");

                    break;

                }

            }

        }

    }

     

    2:集合toString()方法源码解析

    /*

    代码:

    Collection c = new ArrayList();

    c.add("hello");

    c.add("world");

    c.add("java");

     

    System.out.println(c);

     

    为什么c输出的不是地址值呢?

    A:Collection c = new ArrayList();

        这是多态,所以输出c的toString()方法,其实是输出ArrayList的toString()

    B:看ArrayList的toString()

        而我们在ArrayList里面却没有发现toString()。

        以后遇到这种情况,也不要担心,你认为有,它却没有,就应该去它父亲里面看看。

    C:toString()的方法源码

     

        public String toString() {

    Iterator<E> it = iterator(); //集合本身调用迭代器方法,得到集合迭代器

    if (! it.hasNext())

    return "[]";

     

    StringBuilder sb = new StringBuilder();

    sb.append('[');

    for (;;) {

    E e = it.next(); //e=hello,world,java

    sb.append(e == this ? "(this Collection)" : e);

    if (! it.hasNext())

        //[hello, world, java]

    return sb.append(']').toString();

    sb.append(',').append(' ');

    }

    }

     

    */

     

    3:Set集合(理解)

        (1)Set集合的特点

            无序,唯一(不可重复)

        

    import java.util.HashSet;

    import java.util.Set;

     

    /*

    * Collection

    *         |--List

    *             有序(存储顺序和取出顺序一致),可重复

    *         |--Set

    *             无序(存储顺序和取出顺序不一致),唯一

    *

    * HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。

    * 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,

    * 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。

    */

    class SetDemo {

        public static void main(String[] args) {

            // 创建集合对象

            Set<String> set = new HashSet<String>();

     

            // 创建并添加元素

            set.add("hello");

            set.add("java");

            set.add("world");

            set.add("java");

            set.add("world");

     

            // 增强for

            for (String s : set) {

                System.out.println(s);

            }

        }

    }

     

        (2)HashSet集合(掌握)

            A:底层数据结构是哈希表(是一个元素为链表的数组)

            B:哈希表底层依赖两个方法:hashCode()和equals()

             执行顺序:

                首先比较哈希值是否相同

                    相同:继续执行equals()方法

                        返回true:元素重复了,不添加

                        返回false:直接把元素添加到集合

                    不同:就直接把元素添加到集合

            C:如何保证元素唯一性的呢?

                由hashCode()和equals()保证的(必须重写插入元素所在类的hashCode和equals方法)

            D:开发的时候,代码非常的简单,自动生成即可。

            E:集合中允许放入null值,(不管你插入多少null值,最终集合中只会存储一个null值)

            F:LinkedHashSet 底层数据结构有哈希表和链表组成

                说明:LinkHashSet中可以插入null值,但是不管你插入多少null值,最终集合中

                     只会存储一个null值

                哈希表保证元素唯一性

                链表保证元素有序(存储顺序和取出顺序是一致的)

    import java.util.LinkedHashSet;

     

    /*

    * LinkedHashSet:底层数据结构由哈希表和链表组成。

    * 哈希表保证元素的唯一性。

    * 链表保证元素有序。(存储顺序和取出顺序是一致的)

    */

    class LinkedHashSetDemo {

        public static void main(String[] args) {

            // 创建集合对象

            LinkedHashSet<String> hs = new LinkedHashSet<String>();

     

            // 创建并添加元素

            hs.add("hello");

            hs.add("world");

            hs.add("java");

            hs.add("world");

            hs.add("java");

     

            // 遍历

            for (String s : hs) {

                System.out.println(s);

            }

        }

    }

     

            G:HashSet存储字符串并遍历

            

    import java.util.HashSet;

     

    /*

    * HashSet:存储字符串并遍历

    * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?

    * 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。

    * 步骤:

    *         首先比较哈希值

    *         如果相同,继续走,比较地址值或者走equals()

    *         如果不同,就直接添加到集合中    

    * 按照方法的步骤来说:    

    *         先看hashCode()值是否相同

    *             相同:继续走equals()方法

    *                 返回true:    说明元素重复,就不添加

    *                 返回false:说明元素不重复,就添加到集合

    *             不同:就直接把元素添加到集合

    * 如果类没有重写这两个方法,默认使用的Object()。一般来说并不相同。

    * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。

    */

    class HashSetDemo {

        public static void main(String[] args) {

            // 创建集合对象

            HashSet<String> hs = new HashSet<String>();

     

            // 创建并添加元素

            hs.add("hello");

            hs.add("world");

            hs.add("java");

            hs.add("world");

     

            // 遍历集合

            for (String s : hs) {

                System.out.println(s);

            }

        }

    }

     

            H:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

    import java.util.HashSet;

     

    /*

    * 需求:存储自定义对象,并保证元素的唯一性

    * 要求:如果两个对象的成员变量值都相同,则为同一个元素。

    *

    * 目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。

    * 而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。

    * 这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。

    */

    class HashSetDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            HashSet<Student> hs = new HashSet<Student>();

     

            // 创建学生对象

            Student s1 = new Student("林青霞", 27);

            Student s2 = new Student("柳岩", 22);

            Student s3 = new Student("王祖贤", 30);

            Student s4 = new Student("林青霞", 27);

            Student s5 = new Student("林青霞", 20);

            Student s6 = new Student("范冰冰", 22);

     

            // 添加元素

            hs.add(s1);

            hs.add(s2);

            hs.add(s3);

            hs.add(s4);

            hs.add(s5);

            hs.add(s6);

     

            // 遍历集合

            for (Student s : hs) {

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

        (3)TreeSet集合

            A:底层数据结构

    底层数据结构是红黑树(是一个自平衡的二叉树)

            B:保证元素的排序方式

                a:自然排序(元素具备比较性)

                    让元素所属的类实现Comparable接口

                b:比较器排序(集合具备比较性)

                    让集合构造方法接收Comparator的实现类对象

            C:不允许向集合中插入null值

    D:TreeSet对Integer对象排序(使用自然排序)

                

    import java.util.TreeSet;

     

    /*

    * TreeSet:能够对元素按照某种规则进行排序。

    * 排序有两种方式

    * A:自然排序(待比较元素所在的类实现Comparable接口)

    * B:比较器排序(让集合构造方法接收Comparator的实现类对象)

    *

    * TreeSet集合的特点:排序和唯一

    *

    * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。

    */

    class TreeSetDemo {

        public static void main(String[] args) {

            // 创建集合对象

            // 自然顺序进行排序

            TreeSet<Integer> ts = new TreeSet<Integer>();

     

            // 创建元素并添加

            // 20,18,23,22,17,24,19,18,24

            ts.add(20);

            ts.add(18);

            ts.add(23);

            ts.add(22);

            ts.add(17);

            ts.add(24);

            ts.add(19);

            ts.add(18);

            ts.add(24);

     

            // 遍历

            for (Integer i : ts) {

                System.out.println(i);

            }

        }

    }

     

            E:TreeSet存储自定义对象并保证唯一和排序(使用自然排序)

                1:Student.java类:

    /*

    * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口

    */

    public class Student implements Comparable<Student> {

        private String name;

        private int age;

     

        public Student() {

            super();

        }

     

        public Student(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

     

        @Override

        public int compareTo(Student s) {

            // return 0;

            // return 1;

            // return -1;

     

            // 这里返回什么,其实应该根据我的排序规则来做

            // 按照年龄排序,主要条件

            int num = this.age - s.age;

            // 次要条件

            // 年龄相同的时候,还得去看姓名是否也相同

            // 如果年龄和姓名都相同,才是同一个元素

            int num2 = num == 0 ? this.name.compareTo(s.name) : num;

            return num2;

        }

    }

     

                2:TreeSetDemo2.java测试类

    import java.util.TreeSet;

     

    /*

    * TreeSet存储自定义对象并保证排序和唯一。

    *

    * A:你没有告诉我们怎么排序

    *         自然排序,按照年龄从小到大排序

    * B:元素什么情况算唯一你也没告诉我

    *         成员变量值都相同即为同一个元素

    */

    class TreeSetDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            TreeSet<Student> ts = new TreeSet<Student>();

     

            // 创建元素

            Student s1 = new Student("linqingxia", 27);

            Student s2 = new Student("zhangguorong", 29);

            Student s3 = new Student("wanglihong", 23);

            Student s4 = new Student("linqingxia", 27);

            Student s5 = new Student("liushishi", 22);

            Student s6 = new Student("wuqilong", 40);

            Student s7 = new Student("fengqingy", 22);

     

            // 添加元素

            ts.add(s1);

            ts.add(s2);

            ts.add(s3);

            ts.add(s4);

            ts.add(s5);

            ts.add(s6);

            ts.add(s7);

     

            // 遍历

            for (Student s : ts) {

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

            F:TreeSet存储自定义对象排序并保证唯一和排序(比较器排序)

                1:Student.java 类保持原生,不做任何的改变

    public class Student {

        private String name;

        private int age;

     

        public Student() {

            super();

        }

     

        public Student(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

    }

     

                2:MyComparator 类实现了 Comparator接口

    import java.util.Comparator;

    /*

    * 比较器排序:一个实现Comparator接口的类

    */

    class MyComparator implements Comparator<Student> {

     

        @Override

        public int compare(Student s1, Student s2) {

            // int num = this.name.length() - s.name.length();

            // this -- s1

            // s -- s2

            // 姓名长度

            int num = s1.getName().length() - s2.getName().length();

            // 姓名内容

            int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;

            // 年龄

            int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;

            return num3;

        }

     

    }

     

                3:TreeSetDemo.java 测试类

    import java.util.Comparator;

    import java.util.TreeSet;

     

    /*

    * 需求:请按照姓名的长度排序

    *

    * TreeSet集合保证元素排序和唯一性的原理

    来决定。

    * 排序:

    *         A:自然排序(元素具备比较性)

    *             让元素所属的类实现自然排序接口 Comparable

    *         B:比较器排序(集合具备比较性)

    *             让集合的构造方法接收一个比较器接口的子类对象 Comparator

    */

    class TreeSetDemo {

        public static void main(String[] args) {

            // 创建集合对象

            // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序

            // public TreeSet(Comparator comparator) //比较器排序

            // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

     

            // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象

            // 而匿名内部类就可以实现这个东西,这个方式比较常用(推荐)

            TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

                @Override

                public int compare(Student s1, Student s2) {

                    // 姓名长度

                    int num = s1.getName().length() - s2.getName().length();

                    // 姓名内容

                    int num2 = (num == 0 ? s1.getName().compareTo(s2.getName())

                            : num);

                    // 年龄

                    int num3 = (num2 == 0 ? s1.getAge() - s2.getAge() : num2);

                    return num3;

                }

            });

     

            // 创建元素

            Student s1 = new Student("linqingxia", 27);

            Student s2 = new Student("zhangguorong", 29);

            Student s3 = new Student("wanglihong", 23);

            Student s4 = new Student("linqingxia", 27);

            Student s5 = new Student("liushishi", 22);

            Student s6 = new Student("wuqilong", 40);

            Student s7 = new Student("fengqingy", 22);

            Student s8 = new Student("linqingxia", 29);

     

            // 添加元素

            ts.add(s1);

            ts.add(s2);

            ts.add(s3);

            ts.add(s4);

            ts.add(s5);

            ts.add(s6);

            ts.add(s7);

            ts.add(s8);

     

            // 遍历

            for (Student s : ts) {

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

        (4)案例:

            A:获取无重复的随机数

                1:HashSetDemo.java 文件,主要演示HashSet的特点:唯一、无序

    import java.util.HashSet;

    import java.util.Random;

     

    /*

    个1至20的随机数,要求随机数不能重复。

    *

    * 分析:

    *         A:创建随机数对象

    *         B:创建一个HashSet集合

    *             是:就创建一个随机数添加

    *             否:不搭理它

    *         D:遍历HashSet集合

    */

    class HashSetDemo {

        public static void main(String[] args) {

            // 创建随机数对象

            Random r = new Random();

     

            // 创建一个Set集合

            HashSet<Integer> ts = new HashSet<Integer>();

     

            while (ts.size() < 10) {

                int num = r.nextInt(20) + 1;

                ts.add(num);

            }

     

            // 遍历Set集合

            for (Integer i : ts) {

                System.out.println(i);

            }

        }

    }

     

            B:键盘录入学生按照总分从高到底输出

                1: Student.java 文件

    public class Student {

        // 姓名

        private String name;

        // 语文成绩

        private int chinese;

        // 数学成绩

        private int math;

        // 英语成绩

        private int english;

     

        public Student(String name, int chinese, int math, int english) {

            super();

            this.name = name;

            this.chinese = chinese;

            this.math = math;

            this.english = english;

        }

     

        public Student() {

            super();

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getChinese() {

            return chinese;

        }

     

        public void setChinese(int chinese) {

            this.chinese = chinese;

        }

     

        public int getMath() {

            return math;

        }

     

        public void setMath(int math) {

            this.math = math;

        }

     

        public int getEnglish() {

            return english;

        }

     

        public void setEnglish(int english) {

            this.english = english;

        }

        //获取每一个学生成绩的总分的

        public int getSum() {

            return this.chinese + this.math + this.english;

        }

    }

        
     

             2:TreeSetDemo.java 类,主要演示TreeSet的特点

    import java.util.Comparator;

    import java.util.Scanner;

    import java.util.TreeSet;

     

    /*

    个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台

    *

    * 分析:

    *         A:定义学生类

    *         B:创建一个TreeSet集合

    *         C:总分从高到底如何实现呢?        

    个学生信息

    *         E:遍历TreeSet集合

    */

    class TreeSetDemo {

        public static void main(String[] args) {

            // 创建一个TreeSet集合

            TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

                @Override

                public int compare(Student s1, Student s2) {

                    // 总分从高到低

                    int num = s2.getSum() - s1.getSum();

                    // 总分相同的不一定语文相同

                    int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;

                    // 总分相同的不一定数序相同

                    int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;

                    // 总分相同的不一定英语相同

                    int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;

                    // 姓名还不一定相同呢

                    int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())

                            : num4;

                    return num5;

                }

            });

     

            System.out.println("学生信息录入开始");

    个学生信息

            for (int x = 1; x <= 5; x++) {

                Scanner sc = new Scanner(System.in);

                System.out.println("请输入第" + x + "个学生的姓名:");

                String name = sc.nextLine();

                System.out.println("请输入第" + x + "个学生的语文成绩:");

                String chineseString = sc.nextLine();

                System.out.println("请输入第" + x + "个学生的数学成绩:");

                String mathString = sc.nextLine();

                System.out.println("请输入第" + x + "个学生的英语成绩:");

                String englishString = sc.nextLine();

     

                // 把数据封装到学生对象中

                Student s = new Student();

                s.setName(name);

                s.setChinese(Integer.parseInt(chineseString));

                s.setMath(Integer.parseInt(mathString));

                s.setEnglish(Integer.parseInt(englishString));

     

                // 把学生对象添加到集合

                ts.add(s);

            }

            System.out.println("学生信息录入完毕");

     

            System.out.println("学习信息从高到低排序如下:");

            System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");

            // 遍历集合

            for (Student s : ts) {

                System.out.println(s.getName() + "\t" + s.getChinese() + "\t"

                        + s.getMath() + "\t" + s.getEnglish());

            }

        }

    }

     

    4:Collection集合总结(掌握)

        Collection

            |--List    有序,可重复

                |--ArrayList

                    底层数据结构是数组,查询快,增删慢。

                    线程不安全,效率高

                    允许插入null值,而且可以插入多个null,最终集合中会保存所有你插入

                    Null值

     

                |--Vector

                    底层数据结构是数组,查询快,增删慢。

                    线程安全,效率低

                    允许插入null值,而且可以插入多个null,最终集合中会保存所有你插入

                    Null值

     

                |--LinkedList

                    底层数据结构是链表,查询慢,增删快。

                    线程不安全,效率高

                    允许插入null值,而且可以插入多个null,最终集合中会保存所有你插入

                    Null值

     

            |--Set    无序,唯一

                |--HashSet

                    底层数据结构是哈希表。

                    允许插入null值,不管你插入多少null值,最终集合中只会保存一个null值

                    如何保证元素唯一性的呢?

                        依赖两个方法:hashCode()和equals()

                        开发中自动生成这两个方法即可

                    |--LinkedHashSet

                        底层数据结构是链表和哈希表

                        允许插入null值,不管你插入多少null值,最终集合中只会保存一个null值

                        由链表保证元素有序

                        由哈希表保证元素唯一

                |--TreeSet

                    底层数据结构是红黑树。

                    不允许插入null值

                    如何保证元素排序的呢?

                        自然排序

                        比较器排序

                    如何保证元素唯一性的呢?

                        根据比较的返回值是否是0来决定

                        

    5:针对Collection集合我们到底使用谁呢?(掌握)

        唯一吗?

            是:Set

                排序吗?

                    是:TreeSet

                    否:HashSet

            如果你知道是Set,但是不知道是哪个Set,就用HashSet。

                

            否:List

                要安全吗?

                    是:Vector

                    否:ArrayList或者LinkedList

                        查询多:ArrayList

                        增删多:LinkedList

            如果你知道是List,但是不知道是哪个List,就用ArrayList。

        

        如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。

        

        如果你知道用集合,就用ArrayList。

        

    6:在集合中常见的数据结构(掌握)

        ArrayXxx:底层数据结构是数组,查询快,增删慢

        LinkedXxx:底层数据结构是链表,查询慢,增删快

        HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()

        TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序

    第十八天

    1:Map(掌握)

        (1)定义:

    将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

        (2)Map和Collection的区别?

            A:Map 存储的是键值对形式的元素,键唯一,值可以重复。夫妻对

            B:Collection 存储的是单独出现的元素,子接口Set元素唯一,子接口List元素可重复。光棍

        (3)Map接口功能概述(自己补齐)

            A:添加功能

                        public V put(K key, V value):添加元素,这个还有另外一个功能

                        如果键是第一次存储,就直接存储元素,返回null

                        如果键不是第一次存储,就用值把以前的值替换掉,返回以前的值

            B:删除功能

                        public
    void clear():移除集合中的所有元素

                        public V remove(Object key):根据键删除键值对元素,并把值返回

                                        删除不存在的键,返回null

            C:判断功能

                        public
    boolean containsKey(Object key):判断集合是否包含指定的键

                        public
    boolean containsValue(Object value)判断集合是否包含指定的值

                        public
    boolean isEmpty():判断集合是否为空

            D:获取功能

                        Set<Map.Entry<K, V>> entrySet()

                        public V get(Object key):根据键获取值

                        public Set<K> keySet():获取集合中所有键的集合

                        public Collection<V> values():获取集合中所有值的集合

            E:长度功能

                        public
    int size():返回集合中键值对的对数

            F:简单方法功能演示:

    import java.util.HashMap;

    import java.util.Map;

     

    /*

    * 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取学生姓名,请问怎么做呢?

    * 如果采用前面讲解过的集合,我们只能把学号和学生姓名作为一个对象的成员,然后存储整个对象,将来遍历的时候,判断,获取对应的名称。

    * 但是呢,如果我都能把学生姓名拿出来了,我还需要根据编号去找吗?

    * 针对我们目前的这种需求:仅仅知道学号,就想知道学生姓名的情况,Java就提供了一种新的集合 Map。

    * 通过查看API,我们知道Map集合的一个最大的特点,就是它可以存储键值对的元素。这个时候存储我们上面的需求,就可以这样做

    * Map集合的特点:

    *         将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

    *

    * Map集合和Collection集合的区别?

    *         Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对

    *         Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍(11.11)

    *

    * 注意:

    *         Map集合的数据结构值针对键有效,跟值无关    

    *             HashMap,TreeMap等会讲。

    *        Collection集合的数据结构是针对元素有效

    *

    * Map集合的功能概述:

    * 1:添加功能

    *         V put(K key,V value):添加元素。这个其实还有另一个功能?先不告诉你,等会讲

    *             如果键是第一次存储,就直接存储元素,返回null

    *             如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值

    * 2:删除功能

    *         void clear():移除所有的键值对元素

    *         V remove(Object key):根据键删除键值对元素,并把值返回

    * 3:判断功能

    *         boolean containsKey(Object key):判断集合是否包含指定的键

    *         boolean containsValue(Object value):判断集合是否包含指定的值

    *         boolean isEmpty():判断集合是否为空

    * 4:获取功能

    *         Set<Map.Entry<K,V>> entrySet():???

    *         V get(Object key):根据键获取值

    *         Set<K> keySet():获取集合中所有键的集合

    *         Collection<V> values():获取集合中所有值的集合

    * 5:长度功能

    *         int size():返回集合中的键值对的对数

    */

    class MapDemo {

        public static void main(String[] args) {

            // 创建集合对象

            Map<String, String> map = new HashMap<String, String>();

     

            // 添加元素

            // V put(K key,V value):添加元素。这个其实还有另一个功能?先不告诉你,等会讲

            // System.out.println("put:" + map.put("文章", "马伊俐"));//map.put(),第一次存储V,V返回null

            // System.out.println("put:" + map.put("文章", "姚笛"));//map.put(),第二次存储V,V替换,返回原来的V

     

            map.put("邓超", "孙俪");

            map.put("黄晓明", "杨颖");

            map.put("周杰伦", "蔡依林");

            map.put("刘恺威", "杨幂");

     

            // void clear():移除所有的键值对元素

            // map.clear();

     

            // V remove(Object key):根据键删除键值对元素,并把值返回

            // System.out.println("remove:" + map.remove("黄晓明"));//返回杨颖

            // System.out.println("remove:" + map.remove("黄晓波"));//删除不存在的键,返回null

     

            // boolean containsKey(Object key):判断集合是否包含指定的键

            // System.out.println("containsKey:" + map.containsKey("黄晓明"));//true

            // System.out.println("containsKey:" + map.containsKey("黄晓波"));//false

     

            // boolean isEmpty():判断集合是否为空

            // System.out.println("isEmpty:"+map.isEmpty());

            

            //int size():返回集合中的键值对的对数

            System.out.println("size:"+map.size());

     

            // 输出集合名称

            System.out.println("map:" + map);

        }

    }

            G:获取功能演示:

    import java.util.Collection;

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

     

    /*

    * 获取功能:

    * V get(Object key):根据键获取值,如果没有该键,就返回null

    * Set<K> keySet():获取集合中所有键的集合

    * Collection<V> values():获取集合中所有值的集合

    */

    class MapDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            Map<String, String> map = new HashMap<String, String>();

     

            // 创建元素并添加元素

            map.put("邓超", "孙俪");

            map.put("黄晓明", "杨颖");

            map.put("周杰伦", "蔡依林");

            map.put("刘恺威", "杨幂");

     

            // V get(Object key):根据键获取值

            System.out.println("get:" + map.get("周杰伦"));//蔡依林

            System.out.println("get:" + map.get("周杰")); // 返回null

            System.out.println("----------------------");

     

            // Set<K> keySet():获取集合中所有键的集合

            Set<String> set = map.keySet();//set是键的集合

            for (String key : set) {

                System.out.println(key);

            }

            System.out.println("----------------------");

     

            // Collection<V> values():获取集合中所有值的集合

            Collection<String> con = map.values();//con是值的集合

            for (String value : con) {

                System.out.println(value);

            }

        }

    }

            H:Map集合的遍历方式一

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

     

    /*

    * Map集合的遍历。

    * Map -- 夫妻对

    * 思路:

    *         A:把所有的丈夫给集中起来。

    *         B:遍历丈夫的集合,获取得到每一个丈夫。

    *         C:让丈夫去找自己的妻子。

    *

    * 转换:

    *         A:获取所有的键

    *         B:遍历键的集合,获取得到每一个键

    *         C:根据键去找值

    */

    class MapDemo3 {

        public static void main(String[] args) {

            // 创建集合对象

            Map<String, String> map = new HashMap<String, String>();

     

            // 创建元素并添加到集合

            map.put("杨过", "小龙女");

            map.put("郭靖", "黄蓉");

            map.put("杨康", "穆念慈");

            map.put("陈玄风", "梅超风");

     

            // 遍历

            // 获取所有的键

            Set<String> set = map.keySet();

            // 遍历键的集合,获取得到每一个键

            for (String key : set) {

                // 根据键去找值

                String value = map.get(key);

                System.out.println(key + "---" + value);

            }

        }

    }

            J:Map集合的遍历方式二entrySet

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

     

    /*

    * Map集合的遍历。

    * Map -- 夫妻对

    *

    * 思路:

    *         A:获取所有结婚证的集合

    *         B:遍历结婚证的集合,得到每一个结婚证

    *         C:根据结婚证获取丈夫和妻子

    *

    * 转换:

    *         A:获取所有键值对对象的集合

    *         B:遍历键值对对象的集合,得到每一个键值对对象

    *         C:根据键值对对象获取键和值

    *

    * 这里面最麻烦的就是键值对对象如何表示呢?

    * 看看我们开始的一个方法:

    *         Set<Map.Entry<K,V>> entrySet():返回的是键值对对象的集合

    */

    class MapDemo4 {

        public static void main(String[] args) {

            // 创建集合对象

            Map<String, String> map = new HashMap<String, String>();

     

            // 创建元素并添加到集合

            map.put("杨过", "小龙女");

            map.put("郭靖", "黄蓉");

            map.put("杨康", "穆念慈");

            map.put("陈玄风", "梅超风");

     

            // 获取所有键值对对象的集合

            Set<Map.Entry<String, String>> set = map.entrySet();

            // 遍历键值对对象的集合,得到每一个键值对对象

            for (Map.Entry<String, String> me : set) {

                // 根据键值对对象获取键和值

                String key = me.getKey();

                String value = me.getValue();

                System.out.println(key + "---" + value);

            }

        }

    }

     

        (4)Map集合的遍历

    A:Map集合遍历两种方式比较图解

            B:键找值

                a:获取所有键的集合

                b:遍历键的集合,得到每一个键

                c:根据键到集合中去找值

            

            C:键值对对象找键和值

                a:获取所有的键值对对象的集合

                b:遍历键值对对象的集合,获取每一个键值对对象

                c:根据键值对对象去获取键和值

                

            代码体现:

                

    // 创建集合对象

            Map<String, String> map = new HashMap<String, String>();

     

            // 创建元素并添加到集合

            map.put("杨过", "小龙女");

            map.put("郭靖", "黄蓉");

            map.put("杨康", "穆念慈");

            map.put("陈玄风", "梅超风");

     

                

                //方式1 键找值

                

    //方式一:键找值

            Set<String> keys = map.keySet();

            for(String key : keys) {

                String value = map.get(key);

                System.out.println(key + "--" + value);

            }

     

                

                //方式2 键值对对象找键和值

                

    // 方式二:获取所有键值对对象的集合

            Set<Map.Entry<String, String>> set = map.entrySet();

            // 遍历键值对对象的集合,得到每一个键值对对象

            for (Map.Entry<String, String> me : set) {

                // 根据键值对对象获取键和值

                String key = me.getKey();

                String value = me.getValue();

                System.out.println(key + "---" + value);

            }

     

        (5)HashMap集合的练习

                允许插入null-null键值对

            A:HashMap<String,String>

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * HashMap:是基于哈希表的Map接口实现。

    * 哈希表的作用是用来保证键的唯一性的。

    *

    * HashMap<String,String>

    * 键:String

    * 值:String

    */

    class HashMapDemo {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<String, String> hm = new HashMap<String, String>();

     

            // 创建元素并添加元素

            

            hm.put("it001", "马云");

            hm.put("it003", "马化腾");

            hm.put("it004", "乔布斯");

            hm.put("it005", "张朝阳");

            hm.put("it002", "裘伯君"); // wps

            hm.put("it001", "比尔盖茨");

     

            // 遍历

            Set<String> set = hm.keySet();

            for (String key : set) {

                String value = hm.get(key);

                System.out.println(key + "---" + value);

            }

        }

    }

     

            B:HashMap<Integer,String>

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * HashMap<Integer,String>

    * 键:Integer

    * 值:String

    */

    class HashMapDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<Integer, String> hm = new HashMap<Integer, String>();

     

            // 创建元素并添加元素

            // Integer i = new Integer(27);

            // Integer i = 27;

            // String s = "林青霞";

            // hm.put(i, s);

     

            hm.put(27, "林青霞");

            hm.put(30, "风清扬");

            hm.put(28, "刘意");

            hm.put(29, "林青霞");

     

    以上的单个数据

            // hm.put(003, "hello");

            // hm.put(006, "hello");

            // hm.put(007, "hello");

            // hm.put(008, "hello");

     

            // 遍历

            Set<Integer> set = hm.keySet();

            for (Integer key : set) {

                String value = hm.get(key);

                System.out.println(key + "---" + value);

            }

     

            // 下面这种方式仅仅是集合的元素的字符串表示

            // System.out.println("hm:" + hm);

        }

    }

     

            C:HashMap<String,Student>

                1:Student.java文件

    public class Student {

        private String name;

        private int age;

     

        public Student() {

            super();

        }

     

        public Student(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

     

        @Override

        public int hashCode() {

            final int prime = 31;

            int result = 1;

            result = prime * result + age;

            result = prime * result + ((name == null) ? 0 : name.hashCode());

            return result;

        }

     

        @Override

        public boolean equals(Object obj) {

            if (this == obj)

                return true;

            if (obj == null)

                return false;

            if (getClass() != obj.getClass())

                return false;

            Student other = (Student) obj;

            if (age != other.age)

                return false;

            if (name == null) {

                if (other.name != null)

                    return false;

            } else if (!name.equals(other.name))

                return false;

            return true;

        }

     

     

                2:HashMapDemo3.java

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * HashMap<String,Student>

    * 键:String    学号

    * 值:Student 学生对象

    */

    class HashMapDemo3 {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<String, Student> hm = new HashMap<String, Student>();

     

            // 创建学生对象

            Student s1 = new Student("周星驰", 58);

            Student s2 = new Student("刘德华", 55);

            Student s3 = new Student("梁朝伟", 54);

            Student s4 = new Student("刘嘉玲", 50);

     

            // 添加元素

            hm.put("9527", s1);

            hm.put("9522", s2);

            hm.put("9524", s3);

            hm.put("9529", s4);

     

            // 遍历

            Set<String> set = hm.keySet();

            for (String key : set) {

                // 注意了:这次值不是字符串了

                // String value = hm.get(key);

                Student value = hm.get(key);

                System.out.println(key + "---" + value.getName() + "---"

                        + value.getAge());

            }

        }

    }

     

            D:HashMap<Student,String>

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * HashMap<Student,String>

    * 键:Student

    *         要求:如果两个对象的成员变量值都相同,则为同一个对象。

    * 值:String

    */

    class HashMapDemo4 {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<Student, String> hm = new HashMap<Student, String>();

     

            // 创建学生对象

            Student s1 = new Student("貂蝉", 27);

            Student s2 = new Student("王昭君", 30);

            Student s3 = new Student("西施", 33);

            Student s4 = new Student("杨玉环", 35);

            Student s5 = new Student("貂蝉", 27);

     

            // 添加元素

            hm.put(s1, "8888");

            hm.put(s2, "6666");

            hm.put(s3, "5555");

            hm.put(s4, "7777");

            hm.put(s5, "9999");

     

            // 遍历

            Set<Student> set = hm.keySet();

            for (Student key : set) {

                String value = hm.get(key);

                System.out.println(key.getName() + "---" + key.getAge() + "---"

                        + value);

            }

        }

    }

            E:LinkedHashMap的简介

    import java.util.LinkedHashMap;

    import java.util.Set;

     

    /*

    * LinkedHashMap:是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。

    * 由哈希表保证键的唯一性

    * 由链表保证键盘的有序(存储和取出的顺序一致)

    */

    class LinkedHashMapDemo {

        public static void main(String[] args) {

            // 创建集合对象

            LinkedHashMap<String, String> hm = new LinkedHashMap<String, String>();

     

            // 创建并添加元素

            hm.put("2345", "hello");

            hm.put("1234", "world");

            hm.put("3456", "java");

            hm.put("1234", "javaee");

            hm.put("3456", "android");

     

            // 遍历

            Set<String> set = hm.keySet();

            for (String key : set) {

                String value = hm.get(key);

                System.out.println(key + "---" + value);

            }

        }

    }

     

     

        (6)TreeMap集合的练习    

            
    允许value值为null,不允许key值为null     

            A:TreeMap<String,String>

    import java.util.Set;

    import java.util.TreeMap;

     

    /*

    * TreeMap:是基于红黑树的Map接口的实现。

    *

    * HashMap<String,String>

    * 键:String

    * 值:String

    */

    class TreeMapDemo {

        public static void main(String[] args) {

            // 创建集合对象

            TreeMap<String, String> tm = new TreeMap<String, String>();

     

            // 创建元素并添加元素

            tm.put("hello", "你好");

            tm.put("world", "世界");

            tm.put("java", "爪哇");

            tm.put("world", "世界2");

            tm.put("javaee", "爪哇EE");

     

            // 遍历集合

            Set<String> set = tm.keySet();

            for (String key : set) {

                String value = tm.get(key);

                System.out.println(key + "---" + value);

            }

        }

    }

     

            B:TreeMap<Student,String>

                1:Student.java

    public class Student {

        private String name;

        private int age;

     

        public Student() {

            super();

        }

     

        public Student(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

     

    }

     

                2:TreeMapDemo2.java

    import java.util.Comparator;

    import java.util.Set;

    import java.util.TreeMap;

     

    /*

    * TreeMap<Student,String>

    * 键:Student

    * 值:String

    */

    class TreeMapDemo2 {

        public static void main(String[] args) {

            // 创建集合对象,用匿名内部类实现比较器排序

            TreeMap<Student, String> tm = new TreeMap<Student, String>(

                    new Comparator<Student>() {

                        @Override

                        public int compare(Student s1, Student s2) {

                            // 主要条件

                            int num = s1.getAge() - s2.getAge();

                            // 次要条件

                            int num2 = num == 0 ? s1.getName().compareTo(

                                    s2.getName()) : num;

                            return num2;

                        }

                    });

     

            // 创建学生对象

            Student s1 = new Student("潘安", 30);

            Student s2 = new Student("柳下惠", 35);

            Student s3 = new Student("唐伯虎", 33);

            Student s4 = new Student("燕青", 32);

            Student s5 = new Student("唐伯虎", 33);

     

            // 存储元素

            tm.put(s1, "宋朝");

            tm.put(s2, "元朝");

            tm.put(s3, "明朝");

            tm.put(s4, "清朝");

            tm.put(s5, "汉朝");

     

            // 遍历

            Set<Student> set = tm.keySet();

            for (Student key : set) {

                String value = tm.get(key);

                System.out.println(key.getName() + "---" + key.getAge() + "---"

                        + value);

            }

        }

    }

     

        (7)案例

            A:统计一个字符串中每个字符出现的次数

    统计一个字符串中每个字符出现次数图解

    import java.util.Scanner;

    import java.util.Set;

    import java.util.TreeMap;

     

    /*

    * 需求 :"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)

    *

    * 分析:

    *         A:定义一个字符串(可以改进为键盘录入)

    *         B:定义一个TreeMap集合

    *             键:Character

    *             值:Integer

    *         C:把字符串转换为字符数组

    *         D:遍历字符数组,得到每一个字符

    *         E:拿刚才得到的字符作为键到集合中去找值,看返回值

    作为值存储

    ,然后重写存储该键和值

    *         F:定义字符串缓冲区变量

    *         G:遍历集合,得到键和值,进行按照要求拼接

    *         H:把字符串缓冲区转换为字符串输出

    *

    * 录入:linqingxia

    * 结果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1)

    */

    class TreeMapDemo {

        public static void main(String[] args) {

            // 定义一个字符串(可以改进为键盘录入)

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入一个字符串:");

            String line = sc.nextLine();

     

            // 定义一个TreeMap集合

            TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();

            

            //把字符串转换为字符数组

            char[] chs = line.toCharArray();

            

            //遍历字符数组,得到每一个字符

            for(char ch : chs){

                //拿刚才得到的字符作为键到集合中去找值,看返回值

                Integer i = tm.get(ch);

                

    作为值存储

                if(i == null){

                    tm.put(ch, 1);

                }else {

    ,然后重写存储该键和值

                    i++;

                    tm.put(ch,i);

                }

            }

            

            //定义字符串缓冲区变量

            StringBuilder sb= new StringBuilder();

            

            //遍历集合,得到键和值,进行按照要求拼接

            Set<Character> set = tm.keySet();

            for(Character key : set){

                Integer value = tm.get(key);

                sb.append(key).append("(").append(value).append(")");

            }

            

            //把字符串缓冲区转换为字符串输出

            String result = sb.toString();

            System.out.println("result:"+result);

        }

    }

     

            B:集合的嵌套遍历

                a:HashMap嵌套HashMap

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * HashMap嵌套HashMap

    *

    * 传智播客

    *         jc    基础班

    *                 陈玉楼        20

    *                 高跃        22

    *         jy    就业班

    *                 李杰        21

    *                 曹石磊        23

    *

    * 先存储元素,然后遍历元素

    */

    class HashMapDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<String, HashMap<String, Integer>> czbkMap = new HashMap<String, HashMap<String, Integer>>();

     

            // 创建基础班集合对象

            HashMap<String, Integer> jcMap = new HashMap<String, Integer>();

            // 添加元素

            jcMap.put("陈玉楼", 20);

            jcMap.put("高跃", 22);

            // 把基础班添加到大集合

            czbkMap.put("jc", jcMap);

     

            // 创建就业班集合对象

            HashMap<String, Integer> jyMap = new HashMap<String, Integer>();

            // 添加元素

            jyMap.put("李杰", 21);

            jyMap.put("曹石磊", 23);

            // 把基础班添加到大集合

            czbkMap.put("jy", jyMap);

            

            //遍历集合

            Set<String> czbkMapSet = czbkMap.keySet();

            for(String czbkMapKey : czbkMapSet){

                System.out.println(czbkMapKey);

                HashMap<String, Integer> czbkMapValue = czbkMap.get(czbkMapKey);

                Set<String> czbkMapValueSet = czbkMapValue.keySet();

                for(String czbkMapValueKey : czbkMapValueSet){

                    Integer czbkMapValueValue = czbkMapValue.get(czbkMapValueKey);

                    System.out.println("\t"+czbkMapValueKey+"---"+czbkMapValueValue);

                }

            }

        }

    }

     

                b:HashMap嵌套ArrayList

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    *需求:

    个。

    *每一个ArrayList集合的值是字符串。

    *元素我已经完成,请遍历。

    *结果:

    *         三国演义

    *             吕布

    *             周瑜

    *         笑傲江湖

    *             令狐冲

    *             林平之

    *         神雕侠侣

    *             郭靖

    *             杨过

    */

    class HashMapIncludeArrayListDemo {

        public static void main(String[] args) {

            // 创建集合对象

            HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();

     

            ArrayList<String> array1 = new ArrayList<String>();

            array1.add("吕布");

            array1.add("周瑜");

            hm.put("三国演义", array1);

     

            ArrayList<String> array2 = new ArrayList<String>();

            array2.add("令狐冲");

            array2.add("林平之");

            hm.put("笑傲江湖", array2);

     

            ArrayList<String> array3 = new ArrayList<String>();

            array3.add("郭靖");

            array3.add("杨过");

            hm.put("神雕侠侣", array3);

            

            //遍历集合

            Set<String> set = hm.keySet();

            for(String key : set){

                System.out.println(key);

                ArrayList<String> value = hm.get(key);

                for(String s : value){

                    System.out.println("\t"+s);

                }

            }

        }

    }

     

                c:ArrayList嵌套HashMap

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    ArrayList集合嵌套HashMap集合并遍历。

    需求:

    假设ArrayList集合的元素是HashMap。有3个。

    每一个HashMap集合的键和值都是字符串。

    元素我已经完成,请遍历。

    结果:

    周瑜---小乔

    吕布---貂蝉

     

    郭靖---黄蓉

    杨过---小龙女

     

    令狐冲---任盈盈

    林平之---岳灵珊

    */

    class ArrayListIncludeHashMapDemo {

        public static void main(String[] args) {

            // 创建集合对象

            ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();

     

            HashMap<String, String> hm1 = new HashMap<String, String>();

            hm1.put("周瑜", "小乔");

            hm1.put("吕布", "貂蝉");

            // 把元素添加到array里面

            array.add(hm1);

     

            HashMap<String, String> hm2 = new HashMap<String, String>();

            hm2.put("郭靖", "黄蓉");

            hm2.put("杨过", "小龙女");

            // 把元素添加到array里面

            array.add(hm2);

     

            HashMap<String, String> hm3 = new HashMap<String, String>();

            hm3.put("令狐冲", "任盈盈");

            hm3.put("林平之", "岳灵珊");

            // 把元素添加到array里面

            array.add(hm3);

     

            // 遍历

            for (HashMap<String, String> hm : array) {

                Set<String> set = hm.keySet();

                for (String key : set) {

                    String value = hm.get(key);

                    System.out.println(key + "---" + value);

                }

            }

        }

    }

     

                d:多层嵌套

                

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.Set;

     

    /*

    * 多层嵌套

    *         :hashMap里面嵌套hashmap,hashMap里面在嵌套ArrayList

    * 为了更符合要求:

    *         这次的数据就看成是学生对象。

    *

    * 传智播客

    *         bj    北京校区

    *             jc    基础班

    *                     林青霞        27

    *                     风清扬        30

    *             jy    就业班    

    *                     赵雅芝        28

    *                     武鑫        29

    *         sh    上海校区

    *             jc    基础班

    *                     郭美美        20

    *                     犀利哥        22

    *             jy    就业班    

    *                     罗玉凤        21

    *                     马征        23

    *         gz    广州校区

    *             jc    基础班

    *                     王力宏        30

    *                     李静磊        32

    *             jy    就业班    

    *                     郎朗        31

    *                     柳岩        33

    *         xa    西安校区

    *             jc    基础班

    *                     范冰冰        27

    *                     刘意        30

    *             jy    就业班    

    *                     李冰冰        28

    *                     张志豪        29

    */

    class HashMapDemo {

        public static void main(String[] args) {

            // 创建大集合

            HashMap<String, HashMap<String, ArrayList<Student>>> czbkMap = new HashMap<String, HashMap<String, ArrayList<Student>>>();

     

            // 北京校区数据

            HashMap<String, ArrayList<Student>> bjCzbkMap = new HashMap<String, ArrayList<Student>>();

            ArrayList<Student> array1 = new ArrayList<Student>();

            Student s1 = new Student("林青霞", 27);

            Student s2 = new Student("风清扬", 30);

            array1.add(s1);

            array1.add(s2);

            ArrayList<Student> array2 = new ArrayList<Student>();

            Student s3 = new Student("赵雅芝", 28);

            Student s4 = new Student("武鑫", 29);

            array2.add(s3);

            array2.add(s4);

            bjCzbkMap.put("基础班", array1);

            bjCzbkMap.put("就业班", array2);

            czbkMap.put("北京校区", bjCzbkMap);

     

            // 晚上可以自己练习一下

            // 上海校区数据自己做

            // 广州校区数据自己做

     

            // 西安校区数据

            HashMap<String, ArrayList<Student>> xaCzbkMap = new HashMap<String, ArrayList<Student>>();

            ArrayList<Student> array3 = new ArrayList<Student>();

            Student s5 = new Student("范冰冰", 27);

            Student s6 = new Student("刘意", 30);

            array3.add(s5);

            array3.add(s6);

            ArrayList<Student> array4 = new ArrayList<Student>();

            Student s7 = new Student("李冰冰", 28);

            Student s8 = new Student("张志豪", 29);

            array4.add(s7);

            array4.add(s8);

            xaCzbkMap.put("基础班", array3);

            xaCzbkMap.put("就业班", array4);

            czbkMap.put("西安校区", xaCzbkMap);

     

            // 遍历集合

            Set<String> czbkMapSet = czbkMap.keySet();

            for (String czbkMapKey : czbkMapSet) {

                System.out.println(czbkMapKey);

                HashMap<String, ArrayList<Student>> czbkMapValue = czbkMap

                        .get(czbkMapKey);

                Set<String> czbkMapValueSet = czbkMapValue.keySet();

                for (String czbkMapValueKey : czbkMapValueSet) {

                    System.out.println("\t" + czbkMapValueKey);

                    ArrayList<Student> czbkMapValueValue = czbkMapValue

                            .get(czbkMapValueKey);

                    for (Student s : czbkMapValueValue) {

                        System.out.println("\t\t" + s.getName() + "---"

                                + s.getAge());

                    }

                }

            }

        }

    }

     

    2:Collections(理解)    

        (1)是针对集合进行操作的工具类

        (2)面试题:Collection和Collections的区别

            A:Collection 是单列集合的顶层接口,有两个子接口List和Set

            B:Collections 是针对集合进行操作的工具类,可以对集合进行排序和查找等

        (3)常见的几个小方法:

            A:public static <T> void sort(List<T> list):排序,默认情况下是自然排序

            B:public static <T> void sort(List<T> list, Comparator<? super T> c):按照比较器进行排序

                
    说明:如果同时有自然排序和比较器排序,则以比较器排序为主

     

            C:public static <T> int binarySearch(List<?> list,T key):二分查找

            D:public static <T> T max(Collection<?> coll):最大值

            E:public static void reverse(List<?> list):反转

            F:public static void shuffle(List<?> list):随机置换

    F:方法功能演示:

        

    import java.util.Collections;

    import java.util.List;

    import java.util.ArrayList;

     

    /*

    * Collections:是针对集合进行操作的工具类,都是静态方法。

    *

    * 面试题:

    * Collection和Collections的区别?

    * Collection:是单列集合的顶层接口,有子接口List和Set。

    * Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法

    *

    * 要知道的方法

    * public static <T> void sort(List<T> list):排序 默认情况下是自然顺序。

    * public static <T> int binarySearch(List<?> list,T key):二分查找

    * public static <T> T max(Collection<?> coll):最大值

    * public static void reverse(List<?> list):反转

    * public static void shuffle(List<?> list):随机置换

    */

    class CollectionsDemo {

        public static void main(String[] args) {

            // 创建集合对象

            List<Integer> list = new ArrayList<Integer>();

     

            // 添加元素

            list.add(30);

            list.add(20);

            list.add(50);

            list.add(10);

            list.add(40);

     

            System.out.println("list:" + list);

     

            // public static <T> void sort(List<T> list):排序 默认情况下是自然顺序。

            // Collections.sort(list);

            // System.out.println("list:" + list);

            // [10, 20, 30, 40, 50]

     

            // public static <T> int binarySearch(List<?> list,T key):二分查找

            // System.out

            // .println("binarySearch:" + Collections.binarySearch(list, 30));

            // System.out.println("binarySearch:"

            // + Collections.binarySearch(list, 300));

     

            // public static <T> T max(Collection<?> coll):最大值

            // System.out.println("max:"+Collections.max(list));

     

            // public static void reverse(List<?> list):反转

            // Collections.reverse(list);

            // System.out.println("list:" + list);

            

            //public static void shuffle(List<?> list):随机置换

            Collections.shuffle(list);

            System.out.println("list:" + list);

        }

    }

     

        (4)案例

            A:ArrayList集合存储自定义对象的排序

                1:Student.java文件

    /*

    * 对象自然排序:

    *         必须实现Comparable接口,重写里面的 compareTo方法

    */

    public class Student implements Comparable<Student> {

        private String name;

        private int age;

     

        public Student() {

            super();

        }

     

        public Student(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

     

        @Override

        public int compareTo(Student s) {

            int num = this.age - s.age;

            int num2 = num == 0 ? this.name.compareTo(s.name) : num;

            return num2;

        }

    }

     

     

                2:ConnectionsDemo.java文件

    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.Comparator;

    import java.util.List;

     

    /*

    * Collections可以针对ArrayList存储基本包装类的元素排序,存储自定义对象可不可以排序呢?

    *如果同时有自然排序和比较器排序,以比较器排序为主

    */

    class CollectionsDemo {

        public static void main(String[] args) {

            // 创建集合对象

            List<Student> list = new ArrayList<Student>();

     

            // 创建学生对象

            Student s1 = new Student("林青霞", 27);

            Student s2 = new Student("风清扬", 30);

            Student s3 = new Student("刘晓曲", 28);

            Student s4 = new Student("武鑫", 29);

            Student s5 = new Student("林青霞", 27);

     

            // 添加元素对象

            list.add(s1);

            list.add(s2);

            list.add(s3);

            list.add(s4);

            list.add(s5);

     

            // 排序

            // 自然排序

            // Collections.sort(list);

            // 比较器排序

            // 如果同时有自然排序和比较器排序,以比较器排序为主

            Collections.sort(list, new Comparator<Student>() {

                @Override

                public int compare(Student s1, Student s2) {

                    int num = s2.getAge() - s1.getAge();

                    int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;

                    return num2;

                }

            });

     

            // 遍历集合

            for (Student s : list) {

                System.out.println(s.getName() + "---" + s.getAge());

            }

        }

    }

     

            B:模拟斗地主洗牌和发牌

                PokerDemo.java文件

    import java.util.ArrayList;

    import java.util.Collections;

     

    /*

    * 模拟斗地主洗牌和发牌

    *

    * 分析:

    *         A:创建一个牌盒

    *         B:装牌

    *         C:洗牌

    *         D:发牌

    *         E:看牌

    */

    class PokerDemo {

        public static void main(String[] args) {

            // 创建一个牌盒

            ArrayList<String> array = new ArrayList<String>();

     

            // 装牌

            // 黑桃A,黑桃2,黑桃3,...黑桃K

            // 红桃A,...

            // 梅花A,...

            // 方块A,...

            // 定义一个花色数组

            String[] colors = { "♠", "♥", "♣", "♦" };

            // 定义一个点数数组

            String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };

            // 装牌

            for (String color : colors) {

                for (String number : numbers) {

                    array.add(color.concat(number));

                }

            }

            array.add("小王");

            array.add("大王");

     

            // 洗牌

            Collections.shuffle(array);

     

            // System.out.println("array:" + array);

     

            // 发牌

            ArrayList<String> fengQingYang = new ArrayList<String>();

            ArrayList<String> linQingXia = new ArrayList<String>();

            ArrayList<String> liuYi = new ArrayList<String>();

            ArrayList<String> diPai = new ArrayList<String>();

     

            for (int x = 0; x < array.size(); x++) {

                if (x >= array.size() - 3) {

                    diPai.add(array.get(x));

                } else if (x % 3 == 0) {

                    fengQingYang.add(array.get(x));

                } else if (x % 3 == 1) {

                    linQingXia.add(array.get(x));

                } else if (x % 3 == 2) {

                    liuYi.add(array.get(x));

                }

            }

     

            // 看牌

            lookPoker("风清扬", fengQingYang);

            lookPoker("林青霞", linQingXia);

            lookPoker("刘意", liuYi);

     

            lookPoker("底牌", diPai);

        }

     

        public static void lookPoker(String name, ArrayList<String> array) {

            System.out.print(name + "的牌是:");

            for (String s : array) {

                System.out.print(s + " ");

            }

            System.out.println();

        }

    }

    C:模拟斗地主洗牌和发牌并对牌进行排序的原理图解

            D:模拟斗地主洗牌和发牌并对牌进行排序

     

                PokerDemo.java文件

    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.HashMap;

    import java.util.TreeSet;

     

    /*

    * 思路:

    *         A:创建一个HashMap集合

    *         B:创建一个ArrayList集合

    *         C:创建花色数组和点数数组

    开始往HashMap里面存储编号,并存储对应的牌

    * 同时往ArrayList里面存储编号即可。

    * E:洗牌(洗的是编号)

    * F:发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)

    * G:看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)

    */

    class PokerDemo {

        public static void main(String[] args) {

            // 创建一个HashMap集合

            HashMap<Integer, String> hm = new HashMap<Integer, String>();

     

            // 创建一个ArrayList集合

            ArrayList<Integer> array = new ArrayList<Integer>();

     

            // 创建花色数组和点数数组

            // 定义一个花色数组

            String[] colors = { "♠", "♥", "♣", "♦" };

            // 定义一个点数数组

            String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2", };

     

    开始往HashMap里面存储编号,并存储对应的牌,同时往ArrayList里面存储编号即可。

            int index = 0;

     

            for (String number : numbers) {

                for (String color : colors) {

                    String poker = color.concat(number);

                    hm.put(index, poker);

                    array.add(index);

                    index++;

                }

            }

            hm.put(index, "小王");

            array.add(index);

            index++;

            hm.put(index, "大王");

            array.add(index);

     

            // 洗牌(洗的是编号)

            Collections.shuffle(array);

     

            // 发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)

            TreeSet<Integer> fengQingYang = new TreeSet<Integer>();

            TreeSet<Integer> linQingXia = new TreeSet<Integer>();

            TreeSet<Integer> liuYi = new TreeSet<Integer>();

            TreeSet<Integer> diPai = new TreeSet<Integer>();

     

            for (int x = 0; x < array.size(); x++) {

                if (x >= array.size() - 3) {

                    diPai.add(array.get(x));

                } else if (x % 3 == 0) {

                    fengQingYang.add(array.get(x));

                } else if (x % 3 == 1) {

                    linQingXia.add(array.get(x));

                } else if (x % 3 == 2) {

                    liuYi.add(array.get(x));

                }

            }

     

            // 看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)

            lookPoker("风清扬", fengQingYang, hm);

            lookPoker("林青霞", linQingXia, hm);

            lookPoker("刘意", liuYi, hm);

            lookPoker("底牌", diPai, hm);

        }

     

        // 写看牌的功能

        public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {

            System.out.print(name + "的牌是:");

            for (Integer key : ts) {

                String value = hm.get(key);

                System.out.print(value + " ");

            }

            System.out.println();

        }

    }

     

    3:集合大总结

    1:集合(自己补齐)

    Collection(单列集合)

        List(有序,可重复)

            ArrayList

                底层数据结构是数组,查询快,增删慢

                线程不安全,效率高

            Vector

                底层数据结构是数组,查询快,增删慢

                线程安全,效率低

            LinkedList

                底层数据结构是链表,查询慢,增删快

                线程不安全,效率高

        Set(无序,唯一)

            HashSet

                底层数据结构是哈希表。

                哈希表依赖两个方法:hashCode()和equals()

                执行顺序:

                    首先判断hashCode()值是否相同

                        是:继续执行equals(),看其返回值

                            是true:说明元素重复,不添加

                            是false:就直接添加到集合

                        否:就直接添加到集合

                最终:

                    自动生成hashCode()和equals()即可

                    

                LinkedHashSet

                    底层数据结构由链表和哈希表组成。

                    由链表保证元素有序。

                    由哈希表保证元素唯一。

            TreeSet

                底层数据结构是红黑树。(是一种自平衡的二叉树)

                如何保证元素唯一性呢?

    来决定

                如何保证元素的排序呢?

                    两种方式

                        自然排序(元素具备比较性)

                            让元素所属的类实现Comparable接口

                        比较器排序(集合具备比较性)

                            让集合接收一个Comparator的实现类对象

    Map(双列集合)

        A:Map集合的数据结构仅仅针对键有效,与值无关。

        B:存储的是键值对形式的元素,键唯一,值可重复。

        

        HashMap

            底层数据结构是哈希表。线程不安全,效率高

                哈希表依赖两个方法:hashCode()和equals()

                执行顺序:

                    首先判断hashCode()值是否相同

                        是:继续执行equals(),看其返回值

                            是true:说明元素重复,不添加

                            是false:就直接添加到集合

                        否:就直接添加到集合

                最终:

                    自动生成hashCode()和equals()即可

            LinkedHashMap

                底层数据结构由链表和哈希表组成。

                    由链表保证元素有序。

                    由哈希表保证元素唯一。

        Hashtable

            底层数据结构是哈希表。线程安全,效率低

                哈希表依赖两个方法:hashCode()和equals()

                执行顺序:

                    首先判断hashCode()值是否相同

                        是:继续执行equals(),看其返回值

                            是true:说明元素重复,不添加

                            是false:就直接添加到集合

                        否:就直接添加到集合

                最终:

                    自动生成hashCode()和equals()即可

        TreeMap

            底层数据结构是红黑树。(是一种自平衡的二叉树)

                如何保证元素唯一性呢?

    来决定

                如何保证元素的排序呢?

                    两种方式

                        自然排序(元素具备比较性)

                            让元素所属的类实现Comparable接口

                        比较器排序(集合具备比较性)

                            让集合接收一个Comparator的实现类对象

     

    2:到底使用那种集合(自己补齐)

    看需求。

     

    是否是键值对象形式:

        是:Map

            键是否需要排序:

                是:TreeMap

                否:HashMap

            不知道,就使用HashMap。

            

        否:Collection

            元素是否唯一:

                是:Set

                    元素是否需要排序:

                        是:TreeSet

                        否:HashSet

                    不知道,就使用HashSet

                    

                否:List

                    要安全吗:

                        是:Vector(其实我们也不用它,后面我们讲解了多线程以后,我在给你回顾用谁)

                        否:ArrayList或者LinkedList

                            增删多:LinkedList

                            查询多:ArrayList

                        不知道,就使用ArrayList

            不知道,就使用ArrayList

            

    3:集合的常见方法及遍历方式

    Collection:

        add()

        remove()

        contains()

        iterator()

        size()

        

        遍历:

            增强for

            迭代器

            

        |--List

            get()

            

            遍历:

                普通for

        |--Set

     

    Map:

        put()

        remove()

        containskey(),containsValue()

        keySet()

        get()

        value()

        entrySet()

        size()

        

        遍历:

            根据键找值

            根据键值对对象分别找键和值

            

    作业:

        我讲解过的任意一个集合,我要求你存储什么,你就能够存储什么。

        并且,还要能够遍历出来。

     

    4:ArrayList,LinkedList,HashSet,HashMap(掌握)

    存储字符串和自定义对象数据并遍历

     

    5:集合的嵌套遍历(理解)

     

     

    第十九天

    1:异常(理解)

      定义

    程序出现的不正常的情况。

    a)异常的引入

    /*

    * 异常:程序出现了不正常的情况。

    *

    * 举例:今天天气很好,班长出去旅游。骑着自行车,去山里面呼吸新鲜空气。

    :山路塌陷了,班长及时停住了,但是过不去了。严重的问题。

    :班长出门推自行车,发现气没了,把气吹起来。出发前就应该检查的问题。

    *         问题3:班长骑着车在山路上惬意的行驶着,山路两边是有小石子的,中间是平坦的水泥路。

    *             一直在平坦的水泥路上行驶是没有任何问题的,但是呢,他偏偏喜欢骑到小石子上,结果爆胎了。旅游的过程中出现的问题。

    *             no zuo no die。

    *

    * 程序的异常:Throwable

    *         严重问题:Error 我们不处理。这种问题一般都是很严重的,比如说内存溢出。

    *         问题:Exception

    *             编译期问题:不是RuntimeException的异常 必须进行处理的,因为你不处理,编译就不能通过。

    *             运行期问题:RuntimeException    这种问题我们也不处理,因为是你的问题,而且这个问题出现肯定是我们的代码不够严谨,需要修正代码的。

    *

    * 如何程序出现了问题,我们没有做任何处理,最终jvm会做出默认的处理。

    * 把异常的名称,原因及出现的问题等信息输出在控制台。

    * 同时会结束程序。

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            //第一阶段

            int a = 10;

            // int b = 2;

            int b = 0;

            System.out.println(a / b);

            

            //第二阶段

            System.out.println("over");

        }

    }

     

        (2)异常的体系

            Throwable

                |--Error    严重问题,我们不处理。

                |--Exception

                    |--RuntimeException    运行期异常,我们需要修正代码

                    |--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过

        (3)异常的处理:

            A:JVM的默认处理

                把异常的名称,原因,位置等信息输出在控制台,但是呢程序不能继续执行了。

            B:自己处理

                a:try...catch...finally

                    自己编写处理代码,后面的程序可以继续执行

                b:throws

                    把自己处理不了的,在方法上声明,告诉调用者,这里有问题

     

     

        (4)异常知识点代码详解

                a) 异常处理的方式

                

    /*

    * 我们自己如何处理异常呢?

    * A:try...catch...finally

    * B:throws 抛出

    *

    * try...catch...finally的处理格式:

    *         try {

    *             可能出现问题的代码;

    *         }catch(异常名 变量) {

    *             针对问题的处理;

    *         }finally {

    *             释放资源;

    *         }

    *

    * 变形格式:

    *         try {

    *             可能出现问题的代码;

    *         }catch(异常名 变量) {

    *             针对问题的处理;

    *         }

    *

    * 注意:

    *         A:try里面的代码越少越好

    *         B:catch里面必须有内容,哪怕是给出一个简单的提示

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            // 第一阶段

            int a = 10;

            // int b = 2;

            int b = 0;

     

            try {

                System.out.println(a / b);

            } catch (ArithmeticException ae) {

                System.out.println("除数不能为0");

            }

     

            // 第二阶段

            System.out.println("over");

        }

    }

                b) 多个异常的处理

    /*

    * A:一个异常

    * B:二个异常的处理

    *         a:每一个写一个try...catch

    *         b:写一个try,多个catch

    *             try{

    *                 ...

    *             }catch(异常类名 变量名) {

    *                 ...

    *             }

    *             catch(异常类名 变量名) {

    *                 ...

    *             }

    *             ...

    *

    *             注意事项:

    *                 1:能明确的尽量明确,不要用大的来处理。

    *                 2:平级关系的异常谁前谁后无所谓,如果出现了子父关系,父必须在后面。

    *

    * 注意:

    *         一旦try里面出了问题,就会在这里把问题给抛出去,然后和catch里面的问题进行匹配,

    *         一旦有匹配的,就执行catch里面的处理,然后结束了try...catch

    *         继续执行后面的语句。

    */

    class ExceptionDemo2 {

        public static void main(String[] args) {

            // method1();

     

            // method2();

     

            // method3();

     

            method4();

        }

     

        public static void method4() {

            int a = 10;

            int b = 0;

            int[] arr = { 1, 2, 3 };

     

            // 爷爷在最后

            try {

                System.out.println(a / b);

                System.out.println(arr[3]);

                System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?");

            } catch (ArithmeticException e) {

                System.out.println("除数不能为0");

            } catch (ArrayIndexOutOfBoundsException e) {

                System.out.println("你访问了不该的访问的索引");

            } catch (Exception e) {

                System.out.println("出问题了");

            }

     

            // 爷爷在前面是不可以的

            // try {

            // System.out.println(a / b);

            // System.out.println(arr[3]);

            // System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?");

            // } catch (Exception e) {

            // System.out.println("出问题了");

            // } catch (ArithmeticException e) {

            // System.out.println("除数不能为0");

            // } catch (ArrayIndexOutOfBoundsException e) {

            // System.out.println("你访问了不该的访问的索引");

            // }

     

            System.out.println("over");

        }

     

        // 两个异常的处理

        public static void method3() {

            int a = 10;

            int b = 0;

            int[] arr = { 1, 2, 3 };

     

            try {

                System.out.println(arr[3]);

                System.out.println(a / b);

                // System.out.println(arr[3]);

            } catch (ArithmeticException e) {

                System.out.println("除数不能为0");

            } catch (ArrayIndexOutOfBoundsException e) {

                System.out.println("你访问了不该的访问的索引");

            }

     

            System.out.println("over");

        }

     

        // 两个异常

        public static void method2() {

            int a = 10;

            int b = 0;

            try {

                System.out.println(a / b);

            } catch (ArithmeticException e) {

                System.out.println("除数不能为0");

            }

     

            int[] arr = { 1, 2, 3 };

            try {

                System.out.println(arr[3]);

            } catch (ArrayIndexOutOfBoundsException e) {

                System.out.println("你访问了不该的访问的索引");

            }

     

            System.out.println("over");

        }

     

        // 一个异常

        public static void method1() {

            // 第一阶段

            int a = 10;

            // int b = 2;

            int b = 0;

     

            try {

                System.out.println(a / b);

            } catch (ArithmeticException ae) {

                System.out.println("除数不能为0");

            }

     

            // 第二阶段

            System.out.println("over");

        }

    }

                c) JDK7异常处理的新方式

    /*

    * JDK7出现了一个新的异常处理方案:

    *         try{

    *

    *         }catch(异常名1 | 异常名2 | ... 变量 ) {

    *             ...

    *         }

    *

    *         注意:这个方法虽然简洁,但是也不够好。

    *             A:处理方式是一致的。(实际开发中,好多时候可能就是针对同类型的问题,给出同一个处理)

    *            B:多个异常间必须是平级关系。

    */

    class ExceptionDemo3 {

        public static void main(String[] args) {

            method();

        }

     

        public static void method() {

            int a = 10;

            int b = 0;

            int[] arr = { 1, 2, 3 };

     

            // try {

            // System.out.println(a / b);

            // System.out.println(arr[3]);

            // System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?");

            // } catch (ArithmeticException e) {

            // System.out.println("除数不能为0");

            // } catch (ArrayIndexOutOfBoundsException e) {

            // System.out.println("你访问了不该的访问的索引");

            // } catch (Exception e) {

            // System.out.println("出问题了");

            // }

     

            // JDK7的处理方案

            try {

                System.out.println(a / b);

                System.out.println(arr[3]);

            } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {

                System.out.println("出问题了");

            }

     

            System.out.println("over");

        }

     

    }

     

                d) 编译时期异常和运行时期异常的区别

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * 编译时异常和运行时异常的区别

    * 编译期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译

    * 运行期异常:无需显示处理,也可以和编译时异常一样处理

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            // int a = 10;

            // int b = 0;

            // if (b != 0) {

            // System.out.println(a / b);

            // }

     

            String s = "2014-11-20";

            // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            // Date d = sdf.parse(s);

            try {

                Date d = sdf.parse(s);

                System.out.println(d);

            } catch (ParseException e) {

                // e.printStackTrace();

                System.out.println("解析日期出问题了");

            }

        }

    }

                e) 异常中的方法详解

                    public String getMessage():异常的消息字符串

                    public String toString():返回异常的简单信息描述

    public
    void printStackTrace():获取异常类名和异常信息,异常出现的位置

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * 在try里面发现问题后,jvm会帮我们生成一个异常对象,然后把这个对象抛出,和catch里面的类进行匹配。

    * 如果该对象是某个类型的,就会执行该catch里面的处理信息。

    *

    * 异常中要了解的几个方法:

    * public String getMessage():异常的消息字符串        

    * public String toString():返回异常的简单信息描述

    *         此对象的类的 name(全路径名)

    *         ": "(冒号和一个空格)

    *         调用此对象 getLocalizedMessage()方法的结果 (默认返回的是getMessage()的内容)

    * printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。把信息输出在控制台。

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            String s = "2014-11-20";

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            try {

                Date d = sdf.parse(s); // 创建了一个ParseException对象,然后抛出去,和catch里面进行匹配

                System.out.println(d);

            } catch (ParseException e) { // ParseException e = new ParseException();

                // ParseException

                // e.printStackTrace();

     

                // getMessage()

                // System.out.println(e.getMessage());

                // Unparseable date: "2014-11-20"

     

                // toString()

                // System.out.println(e.toString());

                // java.text.ParseException: Unparseable date: "2014-11-20"

     

                e.printStackTrace();

                // 跳转到某个指定的页面(index.html)

            }

     

            System.out.println("over");

        }

    }

                f) 异常的处理方式2:throws

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * 有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。

    * 或者说,我处理不了,我就不处理了。

    * 为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。

    *

    * 格式:

    *         throws 异常类名

    *         注意:这个格式必须跟在方法的括号后面。

    *

    * 注意:

    *         尽量不要在main方法上抛出异常。

    *         但是我讲课为了方便我就这样做了。

    *

    * 小结:

    *         编译期异常抛出,将来调用者必须处理。

    *         运行期异常抛出,将来调用可以不用处理。

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            System.out.println("今天天气很好");

            try {

                method();

            } catch (ParseException e) {

                e.printStackTrace();

            }

            System.out.println("但是就是不该有雾霾");

     

            method2();

        }

     

        // 运行期异常的抛出

        public static void method2() throws ArithmeticException {

            int a = 10;

            int b = 0;

            System.out.println(a / b);

        }

     

        // 编译期异常的抛出

        // 在方法声明上抛出,是为了告诉调用者,你注意了,我有问题。

        public static void method() throws ParseException {

            String s = "2014-11-20";

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Date d = sdf.parse(s);

            System.out.println(d);

        }

    }

     

                g) throw 和 throws
    的区别

    /*

    * throw:如果出现了异常情况,我们可以把该异常抛出,这个时候的抛出的应该是异常的对象。

    *

    * throws和throw的区别(面试题)

        throws

            用在方法声明后面,跟的是异常类名

            可以跟多个异常类名,用逗号隔开

            表示抛出异常,由该方法的调用者来处理

            throws表示出现异常的一种可能性,并不一定会发生这些异常

        throw

            用在方法体内,跟的是异常对象名

            只能抛出一个异常对象名

            表示抛出异常,由方法体内的语句处理

            throw则是抛出了异常,执行throw则一定抛出了某种异常

    */

    class ExceptionDemo {

        public static void main(String[] args) {

            // method();

            

            try {

                method2();

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

     

        public static void method() {

            int a = 10;

            int b = 0;

            if (b == 0) {

                throw new ArithmeticException();

            } else {

                System.out.println(a / b);

            }

        }

     

        public static void method2() throws Exception {

            int a = 10;

            int b = 0;

            if (b == 0) {

                throw new Exception();

            } else {

                System.out.println(a / b);

            }

        }

    }

                h) try.. catch….finally 体系中的finally讲解

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * finally:被finally控制的语句体一定会执行

    * 注意:如果在执行到finally之前jvm退出了,就不能执行了。

    *

    * A:格式

    *         try...catch...finally...

    * B:用于释放资源,在IO流操作和数据库操作中会见到

    */

    class FinallyDemo {

        public static void main(String[] args) {

            String s = "2014-11-20";

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

     

            Date d = null;

            try {

                // System.out.println(10 / 0);

                d = sdf.parse(s);

            } catch (ParseException e) {

                e.printStackTrace();

                System.exit(0);

            } finally {

                System.out.println("这里的代码是可以执行的");

            }

     

            System.out.println(d);

        }

    }

     

                i)final / finally / finalize 三者的区别?

    /*

    * 面试题:

    * 1:final,finally和finalize的区别

    * final:最终的意思,可以修饰类,成员变量,成员方法

    *         修饰类,类不能被继承

    *         修饰变量,变量是常量

    *         修饰方法,方法不能被重写

    * finally:是异常处理的一部分,用于释放资源。

    *         一般来说,代码肯定会执行,特殊情况:在执行到finally之前jvm退出了

    * finalize:是Object类的一个方法,用于垃圾回收

    *

    * 2:如果catch里面有return语句,请问finally里面的代码还会执行吗?

    * 如果会,请问是在return前,还是return后。

    *      会。前。

    *

    *      准确的说,应该是在中间。

    *

    * 3:try...catch...finally的格式变形

    *         A:try...catch...finally

    *         B:try...catch

    *         C:try...catch...catch...

    *         D:try...catch...catch...finally

    *         E:try...finally

    *             这种做法的目前是为了释放资源。

    */

    class FinallyDemo2 {

        public static void main(String[] args) {

            System.out.println(getInt());

        }

     

        public static int getInt() {

            int a = 10;

            try {

                System.out.println(a / 0);

                a = 20;

            } catch (ArithmeticException e) {

                a = 30;

                return a;

                /*

                 * return a在程序执行到这一步的时候,这里不是return a而是return 30;这个返回路径就形成了。

                 * 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40

                 * 再次回到以前的返回路径,继续走return 30;

                 */

            } finally {

                a = 40;

    了。

            }

            // return a;

        }

    }

     

     

     

     

        (5)面试题

            A:编译期异常和运行期异常的区别?

                编译期异常 必须要处理的,否则编译不通过

                运行期异常 可以不处理,也可以处理

            B:throw和throwsde的区别

                throw:

                    在方法体中,后面跟的是异常对象名,并且只能是一个

                    表示抛出异常,由方法体内的语句处理

                    throw抛出的是一个异常对象,说明这里肯定有一个异常产生了

                throws:

                    在方法声明上,后面跟的是异常的类名,可以是多个

                    表示抛出异常,由方法的调用者来处理

                    throws是声明方法有异常,是一种可能性,这个异常并不一定会产生

        (6)finally关键字及其面试题

            A:finally的详解

    用于释放资源,它的代码永远会执行。特殊情况:在执行到finally之前jvm退出了

            B:面试题

                a:final,finally,finalize的区别?

                    Final:最终的意思,可以修饰类,成员变量、成员方法

                            修饰类:类不能被继承

                            修饰变量:变量为常量

                            修饰方法:方法不能被重写

                    Finally:是异常处理的一部分,用于释放资源

                            一般情况下,代码肯定会执行,特殊情况下不能执行:在执行到finally

                                        之前jvm退出了

                    Finalize:是Object类的一个方法,用于垃圾回收的

                b:如果在catch里面有return,请问finally还执行吗?如果执行,在return前还是后?

                    会,前。

                    

                    实际上在中间。这个上课我们讲过

            C:异常处理的变形

                try...catch...finally

                try...catch...

                try...catch...catch...

                try...catch...catch...fianlly

                try...finally

        (7)自定义异常

            A: 定义:

    继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可

     

    注意:1.如果一个类继承了Exception,在抛出异常对象的时候,需要在抛出异常的

            方法上面抛出该异常类

    2.如果一个类继承了RuntimeException,在抛出异常对象的时候,不需要在

                        抛出异常的方法上面抛出该异常类

            B:自定义异常的代码演示

                1: MyException.java类:继承了Exception

    /*

    * java不可能对所有的情况都考虑到,所以,在实际的开发中,我们可能需要自己定义异常。

    * 而我们自己随意的写一个类,是不能作为异常类来看的,要想你的类是一个异常类,就必须继承自Exception或者RuntimeException

    *

    * 两种方式:

    * A:继承Exception

    * B:继承RuntimeException

    *

    * 注意:需要提供两个构造方法

    *             无参构造:用于来创建异常对象

    *             有参构造:用于自定义异常信息

    */

    class MyException extends Exception {

        public MyException() {

        }

     

        public MyException(String message) {

            super(message);

        }

    }

                

                2:Teacher.java类:主要用来抛出异常对象

    class Teacher {

        public void check(int score) throws MyException {

            if (score > 100 || score < 0) {

                throw new MyException("分数必须在0-100之间");

            } else {

                System.out.println("分数没有问题");

            }

        }

     

        // 针对MyException继承自RuntimeException

        // public void check(int score) {

        // if (score > 100 || score < 0) {

        // throw new MyException();

        // } else {

        // System.out.println("分数没有问题");

        // }

        // }

    }

                3: StudentDemo.java 自定义异常的测试类

    import java.util.Scanner;

     

    /*

    * 自定义异常测试类

    */

    class StudentDemo {

        public static void main(String[] args) {

            Scanner sc = new Scanner(System.in);

            System.out.println("请输入学生成绩:");

            int score = sc.nextInt();

     

            Teacher t = new Teacher();

            try {

                t.check(score);

            } catch (MyException e) {

                e.printStackTrace();

            }

        }

    }

     

     

     

     

     

        (8)异常的注意实现

            A:父的方法有异常抛出,子的重写方法在抛出异常的时候必须要小于等于父的异常

            B:父的方法没有异常抛出,子的重写方法不能有异常抛出

            C:父的方法抛出多个异常,子的重写方法必须比父少或者小

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * 异常注意事项:

    * A:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)

    * B:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常

    * C:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws

    */

    class ExceptionDemo {

     

    }

     

    class Fu {

        public void show() throws Exception {

        }

     

        public void method() {

        }

    }

     

    class Zi extends Fu {

        @Override

        public void show() throws ArithmeticException {

     

        }

     

        @Override

        public void method() {

            // String s = "2014-11-20";

            // SimpleDateFormat sdf = new SimpleDateFormat();

            // Date d = sdf.parse(s);

            // System.out.println(d);

        }

    }

     

     

    2:File(掌握)

        (1)说明:

    IO流操作中大部分都是对文件的操作,所以Java就提供了File类供我们来操作文件

    File:文件和目录(文件夹)路径名的抽象表示形式,仅仅是指定路径的文件及文件夹的抽象表示,不进行操作

     

            

        (2)构造方法

            File(String pathname):根据一个路径得到File对象

            File(String parent, String child):根据一个目录和一个子文件/目录得到File对象

            File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

            A:File file = new File("e:\\demo\\a.txt");

            B:File file = new File("e:\\demo","a.txt");

            C:File file = new File("e:\\demo");

             File file2 = new File(file,"a.txt");

            D:构造方法代码演示

    import java.io.File;

     

    /*

    * 我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。

    * 而Java就提供了一个类File供我们使用。

    *

    * File:文件和目录(文件夹)路径名的抽象表示形式

                    //仅仅是指定路径的文件及文件夹的抽象表示,不进行操作

    * 构造方法:

    *         File(String pathname):根据一个路径得到File对象

    *         File(String parent, String child):根据一个目录和一个子文件/目录得到File对象

    *         File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

    */

    class FileDemo {

        public static void main(String[] args) {

            // File(String pathname):根据一个路径得到File对象

            // 把e:\\demo\\a.txt封装成一个File对象

            File file = new File("E:\\demo\\a.txt");

     

            // File(String parent, String child):根据一个目录和一个子文件/目录得到File对象

            File file2 = new File("E:\\demo", "a.txt");

     

            // File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象

            File file3 = new File("e:\\demo");

            File file4 = new File(file3, "a.txt");

     

            // 以上三种方式其实效果一样

        }

    }

     

     

        (3)File类的功能(自己补齐)

            A:创建功能

                        public
    boolean createNewFile():创建文件,如果存在该文件,就不创建

                        public
    boolean mkdir():创建文件夹,如果存在这样的文件夹,就不创建

    public
    boolean mkdirs():创建多层、缺省文件夹,如果父文件夹不存在,会帮你创建出来

                a:创建功能代码演示

    import java.io.File;

    import java.io.IOException;

     

    /*

    *创建功能:

    *public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了

    *public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了

    *public boolean mkdirs():创建多层、缺省文件夹,如果父文件夹不存在,会帮你创建出来

    *

    *骑白马的不一定是王子,可能是班长。

    *注意:你到底要创建文件还是文件夹,你最清楚,方法不要调错了。

    */

    class FileDemo {

        public static void main(String[] args) throws IOException {

            // 需求:我要在e盘目录下创建一个文件夹demo

            File file = new File("e:\\demo");

            System.out.println("mkdir:" + file.mkdir());

     

            // 需求:我要在e盘目录demo下创建一个文件a.txt

            File file2 = new File("e:\\demo\\a.txt");

            System.out.println("createNewFile:" + file2.createNewFile());

     

            // 需求:我要在e盘目录test下创建一个文件b.txt

            // Exception in thread "main" java.io.IOException: 系统找不到指定的路径。

            // 注意:要想在某个目录下创建内容,该目录首先必须存在。

            // File file3 = new File("e:\\test\\b.txt");

            // System.out.println("createNewFile:" + file3.createNewFile());

     

            // 需求:我要在e盘目录test下创建aaa目录

                

             File file4 = new File("e:\\test\\aaa");//test目录不存在,该方法不抛异常。返回false

             System.out.println("mkdir:" + file4.mkdir());

     

             File file5 = new File("e:\\test");

             File file6 = new File("e:\\test\\aaa");

             System.out.println("mkdir:" + file5.mkdir());//创建test

             System.out.println("mkdir:" + file6.mkdir());//在test里创建aaa

     

            // 其实我们有更简单的方法

            File file7 = new File("e:\\aaa\\bbb\\ccc\\ddd");

            System.out.println("mkdirs:" + file7.mkdirs());//mkdirs
    创建多层目录,缺省目录

     

            // 看下面的这个东西:

            File file8 = new File("e:\\liuyi\\a.txt");

            System.out.println("mkdirs:" + file8.mkdirs());

        }

    }

     

            B:删除功能

                        public
    boolean delete():删除文件或者文件夹

                b:删除功能代码演示

    import java.io.File;

    import java.io.IOException;

     

    /*

    * 删除功能:public boolean delete()

    *

    * 注意:

    *         A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。

    *         B:Java中的删除不走回收站。

    *         C:要删除一个文件夹,【该文件夹必须为空】请注意该文件夹内不能包含文件或者文件夹

    */

    class FileDemo {

        public static void main(String[] args) throws IOException {

            // 创建文件

            // File file = new File("e:\\a.txt");

            // System.out.println("createNewFile:" + file.createNewFile());//创建的是文件夹

     

            // 我不小心写成这个样子了

            File file = new File("a.txt");

            System.out.println("createNewFile:" + file.createNewFile());

     

            // 继续玩几个

            File file2 = new File("aaa\\bbb\\ccc");

            System.out.println("mkdirs:" + file2.mkdirs());

     

            // 删除功能:我要删除a.txt这个文件

            File file3 = new File("a.txt");//当前项目文件夹里

            System.out.println("delete:" + file3.delete());

     

            // 删除功能:我要删除ccc这个文件夹

            File file4 = new File("aaa\\bbb\\ccc");

            System.out.println("delete:" + file4.delete());

     

            // 删除功能:我要删除aaa文件夹//删除非空文件夹,返回false

            // File file5 = new File("aaa");

            // System.out.println("delete:" + file5.delete());

     

            File file6 = new File("aaa\\bbb");

            File file7 = new File("aaa");

            System.out.println("delete:" + file6.delete());

            System.out.println("delete:" + file7.delete());

        }

    }

     

            C:重命名功能

                        public
    boolean renameTo(File dest):重新命名此抽象路径名表示的文件

                                        如果路径名相同:就是改名

                                        如果路径名不同:就是改名并剪切

                c:重命名功能代码演示

    import java.io.File;

     

    /*

    * 重命名功能:public boolean renameTo(File dest)

    *         如果路径名相同,就是改名。

    *         如果路径名不同,就是改名并剪切。

    *

    * 路径以盘符开始:绝对路径    c:\\a.txt

    * 路径不以盘符开始:相对路径    a.txt

    */

    class FileDemo {

        public static void main(String[] args) {

            // 创建一个文件对象

            // File file = new File("林青霞.jpg");

            // // 需求:我要修改这个文件的名称为"东方不败.jpg"

            // File newFile = new File("东方不败.jpg");

            // System.out.println("renameTo:" + file.renameTo(newFile));

     

            File file2 = new File("东方不败.jpg");

            File newFile2 = new File("e:\\林青霞.jpg");

            System.out.println("renameTo:" + file2.renameTo(newFile2));

        }

    }

     

            D:判断功能

                        public
    boolean isDirectory():判断是否是目录

                        public
    boolean isFile():判断是否是文件

                        public
    boolean exists():判断是否存在

                        public
    boolean canRead():判断是否可读

                        public
    boolean canWrite():判断是否可写

                        public
    boolean isHidden():判断是否隐藏

                d:判断功能代码演示

    import java.io.File;

     

    /*

    * 判断功能:

    * public boolean isDirectory():判断是否是目录

    * public boolean isFile():判断是否是文件

    * public boolean exists():判断是否存在

    * public boolean canRead():判断是否可读

    * public boolean canWrite():判断是否可写

    * public boolean isHidden():判断是否隐藏

    */

    class FileDemo {

        public static void main(String[] args) {

            // 创建文件对象

            File file = new File("a.txt");

     

            System.out.println("isDirectory:" + file.isDirectory());// false

            System.out.println("isFile:" + file.isFile());// true

            System.out.println("exists:" + file.exists());// true

            System.out.println("canRead:" + file.canRead());// true

            System.out.println("canWrite:" + file.canWrite());// true

            System.out.println("isHidden:" + file.isHidden());// false

        }

    }

     

            E:获取功能

                        public String getAbsolutePath():获取绝对路径

                        public String getPath():获取相对路径

                        public String getName():获取文件或文件夹名称

                        public
    long length():获取长度,字节数

                        public
    long lastModified():获取最后一次的修改时间,毫秒值

                e:获取功能代码演示

    import java.io.File;

    import java.text.SimpleDateFormat;

    import java.util.Date;

     

    /*

    * 获取功能:

    * public String getAbsolutePath():获取绝对路径

    * public String getPath():获取相对路径

    * public String getName():获取名称

    * public long length():获取长度。字节数

    * public long lastModified():获取最后一次的修改时间,毫秒值

    */

    class FileDemo {

        public static void main(String[] args) {

            // 创建文件对象

            File file = new File("demo\\test.txt");

     

            System.out.println("getAbsolutePath:" + file.getAbsolutePath());

            System.out.println("getPath:" + file.getPath());

            System.out.println("getName:" + file.getName());

            System.out.println("length:" + file.length());

            System.out.println("lastModified:" + file.lastModified());

     

            // 1416471971031

            Date d = new Date(1416471971031L);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            String s = sdf.format(d);

            System.out.println(s);

        }

    }

     

            F:高级获取功能

                        public String[] list():获取指定目录下的所有文件获取文件夹的名称数组

                        public File[] listFiles()获取指定目录下所有文件或文件夹的File数组

                f:高级过去功能代码演示

    import java.io.File;

     

    /*

    * 获取功能:

    * public String[] list():获取指定目录下的所有文件或者文件夹的名称数组

    * public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

    */

    class FileDemo {

        public static void main(String[] args) {

            // 指定一个目录

            File file = new File("e:\\");

     

            // public String[] list():获取指定目录下的所有文件或者文件夹的名称数组

            String[] strArray = file.list();

            for (String s : strArray) {

                System.out.println(s);

            }

            System.out.println("------------");

     

            // public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组

            File[] fileArray = file.listFiles();

            for (File f : fileArray) {

                System.out.println(f.getName());

            }

        }

    }

     

            G:过滤器功能

                    public String[] list(FilenameFilter filter)

                    public File[] listFiles(FilenameFilter filter)

                g:过滤器功能代码演示

    import java.io.File;

    import java.io.FilenameFilter;

     

    /*

    * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称

    * A:先获取所有的,然后遍历的时候,依次判断,如果满足条件就输出。

    * B:获取的时候就已经是满足条件的了,然后输出即可。

    *

    * 要想实现这个效果,就必须学习一个接口:文件名称过滤器

    * public String[] list(FilenameFilter filter)

    * public File[] listFiles(FilenameFilter filter)

    */

    class FileDemo2 {

        public static void main(String[] args) {

            // 封装e判断目录

            File file = new File("e:\\");

     

            // 获取该目录下所有文件或者文件夹的String数组

            // public String[] list(FilenameFilter filter)

            String[] strArray = file.list(new FilenameFilter() {

                @Override

                public boolean accept(File dir, String name) {

                    // return false;

                    // return true;

                    // 通过这个测试,我们就知道了,到底把这个文件或者文件夹的名称加不加到数组中,取决于这里的返回值是true还是false

                    // 所以,这个的true或者false应该是我们通过某种判断得到的

                    // System.out.println(dir + "---" + name);

                    // File file = new File(dir, name);

                    // // System.out.println(file);

                    // boolean flag = file.isFile();

                    // boolean flag2 = name.endsWith(".jpg");

                    // return flag && flag2;

                    return new File(dir, name).isFile() && name.endsWith(".jpg");

                }

            });

     

            // 遍历

            for (String s : strArray) {

                System.out.println(s);

            }

        }

    }

     

        (4)案例:

            A:输出指定目录下指定后缀名的文件名称

                a:先获取所有的,在遍历的时候判断,再输出

                b:先判断,再获取,最后直接遍历输出即可

    import java.io.File;

     

    /*

    * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称

    *

    * 分析:

    *         A:封装e判断目录

    *         B:获取该目录下所有文件或者文件夹的File数组

    *         C:遍历该File数组,得到每一个File对象,然后判断

    *         D:是否是文件

    *             是:继续判断是否以.jpg结尾

    *                 是:就输出该文件名称

    *                 否:不搭理它

    *             否:不搭理它

    */

    class FileDemo {

        public static void main(String[] args) {

            // 封装e判断目录

            File file = new File("e:\\");

     

            // 获取该目录下所有文件或者文件夹的File数组

            File[] fileArray = file.listFiles();

     

            // 遍历该File数组,得到每一个File对象,然后判断

            for (File f : fileArray) {

                // 是否是文件

                if (f.isFile()) {

                    // 继续判断是否以.jpg结尾

                    if (f.getName().endsWith(".jpg")) {

                        // 就输出该文件名称

                        System.out.println(f.getName());

                    }

                }

            }

        }

    }

     

            B:批量修改文件名称

     

    import java.io.File;

     

    /*

    * 需求:把E:\评书\三国演义下面的视频名称修改为

    *         00?_介绍.avi

    *

    * 思路:

    *         A:封装目录

    *         B:获取该目录下所有的文件的File数组

    *         C:遍历该File数组,得到每一个File对象

    *         D:拼接一个新的名称,然后重命名即可。

    */

    class FileDemo {

        public static void main(String[] args) {

            // 封装目录

            File srcFolder = new File("E:\\评书\\三国演义");

     

            // 获取该目录下所有的文件的File数组

            File[] fileArray = srcFolder.listFiles();

     

            // 遍历该File数组,得到每一个File对象

            for (File file : fileArray) {

                // System.out.println(file);

                // E:\评书\三国演义\三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi

                // 改后:E:\评书\三国演义\001_桃园三结义.avi

                String name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi

     

                int index = name.indexOf("_");

                String numberString = name.substring(index + 1, index + 4);

                // System.out.println(numberString);

     

                // int startIndex = name.lastIndexOf('_');

                // int endIndex = name.lastIndexOf('.');

                // String nameString = name.substring(startIndex + 1, endIndex);

                // System.out.println(nameString);

                int endIndex = name.lastIndexOf('_');

                String nameString = name.substring(endIndex);

     

                String newName = numberString.concat(nameString); // 001_桃园三结义.avi

                // System.out.println(newName);

     

                File newFile = new File(srcFolder, newName); // E:\\评书\\三国演义\\001_桃园三结义.avi

     

                // 重命名即可

                file.renameTo(newFile);

            }

        }

    }

     

     

     

     

     

    第二十天

    1:递归(理解)

        (1)方法定义中调用方法本身的现象

            举例:老和尚给小和尚讲故事,我们学编程

    /*

    * 递归:方法定义中调用方法本身的现象

    *

    * 方法的嵌套调用,这不是递归。

    * Math.max(Math.max(a,b),c);

    *

    * public void show(int n) {

    *         if(n <= 0) {

    *             System.exit(0);

    *         }

    *         System.out.println(n);

    *         show(--n);

    * }

    *

    * 注意事项:

    *         A:递归一定要有出口,否则就是死递归

    *         B:递归的次数不能太多,否则就内存溢出

    *         C:构造方法不能递归使用

    *

    * 举例:

    *         A:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:

    *             从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:

    *                 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:

    *                     从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:

    *                         ...

    *                     庙挂了,或者山崩了

    *         B:学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费

    *              学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费

    *                 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费

    *                     学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费

    *                         ...

    *                     娶不到媳妇或者生不了娃娃    

    */

     

        (2)递归的注意事项

            A:要有出口,否则就是死递归

            B:次数不能过多,否则内存溢出

            C:构造方法不能递归使用

        (3)递归的案例:

            A:递归求阶乘

    /*

    的阶乘。

    * 下面的知识要知道:

    *         5! = 1*2*3*4*5

    *         5! = 5*4!

    *

    * 有几种方案实现呢?

    *         A:循环实现

    *         B:递归实现

    *             a:做递归要写一个方法

    *             b:出口条件

    *             c:规律

    */

    class DiGuiDemo {

        public static void main(String[] args) {

            int jc = 1;

            for (int x = 2; x <= 5; x++) {

                jc *= x;

            }

            System.out.println("5的阶乘是:" + jc);

            

            System.out.println("5的阶乘是:"+jieCheng(5));

        }

        

        /*

         * 做递归要写一个方法:

         *         返回值类型:int

         *         参数列表:int n

         * 出口条件:

         *         if(n == 1) {return 1;}

         * 规律:

         *         if(n != 1) {return n*方法名(n-1);}

         */

        public static int jieCheng(int n){

            if(n==1){

                return 1;

            }else {

                return n*jieCheng(n-1);

            }

        }

    }

     

            B:兔子问题

    /*

    个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?

    * 分析:我们要想办法找规律

    *             兔子对数

    * 第一个月:     1

    * 第二个月:    1

    * 第三个月:    2

    * 第四个月:    3    

    * 第五个月:    5

    * 第六个月:    8

    * ...

    *

    * 由此可见兔子对象的数据是:

    *         1,1,2,3,5,8...

    * 规则:

    *         A:从第三项开始,每一项是前两项之和

    *         B:而且说明前两项是已知的

    *

    * 如何实现这个程序呢?

    *         A:数组实现

    *         B:变量的变化实现

    *         C:递归实现

    *

    * 假如相邻的两个月的兔子对数是a,b

    * 第一个相邻的数据:a=1,b=1

    * 第二个相邻的数据:a=1,b=2

    * 第三个相邻的数据:a=2,b=3

    * 第四个相邻的数据:a=3,b=5

    * 看到了:下一次的a是以前的b,下一次是以前的a+b    

    */

    class DiGuiDemo2 {

        public static void main(String[] args) {

    :数组实现

            diGui1();

    :用变量的变化实现

            diGui2();

     

    :用递归实现

            System.out.println(fib(20));

        }

    :用变量的变化实现

        public static void diGui2() {

            int a = 1;

            int b = 1;

            for (int x = 0; x < 18; x++) {

                // 临时变量存储上一次的a

                int temp = a;

                a = b;

                b = temp + b;

            }

            System.out.println(b);

            System.out.println("----------------");

        }

     

    :用数组实现

        public static void diGui1() {

            // 定义一个数组

            int[] arr = new int[20];

            arr[0] = 1;

            arr[1] = 1;

            // arr[2] = arr[0] + arr[1];

            // arr[3] = arr[1] + arr[2];

            // ...

            for (int x = 2; x < arr.length; x++) {

                arr[x] = arr[x - 2] + arr[x - 1];

            }

            System.out.println(arr[19]);// 6765

            System.out.println("----------------");

        }

     

        /*

         * 方法: 返回值类型:int 

         *      参数列表:int n

         *      出口条件:
    第一个月是1,第二个月是1

         *      规律:
    从第三个月开始,每一个月是前两个月之和

         */

    :用递归实现

        public static int fib(int n) {

            if (n == 1 || n == 2) {

                return 1;

            } else {

                return fib(n - 1) + fib(n - 2);

            }

        }

    }

     

            C:递归输出指定目录下所有指定后缀名的文件绝对路径

    import java.io.File;

     

    /*

    * 需求:请大家把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。

    *

    * 分析:

    *         A:封装目录

    *         B:获取该目录下所有的文件或者文件夹的File数组

    *         C:遍历该File数组,得到每一个File对象

    *         D:判断该File对象是否是文件夹

    *             是:回到B

    *             否:继续判断是否以.java结尾

    *                 是:就输出该文件的绝对路径

    *                 否:不搭理它

    */

    class FilePathDemo {

        public static void main(String[] args) {

            // 封装目录

            File srcFolder = new File("E:\\JavaSE");

     

            // 递归功能实现

            getAllJavaFilePaths(srcFolder);

        }

     

        private static void getAllJavaFilePaths(File srcFolder) {

            // 获取该目录下所有的文件或者文件夹的File数组

            File[] fileArray = srcFolder.listFiles();

     

            // 遍历该File数组,得到每一个File对象

            for (File file : fileArray) {

                // 判断该File对象是否是文件夹

                if (file.isDirectory()) {

                    getAllJavaFilePaths(file);

                } else {

                    // 继续判断是否以.java结尾

                    if (file.getName().endsWith(".java")) {

                        // 就输出该文件的绝对路径

                        System.out.println(file.getAbsolutePath());

                    }

                }

            }

        }

    }

     

            D:递归删除带内容的目录(小心使用)

    import java.io.File;

     

    /*

    * 需求:递归删除带内容的目录

    * 说明:如果需要删除文件夹,那就需要在删除文件夹之前删除该文件夹里面的所有文件,才允许删除文件夹

    * 目录我已经给定:demo

    *

    * 分析:

    *         A:封装目录

    *         B:获取该目录下的所有文件或者文件夹的File数组

    *         C:遍历该File数组,得到每一个File对象

    *         D:判断该File对象是否是文件夹

    *             是:回到B

    *             否:就删除

    */

    class FileDeleteDemo {

        public static void main(String[] args) {

            // 封装目录

            File srcFolder = new File("demo");

            // 递归实现

            deleteFolder(srcFolder);

        }

     

        private static void deleteFolder(File srcFolder) {

            // 获取该目录下的所有文件或者文件夹的File数组

            File[] fileArray = srcFolder.listFiles();

     

            if (fileArray != null) {

                // 遍历该File数组,得到每一个File对象

                for (File file : fileArray) {

                    // 判断该File对象是否是文件夹

                    if (file.isDirectory()) {

                        deleteFolder(file);

                    } else {

                        // 这一步,仅仅是删除所有文件夹下的所有文件,而不是文件夹

                        System.out.println(file.getName() + "---" + file.delete());

                    }

                }

                //而这一步:是在删除了所有文件夹下的所有文件之后,再来删除所有的空文件夹的

                System.out.println(srcFolder.getName() + "---" + srcFolder.delete());

            }

        }

    }

     

    2:IO流(掌握)

        (1)IO用于在设备间进行数据传输的操作    

        (2)分类:

            A:流向

                输入流    读取数据

                输出流    写出数据

            B:数据类型

                字节流    

                        字节输入流 InputStream

                        字节输出流 OutputStream

                字符流

                        字符输入流 Reader

                        字符输出流 Writer

            注意:

                a:如果我们没有明确说明按照什么分,默认按照数据类型分。

                b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。

     

        (3)代码体现

            A:IO的分类

            

    import java.io.File;

    import java.io.FileNotFoundException;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * IO流的分类:

    *         流向:

    *             输入流    读取数据

    *             输出流
    写出数据

    *         数据类型:

    *             字节流

    *                 字节输入流    读取数据    InputStream

    *                 字节输出流    写出数据    OutputStream

    *             字符流

    *                 字符输入流    读取数据    Reader

    *                 字符输出流    写出数据    Writer

    *

    *         注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。

    *

    * 需求:我要往一个文本文件中输入一句话:"hello,io"

    *

    * 分析:

    *         A:这个操作最好是采用字符流来做,但是呢,字符流是在字节流之后才出现的,所以,今天我先讲解字节流如何操作。

    *         B:由于我是要往文件中写一句话,所以我们要采用字节输出流。

    *

    * 通过上面的分析后我们知道要使用:OutputStream

    * 但是通过查看API,我们发现该流对象是一个抽象类,不能实例化。

    * 所以,我们要找一个具体的子类。

    * 而我们要找的子类是什么名字的呢?这个时候,很简单,我们回想一下,我们是不是要往文件中写东西。

    * 文件是哪个单词:File

    * 然后用的是字节输出流,联起来就是:FileOutputStream

    * 注意:每种基类的子类都是以父类名作为后缀名。

    *         XxxOutputStream

    *         XxxInputStream

    *         XxxReader

    *         XxxWriter

    * 查看FileOutputStream的构造方法:

    *         FileOutputStream(File file)

    *        FileOutputStream(String name)

    *

    * 字节输出流操作步骤:

    *         A:创建字节输出流对象

    *         B:写数据

    *         C:释放资源

    */

    class FileOutputStreamDemo {

        public static void main(String[] args) throws IOException {

            // 创建字节输出流对象

            // 方法一:FileOutputStream(File file)

            //File file = new File("Filefile.txt");

            //FileOutputStream fos = new FileOutputStream(file);

            

            //方法二:
    FileOutputStream(String name)        

            FileOutputStream fos = new FileOutputStream("Stringname.txt");

            /*

             * 创建字节输出流对象了做了几件事情:

             * A:调用系统功能去创建文件

             * B:创建fos对象

             * C:把fos对象指向这个文件

             */

            

            //写数据

            fos.write("hello,IO".getBytes());

            fos.write("java".getBytes());

            

            //释放资源

            //关闭此文件输出流并释放与此流有关的所有系统资源。

            fos.close();

            /*

             * 为什么一定要close()呢?

             * A:让流对象变成垃圾,这样就可以被垃圾回收器回收了

             * B:通知系统去释放跟该文件相关的资源

             */

            //java.io.IOException: Stream Closed

            //fos.write("java".getBytes());

        }

    }

            B:创建字节输出流的步骤及相关方法

     

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 字节输出流操作步骤:

    * A:创建字节输出流对象

    * B:调用write()方法

    * C:释放资源

    *

    * public void write(int b):写一个字节

    * public void write(byte[] b):写一个字节数组

    * public void write(byte[] b,int off,int len):写一个字节数组的一部分

    */

    class FileOutputStreamDemo2 {

        public static void main(String[] args) throws IOException {

            // 创建字节输出流对象

            // OutputStream os = new FileOutputStream("fos2.txt"); // 多态

            FileOutputStream fos = new FileOutputStream("fos2.txt");

     

            // 调用write()方法

    对应的字符值 -- a

            // fos.write(57);

            // fos.write(55);

            

            //public void write(byte[] b):写一个字节数组

            byte[] bys={97,98,99,100,101};

            fos.write(bys);

            

            //public void write(byte[] b,int off,int len):写一个字节数组的一部分

            fos.write(bys,1,3);

            

            //释放资源

            fos.close();

        }

    }

            C:如何实现数据的换行

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 如何实现数据的换行?

    *         为什么现在没有换行呢?因为你值写了字节数据,并没有写入换行符号。

    *         如何实现呢?写入换行符号即可呗。

    *         刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?

    *         因为不同的系统针对不同的换行符号识别是不一样的?

    *         windows:\r\n

    *         linux:\n

    *         Mac:\r

    *         而一些常见的个高级记事本,是可以识别任意换行符号的。

    *

    * 如何实现数据的追加写入?

    *         用构造方法带第二个参数是true的情况即可

    */

    class FileOutputStreamDemo3 {

        public static void main(String[] args) throws IOException {

            // 创建字节输出流对象

            // FileOutputStream fos = new FileOutputStream("fos3.txt");

            // 创建一个向具有指定
    name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。

            FileOutputStream fos = new FileOutputStream("fos3.txt", true);

     

            // 写数据

            for (int x = 0; x < 10; x++) {

                fos.write(("hello" + x).getBytes());

                fos.write("\r\n".getBytes());

            }

     

            // 释放资源

            fos.close();

        }

    }

     

            D:
    加入异常处理的字节输出流操作

    import java.io.FileNotFoundException;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 加入异常处理的字节输出流操作

    */

    class FileOutputStreamDemo4 {

        public static void main(String[] args) {

            // 分开做异常处理

            // FileOutputStream fos = null;

            // try {

            // fos = new FileOutputStream("fos4.txt");

            // } catch (FileNotFoundException e) {

            // e.printStackTrace();

            // }

            //

            // try {

            // fos.write("java".getBytes());

            // } catch (IOException e) {

            // e.printStackTrace();

            // }

            //

            // try {

            // fos.close();

            // } catch (IOException e) {

            // e.printStackTrace();

            // }

     

            // 一起做异常处理

            // try {

            // FileOutputStream fos = new FileOutputStream("fos4.txt");

            // fos.write("java".getBytes());

            // fos.close();

            // } catch (FileNotFoundException e) {

            // e.printStackTrace();

            // } catch (IOException e) {

            // e.printStackTrace();

            // }

     

            // 改进版

            // 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值

            FileOutputStream fos = null;

            try {

                // fos = new FileOutputStream("z:\\fos4.txt");

                fos = new FileOutputStream("fos4.txt");

                fos.write("java".getBytes());

            } catch (FileNotFoundException e) {

                e.printStackTrace();

            } catch (IOException e) {

                e.printStackTrace();

            } finally {

                // 如果fos不是null,才需要close()

                if (fos != null) {

                    // 为了保证close()一定会执行,就放到这里了

                    try {

                        fos.close();

                    } catch (IOException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }

     

            

     

        (4)FileOutputStream写出数据

            A:构造方法以及常用方法

                public FileOutputStream(File file)        

                public FileOutputStream(String name)    

                

    public
    void write(byte
    b[], int
    off, int
    len):一次写一个字节数组的一部分

    public
    void write(byte
    b[]):一次写一个字节数组

    public
    void write(int
    b):一次写一个字节

            B:操作步骤

                a:创建字节输出流对象

                b:调用write()方法

                c:释放资源

                

            C:代码体现:

                FileOutputStream fos = new FileOutputStream("fos.txt");

                

                fos.write("hello".getBytes());

                

                fos.close();

                

            D:要注意的问题?

                a:创建字节输出流对象做了几件事情?

                    1.调用系统功能去创建文件

                    2.创建FileOutputStream 流对象

                    3.把FileOutputStream流对象指向该文件

                b:为什么要close()?

                    1.让流对象变成垃圾,这样就可以被垃圾回收器给回收啦

                    2.通知系统去释放与该文件相关的资源

                c:如何实现数据的换行?

                    答:说明:不同的系统针对不同的换行符的识别是不一样的

                        Windows:\r\n

                        Linux : \n

                        Mac : \r

                        而一些常见的高级记事本,是可以识别任意换行符的。

                d:如何实现数据的追加写入?

                    答:用构造方法带第二个参数是true的情况即可

                        即:FileOutputStream fos = new FileOutputStream("a.txt", true);

        (5)FileInputStream读取数据

            A:操作步骤

                a:创建字节输入流对象

                b:调用read()方法

                c:释放资源

                

            常用方法:

            public
    int read():一次读取一个字节

            public
    int read(byte
    b[]):一次读取一个字节数组

            B:FileInputStream 读取数据的两种方式比较图解

            C:代码体现:

                

    import java.io.FileInputStream;

    import java.io.IOException;

     

    /*

    * 字节输入流操作步骤:

    * A:创建字节输入流对象

    * B:调用read()方法读取数据,并把数据显示在控制台

    * C:释放资源

    *

    * 读取数据的方式:

    * A:int read():一次读取一个字节

    * B:int read(byte[] b):一次读取一个字节数组

    * 返回值其实是实际读取的字节个数

    */

    class FileInputStreamDemo {

        public static void main(String[] args) throws IOException {

            // FileInputStream(String name)

            // FileInputStream fis = new FileInputStream("fis.txt");

            FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");

     

    ::一次读取一个字节

            int by = 0;

            // 读取,赋值,判断

            while ((by = fis.read()) != -1) {

                System.out.print((char) by);

            }

            

    :一次读取一个字节数组

            byte[] b = new byte[1024];

            int len = 0;

            while((len = fis.read(b)) != -1) {

                System.out.print(new String(b, 0, len));

            }

            // 释放资源

            fis.close();

        }

    }

     

        (6)案例:2种实现

            A:复制文本文件

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:把c盘下的a.txt的内容复制到d盘下的b.txt中

    *

    * 数据源:

    *         c:\\a.txt    --    读取数据--    FileInputStream

    * 目的地:

    *         d:\\b.txt    --    写出数据    --    FileOutputStream

    */

    public class CopyFileDemo2 {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            FileInputStream fis = new FileInputStream("a.txt");

            // 封装目的地

            FileOutputStream fos = new FileOutputStream("b.txt");

     

        
     

    :一次读取一个字节

            // 复制数据

            int by = 0;

            while ((by = fis.read()) != -1) {

                fos.write(by);

            }

     

    :一次读取一个字节数组

            byte[] by1 = new byte[1024];

            int len = 0;

            while ((len = fis.read(by1)) != -1) {

                fos.write(by1, 0, len);

            }

            // 释放资源

            fos.close();

            fis.close();

        }

    }

     

            B:复制图片

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:把e:\\林青霞.jpg内容复制到当前项目目录下的mn.jpg中

    *

    * 数据源:

    *         e:\\林青霞.jpg    --读取数据--FileInputStream

    * 目的地:

    *         mn.jpg--写出数据--FileOutputStream

    */

    public class CopyImageDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            FileInputStream fis = new FileInputStream("e:\\林青霞.jpg");

            // 封装目的地

            FileOutputStream fos = new FileOutputStream("mn.jpg");

     

    :一次读取一个字节

            int by = 0;

            while ((by = fis.read()) != -1) {

                fos.write(by);

            }

            

    :一次读取一个字节数组

            byte[] by2 = new byte[1024];

            int len = 0;

            while((len = fis.read(by2)) != -1) {

                fos.write(by2, 0, len);

            }

     

            // 释放资源

            fos.close();

            fis.close();

        }

    }

     

            C:复制视频

            

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中

    *

    * 数据源:

    *         e:\\哥有老婆.mp4--读取数据--FileInputStream

    * 目的地:

    *         copy.mp4--写出数据--FileOutputStream

    */

    public class CopyMp4Demo {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            FileInputStream fis = new FileInputStream("e:\\哥有老婆.mp4");

            // 封装目的地

            FileOutputStream fos = new FileOutputStream("copy.mp4");

     

    :一次读取一个字节

            int by = 0;

            while ((by = fis.read()) != -1) {

                fos.write(by);

            }

            

    :一次读取一个字节数组

            byte[] by2 = new byte[1024];

            int len = 0;

            while((len = fis.read(by2)) != -1) {

                fos.write(by2, 0, len);

            }

            // 释放资源

            fos.close();

            fis.close();

        }

    }

     

        (7)字节缓冲区流

            A:BufferedOutputStream(OutputStream out)

    import java.io.BufferedOutputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。

    * 既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。

    * 这种类被称为:缓冲区类(高效类)

    * 写数据:BufferedOutputStream

    * 读数据:BufferedInputStream

    *

    * 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。

    *

    * 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?

    * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。

    */

    class BufferedOutputStreamDemo {

        public static void main(String[] args) throws IOException {

            // BufferedOutputStream(OutputStream out)

            // FileOutputStream fos = new FileOutputStream("bos.txt");

            // BufferedOutputStream bos = new BufferedOutputStream(fos);

            // 简单写法

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream("bos.txt"));

     

            // 写数据

            bos.write("hello".getBytes());

     

            // 释放资源

            bos.close();

        }

    }

     

            B:BufferedInputStream(InputStream in)

    import java.io.BufferedInputStream;

    import java.io.FileInputStream;

    import java.io.IOException;

     

    /*

    * 注意:虽然我们有两种方式可以读取,但是,请注意,这两种方式针对同一个对象在一个代码中只能使用一个。

    */

    class BufferedInputStreamDemo {

        public static void main(String[] args) throws IOException {

            // BufferedInputStream(InputStream in)

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    "bos.txt"));

     

            // 读取数据

            // int by = 0;

            // while ((by = bis.read()) != -1) {

            // System.out.print((char) by);

            // }

            // System.out.println("---------");

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                System.out.print(new String(bys, 0, len));

            }

     

            // 释放资源

            bis.close();

        }

    }

     

        (8)案例:4种实现

            A:复制文本文件

            B:复制图片

            C:复制视频

                四种方式:

        

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:把e:\\哥有老婆.mp4复制到当前项目目录下的copy.mp4中

    *

    * 字节流四种方式复制文件:

    毫秒

    毫秒

    毫秒

    毫秒

    */

    public class CopyMp4Demo {

        public static void main(String[] args) throws IOException {

            long start = System.currentTimeMillis();

            // method1("e:\\哥有老婆.mp4", "copy1.mp4");

            // method2("e:\\哥有老婆.mp4", "copy2.mp4");

            // method3("e:\\哥有老婆.mp4", "copy3.mp4");

            method4("e:\\哥有老婆.mp4", "copy4.mp4");

            long end = System.currentTimeMillis();

            System.out.println("共耗时:" + (end - start) + "毫秒");

        }

     

        // 高效字节流一次读写一个字节数组:

        public static void method4(String srcString, String destString)

                throws IOException {

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    srcString));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(destString));

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            bis.close();

        }

     

        // 高效字节流一次读写一个字节:

        public static void method3(String srcString, String destString)

                throws IOException {

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    srcString));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(destString));

     

            int by = 0;

            while ((by = bis.read()) != -1) {

                bos.write(by);

     

            }

     

            bos.close();

            bis.close();

        }

     

        // 基本字节流一次读写一个字节数组

        public static void method2(String srcString, String destString)

                throws IOException {

            FileInputStream fis = new FileInputStream(srcString);

            FileOutputStream fos = new FileOutputStream(destString);

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = fis.read(bys)) != -1) {

                fos.write(bys, 0, len);

            }

     

            fos.close();

            fis.close();

        }

     

        // 基本字节流一次读写一个字节

        public static void method1(String srcString, String destString)

                throws IOException {

            FileInputStream fis = new FileInputStream(srcString);

            FileOutputStream fos = new FileOutputStream(destString);

     

            int by = 0;

            while ((by = fis.read()) != -1) {

                fos.write(by);

            }

     

            fos.close();

            fis.close();

        }

    }

     

     

     

            

    3:自学字符流

        IO流分类

            字节流:

                InputStream

                    FileInputStream

                    BufferedInputStream

                OutputStream

                    FileOutputStream

                    BufferedOutputStream

            

            字符流:

                Reader

                    FileReader

                    BufferedReader

                Writer

                    FileWriter

                    BufferedWriter

     

     

     

     

     

     

     

    第二十一天

     

    1:字符流(掌握)

        (1)字节流操作中文数据不是特别的方便,所以就出现了转换流。

         转换流的作用就是把字节流转换字符流来使用。

        (2)转换流其实是一个字符流

            字符流 = 字节流 + 编码表

            1:InputStreamReader(转换流)

                    方法:int read():一次读取一个字符

                        Int read(char[] chs):一次读取一个字符数组

            

    import java.io.FileInputStream;

    import java.io.IOException;

    import java.io.InputStreamReader;

     

    /*

    * InputStreamReader的方法:

    * int read():一次读取一个字符

    * int read(char[] chs):一次读取一个字符数组

    */

    class InputStreamReaderDemo {

        public static void main(String[] args) throws IOException {

            // 创建对象

            InputStreamReader isr = new InputStreamReader(new FileInputStream(

                    "StringDemo.java"));

     

            // 一次读取一个字符

            // int ch = 0;

            // while ((ch = isr.read()) != -1) {

            // System.out.print((char) ch);

            // }

     

            // 一次读取一个字符数组

            char[] chs = new char[1024];

            int len = 0;

            while ((len = isr.read(chs)) != -1) {

                System.out.print(new String(chs, 0, len));

            }

     

            // 释放资源

            isr.close();

        }

    }

        
     

         2:OutputStreamWriter(转换流)

                    Public void write(int c):写入一个字符

                    Public void write(char[] ch):写入一个字符数组

                    Public void write(char[] ch, int off, int len):写入一个字符数组的一部分

                    Public void write(String str):一次写入一个字符串

                    Public void write(String str, int off, int len):写入一个字符串的一部分

     

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.OutputStreamWriter;

     

    /*

    * OutputStreamWriter的方法:

    * public void write(int c):写一个字符

    * public void write(char[] cbuf):写一个字符数组

    * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分

    * public void write(String str):写一个字符串

    * public void write(String str,int off,int len):写一个字符串的一部分

    *

    * 面试题:close()和flush()的区别?

    * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。

    * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。

    */

    class OutputStreamWriterDemo {

        public static void main(String[] args) throws IOException {

            // 创建对象

            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

                    "osw2.txt"));

     

            // 写数据

            // public void write(int c):写一个字符

            // osw.write('a');

            // osw.write(97);

            // 为什么数据没有进去呢?

            // 原因是:字符
    = 2字节

            // 文件中数据存储的基本单位是字节。

            // void flush()

     

            // public void write(char[] cbuf):写一个字符数组

            // char[] chs = {'a','b','c','d','e'};

            // osw.write(chs);

     

            // public void write(char[] cbuf,int off,int len):写一个字符数组的一部分

            // osw.write(chs,1,3);

     

            // public void write(String str):写一个字符串

            // osw.write("我爱林青霞");

     

            // public void write(String str,int off,int len):写一个字符串的一部分

            osw.write("我爱林青霞", 2, 3);

     

            // 刷新缓冲区

            osw.flush();

            // osw.write("我爱林青霞", 2, 3);

     

            // 释放资源

            osw.close();

            // java.io.IOException: Stream closed

            // osw.write("我爱林青霞", 2, 3);

        }

    }

     

        (3)编码表

            A:就是由字符和对应的数值组成的一张表

            B:常见的编码表

                ASCII

                ISO-8859-1

                GB2312

                GBK

                GB18030

                UTF-8

            C:字符串中的编码问题

                编码

                    String -- byte[]

                解码

                    byte[] – String

            StringDemo.java

    import java.io.UnsupportedEncodingException;

    import java.util.Arrays;

     

    /*

    * String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组

    * byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组

    *

    * 编码:把看得懂的变成看不懂的

    * String -- byte[]

    *

    * 解码:把看不懂的变成看得懂的

    * byte[] -- String

    *

    * 举例:谍战片(发电报,接电报)

    *

    * 码表:小本子

    *         字符    数值

    *

    * 要发送一段文字:

    *         今天晚上在老地方见

    *

    *         发送端:今 -- 数值 -- 二进制 -- 发出去

    *         接收端:接收 -- 二进制 -- 十进制 -- 数值 -- 字符 -- 今

    *

    *         今天晚上在老地方见

    *

    * 编码问题简单,只要编码解码的格式是一致的。

    */

    class StringDemo {

        public static void main(String[] args) throws UnsupportedEncodingException {

            String s = "你好";

     

            // String -- byte[]

            byte[] bys = s.getBytes(); // [-60, -29, -70, -61]

            // byte[] bys = s.getBytes("GBK");// [-60, -29, -70, -61]

            // byte[] bys = s.getBytes("UTF-8");// [-28, -67, -96, -27, -91, -67]

            System.out.println(Arrays.toString(bys));

     

            // byte[] -- String

            String ss = new String(bys); // 你好

            // String ss = new String(bys, "GBK"); // 你好

            // String ss = new String(bys, "UTF-8"); // ???

            System.out.println(ss);

        }

    }

     

        (4)IO流中的编码问题

            A:OutputStreamWriter(转换流)

                OutputStreamWriter(OutputStream os):默认编码,GBK

                OutputStreamWriter(OutputStream os,String charsetName):指定编码。

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.OutputStreamWriter;

     

    /*

    * OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流

    * OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流

    * 把字节流转换为字符流。

    * 字符流 = 字节流 +编码表。

    */

    class OutputStreamWriterDemo {

        public static void main(String[] args) throws IOException {

            // 创建对象

            // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

            // "osw.txt")); // 默认GBK

            // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

            // "osw.txt"), "GBK"); // 指定GBK

            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

                    "osw.txt"), "UTF-8"); // 指定UTF-8

            // 写数据

            osw.write("中国");

     

            // 释放资源

            osw.close();

        }

    }

     

            B:InputStreamReader(转换流)

                InputStreamReader(InputStream is):默认编码,GBK

                InputStreamReader(InputStream is,String charsetName):指定编码

                

    import java.io.FileInputStream;

    import java.io.IOException;

    import java.io.InputStreamReader;

     

    /*

    * InputStreamReader(InputStream is):用默认的编码读取数据

    * InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据

    */

    class InputStreamReaderDemo {

        public static void main(String[] args) throws IOException {

            // 创建对象

            // InputStreamReader isr = new InputStreamReader(new FileInputStream(

            // "osw.txt"));

     

            // InputStreamReader isr = new InputStreamReader(new FileInputStream(

            // "osw.txt"), "GBK");

     

            InputStreamReader isr = new InputStreamReader(new FileInputStream(

                    "osw.txt"), "UTF-8");

     

            // 读取数据

            // 一次读取一个字符

            int ch = 0;

            while ((ch = isr.read()) != -1) {

                System.out.print((char) ch);

            }

     

            // 释放资源

            isr.close();

        }

    }

     

            C:编码问题其实很简单

                编码只要一致即可

        (5)字符流

            Reader

                |--InputStreamReader

                    |--FileReader

                |--BufferedReader

            Writer

                |--OutputStreamWriter

                    |--FileWriter

                |--BufferedWriter

            1.FileReader的引入案例

                A:使用字符转换流实现文件的复制

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

     

    /*

    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

    *

    * 数据源:

    *         a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader

    * 目的地:

    *         b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter

    */

    class CopyFileDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            InputStreamReader isr = new InputStreamReader(new FileInputStream(

                    "a.txt"));

            // 封装目的地

            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(

                    "b.txt"));

     

            // 读写数据

            // int ch = 0;

            // while ((ch = isr.read()) != -1) {

            // osw.write(ch);

            // }

     

            char[] chs = new char[1024];

            int len = 0;

            while ((len = isr.read(chs)) != -1) {

                osw.write(chs, 0, len);

                // osw.flush();

            }

     

            // 释放资源

            osw.close();

            isr.close();

        }

    }

     

                B:使用转换流的子类FileReader和FileWriter实现复制文件

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 由于我们常见的操作都是使用本地默认编码,所以,不用指定编码。

    * 而转换流的名称有点长,所以,Java就提供了其子类供我们使用。

    * OutputStreamWriter = FileOutputStream + 编码表(GBK)

    * FileWriter = FileOutputStream + 编码表(GBK)

    *

    * InputStreamReader = FileInputStream + 编码表(GBK)

    * FileReader = FileInputStream + 编码表(GBK)

    *

    /*

    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

    *

    * 数据源:

    *         a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader

    * 目的地:

    *         b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter

    */

    class CopyFileDemo2 {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            FileReader fr = new FileReader("a.txt");

            // 封装目的地

            FileWriter fw = new FileWriter("b.txt");

     

            // 一次一个字符

            // int ch = 0;

            // while ((ch = fr.read()) != -1) {

            // fw.write(ch);

            // }

     

            // 一次一个字符数组

            char[] chs = new char[1024];

            int len = 0;

            while ((len = fr.read(chs)) != -1) {

                fw.write(chs, 0, len);

                fw.flush();

            }

     

            // 释放资源

            fw.close();

            fr.close();

        }

    }

            2:字符缓冲流(BufferedReader和BufferedWriter)的特有方法

    BufferedWriter:

                    public void newLine():根据系统来决定换行符,并插入换行符

                 BufferedReader:

                    public String readLine():一次读取一行数据

                    包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

     

     

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 字符缓冲流的特殊方法:

    * BufferedWriter:

    *         public void newLine():根据系统来决定换行符,并插入换行符

    * BufferedReader:

    *         public String readLine():一次读取一行数据

    *         包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

    */

    class BufferedDemo {

        public static void main(String[] args) throws IOException {

            // write();

            read();

        }

     

        private static void read() throws IOException {

            // 创建字符缓冲输入流对象

            BufferedReader br = new BufferedReader(new FileReader("bw2.txt"));

     

            // public String readLine():一次读取一行数据

            // String line = br.readLine();

            // System.out.println(line);

            // line = br.readLine();

            // System.out.println(line);

     

            // 最终版代码

            String line = null;

            while ((line = br.readLine()) != null) {

                System.out.println(line);

            }

            

            //释放资源

            br.close();

        }

     

        private static void write() throws IOException {

            // 创建字符缓冲输出流对象

            BufferedWriter bw = new BufferedWriter(new FileWriter("bw2.txt"));

            for (int x = 0; x < 10; x++) {

                bw.write("hello" + x);

                // bw.write("\r\n");

                bw.newLine();

                bw.flush();

            }

            bw.close();

        }

     

    }

     

            3:BufferedReader的介绍

    import java.io.BufferedReader;

    import java.io.FileReader;

    import java.io.IOException;

     

    /*

    * BufferedReader

    * 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

    * 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

    *

    * BufferedReader(Reader in)

    */

    class BufferedReaderDemo {

        public static void main(String[] args) throws IOException {

            // 创建字符缓冲输入流对象

            BufferedReader br = new BufferedReader(new FileReader("bw.txt"));

     

            // int ch = 0;

            // while ((ch = br.read()) != -1) {

            // System.out.print((char) ch);

            // }

     

            char[] chs = new char[1024];

            int len = 0;

            while ((len = br.read(chs)) != -1) {

                System.out.print(new String(chs, 0, len));

            }

     

            // 释放资源

            br.close();

        }

    }

        
     

            4:BufferedWriter的介绍

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 字符流为了高效读写,也提供了对应的字符缓冲流。

    * BufferedWriter:字符缓冲输出流

    * BufferedReader:字符缓冲输入流

    *

    * BufferedWriter:字符缓冲输出流

    * 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

    * 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

    */

    class BufferedWriterDemo {

        public static void main(String[] args) throws IOException {

            // BufferedWriter(Writer out)

            // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

            // new FileOutputStream("bw.txt")));

     

            BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));

     

            bw.write("hello");

            bw.write("world");

            bw.write("java");

            bw.flush();

     

            bw.close();

        }

    }

     

     

     

        (6)复制文本文件(5种方式)

            方式1:一次读取一个字符获取字符数组

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

    *

    * 数据源:

    *         a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader

    * 目的地:

    *         b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter

    */

    class CopyFileDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            BufferedReader br = new BufferedReader(new FileReader("a.txt"));

            // 封装目的地

            BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

     

            // 两种方式其中的一种一次读写一个字符数组

            char[] chs = new char[1024];

            int len = 0;

            while ((len = br.read(chs)) != -1) {

                bw.write(chs, 0, len);

                bw.flush();

            }

     

            // 释放资源

            bw.close();

            br.close();

        }

    }

     

            方式2:使用字符缓冲流BufferedWriter和BufferedReader的特有方法

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

    * 要求:使用BufferReader的特有方法:readLine(),一次读取一行数据

    * 数据源:

    *         a.txt -- 读取数据 --

    * 目的地:

    *         b.txt -- 写出数据 --

    */

    class CopyFileDemo2 {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            BufferedReader br = new BufferedReader(new FileReader("a.txt"));

            // 封装目的地

            BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

     

            // 读写数据

            String line = null;

            while ((line = br.readLine()) != null) {

                bw.write(line);

                bw.newLine();//写入一个换行符

                bw.flush();//刷新缓冲区

            }

     

            // 释放资源

            bw.close();

            br.close();

        }

    }

     

     

    2:IO流小结(掌握)

        IO流

            |--字节流

                |--字节输入流

                    InputStream

                        int read():一次读取一个字节

                        int read(byte[] bys):一次读取一个字节数组

                    

                        |--FileInputStream

                        |--BufferedInputStream

                |--字节输出流

                    OutputStream

                        void write(int by):一次写一个字节

                        void write(byte[] bys,int index,int len):一次写一个字节数组的一部分

                        

                        |--FileOutputStream

                        |--BufferedOutputStream

            |--字符流

                |--字符输入流

                    Reader

                        int read():一次读取一个字符

                        int read(char[] chs):一次读取一个字符数组

                        

                        |--InputStreamReader

                            |--FileReader

                        |--BufferedReader

                            String readLine():一次读取一个字符串

                |--字符输出流

                    Writer

                        void write(int ch):一次写一个字符

                        void write(char[] chs,int index,int len):一次写一个字符数组的一部分

                        

                        |--OutputStreamWriter

                            |--FileWriter

                        |--BufferedWriter

                            void newLine():写一个换行符

                            

                            void write(String line):一次写一个字符串

     

     

     

    3:案例(理解 练习一遍)

        A:复制文本文件
    5种方式(掌握)

        CopyFileDemo.java

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

     

    /*

    * 复制文本文件

    *

    * 分析:

    *         复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。

    *         通过该原理,我们知道我们应该采用字符流更方便一些。

    种方式,所以做这个题目我们有5种方式。推荐掌握第5种。

    * 数据源:

    *         c:\\a.txt -- FileReader -- BufferdReader

    * 目的地:

    *         d:\\b.txt -- FileWriter -- BufferedWriter

    */

    class CopyFileDemo {

        public static void main(String[] args) throws IOException {

            String srcString = "c:\\a.txt";

            String destString = "d:\\b.txt";

            // method1(srcString, destString);

            // method2(srcString, destString);

            // method3(srcString, destString);

            // method4(srcString, destString);

            method5(srcString, destString);

        }

     

    :字符缓冲流一次读写一个字符串

        private static void method5(String srcString, String destString)

                throws IOException {

            //创建缓冲区对象

            BufferedReader br = new BufferedReader(new FileReader(srcString));

            BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                //把字符串写入到文件中

                bw.write(line);

                //向文件中写入一个换行符

                bw.newLine();

                //刷新缓冲区

                bw.flush();

            }

            //关闭资源

            bw.close();

            br.close();

        }

     

    :字符缓冲流一次读写一个字符数组

        private static void method4(String srcString, String destString)

                throws IOException {

            //创建缓冲区对象

            BufferedReader br = new BufferedReader(new FileReader(srcString));

            BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

            //创建字符数组

            char[] chs = new char[1024];

            int len = 0;

            while ((len = br.read(chs)) != -1) {

                bw.write(chs, 0, len);

            }

            //关闭资源

            bw.close();

            br.close();

        }

     

    :字符缓冲流一次读写一个字符

        private static void method3(String srcString, String destString)

                throws IOException {

            //创建缓冲区对象

            BufferedReader br = new BufferedReader(new FileReader(srcString));

            BufferedWriter bw = new BufferedWriter(new FileWriter(destString));

     

            int ch = 0;

            while ((ch = br.read()) != -1) {

                bw.write(ch);

            }

            //关闭资源

            bw.close();

            br.close();

        }

     

    :基本字符流一次读写一个字符数组

        private static void method2(String srcString, String destString)

                throws IOException {

            //创建基本字符流对象

            FileReader fr = new FileReader(srcString);

            FileWriter fw = new FileWriter(destString);

            //创建一个字符数组

            char[] chs = new char[1024];

            int len = 0;

            while ((len = fr.read(chs)) != -1) {

                fw.write(chs, 0, len);

            }

            //关闭资源

            fw.close();

            fr.close();

        }

     

        // 基本字符流一次读写一个字符

        private static void method1(String srcString, String destString)

                throws IOException {

            //创建基本字符流对象

            FileReader fr = new FileReader(srcString);

            FileWriter fw = new FileWriter(destString);

     

            int ch = 0;

            while ((ch = fr.read()) != -1) {

                fw.write(ch);

            }

            //关闭资源

            fw.close();

            fr.close();

        }

    }

     

        B:复制图片(二进制流数据) 4种方式(掌握)

        CopyImageDemo.java

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 复制图片

    *

    * 分析:

    *         复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。

    *         通过该原理,我们知道我们应该采用字节流。

    种方式,所以做这个题目我们有4种方式。推荐掌握第4种。

    *

    * 数据源:

    *         c:\\a.jpg -- FileInputStream -- BufferedInputStream

    * 目的地:

    *         d:\\b.jpg -- FileOutputStream -- BufferedOutputStream

    */

    class CopyImageDemo {

        public static void main(String[] args) throws IOException {

            // 使用字符串作为路径

            // String srcString = "c:\\a.jpg";

            // String destString = "d:\\b.jpg";

            // 使用File对象做为参数

            File srcFile = new File("c:\\a.jpg");

            File destFile = new File("d:\\b.jpg");

     

            // method1(srcFile, destFile);

            // method2(srcFile, destFile);

            // method3(srcFile, destFile);

            method4(srcFile, destFile);

        }

     

    :字节缓冲流一次读写一个字节数组

        private static void method4(File srcFile, File destFile) throws IOException {

            //创建字节缓冲流对象

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    srcFile));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(destFile));

            //创建byte数组

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

            //关闭资源

            bos.close();

            bis.close();

        }

     

    :字节缓冲流一次读写一个字节

        private static void method3(File srcFile, File destFile) throws IOException {

            //创建字节缓冲流对象

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    srcFile));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(destFile));

     

            int by = 0;

            while ((by = bis.read()) != -1) {

                bos.write(by);

            }

            //关闭资源

            bos.close();

            bis.close();

        }

     

    :基本字节流一次读写一个字节数组

        private static void method2(File srcFile, File destFile) throws IOException {

            //创建基本字节流对象

            FileInputStream fis = new FileInputStream(srcFile);

            FileOutputStream fos = new FileOutputStream(destFile);

            //创建字节数组

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = fis.read(bys)) != -1) {

                fos.write(bys, 0, len);

            }

            //关闭资源

            fos.close();

            fis.close();

        }

     

    :基本字节流一次读写一个字节

        private static void method1(File srcFile, File destFile) throws IOException {

            //创建基本字节流对象

            FileInputStream fis = new FileInputStream(srcFile);

            FileOutputStream fos = new FileOutputStream(destFile);

     

            int by = 0;

            while ((by = fis.read()) != -1) {

                fos.write(by);

            }

            //关闭资源

            fos.close();

            fis.close();

        }

    }

     

        C:把集合中的数据存储到文本文件

        ArrayListToFileDemo.java

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.util.ArrayList;

     

    /*

    * 需求:把ArrayList集合中的字符串数据存储到文本文件

    *

    * 分析:

    *         通过题目的意思我们可以知道如下的一些内容,

    *             ArrayList集合里存储的是字符串。

    *             遍历ArrayList集合,把数据获取到。

    *             然后存储到文本文件中。

    *             文本文件说明使用字符流。

    *

    * 数据源:

    *         ArrayList<String> -- 遍历得到每一个字符串数据

    * 目的地:

    *         a.txt -- FileWriter -- BufferedWriter

    */

    class ArrayListToFileDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据与(创建集合对象)

            ArrayList<String> array = new ArrayList<String>();

            array.add("hello");

            array.add("world");

            array.add("java");

     

            // 封装目的地

            BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

     

            // 遍历集合

            for (String s : array) {

                // 写数据

                bw.write(s);

                //向文件中写入一个换行符

                bw.newLine();

                bw.flush();

            }

     

            // 释放资源

            bw.close();

        }

    }

     

        D:把文本文件中的数据读取到集合并遍历集合

        FileToArrayListDemo.java

    import java.io.BufferedReader;

    import java.io.FileReader;

    import java.io.IOException;

    import java.util.ArrayList;

     

    /*

    * 需求:从文本文件中读取数据(每一行为一个字符串数据)到集合中,并遍历集合

    *

    * 分析:

    *         通过题目的意思我们可以知道如下的一些内容,

    *             数据源是一个文本文件。

    *             目的地是一个集合。

    *             而且元素是字符串。

    *

    * 数据源:

    *         b.txt -- FileReader -- BufferedReader

    * 目的地:

    *         ArrayList<String>

    */

    class FileToArrayListDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据源

            BufferedReader br = new BufferedReader(new FileReader("b.txt"));

            // 封装目的地(创建集合对象)

            ArrayList<String> array = new ArrayList<String>();

     

            // 读取数据存储到集合中

            String line = null;

            while ((line = br.readLine()) != null) {

                array.add(line);

            }

     

            // 释放资源

            br.close();

     

            // 遍历集合

            for (String s : array) {

                System.out.println(s);

            }

        }

    }

     

        E: 文本文件中存储了几个名称,请大家写一个程序实现随机获取一个人的名字

        GetName.java

    import java.io.BufferedReader;

    import java.io.FileReader;

    import java.io.IOException;

    import java.util.ArrayList;

    import java.util.Random;

     

    /*

    * 需求:我有一个文本文件中存储了几个名称,请大家写一个程序实现随机获取一个人的名字。

    *

    * 分析:

    *         A:把文本文件中的数据存储到集合中

    *         B:随机产生一个索引

    *         C:根据该索引获取一个值

    */

    class GetName {

        public static void main(String[] args) throws IOException {

            // 把文本文件中的数据存储到集合中

            BufferedReader br = new BufferedReader(new FileReader("b.txt"));

            ArrayList<String> array = new ArrayList<String>();

            String line = null;

            while ((line = br.readLine()) != null) {

                array.add(line);

            }

            br.close();

     

            // 随机产生一个索引

            Random r = new Random();

            int index = r.nextInt(array.size());

     

            // 根据该索引获取一个值

            String name = array.get(index);

            System.out.println("该幸运者是:" + name);

        }

    }

     

        F:复制单级文件夹

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:复制单极文件夹

    *

    * 数据源:e:\\demo

    * 目的地:e:\\test

    *

    * 分析:

    *         A:封装目录

    *         B:获取该目录下的所有文件的File数组

    *         C:遍历该File数组,得到每一个File对象

    *         D:把该File进行复制

    */

    class CopyFolderDemo {

        public static void main(String[] args) throws IOException {

            // 封装目录

            File srcFolder = new File("e:\\demo");

            // 封装目的地

            File destFolder = new File("e:\\test");

            // 如果目的地文件夹不存在,就创建

            if (!destFolder.exists()) {

                destFolder.mkdir();

            }

     

            // 获取该目录下的所有文本的File数组

            File[] fileArray = srcFolder.listFiles();

     

            // 遍历该File数组,得到每一个File对象

            for (File file : fileArray) {

                // System.out.println(file);

                // 数据源:e:\\demo\\e.mp3

                // 目的地:e:\\test\\e.mp3

                String name = file.getName(); // e.mp3

                File newFile = new File(destFolder, name); // e:\\test\\e.mp3

     

                copyFile(file, newFile);

            }

        }

        //复制文件:将一个地方的文件复制到另外一个地方

        private static void copyFile(File file, File newFile) throws IOException {

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    file));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(newFile));

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            bis.close();

        }

    }

     

        G:复制单级文件夹中指定的文件并修改名称

            回顾一下批量修改名称

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.FilenameFilter;

    import java.io.IOException;

     

    /*

    * 需求:复制指定目录下的指定文件,并修改后缀名。

    * 指定的文件是:.java文件。

    * 指定的后缀名是:.jad

    * 指定的目录是:jad

    *

    * 数据源:e:\\java\\A.java

    * 目的地:e:\\jad\\A.jad

    *

    * 分析:

    *         A:封装目录

    *         B:获取该目录下的java文件的File数组

    *         C:遍历该File数组,得到每一个File对象

    *         D:把该File进行复制

    *         E:在目的地目录下改名

    */

    class CopyFolderDemo {

        public static void main(String[] args) throws IOException {

            // 封装目录

            File srcFolder = new File("e:\\java");

            // 封装目的地

            File destFolder = new File("e:\\jad");

            // 如果目的地目录不存在,就创建

            if (!destFolder.exists()) {

                destFolder.mkdir();

            }

     

            // 获取该目录下的java文件的File数组

            File[] fileArray = srcFolder.listFiles(new FilenameFilter() {

                @Override

                public boolean accept(File dir, String name) {

                    return new File(dir, name).isFile() && name.endsWith(".java");

                }

            });

     

            // 遍历该File数组,得到每一个File对象

            for (File file : fileArray) {

                // System.out.println(file);

                // 数据源:e:\java\DataTypeDemo.java

                // 目的地:e:\\jad\DataTypeDemo.java

                String name = file.getName();

                File newFile = new File(destFolder, name);

                copyFile(file, newFile);

            }

     

            // 在目的地目录下改名

            File[] destFileArray = destFolder.listFiles();

            for (File destFile : destFileArray) {

                // System.out.println(destFile);

                // e:\jad\DataTypeDemo.java

                // e:\\jad\\DataTypeDemo.jad

                String name =destFile.getName(); //DataTypeDemo.java

                String newName = name.replace(".java", ".jad");//DataTypeDemo.jad

                

                File newFile = new File(destFolder,newName);

                destFile.renameTo(newFile);

            }

        }

     

        private static void copyFile(File file, File newFile) throws IOException {

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    file));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(newFile));

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            bis.close();

        }

    }

     

        H:复制多级文件夹

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 需求:复制多极文件夹

    *

    * 数据源:E:\JavaSE\day21\code\demos

    * 目的地:E:\\

    *

    * 分析:

    *         A:封装数据源File

    *         B:封装目的地File

    *         C:判断该File是文件夹还是文件

    *             a:是文件夹

    *                 就在目的地目录下创建该文件夹

    *                 获取该File对象下的所有文件或者文件夹File对象

    *                 遍历得到每一个File对象

    *                 回到C

    *             b:是文件

    *                 就复制(字节流)

    */

    class CopyFoldersDemo {

        public static void main(String[] args) throws IOException {

            // 封装数据源File

            File srcFile = new File("E:\\JavaSE\\day21\\code\\demos");

            // 封装目的地File

            File destFile = new File("E:\\");

     

            // 复制文件夹的功能

            copyFolder(srcFile, destFile);

        }

     

        private static void copyFolder(File srcFile, File destFile)

                throws IOException {

            // 判断该File是文件夹还是文件

            if (srcFile.isDirectory()) {

                // 文件夹

                File newFolder = new File(destFile, srcFile.getName());

                newFolder.mkdir();

     

                // 获取该File对象下的所有文件或者文件夹File对象

                File[] fileArray = srcFile.listFiles();

                for (File file : fileArray) {

                    copyFolder(file, newFolder);

                }

            } else {

                // 文件

                File newFile = new File(destFile, srcFile.getName());

                copyFile(srcFile, newFile);

            }

        }

     

        private static void copyFile(File srcFile, File newFile) throws IOException {

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    srcFile));

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream(newFile));

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            bis.close();

        }

    }

     

        I:键盘录入学生信息按照总分从高到低存储到文本文件

            1.Student.java

    public class Student {

        // 姓名

        private String name;

        // 语文成绩

        private int chinese;

        // 数学成绩

        private int math;

        // 英语成绩

        private int english;

     

        public Student() {

            super();

        }

     

        public Student(String name, int chinese, int math, int english) {

            super();

            this.name = name;

            this.chinese = chinese;

            this.math = math;

            this.english = english;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getChinese() {

            return chinese;

        }

     

        public void setChinese(int chinese) {

            this.chinese = chinese;

        }

     

        public int getMath() {

            return math;

        }

     

        public void setMath(int math) {

            this.math = math;

        }

     

        public int getEnglish() {

            return english;

        }

     

        public void setEnglish(int english) {

            this.english = english;

        }

        //获取成绩的总分

        public int getSum() {

            return this.chinese + this.math + this.english;

        }

    }

            2.StudentDemo.java

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.util.Comparator;

    import java.util.Scanner;

    import java.util.TreeSet;

     

    /*

    个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件

    *

    * 分析:

    *         A:创建学生类

    *         B:创建集合对象

    *             TreeSet<Student>

    *         C:键盘录入学生信息存储到集合

    *         D:遍历集合,把数据写到文本文件

    */

    class StudentDemo {

        public static void main(String[] args) throws IOException {

            // 创建集合对象

            TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

                @Override

                public int compare(Student s1, Student s2) {

                    int num = s2.getSum() - s1.getSum();

                    int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;

                    int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;

                    int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;

                    int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())

                            : num4;

                    return num5;

                }

            });

     

            // 键盘录入学生信息存储到集合

            for (int x = 1; x <= 5; x++) {

                Scanner sc = new Scanner(System.in);

                System.out.println("请录入第" + x + "个的学习信息");

                System.out.println("姓名:");

                String name = sc.nextLine();

                System.out.println("语文成绩:");

                int chinese = sc.nextInt();

                System.out.println("数学成绩:");

                int math = sc.nextInt();

                System.out.println("英语成绩:");

                int english = sc.nextInt();

     

                // 创建学生对象

                Student s = new Student();

                s.setName(name);

                s.setChinese(chinese);

                s.setMath(math);

                s.setEnglish(english);

     

                // 把学生信息添加到集合

                ts.add(s);

            }

     

            // 遍历集合,把数据写到文本文件

            BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));

            bw.write("学生信息如下:");

            bw.newLine();

            bw.flush();

            bw.write("姓名,语文成绩,数学成绩,英语成绩");

            bw.newLine();

            bw.flush();

            for (Student s : ts) {

                StringBuilder sb = new StringBuilder();

                sb.append(s.getName()).append(",").append(s.getChinese())

                        .append(",").append(s.getMath()).append(",")

                        .append(s.getEnglish());

                bw.write(sb.toString());

                bw.newLine();

                bw.flush();

            }

            // 释放资源

            bw.close();

            System.out.println("学习信息存储完毕");

        }

    }

     

     

        J:把某个文件中的字符串排序后输出到另一个文本文件中

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.util.Arrays;

     

    /*

    * 已知s.txt文件中有这样的一个字符串:"hcexfgijkamdnoqrzstuvwybpl"

    * 请编写程序读取数据内容,把数据排序后写入ss.txt中。

    *

    * 分析:

    *         A:把s.txt这个文件给做出来

    *         B:读取该文件的内容,存储到一个字符串中

    *         C:把字符串转换为字符数组

    *         D:对字符数组进行排序

    *         E:把排序后的字符数组转换为字符串

    *         F:把字符串再次写入ss.txt中

    */

    class StringDemo {

        public static void main(String[] args) throws IOException {

            // 读取该文件的内容,存储到一个字符串中

            BufferedReader br = new BufferedReader(new FileReader("s.txt"));

            String line = br.readLine();

            br.close();

     

            // 把字符串转换为字符数组

            char[] chs = line.toCharArray();

     

            // 对字符数组进行排序

            Arrays.sort(chs);

     

            // 把排序后的字符数组转换为字符串

            String s = new String(chs);

     

            // 把字符串再次写入ss.txt中

            BufferedWriter bw = new BufferedWriter(new FileWriter("ss.txt"));

            bw.write(s);

            bw.newLine();

            bw.flush();

     

            bw.close();

        }

    }

     

        K:用Reader模拟BufferedReader的特有功能

            1:MyBufferedReader.java

    import java.io.IOException;

    import java.io.Reader;

     

    /*

    * 用Reader模拟BufferedReader的readLine()功能

    *

    * readLine():一次读取一行,根据换行符判断是否结束,只返回内容,不返回换行符

    */

    public class MyBufferedReader {

        private Reader r;

     

        public MyBufferedReader(Reader r) {

            this.r = r;

        }

     

        /*

         * 思考:写一个方法,返回值是一个字符串。

         */

        public String readLine() throws IOException {

            /*

             * 我要返回一个字符串,我该怎么办呢? 我们必须去看看r对象能够读取什么东西呢? 两个读取方法,一次读取一个字符或者一次读取一个字符数组

             * 那么,我们要返回一个字符串,用哪个方法比较好呢? 我们很容易想到字符数组比较好,但是问题来了,就是这个数组的长度是多长呢?

             * 根本就没有办法定义数组的长度,你定义多长都不合适。 所以,只能选择一次读取一个字符。

             * 但是呢,这种方式的时候,我们再读取下一个字符的时候,上一个字符就丢失了 所以,我们又应该定义一个临时存储空间把读取过的字符给存储起来。

             * 这个用谁比较和是呢?数组,集合,字符串缓冲区三个可供选择。

             * 经过简单的分析,最终选择使用字符串缓冲区对象。并且使用的是StringBuilder

             */

            StringBuilder sb = new StringBuilder();

     

            // 做这个读取最麻烦的是判断结束,但是在结束之前应该是一直读取,直到-1

            
     

            

            /*

            hello

            world

            java    

            

            104101108108111

            119111114108100

            1069711897

             */

            

            int ch = 0;

            while ((ch = r.read()) != -1) { //104,101,108,108,111

                if (ch == '\r') {

                    continue;

                }

     

                if (ch == '\n') {

                    return sb.toString(); //hello

                } else {

                    sb.append((char)ch); //hello

                }

            }

     

            if (sb.length() > 0) {

                return sb.toString();

            }

     

            return null;

        }

     

        /*

         * 先写一个关闭方法

         */

        public void close() throws IOException {

            this.r.close();

        }

    }

     

            2:MyBufferedReaderDemo.java

    import java.io.FileReader;

    import java.io.IOException;

     

    /*

    * 测试MyBufferedReader的时候,你就把它当作BufferedReader一样的使用

    */

    public class MyBufferedReaderDemo {

        public static void main(String[] args) throws IOException {

            MyBufferedReader mbr = new MyBufferedReader(new FileReader("my.txt"));

     

            String line = null;

            while ((line = mbr.readLine()) != null) {

                System.out.println(line);

            }

     

            mbr.close();

     

            // System.out.println('\r' + 0); // 13

            // System.out.println('\n' + 0);// 10

        }

    }

     

        L:模拟LineNumberReader的特有功能

            1.LineNumberReaderDemo.java

    import java.io.FileReader;

    import java.io.IOException;

    import java.io.LineNumberReader;

     

    /*

    * BufferedReader

    *         |--LineNumberReader

    *             public int getLineNumber()获得当前行号。

    *             public void setLineNumber(int lineNumber):设置当前行号

    */

    public class LineNumberReaderDemo {

        public static void main(String[] args) throws IOException {

            LineNumberReader lnr = new LineNumberReader(new FileReader("my.txt"));

     

    开始才比较好

            // lnr.setLineNumber(10);

     

            // System.out.println(lnr.getLineNumber());

            // System.out.println(lnr.getLineNumber());

            // System.out.println(lnr.getLineNumber());

     

            String line = null;

            while ((line = lnr.readLine()) != null) {

                System.out.println(lnr.getLineNumber() + ":" + line);

            }

     

            lnr.close();

        }

    }

     

            2.MyLineNumberReader.java

    import java.io.IOException;

    import java.io.Reader;

     

    public class MyLineNumberReader {

        private Reader r;

        private int lineNumber = 0;

     

        public MyLineNumberReader(Reader r) {

            this.r = r;

        }

     

        public int getLineNumber() {

            // lineNumber++;

            return lineNumber;

        }

     

        public void setLineNumber(int lineNumber) {

            this.lineNumber = lineNumber;

        }

     

        public String readLine() throws IOException {

            lineNumber++;

     

            StringBuilder sb = new StringBuilder();

     

            int ch = 0;

            while ((ch = r.read()) != -1) {

                if (ch == '\r') {

                    continue;

                }

     

                if (ch == '\n') {

                    return sb.toString();

                } else {

                    sb.append((char) ch);

                }

            }

     

            if (sb.length() > 0) {

                return sb.toString();

            }

     

            return null;

        }

     

        public void close() throws IOException {

            this.r.close();

        }

    }

     

            3.MyLineNumberReaderTest.java

    import java.io.FileReader;

    import java.io.IOException;

     

    public class MyLineNumberReaderTest {

        public static void main(String[] args) throws IOException {

            // MyLineNumberReader mlnr = new MyLineNumberReader(new FileReader(

            // "my.txt"));

     

            MyLineNumberReader2 mlnr = new MyLineNumberReader2(new FileReader(

                    "my.txt"));

     

            // mlnr.setLineNumber(10);

     

            // System.out.println(mlnr.getLineNumber());

            // System.out.println(mlnr.getLineNumber());

            // System.out.println(mlnr.getLineNumber());

     

            String line = null;

            while ((line = mlnr.readLine()) != null) {

                System.out.println(mlnr.getLineNumber() + ":" + line);

            }

     

            mlnr.close();

        }

    }

     

     

    第二十二天

     

    1:登录注册IO版本案例(掌握)

        要求,对着写一遍。

        

        cn.itcast.pojo User

        cn.itcast.dao UserDao

        cn.itcast.dao.impl UserDaoImpl(实现我不管)

        cn.itcast.game GuessNumber

        cn.itcast.test    UserTest

     

    2:数据操作流(操作基本类型数据的流)(理解)

        (1)定义:

    可以操作基本类型的数据

        (2)流对象名称    

            public DataInputStream(InputStream in)    

            public DataOutputStream(OutputStream out)

    (3)代码演示:

    import java.io.DataInputStream;

    import java.io.DataOutputStream;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    /*

    * 可以读写基本数据类型的数据

    * 数据输入流:DataInputStream

    *             DataInputStream(InputStream in)

    * 数据输出流:DataOutputStream

    *             DataOutputStream(OutputStream out)

    */

    class DataStreamDemo {

        public static void main(String[] args) throws IOException {

            // 写

            // write();

     

            // 读

            read();

        }

     

        private static void read() throws IOException {

            // DataInputStream(InputStream in)

            // 创建数据输入流对象

            DataInputStream dis = new DataInputStream(

                    new FileInputStream("dos.txt"));

     

            // 读数据

            byte b = dis.readByte();

            short s = dis.readShort();

            int i = dis.readInt();

            long l = dis.readLong();

            float f = dis.readFloat();

            double d = dis.readDouble();

            char c = dis.readChar();

            boolean bb = dis.readBoolean();

     

            // 释放资源

            dis.close();

     

            System.out.println(b);

            System.out.println(s);

            System.out.println(i);

            System.out.println(l);

            System.out.println(f);

            System.out.println(d);

            System.out.println(c);

            System.out.println(bb);

        }

     

        private static void write() throws IOException {

            // DataOutputStream(OutputStream out)

            // 创建数据输出流对象

            DataOutputStream dos = new DataOutputStream(new FileOutputStream(

                    "dos.txt"));

     

            // 写数据了

            dos.writeByte(10);

            dos.writeShort(100);

            dos.writeInt(1000);

            dos.writeLong(10000);

            dos.writeFloat(12.34F);

            dos.writeDouble(12.56);

            dos.writeChar('a');

            dos.writeBoolean(true);

     

            // 释放资源

            dos.close();

        }

    }

     

    3:内存操作流(理解)

        (1)说明:

    有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。

        (2)三种类型

            A:ByteArrayInputStream,ByteArrayOutputStream

            B:CharArrayReader,CharArrayWriter

            C:StringReader,StringWriter

        (3)代码演示:

    import java.io.ByteArrayInputStream;

    import java.io.ByteArrayOutputStream;

    import java.io.IOException;

     

    /*

    * 内存操作流:用于处理临时存储信息的,程序结束,数据就从内存中消失。

    * 字节数组:

    *         ByteArrayInputStream

    *         ByteArrayOutputStream

    * 字符数组:

    *         CharArrayReader

    *         CharArrayWriter

    * 字符串:

    *         StringReader

    *         StringWriter

    */

    class ByteArrayStreamDemo {

        public static void main(String[] args) throws IOException {

            // 写数据

            // ByteArrayOutputStream()

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

     

            // 写数据

            for (int x = 0; x < 10; x++) {

                baos.write(("hello" + x).getBytes());

            }

     

            // 释放资源

            // 通过查看源码我们知道这里什么都没做,所以根本需要close()

            // baos.close();

     

            // public byte[] toByteArray()

            byte[] bys = baos.toByteArray();

     

            // 读数据

            // ByteArrayInputStream(byte[] buf)

            ByteArrayInputStream bais = new ByteArrayInputStream(bys);

     

            int by = 0;

            while ((by = bais.read()) != -1) {

                System.out.print((char) by);

            }

     

            // bais.close();

        }

    }

     

     

     

    4:打印流(掌握)

        (1)字节打印流,字符打印流

                字节打印流:PrintStream

                字符打印流:PrintWriter

            代码演示:

    import java.io.IOException;

    import java.io.PrintWriter;

     

    /*

    * 打印流

    * 字节流打印流    PrintStream

    * 字符打印流    PrintWriter

    *

    * 打印流的特点:

    *         A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。

    *         B:可以操作任意类型的数据。

    *         C:如果启动了自动刷新,能够自动刷新。

    *         D:该流是可以直接操作文本文件的。

    *             哪些流对象是可以直接操作文本文件的呢?

    *             FileInputStream

    *             FileOutputStream

    *             FileReader

    *             FileWriter

    *             PrintStream

    *             PrintWriter

    *             看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。

    *

    *             流:

    *                 基本流:就是能够直接读写文件的

    *                 高级流:在基本流基础上提供了一些其他的功能

    */

    class PrintWriterDemo {

        public static void main(String[] args) throws IOException {

            // 作为Writer的子类使用

            PrintWriter pw = new PrintWriter("pw.txt");

     

            pw.write("hello");

            pw.write("world");

            pw.write("java");

            

            pw.close();

        }

    }

     

        (2)特点:

            A:只操作目的地,不操作数据源

            B:可以操作任意类型的数据

            C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新

            D:可以直接操作文件

                问题:哪些流可以直接操作文件呢?

                看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的

        E:代码演示

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.PrintWriter;

     

    /*

    * 1:可以操作任意类型的数据。

    *         print()

    *         println()

    * 2:启动自动刷新

    *         PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

    *         这时应该调用println()的方法才可以启动自动刷新

    *         这个时候不仅仅自动刷新了,还实现了数据的换行。

    *

    *         println()

    *        其实等价于于:

    *        bw.write();

    *        bw.newLine();        

    *        bw.flush();

    */

    class PrintWriterDemo2 {

        public static void main(String[] args) throws IOException {

            // 创建打印流对象

            // PrintWriter pw = new PrintWriter("pw2.txt");

            PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

     

            // write()是搞不定的,怎么办呢?

            // 我们就应该看看它的新方法

            // pw.print(true);

            // pw.print(100);

            // pw.print("hello");

     

            pw.println("hello");

            pw.println(true);

            pw.println(100);

     

            pw.close();

        }

    }

     

        (3)复制文本文件

            

    import java.io.BufferedReader;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.PrintWriter;

     

    /*

    * 需求:DataStreamDemo.java复制到Copy.java中

    * 数据源:

    *         DataStreamDemo.java -- 读取数据 -- FileReader -- BufferedReader

    * 目的地:

    *         Copy.java -- 写出数据 -- FileWriter -- BufferedWriter -- PrintWriter

    */

    class CopyFileDemo {

        public static void main(String[] args) throws IOException {

            // 以前的版本

            // 封装数据源

            // BufferedReader br = new BufferedReader(new FileReader(

            // "DataStreamDemo.java"));

            // // 封装目的地

            // BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));

            //

            // String line = null;

            // while ((line = br.readLine()) != null) {

            // bw.write(line);

            // bw.newLine();

            // bw.flush();

            // }

            //

            // bw.close();

            // br.close();

     

            // 打印流的改进版

            // 封装数据源

            BufferedReader br = new BufferedReader(new FileReader(

                    "DataStreamDemo.java"));

            // 封装目的地

            PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true);

            

            String line = null;

            while((line=br.readLine())!=null){

                pw.println(line);

            }

            

            pw.close();

            br.close();

        }

    }

     

    5:标准输入输出流(理解)

        (1)System类下面有这样的两个字段

            in 标准输入流InputStream

            out 标准输出流PrintStream

            A:代码演示:

    import java.io.PrintStream;

     

    /*

    * 标准输入输出流

    * System类中的两个成员变量:

    *        public static final InputStream in "标准"输入流。

    *         public static final PrintStream out "标准"输出流。

    *

    *         InputStream is = System.in;

    *         PrintStream ps = System.out;

    */

    class SystemOutDemo {

        public static void main(String[] args) {

            // 有这里的讲解我们就知道了,这个输出语句其本质是IO流操作,把数据输出到控制台。

            System.out.println("helloworld");

     

            // 获取标准输出流对象

            PrintStream ps = System.out;

            ps.println("helloworld");

            

            ps.println();

            // ps.print();//这个方法不存在

            

            // System.out.println();

            // System.out.print();

        }

    }

     

        (2)三种键盘录入方式

            A:main方法的args接收参数

            B:System.in通过BufferedReader进行包装

                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            C:Scanner

                Scanner sc = new Scanner(System.in);

            D:代码演示

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

     

    /*

    * System.in 标准输入流。是从键盘获取数据的

    *

    * 键盘录入数据的三种方式:

    *         A:main方法的args接收参数。

    *             java HelloWorld hello world java

    *         B:Scanner(JDK5以后的)

    *             Scanner sc = new Scanner(System.in);

    *             String s = sc.nextLine();

    *             int x = sc.nextInt()

    *         C:通过字符缓冲流包装标准输入流实现

    *             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    */

    class SystemInDemo {

        public static void main(String[] args) throws IOException {

            // //获取标准输入流

            // InputStream is = System.in;

            // //我要一次获取一行行不行呢?

            // //行。

            // //怎么实现呢?

            // //要想实现,首先你得知道一次读取一行数据的方法是哪个呢?

            // //readLine()

            // //而这个方法在哪个类中呢?

            // //BufferedReader

            // //所以,你这次应该创建BufferedReader的对象,但是底层还是的使用标准输入流

            // // BufferedReader br = new BufferedReader(is);

            // //按照我们的推想,现在应该可以了,但是却报错了

            // //原因是:字符缓冲流只能针对字符流操作,而你现在是字节流,所以不能是用?

            // //那么,我还就想使用了,请大家给我一个解决方案?

            // //把字节流转换为字符流,然后在通过字符缓冲流操作

            // InputStreamReader isr = new InputStreamReader(is);

            // BufferedReader br= new BufferedReader(isr);

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

     

            System.out.println("请输入一个字符串:");

            String line = br.readLine();

            System.out.println("你输入的字符串是:" + line);

     

            System.out.println("请输入一个整数:");

            // int i = Integer.parseInt(br.readLine());

            line = br.readLine();

            int i = Integer.parseInt(line);

            System.out.println("你输入的整数是:" + i);

        }

    }

     

     

        (3)输出语句的原理和如何使用字符流输出数据

            A:原理

                System.out.println("helloworld");

                

                PrintStream ps = System.out;

                ps.println("helloworld");

            B:把System.out用字符缓冲流包装一下使用

                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

    import java.io.BufferedWriter;

    import java.io.IOException;

    import java.io.OutputStreamWriter;

    /*

    *

    * 案例:用字符缓冲流包装System.out 使用

    * 转换流的应用。

    *

    */

    class SystemOutDemo2 {

        public static void main(String[] args) throws IOException {

            // 获取标准输出流

            // // PrintStream ps = System.out;

            // // OutputStream os = ps;

            // OutputStream os = System.out; // 多态

            // // 我能不能按照刚才使用标准输入流的方式一样把数据输出到控制台呢?

            // OutputStreamWriter osw = new OutputStreamWriter(os);

            // BufferedWriter bw = new BufferedWriter(osw);

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    System.out));

     

            bw.write("hello");

            bw.newLine();

            // bw.flush();

            bw.write("world");

            bw.newLine();

            // bw.flush();

            bw.write("java");

            bw.newLine();

            bw.flush();

            

            bw.close();

        }

    }

     

    6:随机访问流(理解)

        (1)可以按照文件指针的位置写数据和读数据。

        (2)案例:

            A:写数据

            B:读数据

            C:获取和改变文件指针的位置

    import java.io.IOException;

    import java.io.RandomAccessFile;

     

    /*

    * 随机访问流:

    *         RandomAccessFile类不属于流,是Object类的子类。

    *         但它融合了InputStream和OutputStream的功能。

    *         支持对文件的随机访问读取和写入。

    *

    * public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。

    *         模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据

    */

    class RandomAccessFileDemo {

        public static void main(String[] args) throws IOException {

            // write();

            read();

        }

     

        private static void read() throws IOException {

            // 创建随机访问流对象

            RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");

    // 需要严格的按照写入数据的顺序进行读取,切记不可乱读

            int i = raf.readInt();

            System.out.println(i);

            // 该文件指针可以通过
    getFilePointer方法读取,并通过 seek 方法设置。

            System.out.println("当前文件的指针位置是:" + raf.getFilePointer());

     

            char ch = raf.readChar();

            System.out.println(ch);

            System.out.println("当前文件的指针位置是:" + raf.getFilePointer());

     

            String s = raf.readUTF();

            System.out.println(s);

            System.out.println("当前文件的指针位置是:" + raf.getFilePointer());

     

            // 我不想重头开始了,我就要读取a,怎么办呢?

            raf.seek(4);

            ch = raf.readChar();

            System.out.println(ch);

        }

     

        private static void write() throws IOException {

            // 创建随机访问流对象

            RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");

     

            // 怎么玩呢?

            raf.writeInt(100);

            raf.writeChar('a');

            raf.writeUTF("中国");

     

            raf.close();

        }

    }

     

     

    7:合并流(理解)

        (1)定义:

    把多个输入流的数据写到一个输出流中。

        (2)构造方法:

            A:SequenceInputStream(InputStream s1, InputStream s2)

            B:SequenceInputStream(Enumeration<? extends InputStream> e)

        (3)案例:

                A: 把a.txt 和 b.txt 文件复制到 c.txt

    import java.io.BufferedOutputStream;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.SequenceInputStream;

     

    /*

    * 以前的操作:

    * a.txt -- b.txt

    * c.txt -- d.txt

    *

    * 现在想要:

    * a.txt+b.txt -- c.txt

    * 把a.txt 和 b.txt 文件复制到 c.txt

    */

    class SequenceInputStreamDemo {

        public static void main(String[] args) throws IOException {

            // SequenceInputStream(InputStream s1, InputStream s2)

            // 需求:把ByteArrayStreamDemo.java和DataStreamDemo.java的内容复制到Copy.java中

            InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");

            InputStream s2 = new FileInputStream("DataStreamDemo.java");

            SequenceInputStream sis = new SequenceInputStream(s1, s2);

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream("Copy.java"));

     

            // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = sis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            sis.close();

        }

    }

     

             B: 将a.txt 和 b.txt 和 c.txt 文件复制到 d.txt

    import java.io.BufferedOutputStream;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.SequenceInputStream;

    import java.util.Enumeration;

    import java.util.Vector;

     

    /*

    * 以前的操作:

    * a.txt -- b.txt

    * c.txt -- d.txt

    * e.txt -- f.txt

    *

    * 现在想要:

    * a.txt+b.txt+c.txt -- d.txt

    * 将a.txt 和 b.txt 和 c.txt 文件复制到 d.txt

    */

    class SequenceInputStreamDemo2 {

        public static void main(String[] args) throws IOException {

            // 需求:把下面的三个文件的内容复制到Copy.java中

            // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java

     

            // SequenceInputStream(Enumeration e)

            // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。

            // Enumeration<E> elements()

            Vector<InputStream> v = new Vector<InputStream>();

            InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");

            InputStream s2 = new FileInputStream("CopyFileDemo.java");

            InputStream s3 = new FileInputStream("DataStreamDemo.java");

            v.add(s1);

            v.add(s2);

            v.add(s3);

            Enumeration<InputStream> en = v.elements();

            SequenceInputStream sis = new SequenceInputStream(en);

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream("Copy.java"));

     

            // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = sis.read(bys)) != -1) {

                bos.write(bys, 0, len);

            }

     

            bos.close();

            sis.close();

        }

    }

     

     

     

    8:序列化流(理解)

        (1)可以把对象写入文本文件或者在网络中传输

        (2)如何实现序列化呢?

            让被序列化的对象所属类实现序列化接口。

            该接口是一个标记接口。没有功能需要实现。

        (3)注意问题:

            把数据写到文件后,在去修改类会产生一个问题。

            如何解决该问题呢?

                在类文件中,给出一个固定的序列化id值。

                而且,这样也可以解决黄色警告线问题

        (4)面试题:

            什么时候序列化?

            如何实现序列化?

            什么是反序列化?

        (5)案例

                A:Person类进行序列化

    import java.io.Serializable;

     

    /*

    * NotSerializableException:未序列化异常

    *

    * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。

    * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。

    *

    * java.io.InvalidClassException:

    * cn.itcast_07.Person; local class incompatible:

    * stream classdesc serialVersionUID = -2071565876962058344,

    * local class serialVersionUID = -8345153069362641443

    *

    * 为什么会有问题呢?

    *         Person类实现了序列化接口,那么它本身也应该有一个标记值。

    *         开始的时候:

    *         Person.class -- id=100

    *         wirte数据: oos.txt -- id=100

    *         read数据: oos.txt -- id=100    

    *

    *         现在:

    *         Person.class -- id=200

    *         wirte数据: oos.txt -- id=100

    *         read数据: oos.txt -- id=100

    * 我们在实际开发中,可能还需要使用以前写过的数据,不能重新写入。怎么办呢?

    * 回想一下原因是因为它们的id值不匹配。

    * 每次修改java文件的内容的时候,class文件的id值都会发生改变。

    * 而读取文件的时候,会和class文件中的id值进行匹配。所以,就会出问题。

    * 但是呢,如果我有办法,让这个id值在java文件中是一个固定的值,这样,你修改文件的时候,这个id值还会发生改变吗?

    * 不会。现在的关键是我如何能够知道这个id值如何表示的呢?

    * 不用担心,你不用记住,也没关系,点击鼠标即可。

    * 你难道没有看到黄色警告线吗?

    *

    * 我们要知道的是:

    *         看到类实现了序列化接口的时候,要想解决黄色警告线问题,就可以自动产生一个序列化id值。

    *         而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。

    *

    * 注意:

    *         我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢?

    *         使用transient关键字声明不需要序列化的成员变量

    */

    public class Person implements Serializable {

        private static final long serialVersionUID = -2071565876962058344L;

     

        private String name;

     

        // private int age;

     

        private transient int age;

     

        // int age;

     

        public Person() {

            super();

        }

     

        public Person(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

     

        public String getName() {

            return name;

        }

     

        public void setName(String name) {

            this.name = name;

        }

     

        public int getAge() {

            return age;

        }

     

        public void setAge(int age) {

            this.age = age;

        }

     

        @Override

        public String toString() {

            return "Person [name=" + name + ", age=" + age + "]";

        }

    }

     

                B:序列化流的介绍

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.ObjectInputStream;

    import java.io.ObjectOutputStream;

     

    /*

    * 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(ObjectOutputStream)

    * 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 -- 对象(ObjectInputStream)

    */

    public class ObjectStreamDemo {

        public static void main(String[] args) throws IOException,

                ClassNotFoundException {

            // 由于我们要对对象进行序列化,所以我们先自定义一个类

            // 序列化数据其实就是把对象写到文本文件

            // write();

     

            read();

        }

     

        private static void read() throws IOException, ClassNotFoundException {

            // 创建反序列化对象

            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(

                    "oos.txt"));

     

            // 还原对象

            Object obj = ois.readObject();

     

            // 释放资源

            ois.close();

     

            // 输出对象

            System.out.println(obj);

        }

     

        private static void write() throws IOException {

            // 创建序列化流对象

            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(

                    "oos.txt"));

     

            // 创建对象

            Person p = new Person("林青霞", 27);

     

            // public final void writeObject(Object obj)

            oos.writeObject(p);

     

            // 释放资源

            oos.close();

        }

    }

     

     

    9:Properties(理解)

        (1)是一个集合类,Hashtable的子类

                1.Properties代码演示Hashtable的方法

        

    import java.util.Properties;

    import java.util.Set;

     

    /*

    * Properties:属性集合类。是一个可以和IO流相结合使用的集合类。

    * Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

    *

    * 是Hashtable的子类,说明是一个Map集合。

    */

    class PropertiesDemo {

        public static void main(String[] args) {

            // 作为Map集合的使用

            // 下面这种用法是错误的,一定要看API,如果没有<>,就说明该类不是一个泛型类,在使用的时候就不能加泛型

            // Properties<String, String> prop = new Properties<String, String>();

     

            Properties prop = new Properties();

     

            // 添加元素

            prop.put("it002", "hello");

            prop.put("it001", "world");

            prop.put("it003", "java");

     

            // System.out.println("prop:" + prop);

     

            // 遍历集合

            Set<Object> set = prop.keySet();

            for (Object key : set) {

                Object value = prop.get(key);

                System.out.println(key + "---" + value);

            }

        }

    }

     

        (2)特有功能

            A:public Object setProperty(String key,String value)

            B:public String getProperty(String key)

            C:public Set<String> stringPropertyNames()

            D:代码演示特有的功能

    import java.util.Properties;

    import java.util.Set;

     

    /*

    * 特殊功能:

    * public Object setProperty(String key,String value):添加键值对元素

    * public String getProperty(String key):根据指定的键获取元素

    * public Set<String> stringPropertyNames():获取所有的键的集合

    *                         类似于Map集合中的 Set s = map.Keyset()方法

    */

    class PropertiesDemo2 {

        public static void main(String[] args) {

            // 创建集合对象

            Properties prop = new Properties();

     

            // 添加元素

            prop.setProperty("张三", "30");

            prop.setProperty("李四", "40");

            prop.setProperty("王五", "50");

     

            // public Set<String> stringPropertyNames():获取所有的键的集合

            Set<String> set = prop.stringPropertyNames();

            for (String key : set) {

                String value = prop.getProperty(key);

                System.out.println(key + "---" + value);

            }

        }

    }

     

    /*

    * class Hashtalbe<K,V> { public V put(K key,V value) { ... } }

    *

    * class Properties extends Hashtable { public V setProperty(String key,String

    * value) { return put(key,value); } }

    */

     

     

        (3)和IO流结合的方法

            把键值对形式的文本文件内容加载到集合中

            public void load(Reader reader)

            public void load(InputStream inStream)

     

            把集合中的数据存储到文本文件中

            public void store(Writer writer,String comments)

            public void store(OutputStream out,String comments)

            

            A:与IO流结合的方法代码演示

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.Reader;

    import java.io.Writer;

    import java.util.Properties;

     

    /*

    * 这里的集合必须是Properties集合:

    * public void load(Reader reader):把文件中的数据读取到集合中

    * public void store(Writer writer,String comments):把集合中的数据存储到文件

    *

    * 单机版游戏:

    *         进度保存和加载。

    *         三国群英传,三国志,仙剑奇侠传...

    *

    *         吕布=1

    *         方天画戟=1

    */

    class PropertiesDemo3 {

        public static void main(String[] args) throws IOException {

            // myLoad();

     

            myStore();

        }

     

        private static void myStore() throws IOException {

            // 创建集合对象

            Properties prop = new Properties();

     

            prop.setProperty("林青霞", "27");

            prop.setProperty("武鑫", "30");

            prop.setProperty("刘晓曲", "18");

            

            //public void store(Writer writer,String comments):把集合中的数据存储到文件

            Writer w = new FileWriter("name.txt");

            prop.store(w, "helloworld");

            w.close();

        }

     

        private static void myLoad() throws IOException {

            Properties prop = new Properties();

     

            // public void load(Reader reader):把文件中的数据读取到集合中

            // 注意:这个文件的数据必须是键值对形式

            Reader r = new FileReader("prop.txt");

            prop.load(r);

            r.close();

     

            System.out.println("prop:" + prop);

        }

    }

     

     

        (4)案例:

            A:根据给定的文件判断是否有键为"lisi"的,如果有就修改其值为100

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.Reader;

    import java.io.Writer;

    import java.util.Properties;

    import java.util.Set;

     

    /*

    * 我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。

    * 请写一个程序判断是否有"lisi"这样的键存在,如果有就改变其实为"100"

    *

    * 分析:

    *         A:把文件中的数据加载到集合中

    *         B:遍历集合,获取得到每一个键

    *         C:判断键是否有为"lisi"的,如果有就修改其值为"100"

    *         D:把集合中的数据重新存储到文件中

    */

    class PropertiesTest {

        public static void main(String[] args) throws IOException {

            // 把文件中的数据加载到集合中

            Properties prop = new Properties();

            //创建一个
    FileReader对象

            Reader r = new FileReader("user.txt");

            //将文件中的内容加载到Properties集合中

            prop.load(r);

            //关闭读取流

            r.close();

     

            // 遍历集合,获取得到每一个键

            Set<String> set = prop.stringPropertyNames();

            for (String key : set) {

                // 判断键是否有为"lisi"的,如果有就修改其值为"100"

                if ("lisi".equals(key)) {

                    prop.setProperty(key, "100");

                    break;

                }

            }

     

            // 把集合中的数据重新存储到文件中

            Writer w = new FileWriter("user.txt");

            prop.store(w, null);

            w.close();

        }

    }

     

     

            B:写一个程序实现控制猜数字小游戏程序不能玩超过5次

                    1:GuessGame类

    import java.util.Scanner;

     

    /**

    * 这是猜数字小游戏

    *

    * @author
    风清扬

    * @version V1.1

    *

    */

    class GuessNumber {

        private GuessNumber() {

        }

     

        public static void start() {

            // 产生一个随机数

            int number = (int) (Math.random() * 100) + 1;

     

            // 定义一个统计变量

            int count = 0;

     

            while (true) {

                // 键盘录入一个数据

                Scanner sc = new Scanner(System.in);

                System.out.println("请输入数据(1-100):");

                int guessNumber = sc.nextInt();

     

                count++;

     

                // 判断

                if (guessNumber > number) {

                    System.out.println("你猜的数据" + guessNumber + "大了");

                } else if (guessNumber < number) {

                    System.out.println("你猜的数据" + guessNumber + "小了");

                } else {

                    System.out.println("恭喜你," + count + "次就猜中了");

                    break;

                }

            }

        }

    }

     

                    2:测试类

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.Reader;

    import java.io.Writer;

    import java.util.Properties;

     

    /*

    次,超过5次提示:游戏试玩已结束,请付费。

    */

    class PropertiesTest2 {

        public static void main(String[] args) throws IOException {

    ,可以继续玩。否则就提示"游戏试玩已结束,请付费。"

            // 创建一个文件

            // File file = new File("count.txt");

            // if (!file.exists()) {

            // file.createNewFile();

            // }

     

            // 把数据加载到集合中

            Properties prop = new Properties();

            Reader r = new FileReader("count.txt");

            prop.load(r);

            r.close();

     

            // 我自己的程序,我当然知道里面的键是谁

            //根据指定的键获取值

            String value = prop.getProperty("count");

            int number = Integer.parseInt(value);

     

            if (number > 5) {

                System.out.println("游戏试玩已结束,请付费。");

                System.exit(0);

            } else {

                number++;

                prop.setProperty("count", String.valueOf(number));

                Writer w = new FileWriter("count.txt");

                prop.store(w, null);

                w.close();

     

                GuessNumber.start();

            }

        }

    }

     

    10:NIO(了解)

        (1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO

        (2)JDK7的NIO的使用    

            Path:路径

            Paths:通过静态方法返回一个路径

            Files:提供了常见的功能

                复制文本文件

                把集合中的数据写到文本文件

     

    import java.io.IOException;

    import java.nio.charset.Charset;

    import java.nio.file.Files;

    import java.nio.file.Paths;

    import java.util.ArrayList;

     

    /*

    * nio包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。

    * 有空的话了解下,有问题再问我。

    *

    * JDK7的之后的nio:

    * Path:路径

    * Paths:有一个静态方法返回一个路径

    *         public static Path get(URI uri)

    * Files:提供了静态方法供我们使用

    *         public static long copy(Path source,OutputStream out):复制文件

    *         public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)

    */

    class NIODemo {

        public static void main(String[] args) throws IOException {

            // public static long copy(Path source,OutputStream out)

            // Files.copy(Paths.get("ByteArrayStreamDemo.java"), new

            // FileOutputStream(

            // "Copy.java"));

     

            ArrayList<String> array = new ArrayList<String>();

            array.add("hello");

            array.add("world");

            array.add("java");

            Files.write(Paths.get("array.txt"), array, Charset.forName("GBK"));

        }

    }

     

     

     

     

     

     

     

    第二十三天

    1.进程和线程的概述

    /*

    1:要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在。

     

    2:什么是进程?

        通过任务管理器我们就看到了进程的存在。

        而通过观察,我们发现只有运行的程序才会出现进程。

        进程:就是正在运行的程序。

        进程是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。

        

    3:多进程有什么意义呢?

        单进程的计算机只能做一件事情,而我们现在的计算机都可以做多件事情。

        举例:一边玩游戏(游戏进程),一边听音乐(音乐进程)。

        也就是说现在的计算机都是支持多进程的,可以在一个时间段内执行多个任务。

        并且呢,可以提高CPU的使用率。

        

        问题:

            一边玩游戏,一边听音乐是同时进行的吗?

            不是。因为单CPU在某一个时间点上只能做一件事情。

            而我们在玩游戏,或者听音乐的时候,是CPU在做着程序间的高效切换让我们觉得是同时进行的。

            

    4:什么是线程呢?

        在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程。

        线程:是程序的执行单元,执行路径。是程序使用CPU的最基本单位。

        单线程:如果程序只有一条执行路径。

        多线程:如果程序有多条执行路径。

        

    5:多线程有什么意义呢?

        多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。

        程序的执行其实都是在抢CPU的资源,CPU的执行权。

        多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。

        我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。

    */

     

    2.多线程(理解)

        (1)多线程:一个应用程序有多条执行路径

            进程:正在执行的应用程序

            线程:进程的执行单元,执行路径

            单线程:一个应用程序只有一条执行路径

            多线程:一个应用程序有多条执行路径

            

            多进程的意义?

                提高CPU的使用率

            多线程的意义?

                提高应用程序的使用率

        (2)Java程序的运行原理及JVM的启动是多线程的吗?

            A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。

            B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。

            C:多线程代码引入

    /*

    *    进程:

    *        正在运行的程序,是系统进行资源分配和调用的独立单位。

    *        每一个进程都有它自己的内存空间和系统资源。

    *    线程:

    *        是进程中的单个顺序控制流,是一条执行路径

    *        一个进程如果只有一条执行路径,则称为单线程程序。

    *        一个进程如果有多条执行路径,则称为多线程程序。

    *

    * 举例:

    *     扫雷程序,迅雷下载

    *

    * 大家注意两个词汇的区别:并行和并发。

    *        前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。

    *        后者是物理上同时发生,指在某一个时间点同时运行多个程序。

    *

    * Java程序的运行原理:

    *         由java命令启动JVM,JVM启动就相当于启动了一个进程。

    *         接着有该进程创建了一个主线程去调用main方法。

    *

    * 思考题:

    *         jvm虚拟机的启动是单线程的还是多线程的?

    *             多线程的。

    *             原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。

    *             现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。

    */

    class MyThreadDemo {

        public static void main(String[] args) {

            System.out.println("hello");

            new Object();

            new Object();

            new Object();

            new Object();

            //...

            System.out.println("world");

        }

    }

     

        (3)多线程的实现方案(自己补齐步骤及代码    掌握)

            

            A:继承Thread类

                1.继承了Thread类的实现类MyThread.java

    /*

    * 该类要重写run()方法,为什么呢?

    * 不是类中的所有代码都需要被线程执行的。

    * 而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。

    */

    class MyThread extends Thread {

     

        @Override

        public void run() {

            // 自己写代码

            // System.out.println("好好学习,天天向上");

            // 一般来说,被线程执行的代码肯定是比较耗时的。所以我们用循环改进

            for (int x = 0; x < 200; x++) {

                System.out.println(x);

            }

        }

     

    }

     

                2.测试类MyThreadDmeo.java

    /*

    * 需求:我们要实现多线程的程序。

    * 如何实现呢?

    *         由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。

    *         而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。

    *         Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。

    *         但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。

    *         由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,

    *         然后提供一些类供我们使用。我们就可以实现多线程程序了。

    * 那么Java提供的类是什么呢?

    *         Thread

    中方式实现多线程程序。

    *

    :继承Thread类。

    * 步骤

    *         A:自定义类MyThread继承Thread类。

    *         B:MyThread类里面重写run()?

    *             为什么是run()方法呢?

    *         C:创建对象

    *         D:启动线程

    */

    class MyThreadDemo {

        public static void main(String[] args) {

            // 创建线程对象

            // MyThread my = new MyThread();

            // // 启动线程

            // my.run();

            // my.run();

            // 调用run()方法为什么是单线程的呢?

            // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果

            // 要想看到多线程的效果,就必须说说另一个方法:start()

            // 面试题:run()和start()的区别?

            // run():仅仅是封装被线程执行的代码,直接调用是普通方法

            // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。

            // MyThread my = new MyThread();

            // my.start();

            // // IllegalThreadStateException:非法的线程状态异常

            // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。

            // my.start();

     

            // 创建两个线程对象

            MyThread my1 = new MyThread();

            MyThread my2 = new MyThread();

     

            my1.start();

            my2.start();

        }

    }

     

     

     

     

            B:实现Runnable接口

                1.实现了Runnable接口的实现类MyRunnable.java

    public class MyRunnable implements Runnable {

     

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用

                System.out.println(Thread.currentThread().getName() + ":" + x);

            }

        }

     

    }

     

     

                2.测试类MyRunnableDemo

     

    /*

    :实现Runnable接口

    * 步骤:

    *         A:自定义类MyRunnable实现Runnable接口

    *         B:重写run()方法

    *         C:创建MyRunnable类的对象

    *         D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

    */

    public class MyRunnableDemo {

        public static void main(String[] args) {

            // 创建MyRunnable类的对象

            MyRunnable my = new MyRunnable();

     

            // 创建Thread类的对象,并把C步骤的对象作为构造参数传递

            // Thread(Runnable target)

            // Thread t1 = new Thread(my);

            // Thread t2 = new Thread(my);

            // t1.setName("林青霞");

            // t2.setName("刘意");

     

            // Thread(Runnable target, String name)

            Thread t1 = new Thread(my, "林青霞");

            Thread t2 = new Thread(my, "刘意");

     

            t1.start();

            t2.start();

        }

    }

     

            C:多线程实现的两种方式比较

     

        (4)线程名称的设置

            public
    final String getName():获取线程的名称

            public
    final
    synchronized
    void setName(String name):设置线程的名称

            还可以通过带参构造方法给线程设置名称new MyThread("张三");

     

            

            针对不是Thread类的子类如何获取线程对象的名称呢?

            public
    static
    native Thread currentThread():返回当前正在执行的线程对象

            具体代码:Thread.currentThread().getName():获取当前线程对象的名称

            

            A:具体设置线程对象名称的案例

                1.MyThread.java类,继承了Thread

    public class MyThread extends Thread {

     

        //默认构造方法,为了初始化

        public MyThread() {

        }

        //带参构造方法为线程设置名称

        public MyThread(String name){

            super(name);

        }

     

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                System.out.println(getName() + ":" + x);

            }

        }

    }

     

     

                2.MyThreadDemo.java 测试类

     

    /*

    * 如何获取线程对象的名称呢?

    * public final String getName():获取线程的名称。

    * 如何设置线程对象的名称呢?

    * public final void setName(String name):设置线程的名称

    * 还可以通过带参构造方法给线程设置名称new MyThread("张三");

    *

    * 针对不是Thread类的子类中如何获取线程对象名称呢?

    * public static Thread currentThread():返回当前正在执行的线程对象

    * Thread.currentThread().getName()

    */

    class MyThreadDemo {

        public static void main(String[] args) {

            // 创建线程对象

            //无参构造+setXxx()

            // MyThread my1 = new MyThread();

            // MyThread my2 = new MyThread();

            // //调用方法设置名称

            // my1.setName("林青霞");

            // my2.setName("刘意");

            // my1.start();

            // my2.start();

            

            //带参构造方法给线程起名字

            // MyThread my1 = new MyThread("林青霞");

            // MyThread my2 = new MyThread("刘意");

            // my1.start();

            // my2.start();

            

            //我要获取main方法所在的线程对象的名称,该怎么办呢?

            //遇到这种情况,Thread类提供了一个很好玩的方法:

            //public static Thread currentThread():返回当前正在执行的线程对象

            System.out.println(Thread.currentThread().getName());

        }

    }

     

        (5)线程的调度和优先级问题

            A:线程的调度

                a:分时调度

                b:抢占式调度 (Java采用的是该调度方式)

            B:获取和设置线程优先级

                a:默认是优先级为5

                b:优先级范围是1-10

                public
    final
    int getPriority():返回线程对象的优先级

                public
    final
    void setPriority(int
    newPriority):设置线程对象的优先级

     

                具体案例:

                

                1.ThreadPriority类

    public class ThreadPriority extends Thread {

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                //获取当前线程的名称并打印数字

                System.out.println(getName() + ":" + x);

            }

        }

    }

     

     

                2.ThreadPriorityDemo测试类

    /*

    * 我们的线程没有设置优先级,肯定有默认优先级。

    * 那么,默认优先级是多少呢?

    * 如何获取线程对象的优先级?

    *         public final int getPriority():返回线程对象的优先级

    * 如何设置线程对象的优先级呢?

    *         public final void setPriority(int newPriority):更改线程的优先级。

    *

    * 注意:

    *         线程优先级的范围是:1-10。

    *         线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。

    *         

    * IllegalArgumentException:非法参数异常。

    * 抛出的异常表明向方法传递了一个不合法或不正确的参数。

    *

    */

    public class ThreadPriorityDemo {

        public static void main(String[] args) {

            ThreadPriority tp1 = new ThreadPriority();

            ThreadPriority tp2 = new ThreadPriority();

            ThreadPriority tp3 = new ThreadPriority();

     

            tp1.setName("东方不败");

            tp2.setName("岳不群");

            tp3.setName("林平之");

     

            // 获取默认优先级

            // System.out.println(tp1.getPriority());

            // System.out.println(tp2.getPriority());

            // System.out.println(tp3.getPriority());

     

            // 设置线程优先级

            // tp1.setPriority(100000);

            

            //设置正确的线程优先级

            tp1.setPriority(10);

            tp2.setPriority(1);

     

            tp1.start();

            tp2.start();

            tp3.start();

        }

    }

     

     

        (6)线程的控制(常见方法)

            A:休眠线程

                public
    static
    native
    void sleep(long
    millis):让线程休眠

                

                 具体案例:

                1.ThreadSleep类

    import java.util.Date;

     

    public class ThreadSleep extends Thread {

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                System.out.println(getName() + ":" + x + ",日期:" + new Date());

                // 睡眠

    秒钟

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    }

     

                2.ThreadSleepDemo测试类

     

    /*

    * 线程休眠

    *        public static void sleep(long millis)

    */

    public class ThreadSleepDemo {

        public static void main(String[] args) {

            ThreadSleep ts1 = new ThreadSleep();

            ThreadSleep ts2 = new ThreadSleep();

            ThreadSleep ts3 = new ThreadSleep();

     

            ts1.setName("林青霞");

            ts2.setName("林志玲");

            ts3.setName("林志颖");

     

            ts1.start();

            ts2.start();

            ts3.start();

        }

    }

     

            B:加入线程

                public
    final
    void join():等待该线程终止

                

    具体案例:

    1.ThreadJoin类

    public class ThreadJoin extends Thread {

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                System.out.println(getName() + ":" + x);

            }

        }

    }

     

     

    2.ThreadJoinDemo测试类

    /*

    * public final void join():等待该线程终止。

    */

    public class ThreadJoinDemo {

        public static void main(String[] args) {

            ThreadJoin tj1 = new ThreadJoin();

            ThreadJoin tj2 = new ThreadJoin();

            ThreadJoin tj3 = new ThreadJoin();

     

            tj1.setName("李渊");

            tj2.setName("李世民");

            tj3.setName("李元霸");

     

            tj1.start();

            try {

    //线程加入

                tj1.join();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            

            tj2.start();

            tj3.start();

        }

    }

     

            C:礼让线程

                public
    static
    native
    void yield():暂停当前正在执行的线程对象,并执行

                                                            其他线程

                目的:让多个线程的执行顺序更和谐一点,但是也不能保证一个线程执行一次

                

                具体案例:

                1.ThreadYield类

    public class ThreadYield extends Thread {

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                System.out.println(getName() + ":" + x);

                //线程礼让

                Thread.yield();

            }

        }

    }

     

                2.ThreadYieldDemo测试类

    /*

    * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。

    * 让多个线程的执行更和谐,但是不能靠它保证一人一次。

    */

    public class ThreadYieldDemo {

        public static void main(String[] args) {

            ThreadYield ty1 = new ThreadYield();

            ThreadYield ty2 = new ThreadYield();

     

            ty1.setName("林青霞");

            ty2.setName("刘意");

     

            ty1.start();

            ty2.start();

        }

    }

     

     

            D:后台线程

                public
    final
    void setDaemon(boolean
    on):将该线程标记为守护线程或用户线程

                当正在运行的线程都是守护线程时,java虚拟机退出,该方法必须在启动线程前调用

                

                最好的案例说明:坦克大战,老板死了,小弟就没有存在的必要了

                

                1. ThreadDaemon类

                    

    public class ThreadDaemon extends Thread {

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                System.out.println(getName() + ":" + x);

            }

        }

    }

     

     

     

                2. ThreadDaemonDemo测试类

    /*

    * public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。

    * 当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。

    *

    * 游戏:坦克大战。

    */

    public class ThreadDaemonDemo {

        public static void main(String[] args) {

            ThreadDaemon td1 = new ThreadDaemon();

            ThreadDaemon td2 = new ThreadDaemon();

     

            td1.setName("关羽");

            td2.setName("张飞");

     

            // 设置守护线程

            td1.setDaemon(true);

            td2.setDaemon(true);

     

            td1.start();

            td2.start();

     

            Thread.currentThread().setName("刘备");

            for (int x = 0; x < 5; x++) {

                System.out.println(Thread.currentThread().getName() + ":" + x);

            }

        }

    }

     

     

            E:终止线程(掌握)

                public
    final
    void
    stop():让线程停止,过时了,但是还可以使用

    public
    void interrupt():中断线程,把线程的状态终止,并抛出一个InterruptedException异常

                    具体案例:

                1.ThreadStop类

    import java.util.Date;

     

    public class ThreadStop extends Thread {

        @Override

        public void run() {

            System.out.println("开始执行:" + new Date());

     

    秒钟,亲,不要打扰我哦

            try {

                Thread.sleep(10000);

            } catch (InterruptedException e) {

                // e.printStackTrace();

                System.out.println("线程被终止了");

            }

     

            System.out.println("结束执行:" + new Date());

        }

    }

     

                2.ThreadStopDemo测试类

     

    /*

    * public final void stop():让线程停止,过时了,但是还可以使用。

    * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。

    */

    public class ThreadStopDemo {

        public static void main(String[] args) {

            ThreadStop ts = new ThreadStop();

            ts.start();

     

            // 你超过三秒不醒过来,我就干死你

            try {

                Thread.sleep(3000);

                 //ts.stop(); //ts.stop()执行的结果:开始执行:Wed Sep 07 18:23:50 CST 2016

                //线程中断

                ts.interrupt();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

    /*

    * ts.interrupt(): 执行结果:

    * 开始执行:Wed Sep 07 18:21:41 CST 2016

        线程被终止了

        结束执行:Wed Sep 07 18:21:44 CST 2016

    */

     

     

        (7)线程的生命周期(参照    线程生命周期图解.bmp)

            A:新建

            B:就绪

            C:运行

            D:阻塞

            E:死亡

        (8)电影院卖票程序的实现

            A:继承Thread类

                1.SellTicket类(该程序存在线程安全问题,非最终代码,后续改进)

    public class SellTicket extends Thread {

     

    张票

        // private int tickets = 100;

    张票,我们其实应该用静态修饰

        private static int tickets = 100;

     

        @Override

        public void run() {

    张票

    张票,这不合理,所以应该定义到外面

            // int tickets = 100;

     

            // 是为了模拟一直有票

            while (true) {

                if (tickets > 0) {

                    System.out.println(getName() + "正在出售第" + (tickets--) + "张票");

                }

            }

        }

    }

             2.SellTicketDemo测试类(该程序存在线程安全问题,非最终代码,后续改进)

    /*

    张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。

    * 继承Thread类来实现。

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建三个线程对象

            SellTicket st1 = new SellTicket();

            SellTicket st2 = new SellTicket();

            SellTicket st3 = new SellTicket();

     

            // 给线程对象起名字

            st1.setName("窗口1");

            st2.setName("窗口2");

            st3.setName("窗口3");

     

            // 启动线程

            st1.start();

            st2.start();

            st3.start();

        }

    }

     

     

            B:实现Runnable接口

     

            1.SellTicket类(该程序存在线程安全问题,非最终代码,后续改进)

    public class SellTicket implements Runnable {

    张票

        private int tickets = 100;

     

        @Override

        public void run() {

            while (true) {

                if (tickets > 0) {

                    System.out.println(Thread.currentThread().getName() + "正在出售第"

                            + (tickets--) + "张票");

                }

            }

        }

    }

     

     

            2.SellTicketDemo测试类(该程序存在线程安全问题,非最终代码,后续改进)

    /*

    *用Runnable接口的方式实现

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建资源对象

            SellTicket st = new SellTicket();

     

            // 创建三个线程对象

            Thread t1 = new Thread(st, "窗口1");

            Thread t2 = new Thread(st, "窗口2");

            Thread t3 = new Thread(st, "窗口3");

     

            // 启动线程

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

     

        (9)电影院卖票程序出问题

            A:为了更符合真实的场景,加入了休眠100毫秒。

            B:卖票问题

                a:同票多次

                b:负数票

            代码案例体现:

     

            1. SellTicket类

    public class SellTicket implements Runnable {

    张票

        private int tickets = 100;

     

        /*@Override

        public void run() {

            while (true) {

                // t1,t2,t3三个线程

                // 这一次的tickets = 100;

                if (tickets > 0) {

                    // 为了模拟更真实的场景,我们稍作休息

                    try {

                        Thread.sleep(100); // t1就稍作休息,t2就稍作休息

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

     

                    System.out.println(Thread.currentThread().getName() + "正在出售第"

                            + (tickets--) + "张票");

                    // 理想状态:

    正在出售第100张票

    正在出售第99张票

                    // 但是呢?

                    // CPU的每一次执行必须是一个原子性(最简单基本的)的操作。

                    // 先记录以前的值

                    // 接着把ticket--

                    // 然后输出以前的值(t2来了)

    正在出售第100张票

    正在出售第100张票

     

                }

            }

        }*/

        

        @Override

        public void run() {

            while (true) {

                // t1,t2,t3三个线程

                // 这一次的tickets = 1;

                if (tickets > 0) {

                    // 为了模拟更真实的场景,我们稍作休息

                    try {

                        Thread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

     

                    System.out.println(Thread.currentThread().getName() + "正在出售第"

                            + (tickets--) + "张票");

    正在出售第1张票,tickets=0

    正在出售第0张票,tickets=-1

    正在出售第-1张票,tickets=-2

                }

            }

        }

    }

     

            2. SellTicketDemo测试类

    /*

    * 实现Runnable接口的方式实现

    *

    * 通过加入延迟后,就产生了连个问题:

    * A:相同的票卖了多次

    *         CPU的一次操作必须是原子性的

    * B:出现了负数票

    *         随机性和延迟导致的

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建资源对象

            SellTicket st = new SellTicket();

     

            // 创建三个线程对象

            Thread t1 = new Thread(st, "窗口1");

            Thread t2 = new Thread(st, "窗口2");

            Thread t3 = new Thread(st, "窗口3");

     

            // 启动线程

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

     

        (10)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)

            A:是否有多线程环境

            B:是否有共享数据

            C:是否有多条语句操作共享数据

     

         售票程序最终代码体现

            1. SellTicket类

    package cn.itcast_23;

     

    public class SellTicket implements Runnable {

    张票

        private int tickets = 100;

        //创建锁对象

        private Object obj = new Object();

     

    /*    @Override

        public void run() {

            while (true) {

                synchronized(new Object()){

                    if (tickets > 0) {

                        try {

                            Thread.sleep(100);

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                     }

                        System.out.println(Thread.currentThread().getName() + "正在出售第"

                                + (tickets--) + "张票");

                    }

                }

            }

        }

        */

        @Override

        public void run() {

            while (true) {

                //同步代码块

                synchronized (obj) {

                    if (tickets > 0) {

                        try {

                            Thread.sleep(100);

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                        }

                        System.out.println(Thread.currentThread().getName()

                                + "正在出售第" + (tickets--) + "张票");

                    }

                }

            }

        }

    }

     

     

            2. SellTicketDemo测试类

    /*

    * 如何解决线程安全问题呢?

    *

    * 要想解决问题,就要知道哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)

    * A:是否是多线程环境

    * B:是否有共享数据

    * C:是否有多条语句操作共享数据

    *

    * 我们来回想一下我们的程序有没有上面的问题呢?

    * A:是否是多线程环境    是

    * B:是否有共享数据    是

    * C:是否有多条语句操作共享数据    是

    *

    * 由此可见我们的程序出现问题是正常的,因为它满足出问题的条件。

    * 接下来才是我们要想想如何解决问题呢?

    * A和B的问题我们改变不了,我们只能想办法去把C改变一下。

    * 思想:

    *         把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。

    * 问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。

    *

    * 同步代码块:

    *         synchronized(对象){

    *             需要同步的代码;

    *         }

    *

    *         A:对象是什么呢?

    *             我们可以随便创建一个对象试试。

    *         B:需要同步的代码是哪些呢?

    *             把多条语句操作共享数据的代码的部分给包起来

    *

    *         注意:

    *             同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。

    *             多个线程必须是同一把锁。

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建资源对象

            SellTicket st = new SellTicket();

     

            // 创建三个线程对象

            Thread t1 = new Thread(st, "窗口1");

            Thread t2 = new Thread(st, "窗口2");

            Thread t3 = new Thread(st, "窗口3");

     

            // 启动线程

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

        (11)通过售票程序解析同步机制和其优缺点

            1. SellTicket类

    public class SellTicket implements Runnable {

     

    张票

        private int tickets = 100;

     

        // 定义同一把锁

        private Object obj = new Object();

     

        @Override

        public void run() {

            while (true) {

                // t1,t2,t3都能走到这里

                // 假设t1抢到CPU的执行权,t1就要进来

                // 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。

                // 门(开,关)

                synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)

                    if (tickets > 0) {

                        try {

                            Thread.sleep(100); // t1就睡眠了

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                        }

                        System.out.println(Thread.currentThread().getName()

                                + "正在出售第" + (tickets--) + "张票 ");

    正在出售第100张票

                    }

                } //t1就出来可,然后就开门。(开)

            }

        }

    }

     

     

            2. SellTicketDemo测试类

    /*

    * 举例:

    *         火车上厕所。

    *

    * 同步的特点:

    *         前提:

    *             多个线程

    *        解决问题的时候要注意:

    *            多个线程使用的是同一个锁对象

    * 同步的好处

    *        同步的出现解决了多线程的安全问题。

    * 同步的弊端

    *        当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建资源对象

            SellTicket st = new SellTicket();

     

            // 创建三个线程对象

            Thread t1 = new Thread(st, "窗口1");

            Thread t2 = new Thread(st, "窗口2");

            Thread t3 = new Thread(st, "窗口3");

     

            // 启动线程

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

     

        (12)同步解决线程安全问题

            A:同步代码块

                synchronized(对象) {

                    需要被同步的代码;

                }

                

                这里的锁对象可以是任意对象。

                

            B:同步方法

                把同步加在方法上。

                

                这里的锁对象是this

                例如:private synchronized void sellTicket()

                

            C:静态同步方法

                把同步加在方法上。

                

                这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)

                例如:

                

    synchronized (SellTicket.class) {

                        if (tickets > 0) {

                            try {

                                Thread.sleep(100);

                            } catch (InterruptedException e) {

                                e.printStackTrace();

                            }

                            System.out.println(Thread.currentThread().getName()

                                    + "正在出售第" + (tickets--) + "张票 ");

                        }

     

        (13)回顾以前的线程安全的类

            A:StringBuffer

            B:Vector

            C:Hashtable

            D:如何把一个线程不安全的集合类变成一个线程安全的集合类

                用Collections工具类的方法即可。

     

        具体案例:    

    import java.util.ArrayList;

    import java.util.Collections;

    import java.util.Hashtable;

    import java.util.List;

    import java.util.Vector;

     

    public class ThreadDemo {

        public static void main(String[] args) {

            // 线程安全的类

            StringBuffer sb = new StringBuffer();

            Vector<String> v = new Vector<String>();

            Hashtable<String, String> h = new Hashtable<String, String>();

     

            // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你

            // 那么到底用谁呢?

            // public static <T> List<T> synchronizedList(List<T> list)

            List<String> list1 = new ArrayList<String>();// 线程不安全

            List<String> list2 = Collections

                    .synchronizedList(new ArrayList<String>()); // 线程安全

        }

    }

     

     

     

     

     

    第二十四天

    1:多线程(理解)

        (1)JDK5以后的Lock锁

            A:定义

    JDK5以后的针对线程的锁定操作和释放操作(Lock是一个接口,具体实例由其实现类ReentrantLock)

            B:方法:

                实现类:ReenTrantlock的方法:

                void lock():加锁

                void unlock():解锁

            C:具体应用(以售票程序为例)

                1,. SellTicket类

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

     

    public class SellTicket implements Runnable {

     

        // 定义票

        private int tickets = 100;

     

        // 定义锁对象

        private Lock lock = new ReentrantLock();

     

        @Override

        public void run() {

            while (true) {

                try {

                    // 加锁

                    lock.lock();

                    if (tickets > 0) {

                        try {

                            //为了模拟真实环境,对线程进行了延迟

                            Thread.sleep(100);

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                        }

                        System.out.println(Thread.currentThread().getName()

                                + "正在出售第" + (tickets--) + "张票");

                    }

                } finally {

                    // 释放锁

                    lock.unlock();

                }

            }

        }

     

    }

     

     

                2,. SellTicketDemo测试类

    /*

    * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,

    * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。

    *

    * Lock:

    *         void lock(): 获取锁。

    *         void unlock():释放锁。

    * ReentrantLock是Lock的实现类.

    * 通过ReentrantLock类来创建锁对象

    */

    public class SellTicketDemo {

        public static void main(String[] args) {

            // 创建资源对象

            SellTicket st = new SellTicket();

     

            // 创建三个窗口

            Thread t1 = new Thread(st, "窗口1");

            Thread t2 = new Thread(st, "窗口2");

            Thread t3 = new Thread(st, "窗口3");

     

            // 启动线程

            t1.start();

            t2.start();

            t3.start();

        }

    }

     

     

        (2)死锁问题的描述和代码体现

            1. DieLockDemo测试类

    /*

    * 同步的弊端:

    *         A:效率低

    *         B:容易产生死锁

    *

    * 死锁:

    *         两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。

    *

    * 举例:

    *         中国人,美国人吃饭案例。

    *         正常情况:

    *             中国人:筷子两支

    *             美国人:刀和叉

    *         现在:

    支,刀一把

    支,叉一把

    */

    public class DieLockDemo {

        public static void main(String[] args) {

            DieLock dl1 = new DieLock(true);

            DieLock dl2 = new DieLock(false);

     

            dl1.start();

            dl2.start();

        }

    }

     

     

            2. DieLock类(该类继承自Thread)

    /**

    * 死锁演示

    * @author asus1

    *

    */

    public class DieLock extends Thread {

     

        private boolean flag;

     

        public DieLock(boolean flag) {

            this.flag = flag;

        }

     

        @Override

        public void run() {

            if (flag) {

                synchronized (MyLock.objA) {

                    System.out.println("if objA");

                    synchronized (MyLock.objB) {

                        System.out.println("if objB");

                    }

                }

            } else {

                synchronized (MyLock.objB) {

                    System.out.println("else objB");

                    synchronized (MyLock.objA) {

                        System.out.println("else objA");

                    }

                }

            }

        }

    }

     

            3. MyLock(锁对象类)

    /**

    * 死锁演示

    * @author asus1

    *

    */

    public class MyLock {

        // 创建两把锁对象

        public static final Object objA = new Object();

        public static final Object objB = new Object();

    }

     

        (3)生产者和消费者多线程体现(线程间通信问题)

            以学生作为资源来实现的

            

            资源类:Student

            设置数据类:SetThread(生产者)

            获取数据类:GetThread(消费者)

            测试类:StudentDemo

            

            代码:

                A:最基本的版本,只有一个数据。

                    1. Student资源类

    /*

    * Student:资源类

    */

    public class Student {

        public String name;

        public int age;

    }

     

                    2. SetThread(生产者类)

    /*

    * 生产者类:

    */

    public class SetThread implements Runnable {

        //保证每个线程是对同一个对象进行操作

        private Student s;

     

        public SetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            // Student s = new Student();

            s.name = "林青霞";

            s.age = 27;

        }

    }

     

                    3. GetThread(消费者类)

    /*

    * 消费者类

    */

    public class GetThread implements Runnable {

        //保证每个线程是对同一个对象进行操作

        private Student s;

     

        public GetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            // Student s = new Student();

            System.out.println(s.name + "---" + s.age);

        }

    }

     

     

                    4. StudentDemo测试类

    /*

    * 分析:

    *         资源类:Student    

    *         设置学生数据:SetThread(生产者)

    *         获取学生数据:GetThread(消费者)

    *         测试类:StudentDemo

    *

    :按照思路写代码,发现数据每次都是:null---0

    * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个

    * 如何实现呢?

    *         在外界把这个数据创建出来,通过构造方法传递给其他的类。

    *

    */

    public class StudentDemo {

        public static void main(String[] args) {

            //创建资源

            Student s = new Student();

            

            //设置和获取的类

            SetThread st = new SetThread(s);

            GetThread gt = new GetThread(s);

     

            //线程类

            Thread t1 = new Thread(st);

            Thread t2 = new Thread(gt);

     

            //启动线程

            t1.start();

            t2.start();

        }

    }

     

     

                B:改进版本,给出了不同的数据,并加入了同步机制

                    1. Student资源类

    /*

    * 资源类:

    */

    public class Student {

        String name;

        int age;

    }

     

     

                    2. SetThread(生产者类)

    /*

    * 生产者类:

    */

    public class SetThread implements Runnable {

     

        private Student s;

        private int x = 0;

     

        public SetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                //加入了同步代码块,要保证多个线程是同意把锁

                synchronized (s) {

                    if (x % 2 == 0) {

                        s.name = "林青霞";//刚走到这里,就被别人抢到了执行权

                        s.age = 27;

                    } else {

                        s.name = "刘意"; //刚走到这里,就被别人抢到了执行权

                        s.age = 30;

                    }

                    x++;

                }

            }

        }

    }

     

     

                    3. GetThread(消费者)

    /*

    * 消费者类:

    */

    public class GetThread implements Runnable {

        private Student s;

     

        public GetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                //加入了同步代码块

                synchronized (s) {

                    System.out.println(s.name + "---" + s.age);

                }

            }

        }

    }

     

     

                    4. StudentDemo(测试类)

    /*

    * 分析:

    *         资源类:Student    

    *         设置学生数据:SetThread(生产者)

    *         获取学生数据:GetThread(消费者)

    *         测试类:StudentDemo

    *

    :按照思路写代码,发现数据每次都是:null---0

    * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个

    * 如何实现呢?

    *         在外界把这个数据创建出来,通过构造方法传递给其他的类。

    *

    :为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题

    *         A:同一个数据出现多次

    *         B:姓名和年龄不匹配

    * 原因:

    *         A:同一个数据出现多次

    *             CPU的一点点时间片的执行权,就足够你执行很多次。

    *         B:姓名和年龄不匹配

    *             线程运行的随机性

    * 线程安全问题:

    *         A:是否是多线程环境        是

    *         B:是否有共享数据        是

    *         C:是否有多条语句操作共享数据    是

    * 解决方案:

    *         加锁。

    *         注意:

    *             A:不同种类的线程都要加锁。

    *             B:不同种类的线程加的锁必须是同一把。

    */

    public class StudentDemo {

        public static void main(String[] args) {

            //创建资源

            Student s = new Student();

            

            //设置和获取的类

            SetThread st = new SetThread(s);

            GetThread gt = new GetThread(s);

     

            //线程类

            Thread t1 = new Thread(st);

            Thread t2 = new Thread(gt);

     

            //启动线程

            t1.start();

            t2.start();

        }

    }

     

     

                C:等待唤醒机制改进该程序,让数据能够实现依次的出现

                    Object类的方法:

    wait():让线程等待,并释放锁

                    notify():唤醒线程,并加锁

                    notifyAll() (多生产多消费)

                    1. Student(资源类)

    /*

    * 资源类:

    */

    public class Student {

        String name;

        int age;

        boolean flag; // 默认情况是没有数据,如果是true,说明有数据

    }

     

     

                    2. SetThread(生产者类)

    /*

    * 生产者类:加入了等待-唤醒机制

    */

    public class SetThread implements Runnable {

     

        private Student s;

        private int x = 0;

     

        public SetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                synchronized (s) {

                    //判断有没有

                    if(s.flag){

                        try {

                            s.wait(); //t1等着,释放锁

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                        }

                    }

                    

                    if (x % 2 == 0) {

                        s.name = "林青霞";

                        s.age = 27;

                    } else {

                        s.name = "刘意";

                        s.age = 30;

                    }

                    x++; //x=1

                    

                    //修改标记

                    s.flag = true;

                    //唤醒线程

                    s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。

                }

                //t1有,或者t2有

            }

        }

    }

     

                    3. GetThread(消费者类)

    /*

    * 消费者类:加入了等待-唤醒机制

    */

    public class GetThread implements Runnable {

        private Student s;

     

        public GetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                synchronized (s) {

                    if(!s.flag){

                        try {

                            s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候

                        } catch (InterruptedException e) {

                            e.printStackTrace();

                        }

                    }

                    

                    System.out.println(s.name + "---" + s.age);

                    //林青霞---27

                    //刘意---30

                    

                    //修改标记

                    s.flag = false;

                    //唤醒线程

                    s.notify(); //唤醒t1

                }

            }

        }

    }

     

                    4. StudentDemo(测试类)

    /*

    * 分析:

    *         资源类:Student    

    *         设置学生数据:SetThread(生产者)

    *         获取学生数据:GetThread(消费者)

    *         测试类:StudentDemo

    *

    :按照思路写代码,发现数据每次都是:null---0

    * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个

    * 如何实现呢?

    *         在外界把这个数据创建出来,通过构造方法传递给其他的类。

    *

    :为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题

    *         A:同一个数据出现多次

    *         B:姓名和年龄不匹配

    * 原因:

    *         A:同一个数据出现多次

    *             CPU的一点点时间片的执行权,就足够你执行很多次。

    *         B:姓名和年龄不匹配

    *             线程运行的随机性

    * 线程安全问题:

    *         A:是否是多线程环境        是

    *         B:是否有共享数据        是

    *         C:是否有多条语句操作共享数据    是

    * 解决方案:

    *         加锁。

    *         注意:

    *             A:不同种类的线程都要加锁。

    *             B:不同种类的线程加的锁必须是同一把。

    *

    * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。

    * 如何实现呢?

    *         通过Java提供的等待唤醒机制解决。

    *

    * 等待唤醒:

    *         Object类中提供了三个方法:

    *             wait():等待

    *             notify():唤醒单个线程

    *             notifyAll():唤醒所有线程

    *         为什么这些方法不定义在Thread类中呢?

    *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。

    *             所以,这些方法必须定义在Object类中。

    */

    public class StudentDemo {

        public static void main(String[] args) {

            //创建资源

            Student s = new Student();

            

            //设置和获取的类

            SetThread st = new SetThread(s);

            GetThread gt = new GetThread(s);

     

            //线程类

            Thread t1 = new Thread(st);

            Thread t2 = new Thread(gt);

     

            //启动线程

            t1.start();

            t2.start();

        }

    }

     

     

     

     

                D:等待唤醒机制的代码优化。把数据及操作都写在了资源类中

                1. Student(资源类,把数据及操作都写在资源类中)

    /*

    * 资源类:把数据及操作都写在资源类上面

    */

    public class Student {

        private String name;

        private int age;

        private boolean flag; // 默认情况是没有数据,如果是true,说明有数据

     

        //使用同步方法解决线程安全问题

        public synchronized void set(String name, int age) {

            // 如果有数据,就等待

            if (this.flag) {

                try {

                    this.wait();

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

     

            // 设置数据

            this.name = name;

            this.age = age;

     

            // 修改标记

            this.flag = true;

            this.notify();

        }

     

        //使用同步方法解决线程安全问题

        public synchronized void get() {

            // 如果没有数据,就等待

            if (!this.flag) {

                try {

                    this.wait();

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

     

            // 获取数据

            System.out.println(this.name + "---" + this.age);

     

            // 修改标记

            this.flag = false;

            this.notify();

        }

    }

     

     

                2. SetThread(生产者类)

    /*

    * 生产者类:

    */

    public class SetThread implements Runnable {

     

        private Student s;

        private int x = 0;

     

        public SetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                if (x % 2 == 0) {

                    s.set("林青霞", 27);

                } else {

                    s.set("刘意", 30);

                }

                x++;

            }

        }

    }

     

     

                3. GetThread(消费者类)

    /*

    * 消费者类:

    */

    public class GetThread implements Runnable {

        private Student s;

     

        public GetThread(Student s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            while (true) {

                s.get();

            }

        }

    }

     

     

                4. StudentDemo(测试类)

     

    /*

    * 分析:

    *         资源类:Student    

    *         设置学生数据:SetThread(生产者)

    *         获取学生数据:GetThread(消费者)

    *         测试类:StudentDemo

    *

    :按照思路写代码,发现数据每次都是:null---0

    * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个

    * 如何实现呢?

    *         在外界把这个数据创建出来,通过构造方法传递给其他的类。

    *

    :为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题

    *         A:同一个数据出现多次

    *         B:姓名和年龄不匹配

    * 原因:

    *         A:同一个数据出现多次

    *             CPU的一点点时间片的执行权,就足够你执行很多次。

    *         B:姓名和年龄不匹配

    *             线程运行的随机性

    * 线程安全问题:

    *         A:是否是多线程环境        是

    *         B:是否有共享数据        是

    *         C:是否有多条语句操作共享数据    是

    * 解决方案:

    *         加锁。

    *         注意:

    *             A:不同种类的线程都要加锁。

    *             B:不同种类的线程加的锁必须是同一把。

    *

    * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。

    * 如何实现呢?

    *         通过Java提供的等待唤醒机制解决。

    *

    * 等待唤醒:

    *         Object类中提供了三个方法:

    *             wait():等待

    *             notify():唤醒单个线程

    *             notifyAll():唤醒所有线程

    *         为什么这些方法不定义在Thread类中呢?

    *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。

    *             所以,这些方法必须定义在Object类中。

    *

    * 最终版代码中:

    *         把Student的成员变量给私有的了。

    *         把设置和获取的操作给封装成了功能,并加了同步。

    *         设置或者获取的线程里面只需要调用方法即可。

    */

    public class StudentDemo {

        public static void main(String[] args) {

            //创建资源

            Student s = new Student();

            

            //设置和获取的类

            SetThread st = new SetThread(s);

            GetThread gt = new GetThread(s);

     

            //线程类

            Thread t1 = new Thread(st);

            Thread t2 = new Thread(gt);

     

            //启动线程

            t1.start();

            t2.start();

        }

    }

     

     

     

     

     

        (4)线程组

            具体案例介绍

                1. MyRunnable(线程类)

    /*

    * 实现Runnable接口的线程类

    */

    public class MyRunnable implements Runnable {

     

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                //打印当前线程的名称及数字

                System.out.println(Thread.currentThread().getName() + ":" + x);

            }

        }

     

    }

     

                2. ThreadGroupDemo(测试类)

    /*

    * 线程组: 把多个线程组合到一起。

    * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

    *

    * 线程组类:ThreadGroup

    *         构造方法:public ThreadGroup(String name):构造一个带名称的线程组

    *         普通方法:public final String getName():返回此线程组的名称。

    *     注意:默认情况下,所有的线程都属于同一个组,就是main组

    * Thread类:

    *         构造方法:

    *         public Thread(ThreadGroup group,

    Runnable target,

    String name):创建一个属于某个线程组的且带名称的线程

    普通方法

    public final ThreadGroup getThreadGroup():返回该线程所属的线程组

     

    */

    public class ThreadGroupDemo {

        public static void main(String[] args) {

            // method1();

     

            // 我们如何修改线程所在的组呢?

            // 创建一个线程组

            // 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组

            method2();

     

            // t1.start();

            // t2.start();

        }

     

        private static void method2() {

            // ThreadGroup(String name)

            ThreadGroup tg = new ThreadGroup("这是一个新的组");

     

            MyRunnable my = new MyRunnable();

            // Thread(ThreadGroup group, Runnable target, String name)

            Thread t1 = new Thread(tg, my, "林青霞");

            Thread t2 = new Thread(tg, my, "刘意");

            

            System.out.println(t1.getThreadGroup().getName());

            System.out.println(t2.getThreadGroup().getName());

            

            //通过组名称设置后台线程,表示该组的线程都是后台线程

            tg.setDaemon(true);

        }

     

        private static void method1() {

            MyRunnable my = new MyRunnable();

            Thread t1 = new Thread(my, "林青霞");

            Thread t2 = new Thread(my, "刘意");

            // 我不知道他们属于那个线程组,我想知道,怎么办

            // 线程类里面的方法:public final ThreadGroup getThreadGroup()

            ThreadGroup tg1 = t1.getThreadGroup();

            ThreadGroup tg2 = t2.getThreadGroup();

            // 线程组里面的方法:public final String getName()

            String name1 = tg1.getName();

            String name2 = tg2.getName();

            System.out.println(name1);

            System.out.println(name2);

            // 通过结果我们知道了:线程默认情况下属于main线程组

            // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组

            System.out.println(Thread.currentThread().getThreadGroup().getName());

        }

    }

     

     

     

        (5)线程池

            案例代码体现:

            1. MyRunnable(线程类)

    /*

    * 实现Runnable接口的线程类

    */

    public class MyRunnable implements Runnable {

     

        @Override

        public void run() {

            for (int x = 0; x < 100; x++) {

                //打印当前线程的名称及数字

                System.out.println(Thread.currentThread().getName() + ":" + x);

            }

        }

     

    }

     

            2. ExecutorsDemo(线程池类)

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

     

    /*

    * 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

    *

    * 如何实现线程的代码呢?

    *         A:创建一个线程池对象,控制要创建几个线程对象。

    *             public static ExecutorService newFixedThreadPool(int nThreads)

    *         B:这种线程池的线程可以执行:

    *             可以执行Runnable对象或者Callable对象代表的线程

    *             做一个类实现Runnable接口。

    *         C:调用如下方法即可

    *             Future<?> submit(Runnable task)

    *            <T> Future<T> submit(Callable<T> task)

    *        D:我就要结束,可以吗?

    *            可以。

    */

    public class ExecutorsDemo {

        public static void main(String[] args) {

            // 创建一个线程池对象,控制要创建几个线程对象。

            // public static ExecutorService newFixedThreadPool(int nThreads)

            ExecutorService pool = Executors.newFixedThreadPool(2);

     

            // 可以执行Runnable对象或者Callable对象代表的线程

            pool.submit(new MyRunnable());

            pool.submit(new MyRunnable());

     

            //结束线程池

            pool.shutdown();

        }

    }

     

     

        (6)多线程实现的第三种方案

            多线程实现第三种方式介绍:

            1. MyCallable

    import java.util.concurrent.Callable;

     

    //Callable:是带泛型的接口。

    //这里指定的泛型其实是call()方法的返回值类型。

    public class MyCallable implements Callable {

     

        @Override

        public Object call() throws Exception {

            for (int x = 0; x < 100; x++) {

                System.out.println(Thread.currentThread().getName() + ":" + x);

            }

            return null;

        }

     

    }

     

            2. CallableDemo

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

     

    /*

    *     A:创建一个线程池对象,控制要创建几个线程对象。

    *             public static ExecutorService newFixedThreadPool(int nThreads)

    *         B:这种线程池的线程可以执行:

    *             可以执行Runnable对象或者Callable对象代表的线程

    *             做一个类实现Runnable接口。

    *         C:调用如下方法即可

    *             Future<?> submit(Runnable task)

    *            <T> Future<T> submit(Callable<T> task)

    *        D:我就要结束,可以吗?

    *            可以。

    */

    public class CallableDemo {

        public static void main(String[] args) {

            //创建线程池对象

            ExecutorService pool = Executors.newFixedThreadPool(2);

            

            //可以执行Runnable对象或者Callable对象代表的线程

            pool.submit(new MyCallable());

            pool.submit(new MyCallable());

            

            //结束

            pool.shutdown();

        }

    }

     

            多线程案例:求和

            1. MyCallable

    import java.util.concurrent.Callable;

     

    /*

    * 线程求和案例

    */

    public class MyCallable implements Callable<Integer> {

     

        private int number;

     

        public MyCallable(int number) {

            this.number = number;

        }

     

        @Override

        public Integer call() throws Exception {

            int sum = 0;

            for (int x = 1; x <= number; x++) {

                sum += x;

            }

            return sum;

        }

     

    }

     

            2. CallableDemo

    import java.util.concurrent.ExecutionException;

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    import java.util.concurrent.Future;

     

    /*

    *     A:创建一个线程池对象,控制要创建几个线程对象。

    *             public static ExecutorService newFixedThreadPool(int nThreads)

    *         B:这种线程池的线程可以执行:

    *             可以执行Runnable对象或者Callable对象代表的线程

    *             做一个类实现Runnable接口。

    *         C:调用如下方法即可

    *             Future<?> submit(Runnable task)

    *            <T> Future<T> submit(Callable<T> task)

    *        D:我就要结束,可以吗?

    *            可以。

    */

    public class CallableDemo {

        public static void main(String[] args) throws InterruptedException, ExecutionException {

            // 创建线程池对象

            ExecutorService pool = Executors.newFixedThreadPool(2);

     

            // 可以执行Runnable对象或者Callable对象代表的线程

            Future<Integer> f1 = pool.submit(new MyCallable(100));

            Future<Integer> f2 = pool.submit(new MyCallable(200));

     

            // V get()

            Integer i1 = f1.get();

            Integer i2 = f2.get();

     

            System.out.println(i1);

            System.out.println(i2);

     

            // 结束

            pool.shutdown();

        }

    }

     

     

        (7)匿名内部类方法实现多线程

        

    /*

    * 匿名内部类的格式:

    *         new 类名或者接口名() {

    *             重写方法;

    *         };

    *         本质:是该类或者接口的子类对象。

    */

    public class ThreadDemo {

        public static void main(String[] args) {

            // 继承Thread类来实现多线程

            new Thread() {

                public void run() {

                    for (int x = 0; x < 100; x++) {

                        System.out.println(Thread.currentThread().getName() + ":"

                                + x);

                    }

                }

            }.start();

     

            // 实现Runnable接口来实现多线程

            new Thread(new Runnable() {

                @Override

                public void run() {

                    for (int x = 0; x < 100; x++) {

                        System.out.println(Thread.currentThread().getName() + ":"

                                + x);

                    }

                }

            }) {

            }.start();

     

            // 更有难度的,以下的这个代码是不会报错的,可以正常运行,需要能看懂

            new Thread(new Runnable() {

                @Override

                public void run() {

                    for (int x = 0; x < 100; x++) {

                        System.out.println("hello" + ":" + x);

                    }

                }

            }) {

                public void run() {

                    for (int x = 0; x < 100; x++) {

                        System.out.println("world" + ":" + x);

                    }

                }

            }.start();

        }

    }

     

        (8)定时器的介绍

            1. TimerDemo类(任务完成之后,可以终止定时器)

    import java.util.Timer;

    import java.util.TimerTask;

     

    /*

    * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。

    * 依赖Timer和TimerTask这两个类:

    * Timer类:定时

    *         public Timer()

    *         public void schedule(TimerTask task,long delay):

    *                             :安排在指定延迟后执行指定的任务。

    *         public void schedule(TimerTask task, Date time)

    *                             :安排在指定的时间执行指定的任务

     

    *         public void schedule(TimerTask task,long delay,long period)

    *                          :安排指定的任务在指定的时间开始进行重复的固定延迟执行。

    *         public void cancel():终止此计时器,丢弃所有当前已安排的任务。

    *                              这不会干扰当前正在执行的任务(如果存在)。

    * TimerTask类:任务类

    *             子类继承该方法,并重写里面的run()方法

    */

    public class TimerDemo {

        public static void main(String[] args) {

            // 创建定时器对象

            Timer t = new Timer();

            // 3秒后执行爆炸任务

            // t.schedule(new MyTask(), 3000);

            //结束任务

            t.schedule(new MyTask(t), 3000);

        }

    }

     

    // 做一个任务

    class MyTask extends TimerTask {

     

        private Timer t;

        

        public MyTask(){}

        

        public MyTask(Timer t){

            this.t = t;

        }

        //要做的任务

        @Override

        public void run() {

            System.out.println("beng,爆炸了");

            //任务执行完成之后,终止此定时器

            t.cancel();

        }

    }

     

            2. TimerDemo2类(任务完成之后,不终止定时器)

    import java.util.Timer;

    import java.util.TimerTask;

     

    /*

    * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。

    * 依赖Timer和TimerTask这两个类:

    * Timer:定时

    *         public Timer()

    *         public void schedule(TimerTask task,long delay)

    *         public void schedule(TimerTask task,long delay,long period)

    *         public void cancel()

    * TimerTask:任务

    */

    public class TimerDemo2 {

        public static void main(String[] args) {

            // 创建定时器对象

            Timer t = new Timer();

    秒再继续炸

            t.schedule(new MyTask2(), 3000, 2000);

            //该程序不会自动停止

        }

    }

     

    // 做一个任务

    class MyTask2 extends TimerTask {

        @Override

        public void run() {

            System.out.println("beng,爆炸了");

        }

    }

     

            3. 案例:定时删除某个目录下的所有文件

    import java.io.File;

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.Timer;

    import java.util.TimerTask;

     

    /*

    * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)

    */

     

    class DeleteFolder extends TimerTask {

     

        //定时任务

        @Override

        public void run() {

            File srcFolder = new File("demo");

            deleteFolder(srcFolder);

        }

     

        // 递归删除目录

        public void deleteFolder(File srcFolder) {

            //获取源目录下的所有File对象的数组

            File[] fileArray = srcFolder.listFiles();

            

            //判断该File数组是否为null

            if (fileArray != null) {

                //不为null,循环遍历 该数组

                for (File file : fileArray) {

                    

                    //判断该file对象是否为目录

                    if (file.isDirectory()) {

                        //如果为目录,则进行递归

                        deleteFolder(file);

                    } else {

                        //不为目录,则打印被删除文件的名称并同时删除文件

                        System.out.println(file.getName() + ":" + file.delete());

                    }

                }

                //如果File数组为null,则打印被删除文件的名称并同时删除文件

                System.out.println(srcFolder.getName() + ":" + srcFolder.delete());

            }

        }

    }

     

    //测试类

    public class TimerTest {

        public static void main(String[] args) throws ParseException {

            //创建定时器对象

            Timer t = new Timer();

     

            String s = "2014-11-27 15:45:00";

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Date d = sdf.parse(s);

            //在指定的时间,删除某个目录下的所有文件

            t.schedule(new DeleteFolder(), d);

        }

    }

     

     

        (9)多线程的面试题

    1:多线程有几种实现方案,分别是哪几种?

        两种。

        

        继承Thread类

        实现Runnable接口

        

        扩展一种:实现Callable接口。这个得和线程池结合。

     

    2:同步有几种方式,分别是什么?

        两种。

        

        同步代码块

        同步方法

     

    3:启动一个线程是run()还是start()?它们的区别?

        start();

        

        run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用

        start():启动线程,并由JVM自动调用run()方法

     

    4:sleep()和wait()方法的区别

        sleep():必须指时间;不释放锁。

        wait():可以不指定时间,也可以指定时间;释放锁。

     

    5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中

        因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。

        而Object代表任意的对象,所以,定义在这里面。

     

    6:线程的生命周期图

        新建 -- 就绪 -- 运行 -- 死亡

        新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡

        建议:画图解释。

     

     

    2:设计模式(理解)

        (1)面试对象的常见设计原则

            单一

            开闭

            里氏

            依赖注入

            接口

            迪米特

        (2)设计模式概述和分类

            A:经验的总结

            B:三类

                创建型

                结构型

                行为型

        (3)改进的设计模式

            A:简单工厂模式

                1. Animal类(顶层抽象类)

    /*

    * 动物类:抽象类

    */

    public abstract class Animal {

        //吃的方法

        public abstract void eat();

    }

     

                2. Cat类

    /*

    * 猫类:继承动物类

    */

    public class Cat extends Animal {

        @Override

        public void eat() {

            System.out.println("猫吃鱼");

        }

     

    }

     

                3. Dog类

    /*

    * 狗类:继承动物类

    */

    public class Dog extends Animal {

     

        @Override

        public void eat() {

            System.out.println("狗吃肉");

        }

    }

     

                4. AnimalFactory类(动物工厂类)

                

    /*

    * 动物工厂类:专门造动物的

    */

    public class AnimalFactory {

        //构造方法私有,不允许创建对象

        private AnimalFactory() {

        }

        //根据传递过来的类型,创建指定的对象,可通过类名直接调用

        public static Animal createAnimal(String type) {

            if ("dog".equals(type)) {

                return new Dog();

            } else if ("cat".equals(type)) {

                return new Cat();

            } else {

                return null;

            }

        }

    }

     

                5. AnimalDemo(测试类)

    /*

    * 测试类

    */

    public class AnimalDemo {

        public static void main(String[] args) {

            // 具体类调用

            Dog d = new Dog();

            d.eat();

            Cat c = new Cat();

            c.eat();

            System.out.println("------------");

     

            // 工厂改进后

            Animal a = AnimalFactory.createAnimal("dog");

            a.eat();

            a = AnimalFactory.createAnimal("cat");

            a.eat();

     

            // NullPointerException,在使用对象之前,应该先对对象是否为null进行判断

            a = AnimalFactory.createAnimal("pig");

            if (a != null) {

                a.eat();

            } else {

                System.out.println("对不起,暂时不提供这种动物");

            }

        }

    }

     

                

            B:工厂方法模式

                1. Animal(动物类)

    /*

    * 动物类:抽象 类

    */

    public abstract class Animal {

        public abstract void eat();

    }

     

                2. Cat类(猫类)

    /*

    * 猫类:继承自动物类

    */

    public class Cat extends Animal {

     

        @Override

        public void eat() {

            System.out.println("猫吃鱼");

        }

     

    }

     

                3. Dog(狗类)

    /*

    * 狗类:继承自动物类

    */

    public class Dog extends Animal {

     

        @Override

        public void eat() {

            System.out.println("狗吃肉");

        }

     

    }

     

                4. Factory(接口)

    /*

    * Factory:工厂接口

    */

    public interface Factory {

        //定义了创建动物的方法

        public abstract Animal createAnimal();

    }

     

                5. CatFactory(猫工厂)

    /*

    * CatFactory:猫工厂,实现工厂接口,专门用来生成猫

    */

    public class CatFactory implements Factory {

     

        @Override

        public Animal createAnimal() {

            return new Cat();

        }

     

    }

     

                6. DogFactory(狗工厂)

    /*

    * 狗工厂:实现了工厂接口,专门用来造狗

    */

    public class DogFactory implements Factory {

     

        @Override

        public Animal createAnimal() {

            return new Dog();

        }

     

    }

     

                7. AnimalDemo测试类

    /*

    * 测试类

    */

    public class AnimalDemo {

        public static void main(String[] args) {

            // 需求:我要买只狗

            Factory f = new DogFactory();

            Animal a = f.createAnimal();

            a.eat();

            System.out.println("-------");

            

            //需求:我要买只猫

            f = new CatFactory();

            //使用特定的工厂专门造狗,造猫

            a = f.createAnimal();

            a.eat();

        }

    }

     

            C:单例模式(掌握)

                a:饿汉式:

                说明:饿汉式:提前造好一个对象(开发中常用,因为不容易出现问题)

                1.

    /*

    * 单例模式:饿汉式:提前造好一个对象

    */

    public class Student {

        // 构造私有

        private Student() {

        }

     

        // 自己造一个

        // 静态方法只能访问静态成员变量,加静态

        // 为了不让外界直接访问修改这个值,加private

        private static Student s = new Student();

     

        // 提供公共的访问方式

        // 为了保证外界能够直接使用该方法,加静态

        public static Student getStudent() {

            return s;

        }

    }

     

     

                2. StudentDemo测试类

    /*

    * 单例模式:保证类在内存中只有一个对象。

    *

    * 如何保证类在内存中只有一个对象呢?

    *         A:把构造方法私有

    *         B:在成员位置自己创建一个对象

    *         C:通过一个公共的方法提供访问

    */

    public class StudentDemo {

        public static void main(String[] args) {

            //通过单例模式得到对象

            Student s1 = Student.getStudent();

            Student s2 = Student.getStudent();

            System.out.println(s1 == s2);

     

            System.out.println(s1); // null,cn.itcast_03.Student@175078b

            System.out.println(s2);// null,cn.itcast_03.Student@175078b

        }

    }

     

     

                b:懒汉式:

                说明:需要用的时候,才去创建对象。(面试常面)

                1. Teacher类

    /*

    * 单例模式:

    *         饿汉式:类一加载就创建对象

    *         懒汉式:用的时候,才去创建对象

    *

    * 面试题:单例模式的思想是什么?请写一个代码体现。

    *

    *         开发:饿汉式(是不会出问题的单例模式)

    *         面试:懒汉式(可能会出问题的单例模式)

    *             A:懒加载(延迟加载)    

    *             B:线程安全问题

    *                 a:是否多线程环境    是

    *                 b:是否有共享数据    是

    *                 c:是否有多条语句操作共享数据     是

    */

    public class Teacher {

        //构造方法私有化

        private Teacher() {

        }

     

        //定义一个对象

        private static Teacher t = null;

     

        //加入同步关键字解决线程安全问题

        public synchronized static Teacher getTeacher() {

            // t1,t2,t3

            //如果对象为null,就创建,否则不创建

            if (t == null) {

                //t1,t2,t3

                t = new Teacher();

            }

            return t;

        }

    }

     

     

                2. TeacherDemo类

    /*

    * 测试类

    */

    public class TeacherDemo {

        public static void main(String[] args) {

            Teacher t1 = Teacher.getTeacher();

            Teacher t2 = Teacher.getTeacher();

            System.out.println(t1 == t2);

            System.out.println(t1); // cn.itcast_03.Teacher@175078b

            System.out.println(t2);// cn.itcast_03.Teacher@175078b

        }

    }

     

     

     

        (4)Runtime

            JDK提供的一个单例模式应用的类。

            还可以调用dos命令。

            

    import java.io.IOException;

     

    /*

    * Runtime:每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。

    * exec(String command)

    */

    public class RuntimeDemo {

        public static void main(String[] args) throws IOException {

            Runtime r = Runtime.getRuntime();

    //        r.exec("winmine");

            //打开记事本

            // r.exec("notepad");

            //打开计算器

            // r.exec("calc");

            //关机(时间是以秒计算的)

    //        r.exec("shutdown -s -t 10000");

            //取消shutdown的命令

            r.exec("shutdown -a");

        }

    }

     

    /*该Runtime类使用了单例模式

    * class Runtime {

    *         private Runtime() {}

    *         private static Runtime currentRuntime = new Runtime();

    *         public static Runtime getRuntime() {

    *     return currentRuntime;

    *     }

    * }

    */

     

     

     

     

     

     

    第二十五天

    1:如何让Netbeans的东西Eclipse能访问。

        在Eclipse中创建项目,把Netbeans项目的src下的东西给拿过来即可。

        注意:修改项目编码为UTF-8

        

    2:GUI(了解)

        (1)用户图形界面

            GUI:方便直观

            CLI:需要记忆一下命令,麻烦

        (2)两个包:

            java.awt:和系统关联较强(重量级)

            javax.swing:纯Java编写(轻量级)

        (3)主要方法:

            A:javax.swing包下的方法    

     

                构造方法:

                public JFrame(String title):创建对象的同时,设置标题名称

                public JFrame():无参构造

     

                普通方法:

                public
    void setTitle(String title):设置窗体的标题

                public
    void setSize(int
    width, int
    height):设置窗体的大小

    public
    void setSize(Dimension d):通过传入Dimension对象设置窗体大小

                public Dimension(int
    width, int
    height):Dimension类的构造方法

                public
    void setLocation(int
    x, int
    y):设置窗体的坐标

    public
    void setLocation(Point p):通过传入一个Point对象,来设置窗体坐标

    public Point(int
    x, int
    y):Point类的构造方法

                public
    void setVisible(boolean
    b):设置让窗体可见

     

                用一个方法完成窗体大小和坐标的设置

                public
    void setBounds(int
    x, int
    y, int
    width, int
    height):

                参数x、y设置窗体坐标。Width、height设置窗体大小

     

                public
    void setLayout(LayoutManager mgr):设置窗体的布局模式

                            常用的为流式布局:FlowLayout

     

            B:监听机制的应用

                案例:关闭窗体

                

    import java.awt.Frame;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

     

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象

            JFrame f = new JFrame("窗体关闭案例");

     

            // 设置窗体属性

            f.setBounds(400, 200, 400, 300);

     

            //用适配器类改进

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            // 设置窗体可见

            f.setVisible(true);

        }

    }

     

        (4)GUI的继承体系

            组件:组件就是对象

                容器组件:是可以存储基本组件和容器组件的组件。

                基本组件:是可以使用的组件,但是必须依赖容器。

        (5)事件监听机制(理解)

            A:事件源

            B:事件

            C:事件处理

            D:事件监听

        (6)适配器模式(理解)

            应用场景:当一个接口中有蛮多方法的时候,而我们只需要用其中某一个方法,但是呢?

                    用其中的一个方法,就要实现该接口中的所有方法,有点不划算,所以呢?

                    适配器模式就应运而生啦

            A:接口

                    定义一个顶层的接口

            B:抽象适配器类

                    用一个抽象类实现该接口,当然是空实现(不提供具体的方法体)

            C:实现类

                用具体的类继承抽象适配器类,想用哪个方法,就重写哪个方法,不用重写所有方法

            案例解释

                1. UserDao(顶层接口)

    /*

    * 顶层接口:针对用户操作的四种功能

    */

    public interface UserDao {

        public abstract void add();

     

        public abstract void delete();

     

        public abstract void update();

     

        public abstract void find();

    }

     

                2. UserAdapter(适配器类,实现顶层接口)

    /*

    * 定义一个类实现UserDao接口:当然啦,是空实现

    */

    public abstract class UserAdapter implements UserDao {

     

        @Override

        public void add() {

        }

     

        @Override

        public void delete() {

        }

     

        @Override

        public void update() {

        }

     

        @Override

        public void find() {

        }

    }

     

                3. UserDaoImpl(具体实现类,需继承UserAdapter适配器类)

    /*

    * 具体实现类:继承UserAdapter适配器类,重写里面

    *             自己想要使用的方法

    */

    public class UserDaoImpl extends UserAdapter {

        @Override

        public void add() {

            System.out.println("添加功能");

        }

    }

     

                4. UserDaoDemo(测试类)

    /*

    * 问题:

    *         接口(方法比较多) -- 实现类(仅仅使用一个,也得把其他的实现给提供了,哪怕是空实现)

    *         太麻烦了。

    * 解决方案:

    *         接口(方法比较多) -- 适配器类(实现接口,仅仅空实现) -- 实现类(用哪个重写哪个)

    */

    public class UserDaoDemo {

        public static void main(String[] args) {

            UserDao ud = new UserDaoImpl();

            ud.add();

            // 我没有说我们需要四种功能都实现啊。

            UserDao ud2 = new UserDaoImpl2();

            ud2.add();

        }

    }

     

        

        (7)案例:

            A:创建窗体案例

    import javax.swing.JFrame;

    /*

    * 需求:创建一个窗体(该窗体默认情况下是不能关闭的)

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象

            // Frame f = new Frame();

            // Frame(String title)

            JFrame f = new JFrame("林青霞");

     

            // 设置窗体标题

            f.setTitle("HelloWorld");

            // 设置窗体大小

            f.setSize(400, 300); // 单位:像素

            // 设置窗体位置

            f.setLocation(400, 200);

     

            // 调用一个方法,设置让窗体可见

            // f.show();

            f.setVisible(true);

     

            // System.out.println("helloworld");

        }

    }

     

            B:窗体关闭案例

            

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    import javax.swing.JFrame;

    /*

    * 需求:创建一个窗体(该窗体可以直接被关闭的)

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象

            JFrame f = new JFrame("窗体关闭案例");

     

            // 设置窗体属性

            f.setBounds(400, 200, 400, 300);

            

            //用适配器类改进,为窗体添加监听机制

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            // 设置窗体可见

            f.setVisible(true);

        }

    }

     

            C:窗体添加按钮并对按钮添加事件案例。

                界面中的组件布局。

    import java.awt.Button;

    import java.awt.FlowLayout;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

     

    import javax.swing.JFrame;

     

    /*

    * 需求:把按钮添加到窗体,并对按钮添加一个点击事件。

    * A:创建窗体对象

    * B:创建按钮对象

    * C:把按钮添加到窗体

    * D:窗体显示

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象

            JFrame f = new JFrame("添加按钮");

            // 设置属性

            f.setBounds(400, 200, 400, 300);

            // 设置布局为流式布局

            f.setLayout(new FlowLayout());

     

            // 创建按钮对象

            Button bu = new Button("点我啊");

            // bu.setSize(20, 10);

     

            // 把按钮添加到窗体

            f.add(bu);

     

            // 设置窗体可以关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            bu.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    System.out.println("你再点试试");

                }

            });

     

            // 窗体显示

            f.setVisible(true);

        }

    }

     

            D:把文本框里面的数据转移到文本域

    import java.awt.Button;

    import java.awt.FlowLayout;

    import java.awt.TextArea;

    import java.awt.TextField;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

     

    import javax.swing.JFrame;

    /*

    * 需求:将文本框中的数据转移到文本域中

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象

            JFrame f = new JFrame("数据转移");

            // 设置窗体属性和布局

            f.setBounds(400, 200, 400, 300);

            f.setLayout(new FlowLayout());

     

            // 创建文本框

            final TextField tf = new TextField(20);

            // 创建按钮

            Button bu = new Button("数据转移");

            // 创建文本域

            final TextArea ta = new TextArea(10, 40);

     

            // 把组件添加到窗体

            f.add(tf);

            f.add(bu);

            f.add(ta);

     

            // 设置窗体关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            // 对按钮添加事件

            bu.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    // 获取文本框的值

                    String tf_str = tf.getText().trim();

                    // 清空数据

                    tf.setText("");

     

                    // 设置给文本域

                    // ta.setText(tf_str);

                    // 追加和换行

                    ta.append(tf_str + "\r\n");

                    

                    //获取光标

                    tf.requestFocus();

                }

            });

     

            // 设置窗体显示

            f.setVisible(true);

        }

    }

     

            E:更改背景色

    import java.awt.Button;

    import java.awt.Color;

    import java.awt.FlowLayout;

    import java.awt.Frame;

    import java.awt.event.MouseAdapter;

    import java.awt.event.MouseEvent;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    /*

    * 需求:更改背景色

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象,局部内部类访问局部变量,局部变量必须用final修饰

            final Frame f = new Frame("更改背景色");

            // 设置窗体属性和布局

            f.setBounds(400, 200, 400, 300);

            f.setLayout(new FlowLayout());

     

            // 创建四个按钮

            Button redButton = new Button("红色");

            Button greenButton = new Button("绿色");

            Button buleButton = new Button("蓝色");

     

            // 添加按钮

            f.add(redButton);

            f.add(greenButton);

            f.add(buleButton);

     

            // 设置窗体关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            // 对按钮添加动作事件

            // redButton.addActionListener(new ActionListener() {

            // @Override

            // public void actionPerformed(ActionEvent e) {

            // f.setBackground(Color.RED);

            // }

            // });

     

            // 对按钮添加鼠标点击事件

            // redButton.addMouseListener(new MouseAdapter() {

            // @Override

            // public void mouseClicked(MouseEvent e) {

            // f.setBackground(Color.RED);

            // }

            // });

     

            // 对按钮添加鼠标的进入事件

            redButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseEntered(MouseEvent e) {

                    f.setBackground(Color.RED);

                }

            });

            // 对按钮添加鼠标的离开事件

            redButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseExited(MouseEvent e) {

                    f.setBackground(Color.WHITE);

                }

            });

     

            greenButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseEntered(MouseEvent e) {

                    f.setBackground(Color.GREEN);

                }

            });

     

            greenButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseExited(MouseEvent e) {

                    f.setBackground(Color.WHITE);

                }

            });

     

            buleButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseEntered(MouseEvent e) {

                    f.setBackground(Color.BLUE);

                }

            });

     

            buleButton.addMouseListener(new MouseAdapter() {

                @Override

                public void mouseExited(MouseEvent e) {

                    f.setBackground(Color.WHITE);

                }

            });

     

            // 设置窗体显示

            f.setVisible(true);

        }

    }

     

            F:设置文本框里面不能输入非数字字符

    import java.awt.FlowLayout;

    import java.awt.Frame;

    import java.awt.Label;

    import java.awt.TextField;

    import java.awt.event.KeyAdapter;

    import java.awt.event.KeyEvent;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

     

    /*

    * 需求:你输入的如果是非数字字符,就取消你键盘录入的效果。

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象并设置属性

            Frame f = new Frame("不能输入非数字字符");

            f.setBounds(400, 200, 400, 300);

            f.setLayout(new FlowLayout());

     

            // 创建Label标签对象

            Label label = new Label("请输入你的QQ号码,不能是非数字,不信你试试");

            TextField tf = new TextField(40);

     

            // 添加到窗体上

            f.add(label);

            f.add(tf);

     

            // 设置窗体关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            // 给文本框添加事件

            tf.addKeyListener(new KeyAdapter() {

                @Override

                public void keyPressed(KeyEvent e) {

                    // 如果你取得的字符不是数字字符就取消事件

                    // 思路:先获取字符,判断字符,取消事件

                    // char getKeyChar()

                    char ch = e.getKeyChar();

                    // System.out.println(ch);

                    if (!(ch >= '0' && ch <= '9')) {

                        e.consume();

                    }

                }

            });

     

            // 设置窗体可见

            f.setVisible(true);

        }

    }

     

            G:一级菜单

    import java.awt.FlowLayout;

    import java.awt.Frame;

    import java.awt.Menu;

    import java.awt.MenuBar;

    import java.awt.MenuItem;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

     

    /*

    * 需求:制作一级菜单

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象并设置属性

            Frame f = new Frame("一级菜单");

            f.setBounds(400, 200, 400, 300);

            f.setLayout(new FlowLayout());

     

            // 创建菜单栏

            MenuBar mb = new MenuBar();

            // 创建菜单

            Menu m = new Menu("文件");

            // 创建菜单项

            MenuItem mi = new MenuItem("退出系统");

     

            // 谁添加谁呢

            m.add(mi);

            mb.add(m);

     

            // 设置菜单栏

            f.setMenuBar(mb);

     

            // 设置窗体关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

     

            mi.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    System.exit(0);

                }

            });

     

            // 设置窗体可见

            f.setVisible(true);

        }

    }

     

            H:多级菜单

    import java.awt.FlowLayout;

    import java.awt.Frame;

    import java.awt.Menu;

    import java.awt.MenuBar;

    import java.awt.MenuItem;

    import java.awt.event.ActionEvent;

    import java.awt.event.ActionListener;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    import java.io.IOException;

     

    /*

    * 需求:制作多级菜单

    */

    public class FrameDemo {

        public static void main(String[] args) {

            // 创建窗体对象并设置属性

            final Frame f = new Frame("多级菜单");

            f.setBounds(400, 200, 400, 300);

            f.setLayout(new FlowLayout());

            

            final String name = f.getTitle();

     

            // 创建菜单栏

            MenuBar mb = new MenuBar();

            // 创建菜单

            Menu m1 = new Menu("文件");

            Menu m2 = new Menu("更改名称");

            // 创建菜单项

            final MenuItem mi1 = new MenuItem("好好学习");

            final MenuItem mi2 = new MenuItem("天天向上");

            MenuItem mi3 = new MenuItem("恢复标题");

            MenuItem mi4 = new MenuItem("打开记事本");

            MenuItem mi5 = new MenuItem("退出系统");

     

            // 谁添加谁呢

            m2.add(mi1);

            m2.add(mi2);

            m2.add(mi3);

            

            m1.add(m2);

            m1.add(mi4);

            m1.add(mi5);

            

            mb.add(m1);

     

            // 设置菜单栏

            f.setMenuBar(mb);

     

            // 设置窗体关闭

            f.addWindowListener(new WindowAdapter() {

                @Override

                public void windowClosing(WindowEvent e) {

                    System.exit(0);

                }

            });

            

            mi1.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    f.setTitle(mi1.getLabel());

                }

            });

            

            mi2.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    f.setTitle(mi2.getLabel());

                }

            });

            

            mi3.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    f.setTitle(name);

                }

            });

            

            mi4.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    Runtime r = Runtime.getRuntime();

                    try {

                        r.exec("notepad");

                    } catch (IOException e1) {

                        e1.printStackTrace();

                    }

                }

            });

     

            mi5.addActionListener(new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    System.exit(0);

                }

            });

     

            // 设置窗体可见

            f.setVisible(true);

        }

    }

     

        (8)Netbeans的概述和使用

            A:是可以做Java开发的另一个IDE工具,做GUI界面开发特别方便。

            B:使用

                A:四则运算

                    a:修改图标        b:设置皮肤

                    c:设置居中        d:数据校验

                B:登录注册

     

    第二十六天

    1:网络编程(理解)

        (1)网络编程:用Java语言实现计算机间数据的信息传递和资源共享

        (2)网络编程模型

        (3)网络编程的三要素

            A:IP地址

                a:点分十进制

                b:IP地址的组成

                c:IP地址的分类

                d:dos命令

                e:InetAddress

            B:端口

                是应用程序的标识。范围:0-65535。其中0-1024不建议使用。

            C:协议

                UDP:数据打包,有限制,不连接,效率高,不可靠

                TCP:建立数据通道,无限制,效率低,可靠

    /*

    * 网络编程三要素:

        A:IP地址

        B:端口

        C:协议

        

    举例:

        我想和林青霞说话了。肿么办?

        A:我要找到林青霞。

        B:对她说话,要对耳朵说。

        C:我说什么呢?"I Love You"

         但是,她没学过英语,听不懂。

         我没必要说英语,说汉语就可以了:我爱你

        

    IP地址:

        网络中计算机的唯一标识。

        

        计算机只能识别二进制的数据,所以我们的IP地址应该是一个二进制的数据。

        但是呢,我们配置的IP地址确不是二进制的,为什么呢?

            IP:192.168.1.100

            换算:11000000 10101000 00000001 01100100

        假如真是:11000000 10101000 00000001 01100100的话。

        我们如果每次再上课的时候要配置该IP地址,记忆起来就比较的麻烦。

        所以,为了方便表示IP地址,我们就把IP地址的每一个字节上的数据换算成十进制,然后用.分开来表示:

            "点分十进制"

            

        IP地址的组成:网络号段+主机号段

            A类:第一号段为网络号段+后三段的主机号段

                一个网络号:256*256*256 = 16777216

            B类:前二号段为网络号段+后二段的主机号段

                一个网络号:256*256 = 65536

            C类:前三号段为网络号段+后一段的主机号段

        

        IP地址的分类:

            A类    1.0.0.1---127.255.255.254    (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)                            (2)127.X.X.X是保留地址,用做循环测试用的。

            B类    128.0.0.1---191.255.255.254    172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。

            C类    192.0.0.1---223.255.255.254    192.168.X.X是私有地址

            D类    224.0.0.1---239.255.255.254     

            E类    240.0.0.1---247.255.255.254

            

        两个DOS命令:

            ipconfig
    查看本机ip地址

            ping 后面跟ip地址。测试本机与指定的ip地址间的通信是否有问题

            

        特殊的IP地址:

            127.0.0.1 回环地址(表示本机)

            x.x.x.255 广播地址

            x.x.x.0 网络地址

            

    端口号:

        正在运行的程序的标识。

        有效端口:0~65535,其中0~1024系统使用或保留端口。

        

    协议:

        通信的规则

        

        UDP:

            把数据打包

            数据有限制

            不建立连接

            速度快

            不可靠

        

        TCP:

            建立连接通道

            数据无限制

            速度慢

            可靠

        

        举例:

            UDP:发短信

            TCP:打电话

    */

     

        (4)网络编程中主要类介绍:

            A:InetAddress: 此类表示互联网协议 (IP) 地址。

                构造方法:

                public
    static InetAddress getByName(String host):根据主机名或者ip地址

                的字符串表现形式创建IP地址对象

                普通方法:

                public String getHostName():获取主机名

                public String getHostAddress():获取IP地址

                案例演示:

    import java.net.InetAddress;

    import java.net.UnknownHostException;

     

    /*

    * 如果一个类没有构造方法:

    * A:成员全部是静态的(Math,Arrays,Collections)

    * B:单例设计模式(Runtime)

    * C:类中有静态方法返回该类的对象(InetAddress)

    *         class Demo {

    *             private Demo(){}

    *

    *             public static Demo getXxx() {

    *                 return new Demo();

    *             }

    *         }

    *

    * 看IP地址类:InetAddress的成员方法:

    * public static InetAddress getByName(String host):

    *                     根据主机名或者IP地址的字符串表示得到IP地址对象

    *

    *         普通方法:

    *          public String getHostName():获取该IP地址对象的主机名

    *          public String getHostAddress():获取主机IP地址

    */

    public class InetAddressDemo {

        public static void main(String[] args) throws UnknownHostException {

            // public static InetAddress getByName(String host)

            // InetAddress address = InetAddress.getByName("liuyi");

            // InetAddress address = InetAddress.getByName("192.168.12.92");

            InetAddress address = InetAddress.getByName("asus");

     

            // 获取两个东西:主机名,IP地址

            // public String getHostName()

            String name = address.getHostName();

            // public String getHostAddress()

            String ip = address.getHostAddress();

            System.out.println(name + "---" + ip);

        }

    }

     

        
     

            B:    UDP协议下的Socket对象类DatagramSocket

                1.发送端:

     

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

    /*

    * UDP协议发送数据:

    * A:创建发送端Socket对象

    * B:创建数据,并把数据打包

    * C:调用Socket对象的发送方法发送数据包

    * D:释放资源

    *

    * 说明:UDP协议下的接收端和发送端的Socket对象都是同一个类DatagramSocket

    *     

    *     DatagramSocket类的方法:

    *         构造方法:public DatagramSocket()

    *         普通方法:public void send(DatagramPacket p):

    *                 从此套接字发送数据报包

    *              public void close()

    *                 关闭此数据报套接字。

    *              public synchronized void receive(DatagramPacket p):

    *                  从此套接字接收数据报包。

    *                 

    *     DatagramPacket数据包类:

    *         构造方法:public DatagramPacket(byte buf[], int length,

    InetAddress address, int port)

    构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号    

     

    public DatagramPacket(byte buf[], int length):

            构造 DatagramPacket,用来接收长度为 length 的数据包

     

    public synchronized InetAddress getAddress():

                    返回某台机器的 IP 地址对象

                    

    public synchronized byte[] getData():返回数据缓冲区

    public synchronized int getLength():返回将要发送或接收到的数据的长度

    */

    public class SendDemo {

        public static void main(String[] args) throws IOException {

            // 创建发送端Socket对象

            // DatagramSocket()

            DatagramSocket ds = new DatagramSocket();

     

            // 创建数据,并把数据打包

            // DatagramPacket(byte[] buf, int length, InetAddress address, int port)

            // 创建数据

            byte[] bys = "hello,udp,我来了".getBytes();

            // 长度

            int length = bys.length;

            // IP地址对象

            InetAddress address = InetAddress.getByName("192.168.12.92");

            // 端口

            int port = 10086;

            DatagramPacket dp = new DatagramPacket(bys, length, address, port);

     

            // 调用Socket对象的发送方法发送数据包

            // public void send(DatagramPacket p)

            ds.send(dp);

     

            // 释放资源

            ds.close();

        }

    }

     

                2.接收端:

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

     

    /*

    * UDP协议接收数据:

    * A:创建接收端Socket对象

    * B:创建一个数据包(接收容器)

    * C:调用Socket对象的接收方法接收数据

    * D:解析数据包,并显示在控制台

    * E:释放资源

    */

    public class ReceiveDemo {

        public static void main(String[] args) throws IOException {

            // 创建接收端Socket对象

            // DatagramSocket(int port)

            DatagramSocket ds = new DatagramSocket(10086);

     

            // 创建一个数据包(接收容器)

            // DatagramPacket(byte[] buf, int length)

            byte[] bys = new byte[1024];

            int length = bys.length;

            DatagramPacket dp = new DatagramPacket(bys, length);

     

            // 调用Socket对象的接收方法接收数据

            // public void receive(DatagramPacket p)

            ds.receive(dp); // 阻塞式

     

            // 解析数据包,并显示在控制台

            // 获取对方的ip

            // public InetAddress getAddress()

            InetAddress address = dp.getAddress();

            String ip = address.getHostAddress();

            // public byte[] getData():获取数据缓冲区

            // public int getLength():获取数据的实际长度

            byte[] bys2 = dp.getData();

            int len = dp.getLength();

            String s = new String(bys2, 0, len);

            System.out.println(ip + "传递的数据是:" + s);

     

            // 释放资源

            ds.close();

        }

    }

     

            C:    TCP协议下的主要类介绍:

                客户端的主要类:Socket类

                    构造方法

    public Socket(String host, int
    port):创建一个流套接字并将其连接到指定主机上的指定端口号。

    普通方法:

    public OutputStream getOutputStream():返回此套接字的输出流。

    public InputStream getInputStream():返回此套接字的输入流

     

    public
    synchronized
    void close():关闭此套接字

     

                服务器端的主要类:ServerSocket类

                    构造方法

                    public ServerSocket(int
    port):创建绑定到特定端口的服务器套接字

     

                    普通方法

                    public Socket accept():侦听并接受到此套接字的连接

                    

                    案例演示:

                    1.客户端:

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.Socket;

     

    /*

    * TCP协议发送数据:

    * A:创建发送端的Socket对象

    *         这一步如果成功,就说明连接已经建立成功了。

    * B:获取输出流,写数据

    * C:释放资源

    *

    *     TCP协议下的套接字类:

    *         套接字类:发送端的socket

    *             构造方法:public Socket(String host, int port)

    *                     创建一个流套接字并将其连接到指定主机上的指定端口号。

    *             普通方法:

    *             public OutputStream getOutputStream():

    *                                 返回此套接字的输出流。

    *             public InputStream getInputStream():

    *                                 返回此套接字的输入流

    *

    *             public synchronized void close():关闭此套接字

    *

    *

    * 连接被拒绝。TCP协议一定要先看服务器。

    * java.net.ConnectException: Connection refused: connect

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建发送端的Socket对象

            // Socket(InetAddress address, int port)

            // Socket(String host, int port)

            // Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888);

            Socket s = new Socket("192.168.12.92", 8888);

     

            // 获取输出流,写数据

            // public OutputStream getOutputStream()

            OutputStream os = s.getOutputStream();

            os.write("hello,tcp,我来了".getBytes());

     

            // 释放资源

            s.close();

        }

    }

     

                    2.服务器端:                

    import java.io.IOException;

    import java.io.InputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

     

    /*

    * TCP协议接收数据:

    * A:创建接收端的Socket对象

    * B:监听客户端连接。返回一个对应的Socket对象

    * C:获取输入流,读取数据显示在控制台

    * D:释放资源

    *

    * 服务器端的套接字类:ServerSocket

    *         构造方法:

    *         public ServerSocket(int port):创建绑定到特定端口的服务器套接字

    *

    *         普通方法:

    *         public Socket accept():侦听并接受到此套接字的连接

    * 说明:不应该关闭服务器端的套接字连接

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建接收端的Socket对象

            // ServerSocket(int port)

            ServerSocket ss = new ServerSocket(8888);

     

            // 监听客户端连接。返回一个对应的Socket对象

            // public Socket accept()

            Socket s = ss.accept(); // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。

     

            // 获取输入流,读取数据显示在控制台

            InputStream is = s.getInputStream();

     

            byte[] bys = new byte[1024];

            int len = is.read(bys); // 阻塞式方法

            String str = new String(bys, 0, len);

     

            String ip = s.getInetAddress().getHostAddress();

     

            System.out.println(ip + "---" + str);

     

            // 释放资源

            s.close();

            // ss.close(); //这个不应该关闭

        }

    }

     

        (5)Socket机制

            A:通信两端都应该有Socket对象

            B:所有的通信都是通过Socket间的IO进行操作的

        (4)UDP协议发送和接收数据(掌握)

            1.原理图解

            2.发送:步骤

                A:创建UDP发送端的Socket对象

                B:创建数据并把数据打包

                C:发送数据

                D:释放资源

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

    /*

    * 发送端:

    */

    public class SendDemo {

        public static void main(String[] args) throws IOException {

            // 创建发送端的Socket对象

            DatagramSocket ds = new DatagramSocket();

     

            // 创建数据并打包

            byte[] bys = "helloworld".getBytes();

            DatagramPacket dp = new DatagramPacket(bys, bys.length,

                    InetAddress.getByName("192.168.12.92"), 12345);

     

            // 发送数据

            ds.send(dp);

     

            // 释放资源

            ds.close();

        }

    }

     

                

            3.接收:步骤

                A:创建UDP接收端的Socket对象

                B:创建数据包用于接收数据

                C:接收数据

                D:解析数据包

                E:释放资源

    /*

    * 多次启动接收端:

    *         java.net.BindException: Address already in use: Cannot bind

    *         端口被占用。

    */

    public class ReceiveDemo {

        public static void main(String[] args) throws IOException {

            // 创建接收端的Socket对象

            DatagramSocket ds = new DatagramSocket(12345);

     

            // 创建一个包裹

            byte[] bys = new byte[1024];

            DatagramPacket dp = new DatagramPacket(bys, bys.length);

     

            // 接收数据

            ds.receive(dp);

     

            // 解析数据

            String ip = dp.getAddress().getHostAddress();

            String s = new String(dp.getData(), 0, dp.getLength());

            System.out.println("from " + ip + " data is : " + s);

     

            // 释放资源

            ds.close();

        }

    }

     

        (5)TCP协议发送和接收数据(掌握)

            A:原理图解

            

     

            2.发送:步骤

                a.创建TCP客户端的Socket对象

                b.获取输出流,写数据

                c.释放资源

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.Socket;

    /*

    * 客户端:

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 9999);

     

            // 获取输出流

            OutputStream os = s.getOutputStream();

            os.write("今天天气很好,适合睡觉".getBytes());

     

            // 获取输入流

            InputStream is = s.getInputStream();

            byte[] bys = new byte[1024];

            int len = is.read(bys);// 阻塞

            String client = new String(bys, 0, len);

            System.out.println("client:" + client);

     

            // 释放资源

            s.close();

        }

    }

     

                

            3.接收:步骤

                A:创建TCP服务器端的Socket对象

                B:监听客户端连接

                C:获取输入流,读取数据

                D:释放资源

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(9999);

     

            // 监听客户端的连接

            Socket s = ss.accept(); // 阻塞

     

            // 获取输入流

            InputStream is = s.getInputStream();

            byte[] bys = new byte[1024];

            int len = is.read(bys); // 阻塞

            String server = new String(bys, 0, len);

            System.out.println("server:" + server);

     

            // 获取输出流

            OutputStream os = s.getOutputStream();

            os.write("数据已经收到".getBytes());

     

            // 释放资源

            s.close();

            // ss.close();

        }

    }

     

        (6)案例:

            A:UDP

                a:最基本的UDP协议发送和接收数据

                1.发送端

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

    /*

    * 发送端:

    */

    public class SendDemo {

        public static void main(String[] args) throws IOException {

            // 创建发送端的Socket对象

            DatagramSocket ds = new DatagramSocket();

     

            // 创建数据并打包

            byte[] bys = "helloworld".getBytes();

            DatagramPacket dp = new DatagramPacket(bys, bys.length,

                    InetAddress.getByName("192.168.12.92"), 12345);

     

            // 发送数据

            ds.send(dp);

     

            // 释放资源

            ds.close();

        }

    }

     

     

                2.接收端:

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

     

    /*

    * 多次启动接收端:

    *         java.net.BindException: Address already in use: Cannot bind

    *         端口被占用。

    */

    public class ReceiveDemo {

        public static void main(String[] args) throws IOException {

            // 创建接收端的Socket对象

            DatagramSocket ds = new DatagramSocket(12345);

     

            // 创建一个包裹

            byte[] bys = new byte[1024];

            DatagramPacket dp = new DatagramPacket(bys, bys.length);

     

            // 接收数据

            ds.receive(dp);

     

            // 解析数据

            String ip = dp.getAddress().getHostAddress();

            String s = new String(dp.getData(), 0, dp.getLength());

            System.out.println("from " + ip + " data is : " + s);

     

            // 释放资源

            ds.close();

        }

    }

     

                b:把发送数据改进为键盘录入

                1.发送端

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

     

    /*

    * 需求:数据来自于键盘录入

    * 键盘录入数据要自己控制录入结束。

    */

    public class SendDemo {

        public static void main(String[] args) throws IOException {

            // 创建发送端的Socket对象

            DatagramSocket ds = new DatagramSocket();

     

            // 封装键盘录入数据

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            String line = null;

            while ((line = br.readLine()) != null) {

                if ("886".equals(line)) {

                    break;

                }

     

                // 创建数据并打包

                byte[] bys = line.getBytes();

                // DatagramPacket dp = new DatagramPacket(bys, bys.length,

                // InetAddress.getByName("192.168.12.92"), 12345);

                DatagramPacket dp = new DatagramPacket(bys, bys.length,

                        InetAddress.getByName("192.168.12.255"), 12345);

     

                // 发送数据

                ds.send(dp);

            }

     

            // 释放资源

            ds.close();

        }

    }

     

     

                2.接收端:

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

     

    /*

    * 多次启动接收端:

    *         java.net.BindException: Address already in use: Cannot bind

    *         端口被占用。

    */

    public class ReceiveDemo {

        public static void main(String[] args) throws IOException {

            // 创建接收端的Socket对象

            DatagramSocket ds = new DatagramSocket(12345);

     

            while (true) {

                // 创建一个包裹

                byte[] bys = new byte[1024];

                DatagramPacket dp = new DatagramPacket(bys, bys.length);

     

                // 接收数据

                ds.receive(dp);

     

                // 解析数据

                String ip = dp.getAddress().getHostAddress();

                String s = new String(dp.getData(), 0, dp.getLength());

                System.out.println("from " + ip + " data is : " + s);

            }

     

            // 释放资源

            // 接收端应该一直开着等待接收数据,是不需要关闭

            // ds.close();

        }

    }

     

     

                c:一个简易聊天小程序并用多线程改进

                1.发送端,实现多线程

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    import java.net.InetAddress;

    /*

    * 发送端:实现多线程

    */

    public class SendThread implements Runnable {

     

        private DatagramSocket ds;

     

        public SendThread(DatagramSocket ds) {

            this.ds = ds;

        }

     

        @Override

        public void run() {

            try {

                // 封装键盘录入数据

                BufferedReader br = new BufferedReader(new InputStreamReader(

                        System.in));

                String line = null;

                while ((line = br.readLine()) != null) {

                    if ("886".equals(line)) {

                        break;

                    }

     

                    // 创建数据并打包

                    byte[] bys = line.getBytes();

                    // DatagramPacket dp = new DatagramPacket(bys, bys.length,

                    // InetAddress.getByName("192.168.12.92"), 12345);

                    DatagramPacket dp = new DatagramPacket(bys, bys.length,

                            InetAddress.getByName("192.168.12.255"), 12306);

     

                    // 发送数据

                    ds.send(dp);

                }

     

                // 释放资源

                ds.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

     

    }

     

     

                2.接收端,实现多线程

    import java.io.IOException;

    import java.net.DatagramPacket;

    import java.net.DatagramSocket;

    /*

    *接收端:实现多线程

    */

    public class ReceiveThread implements Runnable {

        private DatagramSocket ds;

     

        public ReceiveThread(DatagramSocket ds) {

            this.ds = ds;

        }

     

        @Override

        public void run() {

            try {

                while (true) {

                    // 创建一个包裹

                    byte[] bys = new byte[1024];

                    DatagramPacket dp = new DatagramPacket(bys, bys.length);

     

                    // 接收数据

                    ds.receive(dp);

     

                    // 解析数据

                    String ip = dp.getAddress().getHostAddress();

                    String s = new String(dp.getData(), 0, dp.getLength());

                    System.out.println("from " + ip + " data is : " + s);

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

     

    }

     

                3.测试类

    import java.io.IOException;

    import java.net.DatagramSocket;

     

    /*

    * 测试类:通过多线程改进刚才的聊天程序,这样我就可以实现在一个窗口发送和接收数据了

    */

    public class ChatRoom {

        public static void main(String[] args) throws IOException {

            //创建发送端Socket对象

            DatagramSocket dsSend = new DatagramSocket();

            //创建接收端Socket对象

            DatagramSocket dsReceive = new DatagramSocket(12306);

            //创建发送线程对象

            SendThread st = new SendThread(dsSend);

            //创建接收线程对象

            ReceiveThread rt = new ReceiveThread(dsReceive);

     

            Thread t1 = new Thread(st);

            Thread t2 = new Thread(rt);

            //启动线程

            t1.start();

            t2.start();

        }

    }

     

            B:TCP

                a: 服务器给出反馈

                1.客户端

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.Socket;

    /*

    * 客户端:

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 9999);

     

            // 获取输出流

            OutputStream os = s.getOutputStream();

            os.write("今天天气很好,适合睡觉".getBytes());

     

            // 获取输入流

            InputStream is = s.getInputStream();

            byte[] bys = new byte[1024];

            int len = is.read(bys);// 阻塞

            String client = new String(bys, 0, len);

            System.out.println("client:" + client);

     

            // 释放资源

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(9999);

     

            // 监听客户端的连接

            Socket s = ss.accept(); // 阻塞

     

            // 获取输入流

            InputStream is = s.getInputStream();

            byte[] bys = new byte[1024];

            int len = is.read(bys); // 阻塞

            String server = new String(bys, 0, len);

            System.out.println("server:" + server);

     

            // 获取输出流

            OutputStream os = s.getOutputStream();

            os.write("数据已经收到".getBytes());

     

            // 释放资源

            s.close();

            // ss.close();

        }

    }

     

     

                c:客户端键盘录入服务器控制台输出

                1.客户端

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

     

    /*

    * 需求:客户端键盘录入,服务器输出到控制台

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("127.0.0.1", 22223);

     

            // 键盘录入数据

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            // 把通道内的流给包装一下

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                // 键盘录入数据要自定义结束标记

                if ("886".equals(line)) {

                    break;

                }

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            // 释放资源

            // bw.close();//不需要关闭

            // br.close();//不需要关闭

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(22223);

     

            // 监听客户端连接

            Socket s = ss.accept();

     

            // 包装通道内容的流

            BufferedReader br = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

            String line = null;

            while ((line = br.readLine()) != null) {

                System.out.println(line);

            }

     

            // br.close();

            s.close();

            // ss.close();

        }

    }

     

                d:客户端键盘录入服务器写到文本文件

                1.客户端

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

     

    /*

    * 需求:客户端键盘录入,服务器输出文本文件

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 23456);

     

            // 封装键盘录入

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            // 封装通道内的数据

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                if ("over".equals(line)) {

                    break;

                }

     

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            // bw.close();

            // br.close();

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(23456);

     

            // 监听客户端连接

            Socket s = ss.accept();

     

            // 封装通道内的数据

            BufferedReader br = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

            // 封装文本文件

            BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            bw.close();

            // br.close();

            s.close();

            // ss.close();

        }

    }

     

                e:客户端读取文本文件服务器控制台输出

                1.客户端

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.IOException;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

     

    /*

    * 需求:客户端读取文本文件,服务器输出到控制台

    */

    public class ClientDemo {

        public static void main(String[] args) throws IOException {

            // 创建Socket对象

            Socket s = new Socket("192.168.12.92", 34567);

     

            // 封装文本文件

            BufferedReader br = new BufferedReader(new FileReader(

                    "InetAddressDemo.java"));

            // 封装通道内的流

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            br.close();

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class ServerDemo {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(34567);

     

            // 监听客户端连接

            Socket s = ss.accept();

     

            // 封装通道内的流

            BufferedReader br = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) {

                System.out.println(line);

            }

     

            //关闭连接

            s.close();

        }

    }

     

                f:客户端读取文本文件服务器写到文本文件

                1.客户端

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

     

    /*

    * 需求:上传一个文件到服务器

    *

    * 按照我们正常的思路加入反馈信息,结果却没反应。为什么呢?

    * 读取文本文件是可以以null作为结束信息的,但是呢,通道内是不能这样结束信息的。

    * 所以,服务器根本就不知道你结束了。而你还想服务器给你反馈。所以,就相互等待了。

    *

    * 如何解决呢?

    * A:在多写一条数据,告诉服务器,读取到这条数据说明我就结束,你也结束吧。

    *         这样做可以解决问题,但是不好。

    * B:Socket对象提供了一种解决方案

    *         public void shutdownOutput()

    */

     

    public class UploadClient {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 11111);

     

            // 封装文本文件

            BufferedReader br = new BufferedReader(new FileReader(

                    "InetAddressDemo.java"));

            // 封装通道内流

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) { // 阻塞

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

            

            //自定义一个结束标记

    //        bw.write("over");

    //        bw.newLine();

    //        bw.flush();

            

            //Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了

            s.shutdownOutput();

     

            // 接收反馈

            BufferedReader brClient = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

            String client = brClient.readLine(); // 阻塞

            System.out.println(client);

     

            // 释放资源

            br.close();

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class UploadServer {

        public static void main(String[] args) throws IOException {

            // 创建服务器端的Socket对象

            ServerSocket ss = new ServerSocket(11111);

     

            // 监听客户端连接

            Socket s = ss.accept();// 阻塞

     

            // 封装通道内的流

            BufferedReader br = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

            // 封装文本文件

            BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));

     

            String line = null;

            while ((line = br.readLine()) != null) { // 阻塞

            // if("over".equals(line)){

            // break;

            // }

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            // 给出反馈

            BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

            bwServer.write("文件上传成功");

            bwServer.newLine();

            bwServer.flush();

     

            // 释放资源

            bw.close();

            s.close();

        }

    }

     

                g:上传图片

                1.发送端

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.FileInputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.net.Socket;

    /*

    * 需求:上传图片

    */

    public class UploadClient {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 19191);

     

            // 封装图片文件

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(

                    "林青霞.jpg"));

            // 封装通道内的流

            BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());

     

            byte[] bys = new byte[1024];

            int len = 0;

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

                bos.flush();

            }

            

            s.shutdownOutput();

     

            // 读取反馈

            InputStream is = s.getInputStream();

            byte[] bys2 = new byte[1024];

            int len2 = is.read(bys2);

            String client = new String(bys2, 0, len2);

            System.out.println(client);

     

            // 释放资源

            bis.close();

            s.close();

        }

    }

     

     

                2.服务器端:

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.OutputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class UploadServer {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(19191);

     

            // 监听客户端连接

            Socket s = ss.accept();

     

            // 封装通道内流

            BufferedInputStream bis = new BufferedInputStream(s.getInputStream());

            // 封装图片文件

            BufferedOutputStream bos = new BufferedOutputStream(

                    new FileOutputStream("mn.jpg"));

     

            byte[] bys = new byte[1024];

            int len = 0;

            //读取文件

            while ((len = bis.read(bys)) != -1) {

                bos.write(bys, 0, len);

                bos.flush();

            }

     

            // 给客户端一个反馈

            OutputStream os = s.getOutputStream();

            os.write("图片上传成功".getBytes());

     

            bos.close();

            s.close();

        }

    }

     

                h:多线程改进上传文件

                1.多线程类

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

    /*

    * 多线程类:

    */

    public class UserThread implements Runnable {

        private Socket s;

     

        public UserThread(Socket s) {

            this.s = s;

        }

     

        @Override

        public void run() {

            try {

                // 封装通道内的流

                BufferedReader br = new BufferedReader(new InputStreamReader(

                        s.getInputStream()));

                // 封装文本文件

                // BufferedWriter bw = new BufferedWriter(new

                // FileWriter("Copy.java"));

     

                // 为了防止文件名称冲突

                String newName = System.currentTimeMillis() + ".java";

                BufferedWriter bw = new BufferedWriter(new FileWriter(newName));

     

                String line = null;

                while ((line = br.readLine()) != null) { // 阻塞

                    bw.write(line);

                    bw.newLine();

                    bw.flush();

                }

     

                // 给出反馈

                BufferedWriter bwServer = new BufferedWriter(

                        new OutputStreamWriter(s.getOutputStream()));

                bwServer.write("文件上传成功");

                bwServer.newLine();

                bwServer.flush();

     

                // 释放资源

                bw.close();

                s.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

     

    }

     

                2.客户端

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    import java.net.Socket;

    /*

    * 需求:多线程上传文件

    */

    public class UploadClient {

        public static void main(String[] args) throws IOException {

            // 创建客户端Socket对象

            Socket s = new Socket("192.168.12.92", 11111);

     

            // 封装文本文件

            // BufferedReader br = new BufferedReader(new FileReader(

            // "InetAddressDemo.java"));

            BufferedReader br = new BufferedReader(new FileReader(

                    "ReceiveDemo.java"));

            // 封装通道内流

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(

                    s.getOutputStream()));

     

            String line = null;

            while ((line = br.readLine()) != null) { // 阻塞

                bw.write(line);

                bw.newLine();

                bw.flush();

            }

     

            // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了

            s.shutdownOutput();

     

            // 接收反馈

            BufferedReader brClient = new BufferedReader(new InputStreamReader(

                    s.getInputStream()));

            String client = brClient.readLine(); // 阻塞

            System.out.println(client);

     

            // 释放资源

            br.close();

            s.close();

        }

    }

     

     

                3.服务器端:

    import java.io.IOException;

    import java.net.ServerSocket;

    import java.net.Socket;

    /*

    * 服务器端:

    */

    public class UploadServer {

        public static void main(String[] args) throws IOException {

            // 创建服务器Socket对象

            ServerSocket ss = new ServerSocket(11111);

            //循环接收客户端的连接

            while (true) {

                Socket s = ss.accept();

                new Thread(new UserThread(s)).start();

            }

        }

    }

     

     

    第二十七天

    1:反射(理解)

        (1)类的加载及类加载器

            类的加载:

                系统会通过加载、连接、初始化三步来实现对这个类进行初始化

                    加载:

                        加class文件读取进内存中,并为其创建一个Class对象,

                        任何类在使用时,系统都会建立一个Class对象

                    连接:

                        验证:是否有正确的内部结构,并和其他类协调一致

                        准备:负责为类的静态成员分配内存,并设置默认初始化值

                        解析:将类的二进制数据中的符号引用替换为直接引用

                    初始化:

     

     

     

            类加载器

                A:Bootstrap ClassLoader 根加载器:

                    也称为引导类加载器,负责java核心类的加载(System、String),在JDK的lib下rt.jar中

     

                B:Extension ClassLoader拓展类加载器:

                    负责jre 拓展目录中的jar包的加载(在JDK中JRE的lib目录下的ext目录)

     

                C:System ClassLoader系统类加载器:

                    负责在JVM启动时,加载来自java命令的class文件,以及classpath环境变量所指定的jar包

                    和类路径

            类初始化时机:

    创建类的实例访问类的静态变量,或者为静态变量赋值调用类的静态方法使用反射方式来强制创建某个类或接口对应的java.lang.Class对象初始化某个类的子类直接使用java.exe命令来运行某个主类

        (2)反射:

            A:定义

    通过字节码文件对象,去使用成员变量,构造方法,成员方法

     

            B:获取字节码对象的三种方式

    /*

    * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

    *

    * Person p = new Person();

    * p.使用

    *

    * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。

    * Class类:

    *         成员变量    Field

    *         构造方法    Constructor

    *         成员方法    Method

    *

    * 获取class文件对象的三种方式:

    * A:Object类的getClass()方法

    * B:数据类型的静态属性class

    * C:Class类中的静态方法

    *         public static Class forName(String className)

    *

    * 一般我们到底使用谁呢?

    *         A:自己玩    任选一种,第二种比较方便

    *         B:开发    第三种

    *             为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

    */

    public class ReflectDemo {

        public static void main(String[] args) throws ClassNotFoundException {

            Person p = new Person();

            Class c = p.getClass();

     

            Person p2 = new Person();

            Class c2 = p2.getClass();

     

            System.out.println(p == p2);// false

            System.out.println(c == c2);// true

     

            Class c3 = Person.class;

            // int.class;

            // String.class;

            System.out.println(c == c3);

     

            // ClassNotFoundException

            Class c4 = Class.forName("cn.itcast_01.Person");

            System.out.println(c == c4);

        }

    }

     

     

     

        (3)反射的使用

            A:通过反射获取构造方法并使用

                1).反射获取构造方法的介绍

     

    import java.lang.reflect.Constructor;

     

    /*

    * 通过反射获取构造方法并使用。

    * 主要方法介绍:

    *         public Constructor[] getConstructors():获取所有公共的构造方法

    *         public Constructor[] getDeclaredConstructor():获取所有构造方法

    *         

    *         获取单个构造方法:

    *         public Constructor<T> getConstructor(Class<?>... parameterTypes):

    *         参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

    *

    *

    *         public T newInstance(Object... initargs):

    *         使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,

    *         并用指定的初始化参数初始化该实例。

    */

    public class ReflectDemo {

        public static void main(String[] args) throws Exception {

            // 获取字节码文件对象

            Class c = Class.forName("cn.itcast_01.Person");

     

            // 获取构造方法

            // public Constructor[] getConstructors():所有公共构造方法

            // public Constructor[] getDeclaredConstructors():所有构造方法

            // Constructor[] cons = c.getDeclaredConstructors();

            // for (Constructor con : cons) {

            // System.out.println(con);

            // }

     

            // 获取单个构造方法

            // public Constructor<T> getConstructor(Class<?>... parameterTypes)

            // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

            Constructor con = c.getConstructor();// 返回的是构造方法对象

     

            // Person p = new Person();

            // System.out.println(p);

            // public T newInstance(Object... initargs)

            // 使用此
    Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

            Object obj = con.newInstance();

            System.out.println(obj);

            

            // Person p = (Person)obj;

            // p.show();

        }

    }

     

                2)通过反射去获取该构造方法并使用

    import java.lang.reflect.Constructor;

     

    /*

    * 需求:通过反射去获取该构造方法并使用:

    * public Person(String name, int age, String address)

    *

    * Person p = new Person("林青霞",27,"北京");

    * System.out.println(p);

    */

    public class ReflectDemo2 {

        public static void main(String[] args) throws Exception {

            // 获取字节码文件对象

            Class c = Class.forName("cn.itcast_01.Person");

     

            // 获取带参构造方法对象

            // public Constructor<T> getConstructor(Class<?>... parameterTypes)

            Constructor con = c.getConstructor(String.class, int.class,

                    String.class);

     

            // 通过带参构造方法对象创建对象

            // public T newInstance(Object... initargs)

            Object obj = con.newInstance("林青霞", 27, "北京");

            

            System.out.println(obj);

        }

    }

     

                3)通过反射获取私有构造方法并使用

    import java.lang.reflect.Constructor;

     

    /*

    * 需求:通过反射获取私有构造方法并使用

    * private Person(String name){}

    *

    * Person p = new Person("风清扬");

    * System.out.println(p);

    */

    public class ReflectDemo3 {

        public static void main(String[] args) throws Exception {

            // 获取字节码文件对象

            Class c = Class.forName("cn.itcast_01.Person");

     

            // 获取私有构造方法对象

            // NoSuchMethodException:每个这个方法异常

            // 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。

            Constructor con = c.getDeclaredConstructor(String.class);

     

            // 用该私有构造方法创建对象

            // IllegalAccessException:非法的访问异常。

            // 暴力访问

            con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。

            Object obj = con.newInstance("风清扬");

     

            System.out.println(obj);

        }

    }

     

            B:通过反射获取成员变量并使用

    import java.lang.reflect.Constructor;

    import java.lang.reflect.Field;

     

    /*

    * 通过发生获取成员变量并使用

    *

    * 主要方法介绍:

    *         字节码文件对象的方法:

    *         public Field[] getFields():获取所有的公共成员变量

    *         public Field[] getDeclaredFields():获取所有成员变量

    *

    *         public Field getField(String name):获取单个成员变量

    *

    *         Field对象的方法:

    *         public void set(Object obj, Object value):

    *         将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

    *

    *         public void setAccessible(boolean flag):

    *         暴力访问,flag,设置为true,可以访问私有的变量

    */

    public class ReflectDemo {

        public static void main(String[] args) throws Exception {

            // 获取字节码文件对象

            Class c = Class.forName("cn.itcast_01.Person");

     

            // 获取所有的成员变量

            // Field[] fields = c.getFields();

            // Field[] fields = c.getDeclaredFields();

            // for (Field field : fields) {

            // System.out.println(field);

            // }

     

            /*

             * Person p = new Person(); p.address = "北京"; System.out.println(p);

             */

     

            // 通过无参构造方法创建对象

            Constructor con = c.getConstructor();

            Object obj = con.newInstance();

            System.out.println(obj);

     

            // 获取单个的成员变量

            // 获取address并对其赋值

            Field addressField = c.getField("address");

            // public void set(Object obj,Object value)

            // 将指定对象变量上此
    Field 对象表示的字段设置为指定的新值。

            addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"

            System.out.println(obj);

     

            // 获取name并对其赋值

            // NoSuchFieldException

            Field nameField = c.getDeclaredField("name");

            // IllegalAccessException

            nameField.setAccessible(true);

            nameField.set(obj, "林青霞");

            System.out.println(obj);

     

            // 获取age并对其赋值

            Field ageField = c.getDeclaredField("age");

            ageField.setAccessible(true);

            ageField.set(obj, 27);

            System.out.println(obj);

        }

    }

     

            C:通过反射获取成员方法并使用

    import java.lang.reflect.Constructor;

    import java.lang.reflect.Method;

    /*

    * 通过反射获取方法

    *     主要方法介绍:

    *         字节码文件对象的方法:

    *             public Method[] getMethods():获取自己的包括父亲的公共方法

    *             public method[] getDeclaredMethods():获取自己的所有方法(包括私有)

    *             

    *             获取单个方法

    *             public Method getMethod(String name,Class<?>... parameterTypes)

                     第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型

                     

            Method类的方法:

                public Object invoke(Object obj, Object... args):执行方法

    *             返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数

    */

    public class ReflectDemo {

        public static void main(String[] args) throws Exception {

            // 获取字节码文件对象

            Class c = Class.forName("cn.itcast_01.Person");

     

            // 获取所有的方法

            // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法

            // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法

            // for (Method method : methods) {

            // System.out.println(method);

            // }

     

            Constructor con = c.getConstructor();

            Object obj = con.newInstance();

     

            /*

             * Person p = new Person(); p.show();

             */

     

            // 获取单个方法并使用

            // public void show()

            // public Method getMethod(String name,Class<?>... parameterTypes)

            // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型

            Method m1 = c.getMethod("show");

            // obj.m1(); // 错误

            // public Object invoke(Object obj,Object... args)

            // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数

            m1.invoke(obj); // 调用obj对象的m1方法

     

            System.out.println("----------");

            // public void method(String s)

            Method m2 = c.getMethod("method", String.class);

            m2.invoke(obj, "hello");

            System.out.println("----------");

     

            // public String getString(String s, int i)

            Method m3 = c.getMethod("getString", String.class, int.class);

            Object objString = m3.invoke(obj, "hello", 100);

            System.out.println(objString);

            // String s = (String)m3.invoke(obj, "hello",100);

            // System.out.println(s);

            System.out.println("----------");

     

            // private void function()

            Method m4 = c.getDeclaredMethod("function");

            m4.setAccessible(true);

            m4.invoke(obj);

        }

    }

     

        (4)反射案例

            A:通过反射运行配置文件的内容

    import java.io.FileReader;

    import java.lang.reflect.Constructor;

    import java.lang.reflect.Method;

    import java.util.Properties;

     

    /*

    * 通过配置文件运行类中的方法

    *

    * 反射:

    *         需要有配置文件配合使用。

    *         用class.txt代替。

    *         并且你知道有两个键。

    *             className

    *             methodName

    */

    public class Test {

        public static void main(String[] args) throws Exception {

            // 反射前的做法

            // Student s = new Student();

            // s.love();

            // Teacher t = new Teacher();

            // t.love();

            // Worker w = new Worker();

            // w.love();

            // 反射后的做法

     

            // 加载键值对数据

            Properties prop = new Properties();

            FileReader fr = new FileReader("class.txt");

            prop.load(fr);

            fr.close();

     

            // 获取数据

            String className = prop.getProperty("className");

            String methodName = prop.getProperty("methodName");

     

            // 反射

            Class c = Class.forName(className);

    // 获取构造器

            Constructor con = c.getConstructor();

    // 创建构造器实例对象

            Object obj = con.newInstance();

     

            // 调用方法

            Method m = c.getMethod(methodName);

            m.invoke(obj);//指定obj对象的m方法

        }

    }

     

            B:通过反射越过泛型检查

    import java.lang.reflect.InvocationTargetException;

    import java.lang.reflect.Method;

    import java.util.ArrayList;

     

    /*

    * 需求:通过反射越过泛型检查

    * 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

    */

    public class ArrayListDemo {

        public static void main(String[] args) throws NoSuchMethodException,

                SecurityException, IllegalAccessException,

                IllegalArgumentException, InvocationTargetException {

            // 创建集合对象

            ArrayList<Integer> array = new ArrayList<Integer>();

     

            // array.add("hello");

            // array.add(10);

     

            Class c = array.getClass(); // 集合ArrayList的class文件对象

            Method m = c.getMethod("add", Object.class);

     

            m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello

            m.invoke(array, "world");

            m.invoke(array, "java");

     

            System.out.println(array);

        }

    }

     

            C:通过反射给任意的一个对象的任意的属性赋值为指定的值

    import java.lang.reflect.Field;

    /*

    * 需求:为指定对象的指定属性给定指定的值

    */

    public class Tool {

        public void setProperty(Object obj, String propertyName, Object value)

                throws NoSuchFieldException, SecurityException,

                IllegalArgumentException, IllegalAccessException {

            // 根据对象获取字节码文件对象

            Class c = obj.getClass();

            // 获取该对象的propertyName成员变量

            Field field = c.getDeclaredField(propertyName);

            // 取消访问检查

            field.setAccessible(true);

            // 给对象的成员变量赋值为指定的值

            field.set(obj, value);

        }

    }

     

        (5)动态代理

            代码演示:

            1. UserDao(顶层用户操作接口)

    /*

    * 定义:用户操作接口

    */

    public interface UserDao {

        public abstract void add();

     

        public abstract void delete();

     

        public abstract void update();

     

        public abstract void find();

    }

     

            2. StudentDao(学生接口)

    /*

    * 学生接口:

    *     登录和注册功能

    */

    public interface StudentDao {

        public abstract void login();

     

        public abstract void regist();

    }

     

            3. StudentDaoImpl(学生接口的实现类)

    /*

    * 学生接口的实现类

    */

    public class StudentDaoImpl implements StudentDao {

     

        @Override

        public void login() {

            System.out.println("登录功能");

        }

     

        @Override

        public void regist() {

            System.out.println("注册功能");

        }

     

    }

     

            4. MyInvocationHandler(动态代理类)

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    /*

    * 动态代理

    */

    public class MyInvocationHandler implements InvocationHandler {

        private Object target; // 目标对象

     

        public MyInvocationHandler(Object target) {

            this.target = target;

        }

     

        @Override

        public Object invoke(Object proxy, Method method, Object[] args)

                throws Throwable {

            System.out.println("权限校验");

            Object result = method.invoke(target, args);

            System.out.println("日志记录");

            return result; // 返回的是代理对象

        }

    }

     

            5. Test(测试类)

    import java.lang.reflect.Proxy;

    /*

    * 测试类

    */

    public class Test {

        public static void main(String[] args) {

            UserDao ud = new UserDaoImpl();

            ud.add();

            ud.delete();

            ud.update();

            ud.find();

            System.out.println("-----------");

            // 我们要创建一个动态代理对象

            // Proxy类中有一个方法可以创建动态代理对象

            // public static Object newProxyInstance(ClassLoader loader,Class<?>[]

            // interfaces,InvocationHandler h)

            // 我准备对ud对象做一个代理对象

            MyInvocationHandler handler = new MyInvocationHandler(ud);

            UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()

                    .getClassLoader(), ud.getClass().getInterfaces(), handler);

            proxy.add();

            proxy.delete();

            proxy.update();

            proxy.find();

            System.out.println("-----------");

     

            StudentDao sd = new StudentDaoImpl();

            MyInvocationHandler handler2 = new MyInvocationHandler(sd);

            StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()

                    .getClassLoader(), sd.getClass().getInterfaces(), handler2);

            proxy2.login();

            proxy2.regist();

        }

    }

     

            

    2:设计模式

        (1)装饰设计模式

            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            

            Scanner sc = new Scanner(System.in);

        (2)模版设计模式

            1. GetTime(模板方法)

    /*

    * 模板设计模式:

    *     // 需求:请给我计算出一段代码的运行时间

    */

    public abstract class GetTime {

     

        public long getTime() {

            long start = System.currentTimeMillis();

            // 测试代码抽象,由需要被测试子类实现即可

            code();

     

            long end = System.currentTimeMillis();

     

            return end - start;

        }

        //抽象方法

        public abstract void code();

    }

     

            2. ForDemo(模板方法的子类)

    /*

    * 子类:继承了GetTime类,重写了code方法

    */

    public class ForDemo extends GetTime {

        // 被测试运行时间的代码

        @Override

        public void code() {

            for (int x = 0; x < 100000; x++) {

                System.out.println(x);

            }

        }

     

    }

     

            3. IODemo(模板方法的子类)

    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    /*

    * 子类:继承了GetTime类,重写了code方法

    */

    public class IODemo extends GetTime{

     

        //被测试运行时间的代码(复制视频)

        @Override

        public void code() {

            try {

                BufferedInputStream bis = new BufferedInputStream(

                        new FileInputStream("a.avi"));

                BufferedOutputStream bos = new BufferedOutputStream(

                        new FileOutputStream("b.avi"));

                byte[] bys = new byte[1024];

                int len = 0;

                while ((len = bis.read(bys)) != -1) {

                    bos.write(bys, 0, len);

                }

                bos.close();

                bis.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

        

    }

     

            4. GetTimeDemo(测试类)

    /*

    * 模板设计模式:测试类

    *     测试一段代码的执行时间

    */

    public class GetTimeDemo {

        public static void main(String[] args) {

            // GetTime gt = new GetTime();

            // System.out.println(gt.getTime() + "毫秒");

     

            GetTime gt = new ForDemo();

            System.out.println(gt.getTime() + "毫秒");

     

            gt = new IODemo();

            System.out.println(gt.getTime() + "毫秒");

        }

    }

     

     

    3:JDK新特性

        (1)JDK5(掌握)

            装箱和拆箱

            泛型

            增强for

            静态导入

            可变参数

            枚举

        (2)JDK6(了解)

        (3)JDK7(理解)

            二进制的表现形式

            用_分隔数据

            switch语句可是用字符串

            泛型推断(菱形泛型)

            多catch的使用

            自动释放资源的用法

        (4)JDK8(了解)

            可以去网上了解资料

     

javaSE27复习总结的相关教程结束。

《javaSE27天复习总结.doc》

下载本文的Word格式文档,以方便收藏与打印。