java学习笔记

第一章 Java
Java的特点
1、java语言足够简单,正因为足够简单,所有才能让人们有更多的发挥空间
2、java是一门面向对象的编程语言
3、java是为数不多的多线程编程语言
4、java提供了自动垃圾收集机制,以更好的处理垃圾空间
5、java避免复杂的指针问题,而使用了更加简单的引用来完成内存
匹配
6、java实现任意平台的移植

计算机高级编程语言类型
1、编译型
2、解释型

Java是两种语言的结合
1、编译命令:javac.exe
2、解释命令:java.exe

Java程序组成:java源文件,字节码文件,机器码指令

标识符
类名称、属性名称、方法名称都成为标识符
标识符的基本要求:标识符由字母、数字、—、 符 所 组 成 , 其 中 不 能 以 数 字 开 头 , , 不 能 是 j a v a 中 的 保 留 字 ( 关 键 字 ) 在 编 写 的 时 候 , 尽 量 不 要 去 使 用 数 字 , 命 名 尽 量 有 意 义 , 对 于 符所组成,其中不能以数字开头,,不能是java中的保留字(关键字) 在编写的时候,尽量不要去使用数字,命名尽量有意义,对于 java使有特殊意义,不要使用
Java中的关键字
Abstract boolean break byte ease eath char
Class continue default do double else extends
False final finally float for if implements
Import instanceof int interface lonf native new
Null package private protected public return short
Static synchronized super this throw throws transient
Ture try void volatile while assert enum
Java中有两个未使用到的关键字:goto,const
Java有三个特殊含义标识:ture、false、null

第三章 Java数据类型划分
不同的数据类型可以保存不同的数据内容
Java一共分为两大数据类型:基本数据类型、引用数据类型
1、基本数据类型
1.1、数值型:
整形:byte、short、int、long 默认值:0
浮点型:float、double 默认值:0.0
1.2、字符型:char 默认值:\u000’
1.3、布尔型:boolean 默认值:false
2、引用数据类型:数组、接口 默认值:null
基本数据类型不牵扯内存分配问题,而引用数据类型需要由开发者为其分配空间,而后进行关系匹配

个人选择数据类型原则:
如果想表示整形:int
表示小数:double
描述日期、时间、数字、或表示文件内存大小:long
实现内容传递或者编码转换:byte
实现逻辑控制:boolean
如果想要使用中文:char(避免乱码)
按照保存范围:byte<int<long<double
1.1整形
任何一个数字常量(例如:30、100)那么都属于int类型的数据类型。即:在java之中所有设置的整数内容,默认情况下都是int型数据
所有的变量在同一块代码之中只允许声明一次

在程序的世界里面,数据类型转换有一下规律
1、数据范围小的数据与数据范围大的数据进行数学计算的时候,自动向数据范围大的数据转型后计算;
2、数据范围大的数据要变为数据范围小的数据,必须采用强制转换
3、如果是常量进行强制转换,有两种标记:常量标记(L,l)使用(数据类型)
4、数据大的数据类型也可以转换为数据小的数据类型,这样必须使用“(数据类型)”的格式
小转大:
Int变量 ±long型常量 = long型数据
大转小:
Long num=100;
Int x = (int)num;
如果long变为int时所保存的数据类型超过了int范围,那么依然会出现数据溢出
任意一个整数都属于int型,但是java编译的时候,如果发现使用的数据变量类型为:byte,并且设置的内容在byte范围内,那么就会自动帮助用户实现数据类型转换。反之超过了依然会以 int为主

提示:所有的变量在使用的时候一定不要去相信默认值,都设置具体内容
定义变量的时候直接设置默认值
使用整形就用int,90%以上都适用
1.2浮点型
浮点数就是小数,java之中只要是小数,那么就使用double型数据。double是保存范围最广的数据类型。

由于默认的小数类型是double,所以入股使用了float型,表示需要将double型变为float型,需要强制转换
例如:
Float f1 = 10.2F;
Float f2 = (float)10.2;

所有的数据类型只有double才可以保存小数

1.3字符型;char
Byte是属于字节,按照传统的概念来讲,一个字符等于两个字节,对于字符除了和字节有一些关系之外,最主要的关系在在于int变量的转换

字符可以和int互相转换
‘A’(65)~’Z’(90)
‘a’(97)~’z’(122)
‘0’(48)~’9’(57)

字符与int转换
Char c = ‘A’;
Int num = c;
c = (char)num
1.4布尔型
布尔是一个数学家的名字,布尔型是一种逻辑结果,主要保存有两大数据类型:true、false,这类的数据主要用于一些逻辑判断上
例如:
Boolean flag = ture;
If(flag){
System.out.println(“hello”);

由于设计之初没有考虑到布尔型,那么久使用数字0表示false,而非0表示ture,但是这样的设计对代码开发来说比较混乱,java里面不允许使用0或1来填充布尔型变量内容。那么只能使用false,true
1.5 String型数据
只要是项目开发,100%会使用String,但是与其他基本数据类型相比,String属于引用数据类型(它属于一个类),在java里面只要是类名称,每一个单词首字母都是大写的,但是这个类的使用比较特殊

String 表示的是一个字符串,即:多个字符集,String要求使用“”声明其内容
字符串里面的“+”表示连接操作

任何数据类型加上字符串都是向字符串类型转换

在java里面也支持多种转义字符使用,例如:换行(\n)、制表(\t)、描述\(\)、
双引号(\”)、单引号(\’)
总结:
1、常用的数据类型:整数用:int、小数:double、逻辑:boolean
2、long、byte、char在处理数据的时候回用到
3、数据类型转换用远都是小的数据类型自动向大的数据类型转换,大转小需要强制转换
第四章 Java运算符
Int = 10;
此类方式称为赋值,运算符“=”是实现赋值运算使用的,进行数学计算所使用的四则运算,也属于运算符的定义范畴
在开发之中常使用的积累运算符:四则运算、逻辑运算、三目运算、位运算

简化的运算符: *=、/=、+=、-=、%=
1.1 三目运算:
Int numA=10;
Int numB=20;
Int max=numA > numB?numA:numB;
System.out.println(max);
1.2逻辑运算
与操作
当多个条件使用与进行连接的时候,那么只有多个条件都满足的时候,最终结果才是true,如果有一个条件返回false,那么最终的结果就是false;

单个“=”是赋值,“==”是判断

短路与的使用:
当多个提交件进行与(使用短路与)操作的时候,前面只要有一个条件返回false,那么后面就不在进行判断了,直接返回false;

短路或的使用:
当多个条件进行或(短路或)操作的时候,前面只要有一个条件返回了true,那么后面就不再进行判断力,直接返回true;

总结:
1、运算符写简单的操作
2、三目一定要掌握
3、使用短路与,短路或

第五章 Java程序逻辑控制
1.1程序逻辑控制
程序逻辑主要分为三种逻辑结构:顺序结构、分支结构、循环结构。其中顺序结构最好理解,所有的代码都是有前向后执行的,需要提醒的是顺序是以“{}”为界限的。

分支结构:
分支结构就是一种判断结构。对于分支结构有两类语法支持:if、switch。
If 分支语句:
if If…else If…else if…else ….
If(布尔表达式){
程序语句
} If(布尔表达式){//满足条件时执行
程序语句
}else{//不满足条件是执行
程序语句
} If(布尔表达式1){//满足条件时执行
程序语句
}
If(布尔表达式2){//满足条件时执行
程序语句
}…

Switch语法:
Switch(整数|字符|枚举|String){
Case 内容1:{
满足条件时执行;
Break;
}
Case 内容2:{
满足条件时执行;
Break;
}
Case 内容3:{
满足条件时执行;
Break;
}
Switch只能够判断内容,不能进行布尔表达式的判断
1.2循环语句
有两种循环:while循环、for循环
所有的循环语句必须要有循环初始化条件,每次循环的时候都要修改这个条件,以判断循环是否结束
Do…while循环属于先执行一次,而后在进行判断。即:不管条件是否满足都会执行一次

For循环
For(循环初始化条件;循环判断;循环条件变更){
循环语句;
}
两种语法的选择:
1、如果不知道循环次数,但是知道循环结束条件的时候使用while循环
2、如果已经明确知道了循环次数使用for循环

循环控制:
循环控制有两种语句:continue(退出本次循环)此类语句一定要与判断语句一起使用
Break:退出整个循环

总结:
While循环用于不知道次数,但是知道循环结束条件
For循环用于知道循环次数的循环
Continue和break都需要与if语句结合使用

第六章 方法
方法的基本概念
所谓的方法是指一段可以被重复调用的代码段,利用此操作可以封装执行的代码
在java之中,方法的定义格式比较复杂,所以本次给出的方法有一个要求:指的是定义在主类之中并且由主方法直接调用的方法。方法创建的语法如下:
public static 返回值类型 方法名称(参数类型 变量 、、、){
方法体(本方法要执行的若干操作);
return 返回值;
}
在本定义格式中,发现方法有一个返回值类型,指的是方法方法返回结果,对于此类型有两种:
1、直接设置java中的数据类型(基本数据类型 引用数据类型)
2、方法没有返回值:void
如果方法设置了返回值,那么必须使用return语句返回与之数据类型对应的数据
没有返回值:可以不使用return返回内容,但是可以使用return结束调用
定义方法名称要求:第一个单词首字母小写,而后每个单词首字母大写
在以后的编写代码的时候为了节约代码,可以直接利用方法的返回结果进行输出
如果一个方法使用了void定义为它的返回值,那么可以使用return结束一个方法的调用,但是return不会返回任何内容
只有在方法的返回值为void的前提下才可以使用return结束,使用return结束要与if判断语句一起使用

方法重载
如果说一个方法名称,有可能要执行多项操作,例如:一个add()方法,它可能执行三个整数相加或者可能执行两个小数相加,那么这样的情况下,很明显一个方法体肯定无法满足要求,需要为add()方法定义多个不同的功能实现,所以此类的功能就称为方法的重载,但是在进行方法重载的时候要求方法名称相同,参数类型及个数不同。

方法重载两点说明:
1、在进行方法重载的时候一定要考虑到参数类型的同一,虽然可以实现重载方法返回不同的类型的操作,但是从开发的标准来说,建议所有的重载方法使用同一种返回值类型:
2、方法重载的时候是根据参数类型及个数来区分不同的方法,而不是根据返回值的不同来确定的

方法的递归调用
递归调用是我们迈向数据结构开发的第一步
所谓的递归调用指的就是一个方法自己调用自己的情况,但是如果要想实现自己调用自己,一定需要一个结束的条件,并且每次执行的时候都需要去修改这个结束条件

总结:
1、可以将一些重复执行的代码定义在方法里
2、本次所讲解的方法有它的局限性:定义在主类,并且由主方法直接调用
3、方法的返回值一旦定义了就需要return返回相应数据
4、方法重载(overload)指的是方法名称相同,参数类型及个数不同时,尽量保证返回值类型相同
5、递归调用需要一个结束条件

第七章 面向对象
面向对象:
以一种组件化的形式进行代码的设计,这样开发出来的代码有一个最大的好处,就是重用
在面向对象的程序里面包含有如下的几个特征:
1、封装性:保护内部的定义结构安全性
2、在已有的程序结构上继承继续扩充的新功能
3、多态性:指的是在一个概念范围内的满足
面向对象就是一种组件化思想

类与对象
类与对象是整个面向对象之中最为基础的组成单元,如果需要给出划分定义的话,类就是共性的集合,而对象是一个性的产物。对象能够操作的行为都是有类来决定的,超过了类定义的范畴操作是不能够使用的
类实际上是对象的操作的模板,但是累不能够直接使用,必须通过实例化对象来使用。
类是不能够直接使用的,对象是可以直接使用的,对象是通过类产生的

类与对象的基本定义
如果要在程序中定义类可以使用“class 类名称{}”的语法结构完成,而类之中的组成主要有两点

声明实例化对象:
1、声明并实例化对象: 类名称 对象名称 = new 类名称();
2、声明对象:类名称 对象名称 = null;
实例化对象:对象名称 = new 类名称();
引用数据类型与基本数据类型最大的不同在于需要内存开辟及使用,所有关键字new的主要功能就是开辟内存空间,即:只要是引用数据类型想要使用,那么就必须使用关键字new来开辟空间

当一个对象实例化后那么就可以按照如下的方式利用对象来操作类的结构
1对象.属性:表示要操作类中属性的内容;
2、对象.方法:表示要操作类中的方法

1、堆内存:保存每一个对象的属性内容,堆内存需要使用关键字new才可以开辟;
2、栈内存:保存的时堆内存的地址,但是为了分析方便,可以简单的理解为栈内存保存的是对象名字;

任何情况下只要看见关键字new,都要表示要开辟新的堆内存空间,里面就一定会有所有类中定义的属性,当然所有的属性内柔都是对应数据类型的默认值

引用数据的初步分析
引用是整个java开发之中的核心精髓所在,即:只有掌握了这一基本概念之后,才可以项后面的课程进行深入学习。
在所有的引用分析里面,最关键的还是关键字new,一定要注意的是每一次使用关键字new都一定会开辟一块新的堆内存空间,所以如果你的代码里面声明了两个对象,并且使用了关键字new为两个对象分别实例化操作,那么一定是各自占有各自的堆内存空间,并且不会互相影响。
第八章 深入分析类与对象
封装性
在有private的时候,访问属性的时候发现,外部的对象无法在直接调用类中的属性了,所以现在等于是属性对外部而言就不可见了。

但是如果想要让程序可以正常使用,那么必须想办法让外部的程序可以操作类中的属性才可以,所以在开发之中,针对于属性有这样的以中定义:所有类中的属性都要求使用private声明,如果属性需要被外部所使用,那么按照要求定义相应的setter、getter方法
1、setter方法主要设置内容:public void setTitle(数据类型 变量)有参
2、getter方法主要是取得属性内容:public 数据类型 getTile()无参
总结:
1、封装性就是保证类内部的定义被外部不可见
2、所有的属性必须使用private封装,封装后的属性如果想要被外部访问,要定义setter、getter方法。

构造方法与匿名对象
对象产生的格式:
1、类名称 2、对象名称 = 3、new 4、类名称();
1、类名称规定了对象的类型即:对象可以使用那些属性于方法,都是有类定义的
2、对象名称:如果想要使用对象,需要由一个名字,这是一个唯一标记
3、new:开辟新的堆内存空间,如果没有此语句,对象无法实例化
4、类名称():调用一个和类名称一样的方法,这就是构造方法
通过以上简短的分析发现,所有的构造方法一直被我们调用,但是我们从来没有去定义一个这样的构造方法,之所以能够使用是因为在整个java之中,为了保证程序可以正常执行,那么即使用户没有定义任何的构造方法,也会在程序编译之后自动的为类里面增加一个没有参数、方法名称和类名称相同、没有返回值的构造方法
构造方法定义原则:方法名称与类名称相同,没有返回值

通过代码可以发现,多有的构造方法都是在对象使用关键字new实例化的时候被默认调用的

构造方法与普通方法最大区别?
构造方法是在实例化对象的时候只调用一次
普通方法是在实例化对象产生之后可以被随意调用多次
在实际的工作之中,构造方法的核心作用:在对象实例化时候设置属性的初始化内容,构造方法是为属性初始化准备的

如果一个类中明确的定义了有参构造方法的话,那么不会再默认生成构造方法,即:一个类中至少保留一个构造方法

另外构造方法也属于方法的行列,那么可以对于构造方法进行重载。所以在构造方法重载时,要求只关注参数类型及个数即可

在进行构造方法重载时候有一点代码要求:请按照参数的个数进行升序或降序排列

没有进行构造之前所有属性的值都是对应数据类型的默认值

总结:
1、构造方法定义要求:方法名称与类名称相同,无返回值声明
2、构造方法是在类对象使用关键字new实例化的时候被默认调用的,不管代码如何改变,只要有关键字new,就一定需要构造方法
3、一个类之中至少会保留一个构造方法,如果没有明确的调用构造方法,那么会自动生成一个无参的构造方法
4、构造方法的核心功能是在类对象初始化的时候为类中的属性初始化
5、构造方法重载时,只要求考虑参数类型及个数即可
6、匿名对象只能够调用一次

代码模型
这种功能的类在java开发之中称为简单java类,因为这些类里面不会包含过于复杂的程序逻辑
对于简单java类而言,那么可以给出它第一个开发要求
1、类名称必须存在有意义
2、类之中的所有属性必须封装:private封装后的属性必须提供setter,getter;
3、类之中可以提供多个构造方法,但是必须保留一个无参构造
4、类之中不允许出现任何的输出语句
5、类之中需要提供有一个取得对象完整信息的方法

第九章 数组
数组的基本概念
数组指的是一组相关变量的集合
数组的语法如下:
1、数据类型 数组名称[] = new数据类型[长度]
2、分布完成:
声明数组:数据类型 数组名称[] = null;
开辟数组:数组名称 = new数据类型[长度];
由于数组是一种顺序的结构,并且数组的长度都是固定的,那么可以使用循环方式输出,很明显需要使用for循环,而在java里面为了方便数组输出提供有一个“数组名称.length”的属性,可以取得数组长度。

简化格式:
1、数据类型 数组名称[] = {值,值,…};
完整格式:
2、数据类型 数组名称[] = new数据类型 []{值,值…};
一维数组输出:
public static void pr(int temp[]) {
for(int x = 0;x <temp.length;x ++) {
System.out.println(temp[x]);
}
}
二维数组
在之前的数组里面只有一个“[]”,所以此类数组就是一个普通数组,或者麻烦一点可以把它称为一维数组,如果现在想要描述更多说的数据,那么可以使用二维数组,后面有两个“[][]”

二维数组的定义语法有如下两类:
1、动态初始化:数据类型 数组名称 [][] = new 数据类型[h行的个数][列的个数]
2、静态初始化:数据类型 数组名称 [][] = new 数据类型 [][]{{值,值….},{值,值….}};
二维数组输出:
public static void print(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] + “、”);
}
}
}
数组排序:
public static void sort(int arr[]) {
for(int x=0; x< arr.length;x ++) {
for(int y = 0;y < arr.length - 1; y++) {
if(arr[y] > arr[y + 1]) {
int t = arr[y];
arr[y] = arr[y + 1];
arr[y + 1] = t;
}
}
}
}
也可以使用:java.util.Arrays.sort(数组名称);
数组转至:
public static void reser(int []temp) {
int len = temp.length/2;
int head = 0;
int tail = temp.length - 1;
for(int x = 0;x < len;x ++) {
int tem = temp[head];
temp[head] = temp[tail];
temp[tail] = tem;
head ++;
tail --;

	}
}

对象数组
数组是引用类型,而类也同样是引用类型,所以如果是对象数组的话表示一个引用类型里面嵌套其他的引用类型
对象数组就是将多个对象交给数组同一管理
总结:
1、对象数组的语法定义 对象数组 = 多个对象
2、数组有一个最大的天生短板:长度固定,所以这就限制了数组在开发之中出现
3、数组排序:java.util.Arrays.sort(数组名称)

第十章 String 类的特点
String是一个字符串类型的类,使用“””定义的内容都是字符串,但是String本身毕竟是一个类,虽然这个类在使用上会有一些特殊,但是我们必须从类的角度与内存关系上来分析这个类的作用。

1、String类的两种实例化方式
String str = “hello” ;
以上就是String对象的直接赋值。代码并没有使用关键字new进行
.构造方法:public String (String str),在构造里面依然要接受一个本类对象;
String str = new String(“hello”) ;
2、字符串的比较

如果说现在有两个int型整数想要判断其是否相等,可以使用“”符号完成
String stra = “hello” ;
String strb = new String(“hello”);
String strc = stra ;
System.out.println(stra == strb);//false
System.out.println(stra == strb );//true
System.out.println(strc == strb );//false
通过以上的分析结果发现,“
”现在的确是进行了比较,但是比较的并不是字符串包含的内容,而是它们所在的内存地址的数值,所以“==”是属于数值比较,比较的是内存地址。
而如果说现在要想去比较字符串的内容的话,那么可以使用String类里面定义的方法;
比较内容:public boolean equals(String str);

System.out.println(stra.equals(strb));//true
System.out.println(stra.equals(strc));//true
System.out.println(strc.equals(strb));//true
此时实现了字符串内容的比较,在以后的开发之中,只要是进行字符串相等的判断,千万不要使用“”完成。
面试题:请解释在字符串相等的判断中“
”与“equals()”的区别?
1、“==”是java 提供的关系运算符,主要的功能是进行数值相等的判断,如果用在了String 对象上表示的是进行内存地址数值的比较;
2、“equals()”是由String 提供的一个方法,此方法专门进行字符串内容的比较。

3.3字符串常量就是String 的匿名对象

实际上任何的编程语言都没有提供字符串这一概念,很多的语言里面都是使用了字符数组来描述的字符串的概念。在java里面也没有字符串的概念,但是在所有的开发里面都不能离开字符串的应用,那么最终的结果就是java自己创造了字符串。但是这个字符串依然不属于基本类型数据,它是将字符串作为String类的匿名对象的形式存在的。

为了避免空指向异常的出现可以将字符串写在方法equals()的前面。
在以后的开发之中,如果要判断输入的内容是否是某一字符串,请一定要将字符串写在最前面。

第十一章 String类方法
String 类方法

方法名称	类型	功能	

1 public String(char[] value) 构造 将字符数组变为String类对象
2 public String(char[] value,
int offset,int count) 构造 将部分字符数组变为String
3 public char charAt(int index) 普通 返回指定索引对应的字符信息
4 public char[] toCharArray() 普通 将字符串以字符数组的形式返回(程序之中索引从0开始)
字节与字符串
5 public String(byte[] bytes) 构造 将全部的字节数组变为字符串
6 public String(byte[] bytes,
int offset,int length) 构造 将部分字节数组变为字符串
7 public byte[] getBytes() 普通 将字符串变为字节数组
8 public byte[] getBytes(String charsetName)throws UnsupportedEncodingException 普通 进行编码转换
字符串的比较
9 public boolean equals(Object anObject) 普通 进行相等的判断,区分大小写
10 public boolean equalsIgnoreCase(String anotherString 普通 进行相等判断,不区分大小写
11 public int compareTo(String anoth erString) 普通 判断两个字符串的大小按照字符编码比较
返回值
=0:表示比较的两个字符串内容相等

0:表示大于的结果
<0:表示小于的结果
字符串查找
12 public boolean contains(CharSequence s) 普通 判断指定的内容是佛存在
13 public int indexOf(String str) 普通 后由前向后查找字符串的位置,如果查找到了返回  (一个字母
)位置的索引,找不到返回-1
14 public int indexOf(String str,int fromIndex) 普通 由指定位置从前向后查找指定字符串位置,找不到返回-1
15 public int lastIndexOf(String str) 普通 由后向前查找字符串位置,找不到返回-1
16 public int lastIndexOf(String str,
int fromIndex) 普通 从指定位置由后向前查找指定字符串位置,找不到返回-1
17 public boolean startsWith(String prefix) 普通 判断是否以指定的字符串开头
18 public boolean startsWith(String prefix,
int toffset)
普通 从指定位置开始判断是否以指定的字符串开头
19 public boolean endsWith(String suffix) 普通 判断是否以指定的字符串结尾
字符串替换
20 public String replaceAll(String regex,
String replacement) 普通 全部替换
21 public String replaceFirst(String regex,
String replacement) 普通 替换首个满足条件的内容
字符串截取
22 public String substring(int beginIndex) 普通 从指定索引截取到结尾
23 public String substring(int beginIndex,
int endIndex) 普通 截取部分子字符串的数据
字符串拆分
24 public String[] split(String regex) 普通 按照指定字符串全部拆分
25 public String[] split(String regex,
int limit) 普通 按照指定字符串进行部分拆分

26 public String concat(String str) 普通 字符串连接
27 public String toLowerCase(Locale locale) 普通 转小写
28 public String toUpperCase(Locale locale) 普通 转大写
29 public String trim() 普通 去掉字符串左右两边的空格
30 public int length() 普通 取得字符串长度
31 public String intern() 普通 数据入池
32 public boolean isEmpty() 普通 判断是否是空字符串

字符与字节数组
String str = “hello”;
char c = str.charAt(0);
System.out.println©;
char[] data = str.toCharArray();
     for(int x =0;x <data.length;x ++) {
         System.out.println(data[x]);
     }
String st = new String (data);
System.out.println(st);
System.out.println(new String (data,1,3));
字节与字符数组
String str = “helloworld”;
byte[] data = str.getBytes();
for(int x = 0;x < data.length;x ++) {
     data[x] -=32;        
     }
     System.out.println(new String(data));
     System.out.println(new String(data,0,5));
String sta = “HELLO”;
String stb = “hello”;
System.out.println(sta.compareTo(stb));//只有Stirng类才有大小的判断

字符串查找
String str = “helloworld”;
System.out.println(str.indexOf(“world”));
System.out.println(str.indexOf(“l”));//返回第一个
System.out.println(str.indexOf(“l”,5));
System.out.println(str.lastIndexOf(“l”));
          
if(str.contains(“world”)) {
    System.out.println(“可以查找到数据”);
}
替换
System.out.println(str.replaceAll(“l”,"-"));
 System.out.println(str.replaceFirst(“l”,"-"));
字符串截取
System.out.println(str.substring(5));
System.out.println(str.substring(0,5));
字符串拆分
String sta = “hello world nihao mldn”;
String [] result = sta.split(" “);
String [] re = sta.split(” “,2);
for(int x = 0;x < result.length;x ++) {
    System.out.println(result[x]);
 }
for(int x = 0;x < re.length;x ++) {
    System.out.println(re[x]);
 }
}
数组.length ;
String.length();
将一个字符串首字母变为大写,其余字母变为小写
public static String initcap(String tem){
return tem.substring(0,1).toUpperCase() + tem.substring(1).toLowerCase() ;
有的时候后面字母会不变,那就不要加上toLowerCase()
public class Str{
public static void main(String args[]){
//取出指定索引的字符
String str = “hello”;
char c = str.charAt(0);
System.out.println©;
//将字符串变为字符数组
char [] data = str.toCharArray();
for(int x = 0;x < data.length ;x ++){
System.out.println(data[x]);
}
//将字符串转大写
for(int x = 0;x < data.length ;x ++){
data[x] -= 32;
}
System.out.println(new String (data));
String sta = “helloworld” ;
byte arr[] = sta.getBytes();//将字符串变为字节数组
for(int x = 0;x < arr.length ;x ++){
arr[x] -= 32; //将小写变为大写
}
System.out.println(new String (arr));
System.out.println(new String (arr,5,5));
//判断字符串编码大小
String stra = “Hello” ;
String strb = “HELLO” ;
System.out.println(stra.compareTo(strb));
if(stra.compareTo(strb)>0){
System.out.println(“大于”);
}
//String sta = “helloworld” ;
//返回满足条件单词的第一个字母的索引
System.out.println(sta.indexOf(“world”));
//返回满足条件的第一个索引
System.out.println(sta.indexOf(“l”));
System.out.println(sta.indexOf(“l”,5));
//判断指定字符是否存在
System.out.println(sta.contains(“world”));
//判断是否以指定字符串开始
System.out.println(sta.startsWith(“hello”));
//判断是否以指定字符串结尾
System.out.println(sta.endsWith(“world”));
String strc = “helloworld” ;
//替换字符串中的全部
String resultA = strc.replaceAll(“l”,”");
//替换字符串中的第一个
String resultB = strc.replaceFirst(“l”,"
");
System.out.println(resultA);
System.out.println(resultB);
String strd = “helloworld” ;
//字符串截取,从指定索引开始到结尾
String suba = strd.substring(5);

	//字符串截取,从指定索引开始到指定索引结束
	String subb = strd.substring(0,5) ;
	System.out.println(suba);
	System.out.println(subb);
	
	
	
	
	
	String stre = "hello world nihao mldn" ; 
	
	//将字符串按照指定条件进行拆分为字符数组
	String resu [] = stre.split(" ");
	for(int x = 0;x < resu.length ;x ++){
		System.out.println(resu[x]);
	}
	
	String st = "张三:20|李四:21|王五:22";
	String result [] = st.split("\\|");
	for(int x = 0 ;x < result.length ;x ++){
		String temp[] = result[x].split(":");
		System.out.println("姓名:" + temp[0] + "、年龄:" + temp[1]);
	}
	
	
	
	String t = "hELLO";
	System.out.println(initcap(t));
		
	
}
//将一个字符串首字母变为大写,其余字母变为小写
public static String initcap(String tem){
	return tem.substring(0,1).toUpperCase() + tem.substring(1).toLowerCase() ;
}

}

第十二章 this关键字
在java程序里面它是以“{}”为界限的。如果现在属性名称与参数出现重名的情况下,那么默认的情况下如果没有加入任何限制,指的都是最近的“{}”内容变量名称。所以在这种情况下为了可以明确找到要访问的变量属于类中的属性的时候,需要在变量前面加上this,这样就可以准确的进行属性标记
在以后的程序开发之中,只要是访问类中的属性前面必须加上“this”
调用方法
利用this可以调用普通方法或者构造方法
限制:

class Book{
private String title;
private double price ;

public Book(){
	System.out.println("一个新的Book类对象产生");
}

public Book(String title){
	this() ;
	this.title = title ;
}

public Book(String title, double price) {
	this(title) ;
	this.price = price ;
}

public void getInfo(){
	System.out.println("图书名称:" + this.title + ",价格:" + this.price );
}

}

public class Thi{
public static void main(String args[]){
Book bk = new Book(“Java开发”,89.8);

	bk.getInfo();
	
}

}

1、使用“this”调用构造方法形式只能放在代码的首行
2、进行构造方法互相调用的时候一定要留有出口
也就是说在使用this()互相调用的时候请至少保留一个构造方法没有使用this调用其他构造的情况
表示当前对象:
所谓的当前对象指的就是当前正在调用类方法的对象
总结:
1、类中的属性调用以后都要加上this
2、类中的构造方法间的相互调用,一定要留有出口
3、this表示当前对象,指的是当前正在调用方法的对象,this不是固定的
class Emp{
private int empno ;
private String ename ;
private double sal ;
private String dept ;
public Emp(){
this(0,“无名氏”,0.0,“未定”) ;
}
public Emp(int empno){
this(empno,“临时工”,800.0,“后勤部”) ;
}
public Emp(int empno,String ename){
this(empno,ename,2000.0,“技术部”);
}
public Emp(int empno,String ename,double sal,String dept){
this.empno = empno ;
this.ename= ename ;
this.sal = sal ;
this.dept = dept ;
}
public String getInfo(){
return “雇员编号:” + this.empno + “,姓名:” + this.ename + “,工资:” + this.sal + “,部门:” + this.dept ;
}
}

public class TestDemo{
public static void main(String args[]){
Emp ea = new Emp() ;
Emp eb = new Emp(7369) ;
Emp ec = new Emp(7566,“ALLEN”) ;
Emp ed = new Emp(7839,“KING”,5000.0,“财务部”) ;
System.out.println(ea.getInfo());
System.out.println(eb.getInfo());
System.out.println(ec.getInfo());
System.out.println(ed.getInfo());

}

}
3.3、表示当前对象
所谓的当前对象指的就是当前正在调用类中方法的对象

package First;
class Book{
public void print() {
//哪个对象调用print()方法,this就自动与此对象指向同一块内存地址
//this就表示当前对象
System.out.println("this = " + this);
}
}
public class TEST {

public static void main(String[] args) {
	Book booka = new Book();
	System.out.println("booka = " + booka);
	booka.print();
	System.out.println("--------------------");
	Book bookb = new Book();
	System.out.println("bookb = " + bookb);
	bookb.print();


}

}
之前 this.属性就属于当前对象中的属性,一定是堆内存保存的内容
总结:
1、类中的属性调用以后都要加上this
2、类中的构造方法间的相互调用,一定要保留出口;
3、this表示当前对象,指的是当前正在调用类中方法的对象,this不是一个固定的。

第十三章 引用传递
引用传递核心意义:同一块堆内存空间可以被不同的栈内存所指向,不同栈内存可以对同一堆内存进行内容的修改
String类对象一旦声明不可改变
package quote;

public class DemoTest {

public static void main(String[] args) {
	String msg = "hello";//String一旦声明不可改变
	fun(msg);
	System.out.println(msg);//hello
}
public static void fun(String temp) {
	temp = "world";
}

}
结论:虽然String属于类,属于引用数据类型,但是由于其内容不可改变的特点,很多的时候就直接把String当成基本数据类那样使用就完了,也就是说每一个String变量只能够保存一个数据。
第十四章 简单java类深入

第十五章 对象比较
如果说现在定义一个类,要想判断他的两个对象是否相等,那么必须要实现对象之中所有属性内容的比较
例如:
public boolean compare(Book book) {
if(book == null) {
return false;
}
if(this == book) {
return true;
}
if(this.title.equals(book.title) && this.price == book.price) {
return true;
}else {
return false;
}
}
总结:
1、对象比较是一个类自己定义的功能
2、对象比较时一定要判断是否为null,地址是否相同,属性是否相同。

第十五章 对象比较
class Book1{
private String title ;
private double price ;
public Book1(String title,double price) {
this.title = title ;
this.price = price ;
}
public boolean compare(Book1 book) {
if(book == null) {
return false ;
}
if(this == book) {
return true ;
}
if (this.title.equals(book.title) && this.price == book.price) {
return true ;
}else {
return false ;
}
}
public String getInfo() {
return "图书名称: "+ this.title + ",价格: " + this.price ;
}
}
总结:
1、对象比较一定是某一个类自己定义的功能;
2、对象比较一定时一定要判断是否为null、地址是否相同、属性是否相同
简单java类里面一定要提供对象比较的方法

第十六章static关键字
static定义属性
一旦在定义属性的时候使用了static之后,只要有一个对象修改了属性的内容,那么所有对象的static属性一起修改,也就是说此时static定义的属性是全局属性

static属性与非static属性还有一个最大的区别,所有的非static属性必须产生实例化对象之后才可以进行访问,但是static属性不受实例化对象的限制,也就是说在没有实例化对象的情况下依然可以使用static属性

在编写类的过程之中,所选的首先一定不是static属性(95%),如果需要描述共享信息的时候使用static(可以方便集体修改)可以不用重复开辟没存空间。

3.2 、static定义方法
static定义方法的时候也可以在没有实例化对象的时候直接利用类名称直接调用

static方法与非static方法访问限制
static不能够直接访问非static方法或属性,只能够调用static属性或方法
非static方法可以访问static属性或方法,不受任何限制

为什么会存在这样的限制?
所有的非static属性或方法必须在类已经明确产生了实例化对象才会分配空间,才可以使用
所有的static定义的结构不受实例化对象的限制即:可以在没有实例化对象的时候直接调用

主方法:
public:主方法是程序的开始,所以这个方法对任何的操作都是可见的,那么既然是可见的就必须是有public(公共)
static:证明此方法是由 类名称直接调用的;
void:主方法是一个程序的开始点,既然是所有的开头,那么就不能够回头,执行完毕为止
main:是一个系统规定好的名称不能够修改
String args[]:指的是一个程序运行时传递参数

总结:
1、开发之中首选的一定不是static属性或方法
2、static属性或方法可以在没有实例化对象的时候由类名称直接调用
3、static属性保存在全局数据去
内存区一共有四个:堆内存、栈内存、全局数据区、全局代码区。

第十七章 代码块
普通代码块
普通代码块的作用:防止在方法里面编写的代码变量重复
if(true) {
int num = 10;
System.out.println(“num =” + num);
}

构造块
把代码块写在一个类里面就称为构造块
构造块优先于构造方法执行且如果多次实例化会重复调用

静态块
一个代码使用了static定义就称为静态块分为两种情况
1、非主类静态块:静态块将优先于构造块执行,不管有多少实例化对象,静态块只执行一次,作用:为类中的static属性初始化
2、在主类中的静态块:静态块优先于主方法执行

第十八章 内部类
基本概念
所谓的内部类就是指在一个类的内部继续定义了其他结构类的情况
例如:
class Outer{
private String msg = “hello world”;
class Inner{
public void print() {
System.out.println(msg);
}
}
public void fun() {
Inner in = new Inner();
in.print();
}
}
内部类有一个最大的优点:可以方便访问外部类的私有操作
一旦使用了内部类,私有访问就变得非常简单了
内部类对象实例化语法:
外部类.内部类 对象 = new 外部类().new 内部类();
Outer out = new Outer();
out.fun();
Outer.Inner ine = new Outer().new Inner();
ine.print();
内部类不可能离开外部类的实例化对象,所以一定要先实例化外部类对象后才可以使用内部类对象。如果真的使用到了内部类,也基本上不会像以上的操作那样进行的。一定是通过外部类方问内部类。

static定义内部类
使用了static定义的内部类不受外部类的实例化对象控制
内部类使用了static定义,这个内部类就变为了一个外部类,并且只能访问外部类定义的static操作。相当于定义了一个外部类。
语法:
外部类.内部类 对象 = new 外部类.内部类();

方法中定义内部类
例如:
class Outer {
private String msg = “hello world”;
public void fun(final int num) {
final double sco = 99.9;
class Inner{
public void print() {
System.out.println(Outer.this.msg);
System.out.println(num);
System.out.println(sco);

		}
	}
	new Inner().print();
}

}

总结:
1、内部类只是阐述了基本定义的形式,但是没有讲解如何去使用
2、内部类可以与外部类之间方便的进行私有属性的访问
3、内部类可以使用private声明,声明之后,无法在外部类实例化内部类对象;
语法:
外部类.内部类 对象 = new 外部类().new 内部类();
4、使用static定义的内部类就相当于一个外部类
外部类.内部类 对象 = new 外部类.内部类();
5、内部类可以在方法中定义

第十九章链表
3.1链表的基本形式
链表是一种最为简单的数据结构,它的主要目的是依靠引用关系来实现多个数据的保存,那么假设现在要保存的数据是字符串
class Node{
private String data ;
private Node next ;
public Node(String data) {
this.data = data ;
}
public void setNext(Node next) {
this.next = next ;
}
public Node getNext(){
return this.next ;
}
public String getData() {
return this.data ;
}
}
public class Test1 {

public static void main(String[] args) {
	Node root = new Node("火车头");
	Node n1 = new Node("车厢A");
	Node n2 = new Node("车厢B");
	root.setNext(n1);
	n1.setNext(n2);
	print(root);


}
public static void print(Node current) {
	if(current == null) {
		return ;
	}
	System.out.println(current.getData());
	print(current.getNext()) ;
}

}
3.2、链表的基本雏形
通过分析发现:
. 用户在操作的过程之中完全没有必要去关心Node类是否存在;
. 所有的节点的引用关系不应该由用户处理,应该有一个专门的工具类来进行处理
下面需要定义一个类,来帮助客户端去隐藏所有的链表中给出的细节操作。
class Node{
private String data ;
private Node next ;
public Node(String data) {
this.data = data ;
}
public void setNext(Node next) {
this.next = next ;
}
public Node getNext(){
return this.next ;
}
public String getData() {
return this.data ;
}
//实现节点的添加
//第一次调用(Link): this = Link.root
//第二次调用(Node): this = Link.root.next
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;//保存新节点
} else {//当前节点之后还有节点
//当前节点的下一个节点继续保存
this.next.addNode(newNode);
}
}
//第一次调用(Link): this = Link.root
//第二次调用(Node): this = Link.root.next
public void printNode() {
System.out.println(this.data);//输出当前节点
if(this.next != null) {//现在还有下一个节点
this.next.printNode();//输出下一个
}
}
}
//需要进行Node类对象关系的处理
class Link{//负责数据的设置和输出
private Node root ;
public void add(String data) {//增加数据
//为了可以设置数据的先后关系,所以将data包装在一个Node类对象里
Node newNode = new Node(data);
//保存当前数据的时候,现在还没有根节点
if(this.root == null) {
this.root = newNode ;//将新的节点设置为根节点
}else {//根节点已经存在了
//随后后面增加的元素应该由节点来决定
//从root节点之后找到合适的位置
this.root.addNode(newNode);
}

}
public void print() {//输出数据
	if(this.root != null) {//存在根节点
		this.root.printNode() ;
	}
}

}
public class Test1 {

public static void main(String[] args) {
	Link link = new Link();
	link.add("hello");
	link.add("world");
	link.add("MLDN");
	link.add("nihao");
	link.add("世界");
	link.print();
}

}
通过以上的代码实际上就可以发现链表的基本操作特点
客户端代码不用去关注具体的Node以及引用关系的细节,只关注于提供的Link类中支持的方法;
Link类的主要功能是控制Node类的对象的产生和根节点;
Node类主要负责数据的保存以及引用关系的分配;
3.3、开发可用链表
指的是可以使用的链表实现数据的增加、修改、删除、查询操作
3.3.1、程序的基本结构
在开发具体的可用链表操作之前,首先必须明确一个道理:Node类负责所有的节点数据的保存以及节点关系的匹配,所以Node 类不可能单独去使用,而以上的实现里面Node类是可以单独使用的,外部可以绕过Link类直接操作Node类,这样明显是没有任何意义存在的,所以需要下面需要修改设计结构,让Node类只能够被Link类使用。
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
}
//上面为内部类=========================================
private Node root;

}
3.3.2、数据增加: public void add(数据类型 变量)
如果要进行新数据的增加,则应该由Link类负责节点对象的产生,并且由Link类维护根节点,所有的节点关系匹配交给Node类处理
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
}
//上面为内部类=========================================
private Node root;
public void add(String data) {
if(data == null) {
return ;
}
Node newNode = new Node(data);//要保存的数据
if(this.root == null) {//当前根节点没有数据
this.root = newNode ;//保存根节点
}else {//根节点存在,其他节点交给Node类处理
this.root.addNode(newNode);
}
}
}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();
	all.add("hello");
	all.add("world");
}

}
此时使用了一个不许为null的判断。并不是所有的链表都不许为空
3.3.3、取得保存元素的个数: public int size()
既然每一个链表对象都只有一个root根元素,那么每一个链表就有自己的长度。可以在Link类里面设置一个count属性,随后每一次数据添加完成之后,可以进行个数的自增
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
public void add(String data) {
if(data == null) {
return ;
}
Node newNode = new Node(data);//要保存的数据
if(this.root == null) {//当前根节点没有数据
this.root = newNode ;//保存根节点
}else {//根节点存在,其他节点交给Node类处理
this.root.addNode(newNode);
}
this.count ++ ;
}
public int size() {//取得保存的数据量
return this.count ;
}
}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	System.out.println(all.size());
}

}
3.3.4判断是否是空链表 public boolean isEmpty()
判断链表是否为空有两种方法
第一个:判断root是否有对象(是否为null)
第二个:判断保存的数据量(count)
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
public void add(String data) {
if(data == null) {
return ;
}
Node newNode = new Node(data);//要保存的数据
if(this.root == null) {//当前根节点没有数据
this.root = newNode ;//保存根节点
}else {//根节点存在,其他节点交给Node类处理
this.root.addNode(newNode);
}
this.count ++ ;
}
public int size() {//取得保存的数据量
return this.count ;
}
public boolean isEmpty() {
return this.count == 0 ;
}
}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();
	System.out.println(all.isEmpty());
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	System.out.println(all.size());
	System.out.println(all.isEmpty());
}

}
3.3.5、 数据查询 : public boolean contains(数据类型 变量)
在链表之后一定会保存多个数据,那么基本的判断数据是否存在的方式,以String为例。循环链表中的内容,并且与要查询的数据进行匹配(equals())
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(String data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
public void add(String data) {
if(data == null) {
return ;
}
Node newNode = new Node(data);//要保存的数据
if(this.root == null) {//当前根节点没有数据
this.root = newNode ;//保存根节点
}else {//根节点存在,其他节点交给Node类处理
this.root.addNode(newNode);
}
this.count ++ ;
}
public int size() {//取得保存的数据量
return this.count ;
}
public boolean isEmpty() {
return this.count == 0 ;
}
public boolean contains(String data) {
if (data == null || this.root == null) {
return false ;
}
return this.root.containsNode(data) ;
}
}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();	
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	System.out.println(all.contains("hello"));
}

}
3.3.6、根据索引取得数据 : public 数据类型 get(int index)
通过以上的代码测试发现,链表里面保存了多个String类的对象,在程序里面只有数组里面可以保存多个对象,现在使用的链表与数组相比较的话,优势就是没有长度限制,所以严格意义上来讲就是一个动态的对象数组,那么既然链表属于动态对象数组,那么也应该具备像数组那样可以根据索引取得元素功能
由于是动态对象数组,所以数组中的每一个元素索引的内容都一定是动态生成

class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(String data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public String getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot ;
public void add(String data) {
if(data == null) {
return ;
}
Node newNode = new Node(data);//要保存的数据
if(this.root == null) {//当前根节点没有数据
this.root = newNode ;//保存根节点
}else {//根节点存在,其他节点交给Node类处理
this.root.addNode(newNode);
}
this.count ++ ;
}
public int size() {//取得保存的数据量
return this.count ;
}
public boolean isEmpty() {
return this.count == 0 ;
}
public String get(int index) {
if(index > this.count ) {
return null ;
}
this.foot = 0;
return this.root.getNode(index);
}
public boolean contains(String data) {
if (data == null || this.root == null) {
return false ;
}
return this.root.containsNode(data) ;
}
}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();	
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	System.out.println(all.get(1));
	System.out.println(all.get(5));
}

}
3.3.7、修改指定索引内容 :public void set(int index,数据类型 变量)
修改数据和查询的区别不大,查询的时候当满足索引值得时候,那么此处只需要将数据返回变为数据的重新赋值
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(String data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public String getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
public void setNode(int index, String data) {
if(Link.this.foot ++ == index) {
this.data = data ;
}else {
this.next.setNode(index, data);
}

	}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot  ;
public void add(String data) {
	if(data == null) {
		return ;
	}
	Node newNode = new Node(data);//要保存的数据
	if(this.root == null) {//当前根节点没有数据
		this.root = newNode ;//保存根节点
	}else {//根节点存在,其他节点交给Node类处理
		this.root.addNode(newNode);
	}
	this.count ++ ;
}
public int size() {//取得保存的数据量
	return this.count ;
}
public boolean isEmpty() {
	return this.count == 0 ;
}
public String get(int index) {
	if(index > this.count ) {
		return null ;
	}
	this.foot = 0;
	return this.root.getNode(index);
}
public boolean contains(String data) {
	if (data == null || this.root == null) {
		return false ;
	}
	return this.root.containsNode(data) ;
}
public void set(int index,String data) {
	if(index > this.count) {
		return ; 
	}
	this.foot = 0 ;
	this.root.setNode(index,data);
}

}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();	
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	all.set(1, "你好");
	System.out.println(all.get(1));
	System.out.println(all.get(5));
}

3.3.8、数据删除: public void remove(数据类型 变量)
对于删除数据而言,实际上是要分为两种情况
情况一:要删除的数据是根节点,则root应该变为“根节点.next”,Link类才关系根节点,所以此种情况在Link类中进行处理;
情况二:要删除的数据不是根节点,而是其他普通节点,应该是在Node类里处理,所以此处是从第二个节点开始判断的
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(String data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public String getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
public void setNode(int index, String data) {
if(Link.this.foot ++ == index) {
this.data = data ;
}else {
this.next.setNode(index, data);
}

	}
	public void removeNode(Node previous,String data) {
		if(data.equals(this.data)) {//当前节点为要删除的节点
			previous.next = this.next ;//空出当前节点
		}else {
			this.next.removeNode(this, data);
		}
	}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot  ;
public void add(String data) {
	if(data == null) {
		return ;
	}
	Node newNode = new Node(data);//要保存的数据
	if(this.root == null) {//当前根节点没有数据
		this.root = newNode ;//保存根节点
	}else {//根节点存在,其他节点交给Node类处理
		this.root.addNode(newNode);
	}
	this.count ++ ;
}
public int size() {//取得保存的数据量
	return this.count ;
}
public boolean isEmpty() {
	return this.count == 0 ;
}
public String get(int index) {
	if(index > this.count ) {
		return null ;
	}
	this.foot = 0;
	return this.root.getNode(index);
}
public boolean contains(String data) {
	if (data == null || this.root == null) {
		return false ;
	}
	return this.root.containsNode(data) ;
}
public void set(int index,String data) {
	if(index > this.count) {
		return ; 
	}
	this.foot = 0 ;
	this.root.setNode(index,data);
}
public void remove(String data) {
	if(this.contains(data)) {
		//要删除数据是否是根节点数据
		if(data.equals(this.root.data)) {//为要删除的节点
			this.root = this.root.next ;//空出当前接节点
		}else {
			this.root.next.removeNode(this.root, data);
		}
		this.count -- ;
	}
}

}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();	
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	all.add("nihao");
	all.remove("world");
	System.out.println(all.size());
}

}
3.3.9、将链表变为对象数组:public 数据类型 [] toArray()
任何情况下,不管什么样的类,都不可能在类中使用输出语句,只要是想输出数据一定要将数据返回到调用处进行输出,由于链表属于动态对象数组,所以此处最好的做法是将链表以对象数组的形式返回

class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private String data;
private Node next;
public Node(String data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(String data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public String getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
public void setNode(int index, String data) {
if(Link.this.foot ++ == index) {
this.data = data ;
}else {
this.next.setNode(index, data);
}

	}
	public void removeNode(Node previous,String data) {
		if(data.equals(this.data)) {//当前节点为要删除的节点
			previous.next = this.next ;//空出当前节点
		}else {
			this.next.removeNode(this, data);
		}
	}
	public void toArrayNode() {
		Link.this.retArray[Link.this.foot ++] = this.data ;
		if(this.next != null) {
			this.next.toArrayNode();
		}
	}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot  ;
private String retArray[] ; 
public void add(String data) {
	if(data == null) {
		return ;
	}
	Node newNode = new Node(data);//要保存的数据
	if(this.root == null) {//当前根节点没有数据
		this.root = newNode ;//保存根节点
	}else {//根节点存在,其他节点交给Node类处理
		this.root.addNode(newNode);
	}
	this.count ++ ;
}
public int size() {//取得保存的数据量
	return this.count ;
}
public boolean isEmpty() {
	return this.count == 0 ;
}
public String get(int index) {
	if(index > this.count ) {
		return null ;
	}
	this.foot = 0;
	return this.root.getNode(index);
}
public boolean contains(String data) {
	if (data == null || this.root == null) {
		return false ;
	}
	return this.root.containsNode(data) ;
}
public void set(int index,String data) {
	if(index > this.count) {
		return ; 
	}
	this.foot = 0 ;
	this.root.setNode(index,data);
}
public String [] toArray() {
	if(this.root == null) {
		return null ;
	}
	this.foot = 0 ;
	this.retArray = new String [this.count] ;
	this.root.toArrayNode();
	return this.retArray ;
}
public void remove(String data) {
	if(this.contains(data)) {
		//要删除数据是否是根节点数据
		if(data.equals(this.root.data)) {//为要删除的节点
			this.root = this.root.next ;//空出当前接节点
		}else {
			this.root.next.removeNode(this.root, data);
		}
		this.count -- ;
	}
}

}
public class Test1 {

public static void main(String[] args) {
	Link all = new Link();	
	all.add("hello");
	all.add("world");
	all.add("MLDN");
	all.add("nihao");
	String [] data = all.toArray() ;
	for(int x = 0 ;x < data.length ;x ++) {
		System.out.println(data[x]);
	}
}

}
链表变为对象数组取出是最为重要的功能

第二十章 继承性
1、清楚继承性的主要作用以及实现;
2、继承性相关限制以及使用规则。
3、继承性的最大特征是解决代码重用问题

3.1、继承问题的引出
在不使用继承的时候,很多有一样特征的类中会存在很多代码相同的问题,继承就是解决有特征一样的类代码相同的问题

3.2、继承的的实现
在java之中如果要想使继承使用extends实现关键字完成,而且实现的语法如下:
class 子类 extends 父类{
一定要记住,子类也叫派生类,父类也叫基类、超类
}
范例:
class Person{
private String name ;
private int age;
public void setName(String name) {
this.name = name ;
}
public void setAge(int age) {
this.age = age ;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age ;
}
public String getInfo() {
return "姓名: " + this.name + ",年龄: " + this.age ;
}
}
class Student extends Person{//继承了Person父类

}
public class TestDemo {

public static void main(String[] args) {
	Student stu = new Student();
	stu.setAge(15);
	stu.setName("张三");
	System.out.println(stu.getInfo());
}

}
现在Student类里面没有编写任何的方法,但是由于其继承了Person父类,所以可以直接使用Person类里面定义的方法,如果有需要可以在Student 里面可以扩充自己的方法
范例:
class Person{
private String name ;
private int age;
public void setName(String name) {
this.name = name ;
}
public void setAge(int age) {
this.age = age ;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age ;
}
public String getInfo() {
return "姓名: " + this.name + ",年龄: " + this.age ;
}
}
class Student extends Person{//继承了Person父类
private String school ;
public void setSchool(String school) {
this.school = school ;
}
public String getSchool() {
return this.school ;
}
}
public class TestDemo {

public static void main(String[] args) {
	Student stu = new Student();
	stu.setAge(15);
	stu.setName("张三");
	stu.setSchool("清华大学");
	System.out.println(stu.getInfo() +",学校: " + stu.getSchool());
}

}
通过以上的程序对比就可以非常清楚的发现继承的有点:
-子类可以直接将父类的操作继续使用,属于代码重用
-子类可以继续扩充属于自己的标准

继承的优点:
1、子类可以直接将父类的操作继续使用,属于代码重用
2、子类可以继续扩充自己的方法

3.3、继承的限制
利用extends关键字在大部分的情况下都可以不用去考虑(前提:按照标准格式开发),但是事实上由于要限制用户的使用,所以继承也有自己的一些要求
1、java不允许多重继承、允许多层继承
范例:错误的继承
class A{
}
class B{
}
class C extends A,B{
}
范例:正确的继承
class A{
}
class B extends A{
}
class C extends B{
}
使用多层继承的时候并没有层数的限制,不过从开发的角度认为继承不要超过三层
2、子类在继承的时候严格来讲会继承父类中的全部操作,但是对于所有私有操作属于隐式继承,而所有的非私有操作属于显示继承
范例:观察属性
class A{
private String msg ;
public void setMsg(String msg) {
this.msg = msg ;
}
public String getMsg() {
return this.msg ;
}
}
class B extends A{
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.setMsg(“hello”);
System.out.println(b.getMsg());
}
}
在B类里面一定存在msg属性,因为如果不存在,那么setMsg()设置的内容就不可能被保存,即:getMsg()绝对违法进行内容输出的
但是在B类里面不能够针对于msg属性进行访问,因为它属于私有的,只能够间接的进行私有属性的访问。
所有的private操作不能直接使用,所有的非私有操作可以直接使用
子类对于父类存在私有属性,不能直接使用,但是可以利用父类中的方法操作属性
3、子类对象构造之前一定会默认调用父类的构造(默认调用无参构造)以保证父类对象先实例化,而后在实例化子类对象
如果父类中没有无参构造方法,那么久必须使用“super()”明确调用父类的有参构造
范例:
class A{
public A(){
System.out.println(“A、A类中的构造方法”);
}
}
class B extends A{
public B(){
System.out.println(“B、B类中的构造方法”);
}
}
public class Test {
public static void main(String[] args) {
new B();
}
}
程序运行结果:
A、A类中的构造方法
B、B类中的构造方法
此时可以发现,在没有加入任何操作代码,但是在实例化子类对象前,先去实例化了父类对象,以及调用了父类的无参构造方法
那么此时对于子类构造而言,就相当于隐含了一个“super()”。
public B(){
super() ;//父类中有无参构造是加与不加无区别
System.out.println(“B、B类中的构造方法”);
}
如果此时父类中没有无参构造方法了,那么久必须使用super()明确调用父类的有参构造方法了
范例:
class A{
public A(String title){
System.out.println(“A、A类中的构造方法”);
}
}
class B extends A{
public B(String title){
super(title) ;//父类中有无参构造是加与不加无区别
System.out.println(“B、B类中的构造方法”);
}
}
public class Test {
public static void main(String[] args) {
new B(“hello”);
}
}
通过代码验证:super()与this()不能同时出现,不管子类怎么折腾,他永恒有一个前提:子类对象执行前一定要先执行父类构造,为父类对象初始化后,才轮到子类对象初始化
第二十一章 覆写
继承的主要特征是子类可以根据父类已有的功能进行功能的扩展,但是在子类定义属性或方法的时候有可能定义的属性和方法与父类同名,那么在这样的情况下就称为复写
3.1、方法的覆写
当子类定义了与父类方法名称相同,参数类型及个数、返回值类型相同时就称为方法的覆写
class A{
public void fun() {
System.out.println(“A类中fun()方法”);
}
}
class B extends A{

}
public class Test {
public static void main(String[] args) {
B b = new B();
b.fun();
}
}
运行结果:
A类中fun()方法
因为这个时候子类中并没有fun()方法,所以这个时候子类使用fun()方法时会直接使用A类继承而来的fun()方法
范例:观察复写:
class A{
public void fun() {
System.out.println(“A类中fun()方法”);
}
}
class B extends A{
public void fun() {
System.out.println(“B类中fun()方法”);
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.fun();
}
}
运行结果:
B类中fun()方法
覆写后关于方法调用的说明:
当发生覆写之后,此时会调用实例化子类中已经被覆写的方法
一个类会产生多个子类,那么每一个子类都一定或有自己的实现

覆写结果分析要素:
1、观察实例化的是哪个类
2、观察实例化类里面调用的方法是否被覆写过,如果每有覆写调用父类的方法

覆写的使用原则:
如果现在发现父类中的方法名称工能不足(不适合本子类),但是又必须使用此方法名称时候,就需要覆写这一概念
以上的代码确实已经实现了覆写的功能,但是如果要想更好的实现覆写的操作,还必须考虑到权限的问题,被子类覆写的方法不能够拥有比父类更为严格的控制权限
对于访问控制权限已经学习过三个:public >default>private ,也就是说private的访问权限是最为严格的,即:如果父类的方法使用的是public声明,那么子类覆写此方法的时候,只能是public,如果父类的方法是default,那么子类可以使用public、default。99%的情况下方法都是用public
正确的复写:
class A{
public void fun() {
System.out.println(“A类中fun()方法”);
}
}
class B extends A{
public void fun() {
System.out.println(“B类中fun()方法”);
}
}

第二种
class A{
void fun() {
System.out.println(“A类中fun()方法”);
}
}
class B extends A{
public void fun() {
System.out.println(“B类中fun()方法”);
}
}
错误的复写
class A{
public void fun() {
System.out.println(“A类中fun()方法”);
}
}
class B extends A{
void fun() {
System.out.println(“B类中fun()方法”);
}
}
使用private定义的方法,这个时候发现子类中根本没有覆写使用private定义 的方法,也就是说如果使用了private声明,那么这个方法对于子类是不可见的,就算子类定义了完全符合覆写要求的方法,那么也不能够发生覆写,这个时候子类的方法实际上就是子类自己定义的方法

一旦有了覆写之后,默认情况下,子类所能够调用的一定是覆写过得方法。为了能够明确的由子类调用父类中已经被覆写的方法,那么可以使用“super.方法()”来进行访问。

关于super.方法()与this.方法()的区别?
使用this.方法()会首先从本类中查找是否存在要调用的方法名称,如果存在则直接调用,如果不存在则查找父类中是否存在,如果有就调用,没有就报编译时错误
使用super.方法().明确的表示调用的不是子类中的方法,而直接调用父类的方法。

总结:
覆写必须保证返回值类型相同。
3.2、属性的覆盖
如果说现在子类定义了和父类完全相同的属性名称的时候,就称为属性的覆盖
在任何的开发之中,类中的属性必须封装(99%),那么一旦封装之后就变为私有的了,因为父类的私有属性子类根本看不见,更不会相互影响了。
总结:
1、只要发生了继承关系,那么就一定会存在复写的的应用,复写的应用主要以方法为主;
2、如果现在子类要使用父类指定的方法,但是发现父类的方法不能够满足子类要求的时候就要使用复写来完善子类的功能,同事保留父类的方法名称;
3、被子类复写的方法不能拥有比父类更为严格的访问控制权限

第二十二章 数组操作
3.1开发数组的父类
范例:
class Array{
private int data[] ;
private int foot ;
public Array(int len) {
if(len > 0) {
this.data = new int [len];
}else {
this.data = new int[1] ;
}
}
public boolean add(int num) {
if(this.foot < this.data.length) {
this.data[this.foot ++] = num ;
return true ;
}
return false ;
}
public int [] getData() {
return this.data ;
}
}
public class TestArray {
public static void main(String[] args) {
Array arr = new Array(3);
System.out.println(arr.add(10));
System.out.println(arr.add(20));
System.out.println(arr.add(30));
System.out.println(arr.add(40));
System.out.println(arr.add(50));
int [] ar = arr.getData() ;
print(ar);

}
public static void print(int [] temp) {
	for(int x = 0 ;x < temp.length ;x ++) {
		System.out.println(temp[x]);
	}
}

}
在以上的代码之中发现,此时Array类中没有提供无参构造,因为必须要传入一个数组的大小,否则该程序无法使用,并且Array类就规定了要想增加数据就使用add()方法,要想取出全部数据就使用getData()方法

3.2、开发排序类
如果要真是排序只是在取得数据的时候将数据以排序的方式返回即可,其他的操作和Array类应该没有区别,甚至我们认为连客户端使用的方法都应该相同
范例:
class Array{
private int data[] ;
private int foot ;
public Array(int len) {
if(len > 0) {
this.data = new int [len];
}else {
this.data = new int[1] ;
}
}
public boolean add(int num) {
if(this.foot < this.data.length) {
this.data[this.foot ++] = num ;
return true ;
}
return false ;
}
public int [] getData() {
return this.data ;
}
}
class SortArray extends Array{
//Array类里面现在没有无参构造方法
public SortArray(int len) {
//明确的调用父类的有参构造方法
super(len);
}
public int [] getData() {
java.util.Arrays.sort(super.getData());
return super.getData() ;
}

}
public class TestArray {
public static void main(String[] args) {
SortArray arr = new SortArray(5);
System.out.println(arr.add(100));
System.out.println(arr.add(20));
System.out.println(arr.add(1));
System.out.println(arr.add(25));
System.out.println(arr.add(5));
System.out.println("------------------");
int [] ar = arr.getData() ;
print(ar);
}
public static void print(int [] temp) {
for(int x = 0 ;x < temp.length ;x ++) {
System.out.println(temp[x]);
}
}
}
在这个程序里面,我们的思路:
绝对不改变客户端已有的使用方法
子类现在为了要维持功能的完善,所以必须要根据情况进行父类方法的复写
3.3、开发反转类
反转类的最终要求也是要保证客户端的操作习惯不改变,也是就说父类的方法名称应该继续保留
范例:
class Array{
private int data[] ;
private int foot ;
public Array(int len) {
if(len > 0) {
this.data = new int [len];
}else {
this.data = new int[1] ;
}
}
public boolean add(int num) {
if(this.foot < this.data.length) {
this.data[this.foot ++] = num ;
return true ;
}
return false ;
}
public int [] getData() {
return this.data ;
}
}
class SortArray extends Array{
//Array类里面现在没有无参构造方法
public SortArray(int len) {
//明确的调用父类的有参构造方法
super(len);
}
public int [] getData() {
java.util.Arrays.sort(super.getData());
return super.getData() ;
}
}
class ReverseArray extends Array{
public ReverseArray(int len) {
super(len);
}
public int [] getData() {
int center = super.getData().length / 2 ;
int head = 0 ;
int tail = super.getData().length / 2 - 1 ;
for (int x = 0 ;x < center ;x ++) {
int temp = super.getData()[head];
super.getData()[head] = super.getData()[tail] ;
super.getData()[tail] = temp ;
head ++ ;
tail – ;
}
return super.getData() ;
}
}
public class TestArray {
public static void main(String[] args) {
ReverseArray arr = new ReverseArray(5);
System.out.println(arr.add(100));
System.out.println(arr.add(20));
System.out.println(arr.add(1));
System.out.println(arr.add(25));
System.out.println(arr.add(5));
System.out.println("------------------");
int [] ar = arr.getData() ;
print(ar);
}
public static void print(int [] temp) {
for(int x = 0 ;x < temp.length ;x ++) {
System.out.println(temp[x]);
}
}
}

第二十三章 final关键字
在java之中final称为终结器,在java里面可以使用final定义类,方法、属性。
1、使用final定义的类不能够再有子类
范例错误的继承:
final class A{
}
class B extends A{
}
2、使用final定义的方法不能被子类所覆写
在一些时候由于父类中的某些方法具备某些隐藏的特性,并且子类必须使用此方法操作的时候,就加上final,意思是:子类不要去破坏这个方法的重要作用
范例:错误的复写
class A{
public final void fun() {
}
}
class B extends A{
public void fun() {
}
}
3、使用final定义的变量就成为了常量,常量必须在定义的时候设置好内容,并且不能修改

特别需要隆重介绍的是全局常量:public static final声明的就是全局常量
为了让程序中的常量可以与变量有效的进行区分,所有的常量名称都要求使用大写字母表示。
总结:
1、在以后查看文档的时候,如果发现了final定义的类或方法时,千万不要继承或覆写。
2、使用public static final定义的是全局常量,全局常量每一个字母都要求大写。

对象的多态性
多态性严格来讲只能为其讲解基本概念,以及相关的使用限制
多态性的依赖:方法的覆写;
多态性严格来讲有两种描述方式;
1、方法的多态性
方法的重载:同一个方法名称,会根据传入的参数类型及个数不同,会执行不同的方法体
方法的覆写:同一个方法会根据子类的不同,实现不同的功能
2、对象的多态性
指的是在继承关系之中,子类和父类之间的转换
向上转型:父类 父类对象 = 子类实例;
向上转型:由于所有的子类对象实例都可以自动的向上转型,多以这个代码的最大的意义在于参数类型的同一上,参数类型同一后,还可以调用子类覆写后的方法体,即:同一方法针对于不同的子类有不同的实现

向下转型:子类 子类对象 = (子类)父类实例;
向下转型:指的是父类调用子类的特殊方法:所有的父类发生了转型之后,只能够看见自己定义的全部方法信息,但是看不见子类的特殊方法,此时就需要向下转型,将父类对象转化为子类对象,这样就可以使用子类的特殊功能
对于对象的转型给出以下的经验总结
80%的情况都只会向上转型同时可以得到参数类型的同一方便于我们的程序设计:子类定义的方法大部分情况下请以父类的方法名称为标准准确覆写,不要过多的扩充方法
5%的情况下会使用向下转型,目的调用子类的特殊方法:
15%的情况下是不转型:例如:String

个性化的操作在一个标准的开发之中应该尽量少出现,因为对象的转型操作里面毕竟有了强制问题,容易带来安全隐患

为了保证转型的顺利进行,在java里面提供有一个关键字instanceof,此关键字的使用:
对象 instanceof 类返回boolean

总结:
1、开发之中尽量使用向上转型,以确定参数类型同一,同时发生向上转型之后才可以发生向下转型
2、子类尽量不要扩充过多的与父类无关的操作方法
90%的情况下子类的功能要与父类的方法功能一致

第二十四章 抽象类
所谓的抽象类就是指在普通类里面增加抽象方法的组成部分
抽象方法:指的是没有方法体的方法,同时抽象方法还必须使用abstract关键字进行定义

抽象类的使用原则如下:
1、抽象类必须有子类,即:每一个抽象类必须被子类继承
2、抽象类的子类必须覆写抽象类中的全部抽象方法(强制子类覆写),子类不是抽象类
3、抽象类的实例化对象需要依靠子类完成,采用向上转型的方式处理

总结:
1、抽象类继承子类里面会有明确的方法覆写要求,而普通方法并没有
2,抽象类只是比普通类多了一些抽象方法的定义,其他的组成部分与普通类完全一样
3、普通类可以直接实例化,但是抽象类的对象必须经过向上转型之后才可以得到实例化对象
一个子类只能继承一个抽象类

抽象类的相关限制
1、抽象类里面会存在一些属性,那么抽象类之中一定会存在构造方法,目的为属性初始化,并且子类对象实例化的时候依然满足于先执行父类构造,在执行子类构造
2、抽象类不能够使用final定义
3、外部的抽象类不允许使用static声明,而内部的抽象类允许使用static声明,使用static声明的内部抽象类就相当于是一个外部抽象类,继承的时候会使用外部类.内部类的形式表示类名称
4、任何情况下,如果执行类中static方法的时候,都可以在没有对象的时候直接调用,对于抽象类也是一样
5、有些时候,由于抽象类只需要一个特定的系统的子类操作,所以可以忽略掉外部子类。这样的设计在系统类库之中会比较常见,目的为用户隐藏不需要知道的子类
在任何一个类的构造执行完毕之前,所有属性都是其对应数据类型的默认值,而子类的构造执行之前一定先执行父类的构造。

3.3、抽象类应用———模板设计
abstract class Action{
public static final int EAT = 1 ;
public static final int SLEEP = 4;
public static final int WORK = 9 ;
public void command(int flag) {
switch(flag) {
case EAT :
this.eat();
break ;
case SLEEP:
this.sleep();
break ;
case WORK:
this.sleep();
break ;
case EAT + WORK :
this.eat();
this.work();
break ;
}
}
public abstract void eat () ;
public abstract void sleep () ;
public abstract void work () ;
}
class Robot extends Action{
public void eat () {
System.out.println(“机器人开始充电”);
}
public void sleep () {
System.out.println(“机器人不用睡觉”);
}
public void work () {
System.out.println(“机器人开始工作”);
}
}
class Human extends Action{
public void eat () {
System.out.println(“人类开始吃饭”);
}
public void sleep () {
System.out.println(“人类开始睡觉”);
}
public void work () {
System.out.println(“人类开始工作”);
}
}
class Pig extends Action{
public void eat () {
System.out.println(“猪开始吃饭”);
}
public void sleep () {
System.out.println(“猪开始睡觉养膘”);
}
public void work () {
System.out.println(“猪不用工作”);
}
}
public class Test {

public static void main(String[] args) {
	fun(new Robot()) ;
	System.out.println("---------------");
	fun(new Human());
	System.out.println("---------------");
	fun(new Pig());		
}
public static void fun(Action act) {
	act.command(Action.EAT);
	act.command(Action.SLEEP);
	act.command(Action.WORK);
}		

}
总结:
1、如果真要使用抽象类继承的话,那么就使用抽象类(20%的情况);
2、抽象类强制规定了子类必须要做的事情,而且可以与抽象类的普通方法相配合;
3、不管抽象类如何努力有一个天生最大的短板,单继承局限:一个子类只能继承一个抽象类

第二十五章 接口
3.1、接口的基本定义
如果一个类之中只是由抽象方法和全局常量所组成的,那么这种情况下将不会将其定义为一个抽象类,而只会讲其定义为接口,所谓的接口严格来讲就属于特殊的抽象类,而这个类里面只有抽象方法和全局常量
要定义接口使用interface关键字完成
例如:
interface A{
public static final String MSG = “hello”;
public abstract void print();
}
由于接口里面存在有抽象方法,所以接口对象不能直接使用关键字new进行实例化对象的操作,所以接口的使用原则如下:
1、接口必须有子类,但是此时的子类可以使用implements关键字实现多个接口
2、接口的子类(如果不是抽象类),必须覆写接口中的全部抽象方法
3、接口的对象可以利用子类的向上转型进行实例化操作。

接口可以实现多继承:
interface A{
public abstract void print() ;
}
interface B{
public abstract void get() ;

}
class X implements A ,B{
public void print() {
System.out.println(“A接口的抽象方法”);
}
public void get() {
System.out.println(“B接口的抽象方法”);
}
}
public class TestDemo {
public static void main(String[] args) {
X x = new X() ;
A a = x ;
B b = x ;
a.print();
b.get();
}
}
对于接口而言,发现里面的组成就是抽象方法和全局常量,所以很多的时候,也有一些人为了省略编写可以不用写上abstract或public static final,并且在方法上是否编写public结果都是一样的,因为在接口里面只能使用一种访问权限—public
在接口里面没有写上public ,其最终的访问权限也是public,绝对不是default,为了防止某些不熟悉语法的开发者出现,所以强烈建议在接口定义方法的时候一定要写上public
抽象类和接口一起实现:
class D extends C implements AA,BB
接口中的方法可以简写:
public 数据类型 方法名称();

对于接口的组成,99%的情况下都是以抽象方法为主的。很少情况下接口只有全局常量
一个抽象类可以继承一个抽象类,但是反过来一个接口可以利用entends关键字同时继承多个接口(接口不能继承抽象类)
interface A{
public abstract void print() ;
}
interface B{
public abstract void get() ;
}
interface C extends A,B{
public void funC() ;
}
范例:
interface A{
public abstract void print() ;
}
interface B{
public abstract void get() ;

}
interface C extends A,B{
public void funC() ;
}
class X implements C{
public void print() {
}
public void get() {
}
public void funC() {
}
}
从继承关系上来讲抽象类要比接口限制多了很多
·一个抽象类只能够继承一个抽象的父类,而接口没有这个限制
·一个子类只能够继承一个抽象类,而却可以实现多个接口
在整个java里面,接口的主要功能就是解决单继承局限

在开发之中接口的三大核心作用:
定义不同层次之间的标准
表示一种操作能力
表示将服务器端的远程方法视图暴露给客户端

3.2、接口的实际应用————标准
标准:
interface USB {
public void start();

public void stop();

}
class Computer {
public void plugin(USB usb) {
usb.start();
usb.stop();
}
}
class Flash implements USB {
@Override
public void start() {
System.out.println(“u盘开始工作”);
}
@Override
public void stop() {
System.out.println(“u盘开始工作”);
}
}
class Print implements USB{
@Override
public void start() {
System.out.println(“打印机开始工作”);
}
@Override
public void stop() {
System.out.println(“打印机停止工作”);
}
}
class MP3 implements USB{
@Override
public void start() {
System.out.println(“mp3开始工作”);
}
@Override
public void stop() {
System.out.println(“mp3停止工作”);
}
}
public class DE {
public static void main(String[] args) {
Computer com = new Computer();
com.plugin(new Flash());
System.out.println();
com.plugin(new Print());
System.out.println();
com.plugin(new MP3());
}
}
此时可以很好地描述出现实的关系

3.3接口的应用————工厂设计模式:
interface Fruit{
public void eat() ;
}
class Apple implements Fruit{
public void eat() {
System.out.println("*** 吃苹果");
}
}
class Orange implements Fruit{
public void eat() {
System.out.println("*** 吃橘子");
}
}
class Factory{
public static Fruit getInstance(String className) {
if(“apple”.equals(className)) {
return new Apple() ;
}else if(“orange”.equals(className)) {
return new Orange() ;
}else {
return null ;
}
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit f = Factory.getInstance(“apple”) ;
f.eat();
}
}
3.4接口的应用————代理设计模式:
interface Subject{
public void make();
}
class RealSub implements Subject{
public void make() {
System.out.println(“真实主题”);
}
}
class ProxySubject implements Subject{
private Subject sub ;
public ProxySubject(Subject sub) {
this.sub = sub ;
}
public void prepare() {
System.out.println(“为真实主题做准备”);
}
public void make() {
this.prepare();
this.sub.make();
this.destroy();
}
public void destroy() {
System.out.println(“收尾工作”);
}
}
public class TestProxy {
public static void main(String[] args) {
Subject sub = new ProxySubject(new RealSub()) ;
sub.make();
}
}

3.5、抽象类与接口的区别
抽象类和接口在使用形式上是非常相似的,所以很多人回去问两者的区别
NO 区别 抽象类 接口
1 关键字 abstract class interface
2 组成 构造方法,普通方法,static方法,常量,变量 全局常量。抽象方法
3 子类使用 class 子类 exteds 抽象类 class 子类 implements 接口,接口…
4 关系 抽象类可以实现多个接口 接口不能够继承抽象类,确可以继承多个父接口
5 权限 可以使用多种权限 只能够使用public
6 限制 单继承局限 没有单继承局限
7 子类 抽象类和接口的子类都要复写全部的抽象方法
8 实例化对象 依靠子类的向上转型进行对象的实例化
经过比较可以发现抽象类中支持的功能比接口更多,但是只有一点不好,那就是单继承局限,所以就是这一点就掩盖了抽象类的有点,即当抽象类和接口都可以使用的时候优先考虑接口
·在进行某些公共操作的时候一定要定义出接口;
·有了接口就需要子类完善方法
·如果是自己写的接口,不要使用关键字new直接实例化,使用工厂类完成
总结:
1、接口与抽象类的不同;
2、接口作为标准用于解耦合以及不同层直接的连接桥梁

第二十六章 Object类

3.1、Object类的基本作用
Object是所有类的父类。也就是说任何一个类在定义的时候如果没有明确的继承一个父类的话,那么他就是Object类的子类
class Book{} class Book extends Object{}
在整个java里面类的继承关系一直都存在(除了Object类之外)

既然Object类是所有类的父类,那么最大的好处就在于:利用Object可以接受全部类的对象,因为可以向上自动转型

范例:利用Object 类来接受对象
class Book extends Object{}
public class Demo {
public static void main(String[] args) {
Object obj1 = new Book();//向上转型
Object obj2 = “hello” ;//向上转型
Book b = (Book) obj1 ;
String s = (String) obj2 ;
}
}

既然这样在不确定参数类型的时候,使用Object类是最好的选择

问题:为什么在Object类里面要定义一个无参构造方法?
既然Object类是所有类的父类,那么所有类实例化对象的时候,子类构造方法执行前一定要默认执行父类的无参构造

3.2、取得对象信息toString()

从严格意义上来讲(一般不遵守),任何一个简单java类都应该覆写Object类的三个方法:
·取得对象信息:public String to String() ;
·对象比较:public boolean equals (Object obj) ;
·取得对象HASH码:public int hashCode();
例如:
class Book extends Object{}
public class Demo {
public static void main(String[] args) {
Book b = new Book();
String s = “Hello” ;
System.out.println(b);//输出object.Book@617c74e5
System.out.println(b.toString());//输出object.Book@617c74e5
System.out.println(s);//输出Hello
}
}
发现现在直接输出对象与调用toString()方法后输出的内容功能是完全一样的
在进行对象输出的时候,输出操作会自动调用对象中的toString()方法,将对象变为字符串后在输出,而默认情况下Object类中的toString()为了适应所有对象的输出,所以只输出了对象编码
如果现在有需要,也可以自己根据实际情况来复写此方法

3.3对象比较equals()
对象比较在很多开发之中都是一定要使用到的核心概念,而在之前使用了一个自定义方法compare(),但是这不标准,标准的做法是使用equals()方法来完成
范例:实现对象比较
class Book{
private String title;
private double price;
public Book() {

}
public Book(String title,double price) {
	this.title = title;
	this.price = price;
}
@Override
public String toString() {
	return "图书名称:" + this.title + ",价格:" + this.price;
}
public boolean equals(Object obj) {
	if(this == obj) {
		return true;
	}
	if(this == null) {
		return false;
	}
	if(!(obj instanceof Book)) {
		return false;
	}
	Book book = (Book)obj;
	if(this.title.equals(book.title)&& this.price == book.price) {
		return true;
	}
	return false;
}

}
对象的比较操作写出以上的代码应该就算是比较完整了
3.4、object类可以接受 一切引用数据类型

Object类是所有类的父类,所以Object类的对象可以接受所有类的对象,可是除了类的对象之外,Object类连数组、接口对象都可以接受
范例:接收数组数据
public class Demo {
public static void main(String[] args) {
Object obj = new int [] {1,5,4,3,7,8,9};//向上转型
System.out.println(obj);//[I@2d3fcdbd
if(obj instanceof int []) {
int data [] = (int []) obj ;
for(int x = 0;x < data.length;x ++) {
System.out.println(data[x]);
}
}
}
}
除了数组外,接口也同样可以。
范例:Object接收接口
interface A{
public void fun() ;
}
class B extends Object implements A{
public void fun() {
System.out.println(“hello world”);
}
}
public class Demo {
public static void main(String[] args) {
A a = new B();//接口对象
Object obj = a ;//接受接口对象
A t = (A) obj ;//向下转型
t.fun();
}
}
整个程序的参数就统一在了Object上了
3.5、修改链表
长期一直困扰我们的事情就是链表的问题,因为在讲解所有的知识之前,一直带有疑问:链表不能统一数据,所以就造成了每一次使用链表的时候都要进行重复的开发,但是有了Object之后,这一切就彻底解决了,因为Object任何类型都可以接受,同时在链表之中,由于需要对象比较的功能,这一功能Object也提供有equals()方法

范例:修改可用链表
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private Object data;
private Node next;
public Node(Object data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(Object data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public Object getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
public void setNode(int index, Object data) {
if(Link.this.foot ++ == index) {
this.data = data ;
}else {
this.next.setNode(index, data);
}

	}
	public void removeNode(Node previous,Object data) {
		if(data.equals(this.data)) {//当前节点为要删除的节点
			previous.next = this.next ;//空出当前节点
		}else {
			this.next.removeNode(this, data);
		}
	}
	public void toArrayNode() {
		Link.this.retArray[Link.this.foot ++] = this.data ;
		if(this.next != null) {
			this.next.toArrayNode();
		}
	}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot  ;
private Object[] retArray ; 
public void add(Object data) {
	if(data == null) {
		return ;
	}
	Node newNode = new Node(data);//要保存的数据
	if(this.root == null) {//当前根节点没有数据
		this.root = newNode ;//保存根节点
	}else {//根节点存在,其他节点交给Node类处理
		this.root.addNode(newNode);
	}
	this.count ++ ;
}
public int size() {//取得保存的数据量
	return this.count ;
}
public boolean isEmpty() {
	return this.count == 0 ;
}
public Object get(int index) {
	if(index > this.count ) {
		return null ;
	}
	this.foot = 0;
	return this.root.getNode(index);
}
public boolean contains(Object data) {
	if (data == null || this.root == null) {
		return false ;
	}
	return this.root.containsNode(data) ;
}
public void set(int index,Object data) {
	if(index > this.count) {
		return ; 
	}
	this.foot = 0 ;
	this.root.setNode(index,data);
}
public Object [] toArray() {
	if(this.root == null) {
		return null ;
	}
	this.foot = 0 ;
	this.retArray = new Object [this.count] ;
	this.root.toArrayNode();
	return this.retArray ;
}
public void remove(Object data) {
	if(this.contains(data)) {
		//要删除数据是否是根节点数据
		if(data.equals(this.root.data)) {//为要删除的节点
			this.root = this.root.next ;//空出当前接节点
		}else {
			this.root.next.removeNode(this.root, data);
		}
		this.count -- ;
	}
}

}
public class TestLink {

public static void main(String[] args) {
	Link all = new Link();
	all.add("hello");//String转为Object
	all.add("b");//String转为Object
	all.add("c");//String转为Object
	all.remove("c");//String覆写了equals()方法
	Object data [] = all.toArray();
	for(int x = 0 ;x <data.length ;x ++) {
		String str = (String) data[x] ;//Object变为String
		System.out.println(str);
	}
}

}
从现在开始链表的程序代码就固定了,以后就不需要修改了,以后只要会使用就可以了
总结:
1、Object类对象可以接受一切的数据类型(引用数据类型),包括接口和数组,解决了数据统一问题
2、toString()在对象输出时调用、equals()在对象比较时调用

取得对象哈希码:public int hashCode() ;

3.4、宠物商店
范例:定义一个宠物的标准
interface Pet{
public String getName();//得到宠物的名字
public int getAge();//得到宠物的年龄
}
宠物商店与具体的宠物没有任何的关系,它只宠物这个接口有关
范例:实现宠物商店
class Link{//链表类,外部只能够看见这一个类
//之所以定义在内部,主要是让其为Link类服务
private class Node{//定义一个节点类
private Object data;
private Node next;
public Node(Object data) {
this.data = data;
}
public void addNode(Node newNode) {
if(this.next == null) {//当前节点为空
this.next = newNode ;
}else {//向后继续保存
this.next.addNode(newNode);
}
}
public boolean containsNode(Object data) {
if(data.equals(this.data)) {
return true;
} else {
if(this.next != null) {
return this.next.containsNode(data);
} else {
return false ;
}
}
}
public Object getNode(int index) {
if(Link.this.foot ++ == index) {
return this.data ;
}else {
return this.next.getNode(index);
}
}
public void setNode(int index, Object data) {
if(Link.this.foot ++ == index) {
this.data = data ;
}else {
this.next.setNode(index, data);
}

	}
	public void removeNode(Node previous,Object data) {
		if(data.equals(this.data)) {//当前节点为要删除的节点
			previous.next = this.next ;//空出当前节点
		}else {
			this.next.removeNode(this, data);
		}
	}
	public void toArrayNode() {
		Link.this.retArray[Link.this.foot ++] = this.data ;
		if(this.next != null) {
			this.next.toArrayNode();
		}
	}
}
//上面为内部类=========================================
private Node root;//需要根节点
private int count = 0 ;//保存元素个数
private int foot  ;
private Object[] retArray ; 
public void add(Object data) {
	if(data == null) {
		return ;
	}
	Node newNode = new Node(data);//要保存的数据
	if(this.root == null) {//当前根节点没有数据
		this.root = newNode ;//保存根节点
	}else {//根节点存在,其他节点交给Node类处理
		this.root.addNode(newNode);
	}
	this.count ++ ;
}
public int size() {//取得保存的数据量
	return this.count ;
}
public boolean isEmpty() {
	return this.count == 0 ;
}
public Object get(int index) {
	if(index > this.count ) {
		return null ;
	}
	this.foot = 0;
	return this.root.getNode(index);
}
public boolean contains(Object data) {
	if (data == null || this.root == null) {
		return false ;
	}
	return this.root.containsNode(data) ;
}
public void set(int index,Object data) {
	if(index > this.count) {
		return ; 
	}
	this.foot = 0 ;
	this.root.setNode(index,data);
}
public Object [] toArray() {
	if(this.root == null) {
		return null ;
	}
	this.foot = 0 ;
	this.retArray = new Object [this.count] ;
	this.root.toArrayNode();
	return this.retArray ;
}
public void remove(Object data) {
	if(this.contains(data)) {
		//要删除数据是否是根节点数据
		if(data.equals(this.root.data)) {//为要删除的节点
			this.root = this.root.next ;//空出当前接节点
		}else {
			this.root.next.removeNode(this.root, data);
		}
		this.count -- ;
	}
}

}
interface Pet{
public String getName();//得到宠物的名字
public int getAge();//得到宠物的年龄
}
class PetShop{
private Link pets = new Link() ;
public void add(Pet pet) {
this.pets.add(pet);
}
public void delete(Pet pet) {
this.pets.remove(pet);
}
public Link search(String keyWord) {
Link result = new Link() ;
Object obj[] = this.pets.toArray();
for (int x = 0 ; x < obj.length ;x ++) {
Pet p = (Pet) obj[x];
if(p.getName().contains(keyWord)){
result.add§;
}
}
return result ;
}
}
class Cat implements Pet{
private String name ;
private int age ;
public Cat(String name,int age) {
this.name = name ;
this.age = age ;
}
public boolean equals(Object obj) {
if(this == obj) {
return true ;
}
if(obj == null) {
return false ;
}
if(!(obj instanceof Cat)) {
return false ;
}
Cat c = (Cat) obj;
if(this.name.equals(c.name) && this.age == c.age) {
return true ;
}
return false ;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age ;
}
public String toString() {
return “猫的名字 :” + this.name + “,年龄 :” + this.age ;
}
}
class Dog implements Pet{
private String name ;
private int age ;
public Dog(String name,int age) {
this.name = name ;
this.age = age ;
}
public boolean equals(Object obj) {
if(this == obj) {
return true ;
}
if(obj == null) {
return false ;
}
if(!(obj instanceof Dog)) {
return false ;
}
Dog c = (Dog) obj;
if(this.name.equals(c.name) && this.age == c.age) {
return true ;
}
return false ;
}
public String getName() {
return this.name ;
}
public int getAge() {
return this.age ;
}
public String toString() {
return “狗的名字 :” + this.name + “,年龄 :” + this.age ;
}
}
public class TestCW {
public static void main(String[] args) {
PetShop shop = new PetShop();
shop.add(new Cat(“加菲猫”,5));
shop.add(new Cat(“黑猫”,10));
shop.add(new Dog(“拉布拉多”,5));
shop.add(new Dog(“黄狗”,5));
Link all = shop.search(“猫”);
Object obj [] = all.toArray();
for(int x = 0 ;x < obj.length ;x ++) {
System.out.println(obj[x]);
}
}
}

第二十七章 扩展概念
匿名内部类
interface Mesg{
public void print();
}
public class Ga {
public static void main(String[] args) {
fun(new Mesg() {
public void print() {
System.out.println(“hello”);
}
});
}
public static void fun(Mesg msg) {
msg.print();
}
}
使用匿名内部类有一个前提:必须基于接口或抽象类的应用

3.1认识包装类
java在设计之初有一个基本原则:一切皆对象,一切的操作的形式进行描述。但是这里就会出现一个矛盾,基本数据类型不是对象。

在java里面为了方便用户的使用,所以转门提供了一组包装类,来包装所有的基本类型:
byte(Byte)、short(Short)、int(Integer)、long(Long)、float(Float)、double(Double)、char(Characte)、boolean(Boolean)
以上给出的包装类又分为两种类型:
对象包装类:Characte、Boolean
数值包装类:(Number直接子类):Byte、Short、Integer、Long、Float、Double
Number是一个抽象类,里面定义了六种操作方法:intValue()、doubleValue()、floatValue()、byteValue()、shortValue()、longValue()

3.2装箱与拆箱操作
1、装箱操作:将基本数据类型变为包装类的形式
每个包装类的构造方法都可以接受各自数据类型的变量
2、拆箱操作:从包装类中取出被包装的数据
利用Number类中提供的一系列的:xxxValue()方法完成

数据类型转换
范例:自动装箱和拆箱
public class YYCD {
public static void main(String[] args) {
Integer in = 10 ;
int temp = in ;
in ++ ;
System.out.println(temp * in);
}
}
3.3、数据类型转换
包装类的最多的情况下实际上是它的数据类型转换上,在包装类里面提供有将String型数据类型变为基本数据类型的方法:
Integer类:public static int parseInt(String s)
Double类:public static double parseDouble (String s)
Boolean类:public static boolean parseBoolean (String s)
范例:将字符串变为基本数据类型
String str = “123”;
int m = Integer.parseInt(str);
System.out.println(m);
此时实现了字符串变为基本数据类型的操作,但是在这样的转换过程中请一定要注意被转换的字符串一定要有数字组成
String sta=“10.2”;
double b = Double.parseDouble(sta);
System.out.println(b);

String bo =“true”;
boolean va = Boolean.parseBoolean(bo);
System.out.println(va);
在boolean进行转化的过程中,如果字符串不是true或者false,那么将统一按照false处理
基本数据类型变为字符串:public static String valueOf(数据类型 变量)
int num = 100;
String st = String.valueOf(num);
System.out.println(st);

Integer im = 10;//自动装箱
int i = im;//自动拆箱
System.out.println(i);
在使用包装类的时候,很少利用构造方法完成,几乎都是利用直接赋值的方式完成,但是在判断内容是否相等的时候要用equals()方法

Object此时可以统一天下了
Object可以接受一切的引用数据类型,由于存在有自动装箱与拆箱的机制,那么Object可以存放基本数据类型了
流程:基本数据类型—>自定装箱(称为对象)—>向上转型称为Object
例如:
Object obj = 10;
int tt = (Integer)obj;
System.out.println(tt);

总结:
字符串与基本数据类型转换:
字符串变为基本数据类型,包装类的parseXxx()方法
基本数据类型变为字符串依靠:ValueOf(数据类型 变量)

第二十八章 包的定义及使用
如果在定义包的时候出现了“.”,那么久表示子目录,如果类中有包的定义了,那么久使用命令去生成包,不要去使用手工创建
·打包编译:javac -d .Hello.java;
-| “-d”:生成目录,根据package的定义生成;
-|“.”设置保存的路径,如果为“.”表示在当前所在路径下生成
·在解释程序的时候不要进入到包的里面解释程序,应该在包的外面输入类的完整路径
|-输入:java cn.mldn.demo.Hello
以后所有的类都应该定义在包之中,那么完整的类名称就是“包.类”

3.2、包的导入
包的导入使用import语句导入:
·import cn.mldn.util.Message;
关于public class 和class 的声明区别?
·public class:文件名称必须与类名称保持一致,在一个*.java文件里面只能够有一个类需要被不同的包所访问,那么久一定要定义为public class
·class:文件名称可以与类名称不一致,并且一个*.java里面可以有多个class定义,编译后会形成多个*.class文件,如果一个类使用的是class定义,那么表示这个类只能够被本包所访问

第二十九章 访问控制权限
在java里面支持四种访问控制权限。public、protected、default、private
no 范围 public protected default private
1 在同一个类中 可以访问 可以访问 可以访问 可以访问
2 在同一包中的不同类 可以访问 可以访问 可以访问
3 在不同包的子类里面 可以访问 可以访问
4 在不同包的非子类里面 可以访问
除了public之外,对于封装可以使用private、protected、default只不过一般不会去考虑使用default
范例:使用protected定义
package cn.protect;
public class Test {
protected String info = “hello” ;
}

package cn.demo;
import cn.protect.Test;
public class Demo extends Test {
public void print() {
System.out.println(super.info);
}
}

package cn.demo;
public class TestDemo {
public static void main(String[] args) {
new Demo().print();
}
}
总结:
1、java的封装性private、protected、default三种权限为主
2、对于权限的选择,给出以下的建议
·声明属性就使用private
·声明方法就使用public

关于命名要求:
·类名称每一个单词的首字母大写,其余小写,例如:UserName
·属性名称第一个单词字母小写,其余首字母大写,例如:userName
·方法名称第一个单词字母小写,其余首字母大写,例如:userName()
·常量名称全部大写,例如:STUDENT
·包名称使用小写字母,例如:cn.mldn.demo

3.2、构造方法私有化
范例:
class Singleton{
private Singleton() { }
public void print() {
System.out.println(“hello world”);
}
}
分析步骤:
1、构造方法使用private声明(private Singleton() { }),那么接表示这个构造方法只能够被类的内部所使用,既然如此可以在类的内部实例化一个对象;
class Singleton{
Singleton instance = new Singleton() ;
private Singleton() {
}
public void print() {
System.out.println(“hello world”);
}
}
2、现在的instance在Singleton类里面只是一个普通的类属性。而所有的普通的类属性必须在类产生实例化对象对象之后才可以使用,是否存在一种方式,可以让这个类的属性不受Singleton类实例化对象的控制
如果使用了static声明instance属性,那么久表示可以在一个类没有产生实例化对象的时候直接使用该属性
class Singleton{
static Singleton instance = new Singleton() ;
private Singleton() {
}
public void print() {
System.out.println(“hello world”);
}
}
public class TestDemo {
public static void main(String[] args) {
Singleton s = null ;
s = Singleton.instance ;
s.print();
}
}
3、在一个类定义的时候首先想到的就是类中的属性需要进行封装,
private static Singleton instance = new Singleton() ;
3、一旦封装之后如果想要访问此属性,只能够通过getter()方法,那么现在就需要提供有一个getter()方法,可以不受类实例化对象的控制,
继续使用static属性
class Singleton{
private static final Singleton INSTANCE = new Singleton() ;
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE ;
} public void print() {
System.out.println(“hello world”);
}
}
public class TestDemo {
public static void main(String[] args) {
Singleton s = null ;
s = Singleton.getInstance() ;
s.print();
}
}
程序的特点:构造方法私有化,在类的内部定义static属性与方法,利用static方法取得本类的实例化对象,这样不管外部产生多少个Singleton类的对象,但是本质上永远只有唯一的一个实例化对象

代码意义:
如果说现在要想控制一个类中实例化对象的产生个数,那么首先要锁定的就是类中的构造方法,因为在实例化任何新对象,都要使用构造方法,如果构造方法被锁了,那么自然就无法产生新的实例化对象了
可是既然需要是一个实例化对象,那么就可以在类的内部使用static方式来定义一个公共的对象,并且每一次通过static方法返回唯一的一个对象,这样外部不管有多少次调用,那么最终一个类只能够产生唯一的一个对象,这样的设计就属于单例设计模式(Singleton)
作用:让一个类在一个系统里面只允许有一个实例化对象

3.2多例设计模式

既然存在单例设计模式,那么就一定存在多例设计模式,单例设计模式是让一个类只能产生一个实例化对象,多例设计模式可以让一个类产生指定多个实例化对象
范例:定义一个表示性别的类
class Sex{
private String title ;
private static final Sex MANE = new Sex(“男”) ;
private static final Sex FEMANE = new Sex(“女”) ;
private Sex(String title) {//构造私有化
this.title = title ;
}
public String toString () {
return this.title ;
}
public static Sex getInstance(String ch) {
switch(ch) {
case “man”:
return MANE;
case “woman”:
return FEMANE;
default:
return null;
}
}
}
public class TestSex {
public static void main(String[] args) {
Sex sex = Sex.getInstance(“man”);
System.out.println(sex);
}
}
在JDK1.7之前,Switch只能够利用int或char进行判断,但是正因为如果纯粹是数字或字符意义不明确,所以增加了String的支持
单例设计模式和多例设计模式的核心的构造方法私有化

第三十章 异常的捕获及处理

异常是java的一个重大特色,合理的使用异常处理,可以让我们的程序更加的健壮

3.1、异常的产生

异常是一种导致程序中断执行的指令流,异常一旦出现并且没有进行合理处理的话,那么程序就会中断执行
一旦产生异常之后,发现产生异常的语句以及之后的语句将不在执行,默认情况下,是进行异常信息的输出,而后自动结束程序的执行
要处理的是:及时出现了异常,那么也应该让程序执行完毕

3.2、处理异常
如果要想进行异常的处理,在java之中提供了三个关键字,try、catch、finally,而这三个关键字的使用语法如下
try {
//有可能出现异常的语句
}[catch(异常类型 对象) {
//异常的处理;
}[catch(异常类型 对象) {
//异常的处理;
}[catch(异常类型 对象) {
//异常的处理;
}…] [finally {
不管是否出现异常,都统一执行的代码 ;
}]
对于以上的组合:try…catch、try…catch…finally、try…finally

范例:异常应用处理
public class Test {
public static void main(String[] args) {
System.out.println(“hello”);
try {
System.out.println(“除法计算开始:” + (10/0));
System.out.println(“");
}catch(ArithmeticException e) {
System.out.println(“出现异常了”);
}
}
}
由于使用了异常处理,这样即使程序中出现了异常,发现也可以正常的执行完毕
出现异常的目的是为了解决异常,所以为了能够进行异常的处理,可以使用异常类中提供的printStackTrace()方法进行异常信息完整的输出
public class Test {
public static void main(String[] args) {
System.out.println(“hello”);
try {
System.out.println(“除法计算开始:” + (10/0));
System.out.println("
”);
}catch(ArithmeticException e) {
e.printStackTrace();
}
System.out.println("---------");
}
}
java.lang.ArithmeticException: / by zero
at Firstjava/cn.zz.tr.Test.main(Test.java:6)
此时发现打印的异常信息是很完整的

public class Test {
public static void main(String[] args) {
System.out.println(“hello”);
try {
System.out.println(“除法计算开始:” + (10/0));
System.out.println("***********");
}catch(ArithmeticException e) {
e.printStackTrace();
}finally {
System.out.println(“不管是否出现异常我都执行”);
}
System.out.println("---------");
}
}
在异常捕获的时候发现一个try语句后面可以跟着多个catch语句

3.3、异常的处理流程(核心)
算数异常
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.ArithmeticException

数字类型转换异常
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.IllegalArgumentException
java.lang.NumberFormatException
经过异常类的观察可以发现所有的异常类都是Throwable的子类,而在Throwable下面有两个子类
请解释Error和Exception的区别
Error:指的是JVM错误 即此时的程序还没有执行,如果没有执行用户无法处理
Exception:指的是程序运行中的产生的异常,用户可以处理
也就是所谓的异常处理指的就是Exception以及它的子类异常
1、当程序在运行的过程之中出现了异常后,那么会有JVM自动根据异常的类型产生实例化与之类型匹配的异常对象
2、产生异常之后会判断当前的语句是否存在有异常的处理,如果没有没有异常处理,那么就交给JVM进行默认的异常处理,处理的方式:输出异常信息,而后结束程序的调用
3、如果此时存在有异常的捕获操作,那么会由try语句来捕获产生的异常类实例化对象,而后与try语句后的每一个catch进行比较,如果有符合的捕获类型,则使用当前的catch的语句来进行异常的处理,如果不匹配,则向下继续匹配其他的catch语句
4、不管最后的异常处理是否能够匹配,那么都要向后执行,如果此时程序中存在有finally语句,那么就先执行finally后面的代码,但是执行完毕之后需要根据之前的catch匹配的结果来决定如何执行,如果之前已经成功的捕获了异常,那么就继续执行finally之后的代码,如果之前没有成功的捕获异常,那么即将此异常交给JVM进行默认处理,输出异常信息,而后结束程序的调用
5、整个过程就像方法的重载一样。根据catch后面的参数类型进行匹配,但是所有java对象都存在自动向上转型的操作支持,也就是说如果真要匹配类型,简单的做法是匹配Exception就够了
范例:使用Exception处理异常
public class Test {
public static void main(String[] args) {
System.out.println(“hello”);
try {
int x = Integer.parseInt(args[0]);
int y = Integer.parseInt(args[1]);
System.out.println(“除法计算开始:” + (x/y));
System.out.println("***********");
}catch(Exception e) {
e.printStackTrace();
}finally {
System.out.println(“不管是否出现异常我都执行”);
}
System.out.println("---------");
}
}
此时所有的异常都是用了Exception进行处理,所以程序之中不用去关心到底使用哪一个异常。
两点说明:
·在编写多个catch捕获异常的时候,捕获范围大的异常一定要放在捕获范围小的之后,否则程序编译错误
·虽然直接捕获Exception比较方便,但是这样也不好,因为所有的异常都会按照同样的一种方式进行处理;在一些要求严格的项目里,异常分开处理会更好。

3.4、 throws关键字

throws关键字主要用在方法声明上,指的是当方法之中 出现异常后交由被调用处来处理
范例:使用throws
class MyMath{
public static int div(int x ,int y)throws Exception {
return x/y ;
}
}
public class TestDemo {
public static void main(String[] args) {
try{
System.out.println(MyMath.div(10, 2));
}catch (Exception e) {
e.printStackTrace();
}
}
调用了throws声明的方法之后,那么不管操作是否出现异常,都必须使用try…catch来进行异常的 处理
class MyMath{
public static int div(int x ,int y)throws Exception {
return x/y ;
}
}
public class TestDemo {
public static void main(String[] args)throws Exception {
System.out.println(MyMath.div(10, 2));
}
}
在主方法上使用throws Exception抛出异常,那么这个异常就将交个JVM进行处理,也就是采用默认的异常处理方式,输出异常信息,而后结束方法调用
在主方法上不要加上throws,因为程序如果出错了,也希望可以正常的结束方法的调用

3.5 throw关键字

在程序之中可以直接使用throw手工的抛出一个异常类的实例化对象
范例:自己定义一个异常
public class TestDemo {
public static void main(String[] args){
try {
throw new Exception(“自己定义的异常”);
}catch(Exception e) {
e.printStackTrace();
}
}
}
请解释throw和throws的区别?
·throw:指的是在方法之中人为的抛出一个异常类对象(这个异常类对象有可能是存在的,也有可能是自己定义的)
·throws:在方法的声明上使用,表示此方法在调用时有可能出现异常,如果出现就处理,不出现接执行代码

3.6、重要的代码模型:异常的使用格式

class MyMath{
int result = 0 ;
public static int div(int x ,int y)throws Exception {
System.out.println(“计算开始:”);
try{
return x/y ;
}catch(Exception e) {
throw e ;
}finally {
System.out.println(“计算结束”);
}
}
}
public class TestDemo {
public static void main(String[] args){
try {
System.out.println(MyMath.div(10,2));
}catch(Exception e) {
e.printStackTrace();
}
}
}
3.7、RuntimeException类

这类异常可以不用强制处理

3.8、assert关键字

assert关键字是在JDK1.4的时候引入的,其主要功能是进行断言。
在java中的断言指的是程序执行到某行代码处时一定是预期的结果
public class TestAssert {
public static void main(String[] args) {
int num = 10 ;
assert num == 20: “num的内容不是20” ;
System.out.println("num = " + num);
}
}
默认情况下断言是不应该影响程序的运行的,也就是说在java解释程序的时候断言是不起作用的

总结:
1、Exception最大的父类是Throwable,但是在编写代码的时候尽量不要使用Throwable,因为Throwable下面还包含一个Error子类,我们能够处理的只有Exception子类:
2、异常处理的的标准格式try、catch、finally、throw、throws
3、清楚Exception 和RuntimeException的区别

第三十二章 Eclipse的使用
快捷键
1、ALT + /:进行代码提示
2、CTRL + 1 :为错误的代码给出纠正方案
3、CTRL + SHIFT + O:组织导入,导入其他包的类
4、CTRL + D:删除当前行代码
5、CTRL + /:使用单行注释
6、CTRL + H :强力搜索
7、CTRL + ALT + 向下的箭头

第三十三章 java 5新特性
可变参数
例如:
public static int add(int … tem) {
int sum =0;
for(int x = 0;x < tem.length;x ++) {
sum +=tem[x];
}
return sum;
}
System.out.println(add(10,2,2,6,54,87,7));

增强型for循环
语法如下:
for(类型 变量 :数组 |集合){
//次循环会自动的将数组的内容设置给变量
}
int[] data = new int[] {1,2,3,4,5,6,7,8,9};
for(int y:data) {
System.out.println(y);
}

总结:
foreach循环支持数组的直接访问,避免了索引访问带来的麻烦

第三十四章 泛型
3.1、泛型的引出
范例:
class Point{
private T x ;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class Test {

public static void main(String[] args) {
	Point<String> p = new Point<String>();
	p.setX("东经32度");
	p.setY("北纬56度");
	String x =  p.getX();
	String y =  p.getY();
	System.out.println("x坐标 :" + x + ",y坐标 :" + y);
	
	Point<Integer> p1 = new Point<Integer>();
	p1.setX(10);
	p1.setY(20);
	Integer x1 =  p1.getX();
	Integer y1 =  p1.getY() ;
	System.out.println("x坐标 :" + x1 + ",y坐标 :" + y1);
	
	Point<Double> p2 = new Point<Double> ();
	p2.setX(5.3);
	p2.setY(6.7);
	Double x2 =  p2.getX();
	Double y2 =  p2.getY() ;
	System.out.println("x坐标 :" + x2 + ",y坐标 :" + y2);		
}

}
发现使用了泛型之后,所有类中的属性都是动态设置的,而所有使用泛型标记的方法参数类型也都发生改变,这样就相当于避免了向下转型的问题,从而解决了类对象转换的安全隐患
但是需要说明的是,如果要想使用泛型,那么它能够采用的类型只能够是类,即:不能够是基本类型,只能够是引用类型
对于泛型的两点说明:
·如果在使用泛型类或者接口的时候,没有设置泛型的具体类型,那么会出现编译时的警告,同时为了保证程序不出错,所有泛型都将使用Object表示

3.2、通配符

所以现在最应该解决的是,需要有一种方式可以接受一个类的任意泛型类型,但是不能够修改,只能够取出,那么就可以使用?来描述
范例:
class Message{
private T msg ;

public T getMsg() {
	return msg;
}

public void setMsg(T msg) {
	this.msg = msg;
}

}
public class TestMessage {
public static void main(String[] args) {
Message m1 = new Message();
m1.setMsg(10);
fun(m1);
}
public static void fun(Message<?> temp) {
System.out.println(temp.getMsg());
}
}
在“?”通配符基础上还会有两个子的通配符:
·?extends 类:设置泛型上线,可以在声明上和方法参数上使用;
|-?extends Number:意味着可以设置Number或者Number的子类(Integer、Double)
·?super类:设置泛型下线,方法参数上使用;
|-?super String:意味着只能够设置String或者是它的父类Object

范例:设置泛型上线
class Message{
private T msg ;

public T getMsg() {
	return msg;
}

public void setMsg(T msg) {
	this.msg = msg;
}

}
public class TestMessage {
public static void main(String[] args) {
Message m1 = new Message();
m1.setMsg(10);
fun(m1);
}
public static void fun(Message<? extends Number> temp) {
System.out.println(temp.getMsg());
}
}
如果现在设置了非Number或者是其子类的话,那么将会出现语法错误。

范例:设置泛型的下线
class Message{
private T msg ;

public T getMsg() {
	return msg;
}

public void setMsg(T msg) {
	this.msg = msg;
}

}
public class TestMessage {
public static void main(String[] args) {
Message m1 = new Message();
m1.setMsg(“hello”);
fun(m1);
}
public static void fun(Message<? super String> temp) {
System.out.println(temp.getMsg());
}
}

3.3、泛型接口

范例:定义一个泛型接口
//如果是接口命名在前面加上I
//如果是抽象类,在前面加上abstract
interface IMessage{
public void print(T t);
}
在接口上必须要定义其响应的子类,所以如果要定义子类有两种形式
形式一:在子类继续设置泛型
interface IMessage{
public void print(T t);
}
class MessageImpl implements IMessage{
@Override
public void print(T t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage msg = new MessageImpl();
msg.print(“hello world”);
}
}

形式二:在子类不设置泛型,而为父接口明确的定义一个泛型
interface IMessage{
public void print(T t);
}
class MessageImp implements IMessage{
@Override
public void print(String t) {
System.out.println(t);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage msg = new MessageImpl();
msg.print(“hello world”);
}
}

3.4、泛型方法

范例:泛型方法定义
public class Demo {
public static void main(String[] args) {
String str = fun(“hello” );
System.out.println(str.length());
}
public static T fun(T t) {
return t ;
}
}
总结:
1、泛型解决的是向下转型所带来的安全隐患,其核心的组成就是在声明类或者接口的时候不设置参数或属性的类型
2、“?”可以接收任意的泛型类型,只能够取出,但是不能够修改

第三十五章 枚举
范例:定义枚举
enum Color{//定义枚举
RED,GREEN,BLUE;//此处为实例化对象
}
public class Test {
public static void main(String[] args) {
Color red = Color.RED ;
System.out.println(red);
}
}
可以发现使用枚举之后可以完全替代多例设计模式
但是需要说明的是,严格来讲枚举不是一个新的功能,在java里面虽然使用enum关键字定义了枚举,但是使用enum定义的枚举就相当于是一个类继承了Enum类而已
public abstract class Enum<E extends Enum>
extends Object
implements Comparable, Serializable
Enum是一个抽象类,里面定义的构造如下:
protected Enum(String name, int ordinal)
Enum类的构造方法依然是被封装的,所以也属于构造方法私有化的范畴,所有的多例设计模式构造方法私有化
在Enum类里面定义了两个方法:
·取得枚举的索引:public final int ordinal();
·取得枚举的名字:public final String name();
除了以上的两个方法之外,使用enum关键字定义的枚举类里面还有一个values()方法,这个方法将枚举对象以对象数组的形式全部返回
enum Color{//定义枚举
RED,GREEN,BLUE;//此处为实例化对象
}
public class Test {
public static void main(String[] args) {
for(Color c:Color.values()) {
System.out.println(c.ordinal() + “-” + c.name());
}
}
}
3.2、定义其它结构

虽然发现枚举的定义比较简单,可是对于之前讲解的多例设计模式里面发现还可以在类中定义属性和方法等,实际上枚举也可以,可是有一点要求:
·枚举之中定义的构造方法不能够使用public声明,如果没有无参构造请手工调用构造传递参数;
·枚举对象必须放在首行,随后才可以定义属性、构造、普通方法
范例:扩充枚举功能
enum Color{//定义枚举
RED(“红色”),GREEN(“绿色”),BLUE(“蓝色”);//此处为实例化对象
private String title ;
private Color(String title) {
this.title = title ;
}
public String toString() {
return this.title ;
}
}
public class Test {
public static void main(String[] args) {
for(Color c:Color.values()) {
System.out.println©;
}
}
}
此时与之前定义的多例设计模式操作就完全相同了,而且代码更加简单,枚举还可以实现接口
范例:枚举实现接口
interface Message{
public String getTitle();
}
enum Color implements Message{//定义枚举
RED(“红色”),GREEN(“绿色”),BLUE(“蓝色”);//此处为实例化对象
private String title ;
private Color(String title) {
this.title = title ;
}
public String toString() {
return this.title ;
}
@Override
public String getTitle() {
return this.title;
}

}
public class Test {
public static void main(String[] args) {
Message msg = Color.RED ;
System.out.println(msg.getTitle());
}
}
第三十六章 Annotation
Annotation是JKD1.5最大的特色,利用注解的形式来实现程序的不同功能实现
在java SE里面支持自定义Annotation的开发,并且提供了三个最为常用的基础Annotation:@Override、@Deprecated、@SuppressWarnings

3.1、@Override

准确的覆写父类的方法
@Override
public String getTitle() {
return this.title;
}

3.2、声明过期操作:@Deprecated

范例:声明过期操作
class Book{
@Deprecated
public void fun() {
}
}
public class Demo {
public static void main(String[] args) {
Book book = new Book();
book.fun();
}
}
3.3、压制警告:@SuppressWarnings

可以压制多个警告

第三十七章 java8新特性
接口定义的增强
在接口里面可以使用default定义普通方法
也可以使用static定义方法直接有接口名称调用
范例:
interface IDemo{
public void print();
default void fun() {
System.out.println(“毁三观的方法”);
}
static void get() {
System.out.println(“直接有接口调用”);
}
}
class MessageImpl implements IDemo{
@Override
public void print() {
System.out.println(“hello world”);
}
}
public class Demo {
public static void main(String[] args) {
IDemo id = new MessageImpl();
id.fun();
IDemo.get();
}
}

Lamda表达式

前提条件匿名内部类
例如:
interface IMessage{
public void print();
}
public class TE {

public static void main(String[] args) {
	
	fun(()->System.out.println("hello world !"));
}
public static void fun(IMessage msg) {
	msg.print();
}

}
对于Lamda表达式的语法有三种形式:
(参数)->单行语句:
(参数)->{单行语句};
(参数)->表达式。

方法的引用
范例:函数式接口
@FunctionalInterface
interface IMessage{
public R upper();
}
public class Demo {
public static void main(String[] args) {
IMessage msg = “hello” :: toUpperCase ;
String str = msg.upper() ;
System.out.println(str);
}
}
函数式接口中只能定义一个方法

方法引用
所谓的方法引用就是指为一个方法设置别名,相当于一个方法定义了不同的名字
在java8之中一共定义了四种形式:
引用静态方法:类名称::static方法名称
引用某个对象的方法:实例化对象::普通方法
引用特定类型的方法:特定类::方法(普通方法)
引用构造方法:类名称::new
范例:实现静态方法的引用
/**
*
*
*实现方法的引用接口

  • @param

    引用方法参数类型

  • @param 引用方法返回类型
    */
    interface Message<P,R>{
    public R zhuanhuan(P p) ;

}
public class Test {
public static void main(String[] args) {
//将String.valueOf()方法变为了IMessage接口里面的zhuanhuan方法
Message<Integer,String> msg = String::valueOf;
String str = msg.zhuanhuan(1000);
System.out.println(str.replaceAll(“0”, “9”));
}
}

函数式接口
1、功能性接口(Function):Interface Function<T,R>{public R apply(T t);}
此接口需要接受一个参数,并且返回一个处理结果
2、消费型接口(Consumer):Interface Consumer{public void accept(T t);}
此接口只是负责接受数据(引用数据是不需要返回),并且不返回处理结果
3、供给型接口(Supplier):Interface Supplier{public T get();}
此接口不接收参数,但是可以返回结果
4、断言型接口(Predicate):Interface Predicate{public boolean test(T t);}
进行判断操作使用

第三十八 java多线程的实现
3.1、线程与进程

java是一门为数不多的支持多线程编程语言
如果要想解释多线程之前,首先要来知道什么叫进程?在操作系统的定义中,进程指的是一次程序的完整运行,在这个运行过程之中内存、处理器、IO等资源操作都要为这个进程服务
线程是在进程基础上进一步划分的结果,即一个进程上可以同时创建多个线程
线程是比进程更快的处理单元,而且占用资源也小。那么多线程的应用就是性能最高的应用
总结:线程离不开进程。进程如果消失后线程一定会消失,反之线程消失了,进程未必消失了

3.2、多线程的实现
如果想要在java之中实现多线程有两种途径:
·继承Thread类:
·实现Runnable接口(Callable接口);

3.2.1、继承Thread类:
Thread类是一个支持多线程的功能类,只要有一个子类就可以实现多线程支持
所有程序的起点是main()方法,但是多有的进程也一定要有一个自己的起点,那么这个起点就是run()方法,也就是所在多线程的每个主体类之中都必须覆写Thread类之中提供的run()方法
public void run();
这个方法没有返回值,那么也就表示线程一旦开始就要一直执行,不能够返回内容
范例:多线程执行
class TestThread extends Thread{
private String name ;
public TestThread(String name) {
this.name = name ;
}
@Override
public void run() {
for(int x = 0 ;x < 200 ;x ++) {
System.out.println(this.name + “–>” + x);
}
}
}
public class MyThread {
public static void main(String[] args) {
TestThread m1 = new TestThread(“线程A”);
TestThread m2 = new TestThread(“线程B”);
TestThread m3 = new TestThread(“线程C”);
m1.run();
m2.run();
m3.run();
}
}

启动多线程
public void start():调用此方法执行的方法体是run()定义的
class TestThread extends Thread{
private String name ;
public TestThread(String name) {
this.name = name ;
}
@Override
public void run() {
for(int x = 0 ;x < 200 ;x ++) {
System.out.println(this.name + “–>” + x);
}
}
}
public class MyThread {
public static void main(String[] args) {
TestThread m1 = new TestThread(“线程A”);
TestThread m2 = new TestThread(“线程B”);
TestThread m3 = new TestThread(“线程C”);
m1.start();
m2.start();
m3.start();
}
}
此时每一个线程对象交替执行
疑问?为什么启动多线程不是调用run()而是start()
使用ThreadL类的start()方法不仅仅要启动多线程执行代码,还要去根据不同的操作系统进行资源分配

3.2.2实现Runnable接口

虽然Thread类可以实现多线程主体定义,但是他有一个问题,java具有单继承局限,正因为如此在任何情况下,针对于类的继承都应该是回避的问题,在java里面专门提供了Runnable接口
定义:
@FunctionalInterface
public interface Runnable{
public void run();
}
不管何种情况下,如果要想启动多线程一定依靠Thread类完成
public Thread(Runnable target):接受Runnable接口对象
以后用Runnable实现线程主体类,用Thread启动多线程
范例:启动多线程
class TestThread implements Runnable{
private String name ;
public TestThread(String name) {
this.name = name ;
}
@Override
public void run() {
for(int x = 0 ;x < 200 ;x ++) {
System.out.println(this.name + “–>” + x);
}
}
}
public class MyThread {
public static void main(String[] args) {
TestThread m1 = new TestThread(“线程A”);
TestThread m2 = new TestThread(“线程B”);
TestThread m3 = new TestThread(“线程C”);
new Thread(m1).start();
new Thread(m2).start();
new Thread(m3).start();
}
}
3.3、多线程两种实现方式
请解释Runnable接口和Thread类实现多线程的区别?
首先一定要明确的是,使用Runnable接口与使用Thread类相比,解决了单继承局限,所以不管后面的区别与联系是什么,至少这一点上就已经下了死定义–如果要使用一定使用Runnable
public class Thread extends Object implements Runnable{}
Thread类是Runnable接口的子类,使用Runnable接口实现多线程可以避免单继承局限
Runnable接口实现多线程可以比Thread类实现多线程更加清楚的描述数据共享的概念
3.4、第三种实现方式
使用Runnable接口实现多线程可以避免单继承局限,的确很好,但是有一个问题,Runnable接口里面的run()方法,不能返回操作结果,为了解决这样的矛盾,提供了一个新的接口Callable接口
@FunctionalInterface
public interface Callable{
public V call() throws Exception;
}
call()方法执行完线程主体可以返回一个结果,而返回结果的类型由Callable接口上的泛型来决定。
范例:
import java.util.concurrent.Callable;

class TestThread implements Callable{
private int ticket = 10 ;
@Override
public String call() throws Exception {
for(int x = 0 ;x < 100 ;x ++) {
if(this.ticket > 0) {
System.out.println(“卖票,ticket =” + this.ticket);
}
}
return “票已卖光”;
}
}
此时观察Thread类里面发现并没有直接支持Callable接口的多线程应用
范例:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class TestThread implements Callable{
private int ticket = 10 ;
@Override
public String call() throws Exception {
for(int x = 0 ;x < 100 ;x ++) {
if(this.ticket > 0) {
System.out.println(“卖票,ticket =” + this.ticket);
ticket – ;
}
}
return “票已卖光”;
}
}
public class MyThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestThread mt = new TestThread() ;
TestThread mt1 = new TestThread() ;
FutureTask task = new FutureTask(mt);
FutureTask task1 = new FutureTask(mt1);
new Thread(task).start();
new Thread(task1).start();
System.out.println(“A线程的返回结果 :” + task.get());
System.out.println(“B线程的返回结果 :” + task1.get());
}
}

线程常用的操作方法
线程的命名:
构造方法:public Thread(Runnable target, String name)
设置名字:public void setName(String name)
取得名字:public final String getName()
取得当前执行线程的对象:public static Thread currentThread()

范例:
class Demo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class TestDemo {
public static void main(String[] args) {
Demo de = new Demo();
new Thread(de,“自己的线程A”).start();
new Thread(de).start();
new Thread(de,“自己的线程B”).start();
new Thread(de).start();
new Thread(de,“自己的线程C”).start();
new Thread(de).start();
new Thread(de).start();
}
}
第三十九章 多线程的常用操作方法
线程的命名与取得
如果想要进行多线程名称操作,可以使用Thread类的如下
方法:
构造方法:public Thread(Runnable target,String name);
设置名字:public final void setName(String name);
取得名字:public final String getName();
取得当前线程对象:public static Thread currentThread();

3.2、线程的休眠
所谓的线程休眠指的就是让线程执行的速度变慢一点。休眠方法:public static void sleep(long millis);这个方法有异常抛出
因为每次执行到run()方法的线程对象都必须进行休眠,所以执行速度会变慢。
默认情况下,在休眠中如果设置了多个对象,那么多有的线程对象将一起进入到run()方法(所谓的一起休眠是因为先后顺序太短了,但是实际上有区别)

线程的优先级
多为的优先级指的是优先级越高越有可能先执行。在Thread类里面提供有一下的两个方法进行优先级操作
设置优先级:public final void setPriority(int newPriority)
取得优先级:public final int getPriority()

发现设置和取得优先级都适用了int数据类型,对于此内容有三种取值;
最高优先级:public static final int MAX_PRIORITY
中等优先级:public static final int NORM_PRIORITY
最低优先级:public static final int MIN_PRIORITY
范例:
class Demo implements Runnable{
@Override
public void run() {
for(int x = 0 ;x < 20 ;x ++) {
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ",x = " + x);
}
}
}
public class TestDemo {
public static void main(String[] args) {
Demo de = new Demo();
Thread t1 = new Thread(de,“自己的线程A”);
Thread t2 = new Thread(de,“自己的线程B”);
Thread t3 = new Thread(de,“自己的线程c”);
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
设置优先级只是有可能先执行
总结:
1、Thread.currentThread可以取得当前线程对象
2、Thread.sleep()主要是休眠,感觉上是几个线程一起休眠,但是实际上是有先后顺序的

第四十章 线程的同步与死锁
同步问题的引出
所谓的同步指的是多个线程访问统一资源的时所需要考虑的问题

同步操作
在java里面如果想实现线程同步可以使用synchronized关键字,而这个关键字可以通过两种方法使用
一种是同步代码块:
public void run() {
for(int x = 0;x < 20; x ++) {
synchronized(this) {
if(this.ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + “-------” + “买票:” + this.ticket --);
}
}
}

}

另一种是同步方法:
class Tic implements Runnable{
private int ticket = 60 ;
@Override
public void run() {
for(int x = 0 ;x < 100 ;x ++) {
this.sale();
}

}
public synchronized void sale() {
	if(this.ticket > 0) {
		try {
			Thread.sleep(100);
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "卖票,ticket=" + this.ticket -- );
	}
}

}
public class Test {
public static void main(String[] args) {
Tic t1= new Tic() ;
Tic t2 = new Tic() ;
Tic t3 = new Tic() ;
new Thread(t1 ,“线程A”).start();
new Thread(t2 ,“线程B”).start();
new Thread(t3 ,“线程C”).start();
}
}
同步操作与异步操作相比,异步操作要高于同步操作,但是同步操作时数据的安全性较高,属于安全的线程操作
3.3、死锁
线程如果同步过多就有可能造成死锁

第四十一章 生产者与消费者

生产者和消费者指的是两个不同的线程对象,操作同一资源的情况,具体的操作流程如下
·生产者负责生产数据,消费者负责取走数据;
·生产者生产完一组数据,消费者就要取走一组数据

范例:
class Info{
private String title ;
private String content ;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
class Productor implements Runnable{
private Info info ;
@Override
public void run() {
for(int x = 0 ;x < 100 ;x ++) {
if(x%2 == 0) {
this.info.setTitle(“张三”);
try {
Thread.sleep(100);
} catch (InterruptedException e) {

				e.printStackTrace();
			}
			this.info.setContent("好学生一个");
		}else {
			this.info.setTitle("小兔子");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			this.info.setContent("可爱的");
		}
	}		
}
public Productor(Info info) {		
	this.info = info;
}

}
class Customer implements Runnable{
private Info info ;
public Customer(Info info) {
this.info = info;
}
@Override
public void run() {
for(int x = 0 ;x < 100 ; x++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {

			e.printStackTrace();
		}
		System.out.println(this.info.getTitle() + "-" + this.info.getContent());
	}		
}

}
public class Demo {
public static void main(String[] args) {
Info info = new Info();
new Thread(new Productor(info)).start();
new Thread(new Customer(info)).start();
}
}
通过以上代码可以发现两个严重问题:
·数据错位,发现不在是一个所需要的完整数据;
·数据重复取出,数据重复设置

3.2、解决数据错乱问题
数据的错位完全是因为非同步的操作所造成的,所以应该使用同步处理,因为取和设置是两个不同的操作,所以要想进行同步控制,那么就需要将其定义在一个类里面完成
范例:使用同步处理
class Info{
private String title ;
private String content ;
public synchronized void set(String title , String content) {
this.title = title ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {

		e.printStackTrace();
	}
	this.content = content ;
}
public synchronized void get() {
	System.out.println(this.title + "-" + this.content);
}

}
class Productor implements Runnable{
private Info info ;
@Override
public void run() {
for(int x = 0 ;x < 100 ;x ++) {
if(x%2 == 0) {
this.info.set(“张三”,“好学生一个”);
}else {
this.info.set(“小兔子”,“好可爱”);
}
}
}
public Productor(Info info) {
this.info = info;
}
}
class Customer implements Runnable{
private Info info ;
public Customer(Info info) {
this.info = info;
}
@Override
public void run() {
for(int x = 0 ;x < 100 ; x++) {
this.info.get();
}
}
}
public class Demo {
public static void main(String[] args) {
Info info = new Info();
new Thread(new Productor(info)).start();
new Thread(new Customer(info)).start();
}
}
此时数据错位的问题很好地得到了解决,但是重复操作问题更加严重了
3.3、解决重复问题
要想解决重复问题,必须要加入等待与唤醒机制
·等待:public final void wait()throws InterruptedException
·唤醒第一个等待线程:public final void notify()
·唤醒全部线程,哪个优先级高就先执行:public final void notifyAll()
范例:修改重复问题
class Info{
private String title ;
private String content ;
private boolean flag = true ;
//flag=true:表示可以生产,不可以取走
//flag=false:表示可以取走,不可以生产
public synchronized void set(String title , String content) {
//重复进入到set()方法里面,发现不能够生产,所以要等待
if(this.flag == false) {
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title ;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content ;
this.flag = false ;//修改生产标记
super.notify();//唤醒其他等待线程
}
public synchronized void get() {
if(this.flag == true) {//还没生产
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title + “-” + this.content);
this.flag = true;//继续唤醒其他的线程
super.notify();
}
}
class Productor implements Runnable{
private Info info ;
@Override
public void run() {
for(int x = 0 ;x < 100 ;x ++) {
if(x%2 == 0) {
this.info.set(“张三”,“好学生一个”);
}else {
this.info.set(“小兔子”,“好可爱”);
}
}
}
public Productor(Info info) {
this.info = info;
}
}
class Customer implements Runnable{
private Info info ;
public Customer(Info info) {
this.info = info;
}
@Override
public void run() {
for(int x = 0 ;x < 100 ; x++) {
this.info.get();
}
}
}
public class Demo {
public static void main(String[] args) {
Info info = new Info();
new Thread(new Productor(info)).start();
new Thread(new Customer(info)).start();
}
}
请解释sleep()与wait()的区别?
·sleep()是Thread类定义的方法,wait()是Object定义的方法;
·sleep()可以设置休眠时间,时间一到自动唤醒,而wait()需要等待notify()进行唤醒

第四十二章java基础类库

虽然在所有的项目里面,String类都一定要使用,可以String类有一个问题不得不重复,那么就是String类的内容不可改变,为此在java里面提供有另外一个类——StringBuffer类(里面的内容可以修改)。
String类的对象可以使用“+”,进行字符串的连接操作,但是在StringBuffer类里面必须使用append()方法进行追加
·方法:public StringBuffer append(数据类型 变量)
范例:
public class Demo {

public static void main(String[] args) {
	//StringBuffer不可以直接像String类那样实例化
	StringBuffer buf = new StringBuffer() ;
	buf.append("hello ").append("world") ;	
	change(buf);
	System.out.println(buf);
}
public static void change(StringBuffer temp) {
	temp.append("\n").append("Hello CSDN");
}

}
发现StringBuffer类的内容是可以进行修改的,而String类的内容是不可以修改的
String StringBuffer
public final class String
extends Object
implements Serializable,
Comparable, CharSequence public final class StringBuffer
extends Object
implements Serializable, CharSequence
发现String与StringBuffer都是CharSequence的接口子类,以后见到CharSequence可以直接传递一个字符串
范例:
public class Test {
public static void main(String[] args) {
CharSequence seq = “hello” ;//向上转型
System.out.println(seq);//调用覆写的toString()方法
}
}
虽然String和StringBuffer类都有着共同的接口,但是这两个类对象之间要转换不能够直接转换。
1、将String对象转换为StringBuffer类对象
方式一:利用StringBuffer类的构造方法完成:public StringBuffer(String str)
方式二:利用append()方法:public StringBuffer append(String str)
范例:
public class Test {
public static void main(String[] args) {
CharSequence seq = “hello” ;//向上转型
System.out.println(seq);//调用覆写的toString()方法
//将String变为StringBuffer
StringBuffer buf = new StringBuffer(“hello”);
StringBuffer but = new StringBuffer();
but.append(“world”); //将String变为StringBuffer
System.out.println(buf);
System.out.println(but);
}
}
2、将StringBuffer类对象变为String类对象
·利用toString()方法可以将StringBuffer变为String
范例:
public class Test {
public static void main(String[] args) {
StringBuffer bt = new StringBuffer(“hello”);
String str = bt.toString();
System.out.println(str);
}
}
也可以利用String类的构造方法public String(StringBuffer buffer)实现StringBuffer与String类的转换
在String类里面也提供了一个和StringBuffer比较的方法public boolean contentEquals(StringBuffer sb)
范例:比较
public class STA {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer(“hello”);
System.out.println(“hello”.contentEquals(buf));
}
}
String类之中定义了许多的方法便于用户的开发,而在StringBuffer 类里面也定义了许多的操作方法,而且有许多方法与String类是正好互补的
1、字符串反转:public StringBuffer reverse()
StringBuffer buf = new StringBuffer(“hello”);
System.out.println(buf.reverse());//字符串反转
2、在指定的索引位置增加数据
public StringBuffer insert(int offset,数据类型 变量)
public class STA {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer(“hello”);
buf.insert(5, " world ");
System.out.println(buf);//字符串反转
}
}
3、删除部分数据:public StringBuffer delete(int start, int end)
范例:
public class STA {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer(“hello”);
buf.insert(5, " world ");
buf.delete(5, 11);
System.out.println(buf);//字符串反转
}
}
从jdk1.5之后增加一个字符串操作类StringBuilder
public final class StringBuilder
extends Object
implements Serializable, CharSequence
请解释三者的区别
·String 的内容一旦声明则不可改变,而StringBuffer和StringBuilder声明的内容可以改变
·StringBuffer类中提供的方法都是同步方法,属于安全的线程操作,而StringBuilder类中的方法都属于异步方法,属于非线程安全的操作

Runtime类
在每一个JVM进程里面都会存在一个Runtime类的对象,这个类的主要功能是取得一些与运行时环境有关的属性或者创建新的进程等操作
在Runtime类定义的时候它的构造方法已经被私有化了,这就属于单例设计模式,这就保证在JVM进程里面只有唯一的一个RuntimeLie的对象
取得实例化对象:public static Runtime getRuntime()
·返回所有的可用内存空间:public long totalMemory()
·返回最大可用内存空间:public long maxMemory()
·返回空余内存空间:public long freeMemory()

System类

在System类里面定义有一个重要的方法
·取得当前的系统时间
public static long currentTimeMillis()
范例:计算某一操作所用时间
public class TestSystem {
public static void main(String[] args) {
long start = System.currentTimeMillis();
String str = “” ;
for(int x = 0 ;x < 3000 ;x ++) {
str += x ;
}
long end = System.currentTimeMillis() ;
System.out.println(end - start);
}
}
在System类里面定义了一个操作方法:public static void gc()这个gc()方法并不是新的方法,而是间接调用了Runtiem类中的gc()方法

第四十三章 数字操作类

本次主要讲解数学操作类的使用

3.1、Math类

Math就是一个专门提供数学计算的操作类里面提供了一系列数学操作方法
在Math类里面提供的一切方法都是static方法,因为Math类里面没有普通属性
在整个Math类里面有一个方法时比较重要的
·四舍五入:public static long round(double a)
范例:四舍五入
public class TestMath {
public static void main(String[] args) {
System.out.println(Math.round(15.5));//16
System.out.println(Math.round(-15.5));//-15
System.out.println(Math.round(-15.51));//-16
}
}
如果进行负数四舍五入的时候,操作的数据小数位大于0.5才进位,小于等于0.5不进位

3.2、Random类

这个类的主要功能是取得随机数的操作类
范例:随机生成不大于100的整数
public class TestRandom {

public static void main(String[] args) {
	Random ran = new Random() ;
	for(int x = 0 ;x < 10 ;x ++) {
		System.out.println(ran.nextInt(100));
	}
}

}

范例:37选6
import java.util.Random;
public class TestRandom {
public static void main(String[] args) {
Random ran = new Random() ;
int data[] = new int [7] ;
int foot = 0 ;
while(foot < 7) {
int t = ran.nextInt(37) ;
if(!isRepeat(data, t)) {
data[foot ++] = t ;
}
}
java.util.Arrays.sort(data);
for(int x = 0 ;x < data.length ;x ++) {
System.out.print(data[x] + “、”);
}
}
/**
* 此方法主要是判断是否存在重复的内容,但是不允许保存0
* @param temp 指的是已保存的数据
* @param num 新生成的数据
* @param return 如果存在返回TRUE,否则返回FALSE
* */
public static boolean isRepeat(int temp[],int num) {
if(num == 0) {
return false ;
}
for(int x = 0 ;x <temp.length ; x ++) {
if(temp[x] == num) {
return true ;
}
}
return false ;
}
}

3.3、大整数操作类:BigInteger

BigInteger构造方法:public BigInteger(String val),它接受的是String型。
范例:
import java.math.BigInteger;
public class TsetInteger {
public static void main(String[] args) {
BigInteger bigA = new BigInteger(“456478612456458445243454123”) ;
BigInteger bigB = new BigInteger(“45516546578645454123”) ;
System.out.println("加法操作 : " + bigA.add(bigB));
System.out.println(“减法操作:” + bigA.subtract(bigB));
System.out.println(“乘法操作 :” + bigA.multiply(bigB));
System.out.println(“除法操作 :” + bigA.divide(bigB));
BigInteger result [] = bigA.divideAndRemainder(bigB) ;
System.out.println("商: " + result[0] + ", 余数: " + result[1]);
}
}
在java里面虽然提供了大数字操作类,但是很多的时候,我们的项目开发可能对于数字要求会更加的敏感,而这个时候java本身提供的数字操作类是帮助不大的

3.4、大浮点数:BigDecimal

BigInteger不能够保存小数,而BigDecimal可以保存小数数据,在BigDecimal类里面提供有如下构造
·构造一:public BigDecimal(String val)
·构造二:public BigDecimal(double val)
BigDecimal可以实现准确的四舍五入,可是在BigDecimal里面没有直接提供四舍五入计算,可以存在有一个除法计算
·除法操作: public BigDecimal divide(BigDecimal divisor,
int scale,int roundingMode)
BigDecimal divisor:被除数
int scale:保留的小数位
int roundingMode:进位模式(public static final int ROUND_HALF_UP

范例:准确的四舍五入
import java.math.BigDecimal;

class Math{
/**
* 实现准确的四舍五入操作
* @param num 要进行四舍五入操作的数字
* @param scale 要保留的小数为数
* @return 处理后的四舍五入数据
*/
public static double round(double num,int scale) {
BigDecimal biga = new BigDecimal(num);
BigDecimal bigb = new BigDecimal(1);
return biga.divide(bigb,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
public class TestDecimal {
public static void main(String[] args) {
System.out.println(Math.round(189.65645864565, 2));
}
}

第四十四章 日期操作类

3.1、Date类
在java里面提供有一个java.util.Date的类,它直接就表示当前的日期
范例:输出当前的日期时间
import java.util.Date;
public class MyDate {
public static void main(String[] args) {
Date date = new Date() ;
System.out.println(date);
}
}
这个时候的确是输出了当前的日期时间,只不过这个格式实在难看
一直以来强调过一个概念:long可以描述出日期时间数据,那么这一点在Date类的方法上也是可以看见的,在Date类里面有几个重要的方法
·无参构造:public Date()
·有参构造:public Date(long date)
·将Date转换为Long型:public long getTime()
范例:Date与Long之间的转换
import java.util.Date;
public class MyDate {
public static void main(String[] args) {
long cur = System.currentTimeMillis() ;
Date date = new Date(cur) ;//long转换为Date
System.out.println(date);
System.out.println(date.getTime());//Date转换为long
}
}
以后的代码编写之中,依然需要以上的转换操作,尤其是getTime()方法

3.2、日期格式化:SimpleDateFormat

·构造方法:public SimpleDateFormat(String pattern):需要传递转换格式
·将Date转化为String: public final String format(Date date)
·将String转化为Date: public Date parse(String source)

throws ParseException
常见的转换单位:年(yyyy)、月(MM)、日(dd)、时(HH)、分(mm)、秒(ss)、毫秒(SS)
范例:日期格式化
import java.text.SimpleDateFormat;
import java.util.Date;
public class MySimpleDateFormat {
public static void main(String[] args) {
Date date = new Date() ;
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SS”) ;
String str = sdf.format(date) ;
System.out.println(str);
}
}
除了将日期变为字符串之外,也可以将字符串转换为日期
范例:将字符串转换为日期
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringDate {
public static void main(String[] args) throws ParseException {
String str = “2021-11-14 11:11:11.111” ;
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SS”) ;
Date date = sdf.parse(str);
System.out.println(date);
}
}
在将字符串变为日期型数据的时候,如果日期型数据给出的月份不对,那么会自动进行进位,如果给定的字符串与要转换的格式不匹配,那么就会出现异常
总结:关于数据类型的转换
在数据表的操作里面重点说过了有几个常用类型:varchar2(String)、clob(String)、Number(double、int)、date(java.util.Date)
Date与String类之间的转换依靠的是SimpleDateFormat;
String与基本类型之间的转换依靠的是包装类与String.valueOf()方法
Long与Date转换依靠的是Date类提供的构造以及getTime()方法

3.3、Calendar类
Date类和SimpleDate类两个往往是一起使用的,但是Calendar类主要是进行一些简单的日期计算的
定义:Calendar是一个抽象类
public abstract class Calendar
extends Object
implements Serializable, Cloneable, Comparable
这是一个抽象类,那么应该依靠子类进行实例化操作,但是在这个类里面它提供有一个static方法,此方法返回的是本类对象
public static Calendar getInstance()
范例:取得当前的日期时间
import java.util.Calendar;
public class MyClendar {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance() ;
StringBuffer buf = new StringBuffer();
buf.append(cal.get(Calendar.YEAR)).append(“年”).append("-");
buf.append(cal.get(Calendar.MONTH) + 1).append(“月”).append("-") ;
buf.append(cal.get(Calendar.DAY_OF_MONTH)).append(" “);
buf.append(cal.get(Calendar.HOUR_OF_DAY)).append(”😊;
buf.append(cal.get(Calendar.MINUTE)).append("😊;
buf.append(cal.get(Calendar.SECOND));
System.out.println(buf);
}
}
如果要进行日期计算这个类要比Date容易,如果使用Date进行天的计算,那么就需要使用long完成
总结:
1、以后数据库中的日期型数据就使用java.util.Data表示
2、代码模型:SimpleDateFromat类实现String与Date间的相互转换

第四十五章 比较器

3.1、Arrays类

在这个类里面存在有二分查找法:public static int binarySearch(数据类型[]a,数据类型 key)。但是如果进行二分查找,那么数组必须是排序后的内容。

范例:实现二分查找
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int data [] = new int [] {1,5,9,8,6,3,2,4,7,10} ;
java.util.Arrays.sort(data);
System.out.println(Arrays.binarySearch(data, 9));
}
}

· Arrays类提供了数组比较:public static boolean equals(数据类型[] a,数据类型[] b),与object没有关系

范例:实现数组比较
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int dataA [] = new int[] {1,2,3};
int dataB [] = new int[] {1,2,3};
System.out.println(Arrays.equals(dataA, dataB));
}
}
要想判断数组是否相同,需要顺序完全一致

·数组填充:public static void fill(数据类型[] a,数据类型 val)
·将数组变为字符串输出:public static String toString(数据类型[] a)

范例:填充数组
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args) {
int dataC[] = new int[10];
Arrays.fill(dataC, 6);
System.out.println(Arrays.toString(dataC));
}
}
3.2、比较器:Comparable(核心)

对象数组排序:public static void sort(Object [] a)
比较的规则就是由Comparable接口定义的
Public interface Comparable{
Public int compareTo(T o);
}
实际上String类就是Comparable接口的子类,之前使用的方法就是compareTo()方法就是比较的操作功能,返回三类数据:1(大于)、-1(小于)、0(等于)。
CompareTo()方法由Arrays.sort()自动进行调用
范例:实现比较器
import java.util.Arrays;

class Book implements Comparable{
private String title ;
private double price ;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
@Override
public String toString() {
return "书名 : " + this.title + “,价格 :” + this.price + “\n”;
}

@Override
public int compareTo(Book o) {//Arrays.sort()会自动调用此方法
	if(this.price > o.price) {
		return 1;
	}else if(this.price< o.price) {
		return -1 ;
	}else {
		return 0;
	}		
}

}
public class Test {

public static void main(String[] args) {
	Book books [] = new Book [] {
			new Book("java开发",79.8),
			new Book("jsp开发",58.8),
			new Book("oracle开发",89.8),
			new Book("前端开发",69.8)
	};
	Arrays.sort(books);
	System.out.println(Arrays.toString(books));
}

}

总结:
以后不管何种情况下,只要是一组对象要排序,对象所在的类一定要实现Comparable接口
3.4、挽救的比较器:Comparator
Comparable接口的主要特征是在类定义的时候就默认实现号的接口,那么如果说现在有一个类已经开发完善了

第四十六章 正则表达式
所有的开发一定要有正则的支持
1、记下常用的正则标记
2、掌握String类对正则的支持
范例:
public class TestDemo {
public static void main(String[] args) {
String str = “123” ;
System.out.println(str.matches("\d+"));
}
}
以前用很多行代码进行判断的操作,现在只用一行简单的代码就可以实现操作了,其中出现的“\d+”就是正则表达式
在java.util.regex包里面定义了两个主要的类:
·Pattern类:此类对象如果要想使用必须使用compile()方法,方法的功能是编译正则
public static Pattern compile(String regex);
·Matcher类:通过Pattern类取得
public Matcher matcher(CharSequence input);
String stb = “heiaiwedhfa4ae6df54asfdaewadfes”;
Pattern compile = Pattern.compile("[e]");//Pattern类通过static方法拿到Pattern类的对象
Matcher m = compile.matcher(stb);//Matcher通过Pattern的方法matcher(CharSequence input)拿到Matcher类的对象
while(m.find()) {//Matcher类对象通过find()方法得到取得的结果
System.out.println(m.group());Matcher类对象通过group()方法输出结果
}

3.2、正则标记
1、单个字符(数量:1)
·字符:表示由一个字符组成
·\:表示转义字符“\”
·\t:表示一个“\t”符号
·\n:表示匹配换行(\n)
2、字符集(数量:1)
·[abc]:表示可能是字符a、b、c中的任意一位字符
·[^abc]:表示不是a、b、c中的任意一位字符
·[a-z]:表示所有的小写字母
·[a-z A-Z]:表示任意的一位字母,不区分大小写
·[0-9]:表示任意一位数字
3、简化的字符集表达式(数量:1)
·.:表示任意的一位字符
·\d:等价于[0-9]
·\D:等价于[^0-9]
·\s:表示任意的一位空白字符例如:“\t”、“\n”
·\S:表示任意的一位非空白字符
·\w:等价于[a-z A-Z _ 0-9],表示由任意的字母数字_所组成
·\W: 等价于[^a-z A-Z _ 0-9],表示不是由任意的字母数字_所组成
4、边界匹配(在java script中使用)
^:正则的开始
$:正则的结束
5、数量表达式
正则?:表示此正则可以出现0或1次
正则+:表示此正则可以出现1次或多次
正则*:表示此正则可以出现0、1次或多次
正则{n}:表示次正则正好出现n次
正则{n,}:表示次正则正好出现n次或n次以上
正则{n,m}:表示此正则出现n~m次
6、逻辑运算
正则1正则2:正则1判断完成之后继续判断正则2
正则1|正则2:正则1或正则2有一组满足即可
(正则):将多个正则作为一组,可以为这一组单独设置出现的次数
3.3、String类对正则的支持
在jdk1.4之后,由于正则的引入,所以String类里面也相应的增加了新的操作方法支持
public boolean matches(String regex):正则验证,使用指定的字符串判断其是否符合给出的的正则表达式结构
public String replaceAll(String regex, String replacement):全部替换
public String replaceFirst(String regex, String replacement):替换首个
public String[] split(String regex):全部拆分
public String[] split(String regex, int limit):部分拆分

范例:实现字符串替换
public class TestDemo {
public static void main(String[] args) {
String str = “weldsafk*)()*asdlkfjao#$afdklja” ;
String regex ="[^a-z]";
System.out.println(str.replaceAll(regex,""));
}
}
范例:字符串拆分
public class TestDemo {
public static void main(String[] args) {
String str = “lak8dfja5644asdf99ja” ;
String regex ="\d+";
String result [] = str.split(regex);
for(int x = 0 ;x < result.length ;x ++) {
System.out.println(result[x]);
}
}
}
所有正则之中最应该兴奋的事情是因为可以使用它进行验证
范例:验证一个字符串是否是数字,如果是将其变为double型
public class TestDemo {
public static void main(String[] args) {
String str = “10.2” ;
String regex ="\d+(\.\d+)?";
System.out.println(str.matches(regex));
if(str.matches(regex)) {
System.out.println(Double.parseDouble(str));
}
}
}
范例:判断给定的字符串是否是IP地址(IPV4)
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = “192.168.1.1” ;
String regex ="(\d{1,3}\.){3}\d{1,3}";
System.out.println(str.matches(regex));
}
}
范例:给定一个字符串判断是否是日期格式,如果是则将其转换为Data型数据
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = “2009-03-23” ;
String regex ="\d{4}-\d{2}-\d{2}";
System.out.println(str.matches(regex));
if(str.matches(regex)) {
Date data = new SimpleDateFormat(“yyyy-MM-dd”).parse(str);
System.out.println(data);
}
}
}
范例:判断电话号码,一般要编写电话号码一下几种格式都是满足的:
·格式一:51283346
·格式二:010-51283346
·格式三:(010)-51283346
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = “51283346” ;
String regex ="((\d{3,4}-)|(\(\d{3,4}\))-)?\d{7,8}";
System.out.println(str.matches(regex));
}
}
范例:验证email地址
·要求格式一:email由字母、数字、所组成
·要求格式二:用户名要求由字母、数字、
、.组成,其中必须以字母开头和结尾,用户名长度不超过30最后的根域名只能是.com、.cn、.net、.com.cn、.net.cn、.edu、.gov、.org
public class TestDemo {
public static void main(String[] args) throws Exception{
String str = “hello_123@mldn.cn” ;
String regex ="[a-zA-Z][a-zA-Z0-9_\.]{0,28}@\w+\.(net|cn|com|\.cn|net\.cn|org|gov|edu)";
System.out.println(str.matches(regex));
}
}
范例:验证汉字
public class TestDemo {
public static void main(String[] args) throws Exception{
String sta = “你好”;
String reg = “.+”;
System.out.println(sta.matches(reg));
}
}

总结:
1、利用正则实现验证代码可以最少化
2、一定要清楚String类对正则支持的几个方法,以及所有讲解过的相关程序

第四十七章 反射机制
3.1、 认识反射

反射的话先通过“反”来理解,既然有“反”就一定有“正”,在正常情况下,一定是先有类。而后才有对象。

所谓的“反”就是指可以利用对象找到对象的出处,在object类提供有一个方法
取得class对象:public final Class<?> getClass()
范例:观察反
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date() ;
System.out.println(date.getClass());
}
}
class java.util.Date
发现调用了getClass()方法后的就输出了类的完整名称,等于是找到了对象的出处。

3.2、 Class类对象实例化

Java.lang.Class是一个类,这个类是反射操作的源头。即:所有的反射都要从此类开始进行,而最关键的是,这个类有三种实例化方式:
·第一种:调用object类中的getClass() :
范例:
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date() ;
Class<?> cls = date.getClass() ;
System.out.println(cls);
}
}
·第二种:使用“类.class”取得:
范例:
import java.util.Date;
public class Test {
public static void main(String[] args) {
Class<?> cls = Date.class ;
System.out.println(cls);
}
}
之前是在产生了类的实例化对象之后取得的Class类对象,但是此时并没有实例化对象的产生
·第三种:调用class类提供的一个方法:
例化Class对象:publicstatic Class<?> forName(String className)
throws ClassNotFoundException
范例:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// Date date = new Date() ;
// Class<?> cls = date.getClass() ;
// System.out.println(cls);

// Class<?> cls = Date.class ;
// System.out.println(cls);

	Class<?> cls = Class.forName("java.util.Date");
	System.out.println(cls);
}

}
此时可以不使用import语句导入一个明确的类,而类名称是采用字符串的形式描述的。

3.3、反射实例化对象

当拿到一个类的时候,肯定要直接使用关键字new进行对象实例化,这属于习惯性做法,但是如果有了Class类对象,那么就可以做到利用反射来实现对象实例化操作:
实例化对象方法:public Constructor getConstructor​(Class<?>… parameterTypes)
throws NoSuchMethodException, SecurityException
拿到Constructor对象可以调用Constructor类中newInstance()方法
public T newInstance​(Object… initargs) throws
InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
范例:利用反射实例化对象
class Book{
public Book() {
System.out.println("*************");
}
@Override
public String toString() {
return “这是一本书”;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName(“fs.Book”);
Object obj = cls.getDeclaredConstructor().newInstance() ;
Book book = (Book) obj ;
System.out.println(book);
}
}
有了反射之后,以后实例化对象的操作不在只是单独的依靠关键字new完成了,反射也同样可以完成,但是这并不表示new就被完全却代了。
在任何开发之中,new是造成耦合的最大元凶,一切的耦合都来源与new。
范例:修改工厂设计模式
package fs;
interface Fruit{
public void eat();
}
class Apple implements Fruit{
@Override
public void eat() {
System.out.println(“吃苹果”);
}
}
class Orange implements Fruit{
@Override
public void eat() {
System.out.println(“吃橘子”);
}
}
class Factory{
public static Fruit getIntance(String className) {
Fruit f = null ;
try {
f = (Fruit) Class.forName(className).getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f ;
}
}
public class TestFactory {
public static void main(String[] args) {
Fruit f = Factory.getIntance(“fs.Apple”);
f.eat();
}
}
此时的程序就真正完成了解耦合的目的,而且可扩展性非常强

3.4、 使用反射调用构造

在Class类里面提供有一个方法可以取得构造:
·取得全部构造:public Constructor<?>[] getConstructors()
throws SecurityException

·取得一个指定参数顺序的构造:public Constructor<T> getConstructor(Class<?>... parameterTypes)

throws NoSuchMethodException,SecurityException

以上两个方法返回的都是“java.lang.reflect.Constructor”类的对象。在这个类中提供有一个明确传递有参构造内容的实例化对象方法:
public T newInstance(Object… initargs)
throws InstantiationException,IllegalAccessException,
IllegalArgumentException,InvocationTargetExceptionClass<?>

范例:利用反射调用构造
package fs;

import java.lang.reflect.Constructor;
class Book{
private String title ;
private double price ;
public Book(String title , double price) {
this.title = title ;
this.price = price ;
}
@Override
public String toString() {
return "图书名称 : " + this.title + “, 价格 :” + this.price ;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName(“fs.Book”);
Constructor<?> con = cls.getConstructor(String.class,double.class) ;
Object obj = con.newInstance(“java开发” , 79.8) ;
System.out.println(obj);
}
}
简单java类的开发之中不管有多少构造方法,请至少保留有无参构造

3.5、 反射调用方法

在Class类里面提供有一下取得类中方法的操作:
· 取得一个类中的全部方法:public Method[] getMethods()throws SecurityException
·取得指定方法:public Method getMethod(String name, Class<?>… parameterTypes)
throws NoSuchMethodException,SecurityException
以上的两个操作返回的是"java.lang.reflect.Method"类的对象,在这个类中重点关注一个方法
· 调用方法:public Object invoke(Object obj,Object… args)
throws IllegalAccessException,IllegalArgumentException,
InvocationTargetException
范例:反射调用方法
package fs.cn;

import java.lang.reflect.Method;
class Book{
private String title ;
public void setTitle(String title) {
this.title = title ;
}
public String getTitle() {
return title ;
}
}
public class TestDemo {
public static void main(String[] args) throws Exception {
String fileName = “title” ; //操作成员
Class<?> cls = Class.forName(“fs.cn.Book”) ;
Object obj = cls.getDeclaredConstructor().newInstance();
Method setMet = cls.getMethod(“set” + initcap(fileName),String.class) ;
Method getMet = cls.getMethod(“get” + initcap(fileName),String.class) ;
setMet.invoke(obj, “java开发”) ;//等价于Book类对象.setTitle(“java开发”) ;
System.out.println(getMet.invoke(obj));
}
public static String initcap(String str) {
return str.substring(0,1).toUpperCase() + str.substring(1) ;
}
}
3.6、反射调用成员
类中属性一定要在本类实例化对象产生之后才可以分配内存空间,在Class类里面提供有取得成员的方法
·取得全部成员:public Field[] getDeclaredFields()throws SecurityException
·取得部分成员:public Field getDeclaredField(String name)
throws NoSuchFieldException,SecurityException
返回类型是java.lang.reflect.Field类,在这个类里面有两个重要的方法
·取得属性内容:public Object get(Object obj)
throws IllegalArgumentException,IllegalAccessException
·设置属性内容:public void set(Object obj, Object value)
throws IllegalArgumentException,IllegalAccessException

第四十八章 国际化程序
总结:
1、资源文件:文件名称每个单词首字母大写,而后后缀必须是“*.properties”
2、通过ResourceBundle类可以读取指定的CLASSPATH下的资源文件,读取时不需要设置文件后缀
3、Locale类用于指定读取的资源文件的语言环境

第四十九章 文件操作类

在java编程里面,对于所有的初学者而言,最麻烦的部分可能就是JavaIO了,英文因为这里面所牵扯的父类与子类实在是太多了,学习原则:抽象类中定义的抽象方法会根据实例化其子类的不同,也会完成不同的功能。
使用File类来进行文件的操作
具体内容
如果要进行所有的文件及内容的开发操作,应该使用java.io包来完成,而在java.io包里面一共有五个核心类,一个核心接口:
·五个核心类:File、InputStream、OutputStream、Reader、Writer
·一个核心接口:Serializable
在整个java.io包里面,File类是唯一一个与文件本身操作有关的类,但是不涉及到文件的具体内容(只能创建、删除)
如果要想使用File类,那么首先就需要通过它提供的 构造方法定义一个要操作文件的路径
·构造方法:public File(String pathname);设置完整路径(重要)
·构造方法:public File(File parent,String child);设置父路径与子文件路径
·创建文件:public boolean createNewFile()throws IOException;
|-如果目录不能访问;
|-如果文件重名,或文件名称错误;这样就会抛异常
·删除文件:public boolean delete();
·判断文件是否存在:public boolean exists()
范例:文件的创建与删除
import java.io.File;
public class TestDemo {
public static void main(String[] args) throws Exception {
File file = new File(“e:/test.txt”) ;//设置文件路径
if(file.exists()) {//文件存在
file.delete() ;//删除文件
}else {//文件不存在创建文件
System.out.println(file.createNewFile());
}
}
}
以上的程序已经完成了具体的文件创建与删除的操作,但是此时的文件会存在有两个问题
·在windows系统里面支持的是“\”路径分隔符,在linux下面使用的是“/”路径分隔符;
·在File 类里面提供有一个常量:public static final String separator
File file = new File(“e:” + File.separator+“test.txt”) ;//设置文件路径
在进行java.io 操作的过程之中,会出现有延迟情况,因为现在的问题是java程序通过JVM间接的调用操作体统的文件处理函数,所以中间会出现延迟情况
以上已经实现了文件的创建操作,但是这个时候是直接创建在了根路径下,下面来创建包含有子目录的文件
·找到父路径:public File getParentFile()
·创建父路径:public boolean mkdir()
·创建多级目录:public boolean mkdirs()
范例:创建文件夹和文件
import java.io.File;
public class TestDemo {
public static void main(String[] args) throws Exception {
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”) ;//设置文件路径
if(!file.getParentFile().exists()) {//现在父路径不存在
file.getParentFile().mkdir() ;
}
if(file.exists()) {//文件存在
file.delete() ;//删除文件
}else {//文件不存在创建文件
System.out.println(file.createNewFile());
}
}
}
在File类里面还提供有一系列取得文件内容信息的操作
· 取得文件内容信息大小:public long length()
·判断是否是文件:public boolean isFile()
·判断是否是目录:public boolean isDirectory()
·最后一次修改时间:public long lastModified()
范例:查看文件大小,以及最后一次修改时间
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo {
public static void main(String[] args) {
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.jpg”) ;
System.out.println(file.getParent());
System.out.println(file.getName());
if(file.exists()) {
System.out.println(“是否是路径 :” + file.isDirectory());
System.out.println(“是否是文件 :” + file.isFile());
System.out.println(file.length());
System.out.println(“最后一次修改时间 :” + new SimpleDateFormat(“yyyy-MM-dd HH:mm:sss”).format(new Date(file.lastModified())));
}
}
}
整个取得过程里面都是取得文件相关信息,但是不包含文件的内容
以上所有操作都是围绕文件进行的,但是在整个磁盘上除了文件之外,还会包含有使用的目录,那么对于目录而言,最为常用的功能就是列出目录组成,在File类里面定义有如下的两个列出目录的方法
·列出目录下的信息:public String[] list()
·列出所有的信息一File类对象包装:public File[] listFiles()
范例:列出信息
import java.io.File;
public class DemoList {
public static void main(String[] args) {
File file = new File(“e:” + File.separator) ;
if(file.isDirectory()) {
String result [] = file.list() ;
System.out.println(result.toString());
for(int x = 0 ;x <result.length ;x ++) {
System.out.println(result[x]);
}
}
}
}
此时确实列出了目录中的内容了,但是所列出来的是子目录下文件的名字。
范例:列出去不的File 类的对象
import java.io.File;
public class DemoList {
public static void main(String[] args) {
File file = new File(“e:” + File.separator) ;
if(file.isDirectory()) {
File result [] = file.listFiles() ;
System.out.println(result.toString());
for(int x = 0 ;x <result.length ;x ++) {
System.out.println(result[x]);
}
}
}
}
范例:列出一个目录的资源管理器
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DemoList {
public static void main(String[] args) {
File file = new File(“e:” + File.separator) ;
if(file.isDirectory()) {
File result [] = file.listFiles() ;
System.out.println(result.toString());
for(int x = 0 ;x <result.length ;x ++) {
System.out.println(result[x].getName() + “\t\t” + “修改日期 :” + new SimpleDateFormat(“yyyy-MM-dd HH:mm:sss”).format(new Date(result[x].lastModified())) + “\t\t” + (result[x].isDirectory()?“文件夹”:“文件”) + “\t\t” + (result[x].isFile()?“result[x].length()”:""));
}
}
}
public static void print(File file) {
if(file.isDirectory()) {
File result[] = file.listFiles() ;
if(result != null) {
for(int x = 0 ;x < result.length ;x ++) {
print(result[x]) ;
}
}
}
System.out.println(file);
}
}
通过一些列验证可以发现,取得文件对象列表会更加的方便,因为可以继续取出很多的内容
总结:
1、File类本身只是操作文件的,不涉及到内容
2、File类中的重要方法:
·设置完整路径:public File(String pathname)
·删除文件:public boolean delete();
·判断文件是否存在:public boolean exists()
·找到父路径:public File getParentFile()
·创建父路径:public boolean mkdir()
·创建多级目录:public boolean mkdirs()
3、在使用File类操作的时候路径分隔符使用:File.separator

第五十章 字节流与字符流

File类虽然可以操作文件,但是并不是操作文件的内容,如果要操作文件内容只能够通过两种途径完成:字节流、字符流
如果要进行输入、输出操作一般都会按照如下的步骤进行(以文件操作为例):
·通过File类定义一个要操作文件的路径
·通过字节流或字符流子类对象为父类对象实例化
·进行数据的读(输入)、写(输出)操作:
·数据流属于资源操作,资源操作必须关闭。
对于java.io包而言它定义了两类流
·字节流(JDK1.0):InputStream、OutputStream;
·字符流(JDK1.1):Reader、Writer

3.1、字节输出流:OutputStream(重点)(向文件中输出内容)

OutputStream类是一个专门进行字节数据输出的一个类,这个类的定义如下
public abstract class OutputStream
extends Object implements Closeable, Flushable
首先发现OutputStream类实现了两个接口:Closeable、Flushable
Closeable接口 JDK1.5 Flushable接口 JDK1.5
public interface Closeable
extends AutoCloseable{
public void close()
throws IOException
} public interface Flushable{
public void flush()
throws IOException
}
但是OutputStream是在JKD1.0的时候就有了,这个类原本就定义了close()与flush()两个操作方法,所以现在以上的两个接口就几乎可以忽略了
在OutputStream类里面一共提供有三个输出的方法:
·输出单个字节:public abstract void write(int b)throws IOException
·输出全部字节数组:public void write(byte[] b)throws IOException
·输出部分字节数组:public void write(byte[] b,int off,int len)
throws IOException
OutputStream本身是属于抽象类,如果要想为抽象类进行对象实例化操作,那么一定要使用抽象类的子类,本次由于要进行文件操作多以可以使用FileOutputStream,在这个子类里面定义有如下的构造方法
·创建或覆盖已有文件:public FileOutputStream(File file)
throws FileNotFoundException
·文件内容追加:public FileOutputStream(File file,
boolean append) throws FileNotFoundException
范例:定义输出流
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Demo {
public static void main(String[] args) throws Exception {
//定义要输出文件路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(!file.getParentFile().exists()) {//文件目录不存在
file.getParentFile().mkdirs();//创建目录
}
//使用OutputStream和其子类进行对象实例化,此时目录存在,文件不存在
OutputStream output = new FileOutputStream(file) ;
//进行文件内容输出
String str = "好好学习 天天向上 " ;
byte data[] = str.getBytes() ;//将字符串变为字节数组
output.write(data);//将内容使用字节数组全部输出
output.close(); //关闭操作
}
}
以上是将字节数组的内容进行了输出,并且发现,如果此时要输出的文件不存在,那么会自动进行创建,可是对于输出操作在整个OutputStream类里面一共定义有三个方法
范例:输出单个字节内容
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Demo {
public static void main(String[] args) throws Exception {
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(!file.getParentFile().exists()) {//文件目录不存在
file.getParentFile().mkdirs();//创建目录
}
//使用OutputStream和其子类进行对象实例化,此时目录存在, 文件不存在
OutputStream output = new FileOutputStream(file) ;
String str = "好好学习 天天向上 " ;
byte data[] = str.getBytes() ;//将字符串变为字节数组
for(int x = 0 ;x < data.length ;x ++) {
output.write(data[x]);//输出单个字节数组
}
output.close();
}
}
范例:输出部分字节
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Demo {
public static void main(String[] args) throws Exception {
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(!file.getParentFile().exists()) {//文件目录不存在
file.getParentFile().mkdirs();//创建目录
}
//使用OutputStream和其子类进行对象实例化,此时目录存在, 文件不存在
OutputStream output = new FileOutputStream(file) ;
String str = "好好学习 天天向上 " ;
byte data[] = str.getBytes() ;//将字符串变为字节数组
output.write(data,6,5); //输出部分字节
output.close();
}
}
但是每一次都是覆盖已有的内容,这样不好,我们希望可以实现内容的追加,那么只需要替换FileOuptutStream类的构造方法即可
范例:实现内容的追加
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Demo {
public static void main(String[] args) throws Exception {
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(!file.getParentFile().exists()) {//文件目录不存在
file.getParentFile().mkdirs();//创建目录
}
//使用OutputStream和其子类进行对象实例化,此时目录存 在, 文件不存在
OutputStream output = new FileOutputStream(file,true) ;//实现追加
String str = “好好学习 天天向上 \r\n” ;//\r\n换行
byte data[] = str.getBytes() ;//将字符串变为字节数组
output.write(data); //单个字节数组全部输出
output.close();
}
}
只要是是程序输出内容,都可以利用OutputStream类完成
把内容输出到文件中,在磁盘的文件中可以看到输出的内容

3.2、字节输入流:InputStream(读取内容到终端)

如果程序需要进行数据读取操作,可以利用InputStream类实现功能,此类定义如下
public abstract class InputStream extends Objectimplements Closeable
虽然此类实现了Closeable接口但是与OutputStream类一样,不用去考虑此接口的存在,在InputStream类里面也定义有数据读取的方法
数据读取的方法
读取单个字节:public abstract int read()throws IOException
    -返回值:返回读取的字节内容,如果发现已经没有内容,返回 -1
将读取的数据保存在字节数组里:public int read(byte[] b)throws IOException
    -返回值:返回读取的数据长度,如果已经读取到结尾了返回 -1
将读取的数据保存在部分字节数组里:public int read(byte[] b,int off,int len)throws IOException
    -返回值:读取的部分数据长度,如果已经读取到结尾了返回 -1
InputStream是一个抽象类,如果要想进行文件读取使用用FileInputStream子类进行实例化
构造方法:public FileInputStream(File file)throws FileNotFoundException

范例:向数组里读取数据
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestInputStream {
public static void main(String[] args) throws Exception {
//1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
//需要判断文件是否存在后才可以读取
if(file.exists()) {//文件存在
//使用InputStream进行读取
InputStream input = new FileInputStream(file) ;
byte data [] = new byte[1024] ;//准备处一个1024的数组
input.read(data) ;//将内容保存在字节数组之中
//关闭输入流
input.close();
System.out.println("【" + new String(data) + “】”);//将字节数组变为字符串
}
}
}

范例:二
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestInputStream {
public static void main(String[] args) throws Exception {
//1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(file.exists()) {//文件存在
//使用InputStream进行读取
InputStream input = new FileInputStream(file) ;
byte data [] = new byte[1024] ;//准备处一个1024的数组
int len = input.read(data) ;//将内容保存在字节数组之中,并取得字节数组的长度
//关闭输入流
input.close();
System.out.println("【" + new String(data,0,len) + “】”);//将部分字节数组变为字符串输出
}
}
}
范例:单个字节数据读取
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestInputStream {
public static void main(String[] args) throws Exception {
//1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “test.txt”);
if(file.exists()) {//文件存在
//使用InputStream进行读取
InputStream input = new FileInputStream(file) ;
byte data [] = new byte[1024] ;//准备处一个1024的数组
int foot = 0 ;//表示字节数组操作角标
int temp = 0 ;//表示每次接受的字节数组
//(temp = input.read()),表示将read()方法读取的内容给 了temp变量
//(temp = input.read()) != -1,判断读取的temp内容是 否是-1
while((temp = input.read()) != -1) {//每次有内容读取 一个字节
data[foot ++] =(byte) temp ;//有内容进行保存
}
//关闭输入流
input.close();
System.out.println("【" + new String(data,0,foot) + “】”);//将部分字节数组变为字符串输出
}
}
}此类读取数据的方式是在以后的开发之中使用最多的情况

3.3、字符输出流:Writer(输出内容到文件中)

Writer类是在JDK1.1之后增加的,其类的定义如下:
public abstract class Writer extends Object
implements Appendable, Closeable, Flushable
这个类除了实现Closeable与Flushable接口外,又多实现了一个Appendable接口,这个接口定义如下:
public interface Appendable{
public Appendable append(char c)
throws IOException ;
public Appendable append(CharSequence csq)
throws IOException ;
public Appendable append(CharSequence csq,
int start,int end)throws IOException ;
}
在Appendable接口里面定义了追加的操作,而且追加的数据都是字符或者字符串
在Writer类里面定义有一下的输出方法(部分);
·输出全部字符数组:public void write(char[] cbuf)throws IOException
·输出字符串:public void write(String str)throws IOException
Writer是一个抽象类,如果要想为这个类实例化,应该使用FileWriter子类
范例:使用Writer实现内容输出
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class TestWriter {
public static void main(String[] args)throws Exception {
// 1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.txt”);
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs() ;
}
//实例化Writer类对象
Writer out = new FileWriter(file) ;
//进行内容输出
String str = “hello world” ;
out.write(str);//输出字符串数据
out.close();//关闭输出流
}
}

范例:输出字符数组
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class TestWriter {
public static void main(String[] args)throws Exception {
// 1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.txt”);
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs() ;
}
Writer out1 = new FileWriter(file) ;
String str1 = “HELLO WORLD” ;
char data[] = str1.toCharArray() ;//将字符串变为字节数组
for(int x = 0 ;x < data.length ; x ++) {
out1.write(data[x]);//输出全部字节数组
}
out1.close();
}
}
可以发现Writer作为字符输出流,可以直接进行字符串的输出,这一点就比OutputStream强了

3.4、字符输入流:Reader (读取文件内容到中端)

Reader是进行字符数据读取的输入流,其本身也是一个抽象类:
public abstract class Reader extends Object
implements Readable, Closeable
在Reader类里面也提供有一系列的read()方法:
读取内容到字符数组:public int read(char[] cbuf)throws IOException
返回值:表示读取的数据长度,如果已经到结尾了,返回-1;
为Reader类实例化的可以使用FileReader子类完成
范例:使用Reader读取数据
import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class Test {
public static void main(String[] args) throws Exception {
// 1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.txt”);
if(file.exists()) {
Reader in = new FileReader(file) ;
char data[] = new char[1024] ;
int len = in.read(data) ;//将内容保存在字符数组之中,并取得字节数组的长度
in.close();
System.out.println("【" + new String( data,0,len) + “】”);
}
}
}

范例二:读取部分字符数组
import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class TestReader {
public static void main(String[] args) throws Exception {
// 1、定义文件输入路径
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.txt”);
if(file.exists()) {
Reader in = new FileReader(file) ;
char data[] = new char[1024] ;//开辟一个1024长度的字符数组
int foot = 0 ;
int temp = 0 ;
while((temp = in.read()) != -1) {
data[foot ++] = (char) temp ;
}
in.close();
System.out.println("【" + new String( data,0,foot) + “】”);
}
}
}

与字节输入流相比结构几乎一样,只是数据类型由byte更换为了char而已

3.5、字节流与字符流的区别

字节流与字符流最大的区别是,字节流直接与中端进行数据交互,而字符流需要将数据经过缓冲区处理后才可以输出
在使用OutputStream输出数据的时候即使最后没有关闭输出流,那么内容也可以正常输出,但是反过来如果使用的是字符输出流,如果不关闭,那么就表示在缓冲区之中处理的内容不会被强制性的清空,所以就不会输出数据,如果现在有特殊清空不能够关闭字符输出流,可以使用flush()方法强制清空缓冲区

3.6、文件拷贝

范例:实现文件拷贝
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class Demo {
public static void main(String[] args)throws Exception {
long start = System.currentTimeMillis() ;
if(args.length != 2) {
System.out.println(“执行命令错误”);
System.exit(1);
}
File inFile = new File(args[0]) ;
if(!inFile.exists()) {
System.out.println(“源文件不存在,请确认执行路径”);
System.exit(1);
}
//如果文件存在时,那么需要定义输出文件,同时要考虑输出文件目录
File outFile = new File(args[1]) ;
if(!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs() ;
}
//实现文件内容拷贝
InputStream input = new FileInputStream(inFile) ;
OutputStream output = new FileOutputStream(outFile) ;
//实现文件拷贝
int temp = 0 ;
byte data[] = new byte[1024] ;
//将每次读取进来的数据保存在字节数组里面,并且返回读取的个数
while((temp = input.read(data)) != -1) {
output.write(data,0,temp);
}
input.close();
output.close();
long end = System.currentTimeMillis() ;
System.out.println("拷贝花费的时间 : " + (end - start));
}
}

第五十一章:字符编码

计算机中所有的信息组成都是二进制数据,那么所有能够描述出的中文文字都是经过处理后的结果,在计算机的世界里所有的语言文字都会使用编码来进行描述,例如:常见的编码ASCII码。在工作里面最为常见的编码如下:
·GBK、GBK2312:中文的额国标编码,其中GBK包含有简体中文和繁体中文,而GBK2312只包含简体中文
·ISO8859-1:是国际编码,可以描述任何的文字信息
·UNICODE:是十六进制编码,造成传输的无用数据过多
·UTF编码(UTF-8):融合了ISO8859-1和UNICODE编码特点
在以后的所有开发里面,使用的都是UTF-8编码
所谓的乱码最本质的方式就是编码与解码的字符集不统一
内存操作流
针对于内存流,java.io 包里面提供了两组操作:
·字节内存流:ByteArrayInputStream、ByteArrayOutputStream
·字符内存流: CharArrayReader、CharArrayWriter
名称 ByteArrayInputStream ByteArrayOutputStream
继承结构 java.lang.Object
java.io.InputStream
java.io.ByteArrayInputStream java.lang.Object
java.io.OutputStream
java.io.ByteArrayOutputStream
构造方法 public ByteArrayInputStream(byte[] buf) public ByteArrayOutputStream()
表示将要操作的数据设置到输入流 从内存输出数据
以文件操作为例:
输出→(OutputStream):→程序→OutputStream→文件;
输入←(InputStream):←程序←InputStream←文件;
以内存操作为例:
输出(InputStream):→程序:→InputStream→内存;
输入(OutputStream)←程序←InputStream←内存;

范例:实现一个小写字母转大写的操作
public static char toLowerCase(char ch)
public static int toLowerCase(int codePoint)
public static char toUpperCase(char ch)
public static int toUpperCase(int codePoint)

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class TestToUpperCase {
public static void main(String[] args) throws Exception{
String str = "Hello*World!!! " ;
//本次通过内存流实现转换,先将数据保存在内存流里面,而后取出每一个数据
//将所有要读取的数据设置到内存输入流之中,本次利用向上转型
InputStream input = new ByteArrayInputStream(str.getBytes()) ;
//为了能够将所有的内存流数据取出,可以利用ByteArrayOutputStream
OutputStream output = new ByteArrayOutputStream() ;
int temp = 0 ;//读取一个字节数据
//经过此次循环之后,所有的数据都将保存在内存流输出对象之中
while((temp = input.read())!= -1) {//每次读取一个数据
output.write(Character.toUpperCase(temp));//字节输出流
}
System.out.println(output);
input.close();
output.close();
}
}
以上所有的输入和输出流都发生了向上转型,向上转型的好处是可以得到操作模式的统一,但是千万不要忽略一个问题,每一个子类都有每一个子类自己的功能,在ByteArrayOutputStream(向中端输出内容)里面有有一个重要的方法:public byte[] toByteArray(),这个方法可以将所有的保存在内存中的数据变为字节数组存在

范例:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class TestByteArrayOutputStream {
public static void main(String[] args) throws Exception{
File fileA = new File(“e:” + File.separator + “infoa.txt”) ;
File fileB = new File(“e:” + File.separator + “infob.txt”) ;
InputStream inputA = new FileInputStream(fileA) ;
InputStream inputB = new FileInputStream(fileB) ;
ByteArrayOutputStream output = new ByteArrayOutputStream() ;
int temp = 0 ;//每次读取一个字节
while((temp = inputA.read()) != -1) {
output.write(temp);
}
while((temp = inputB.read()) != -1) {
output.write(temp);
}
//现在所有的内容都保存在内存流里面,所有的内容变为字节数组取出
byte data [] = output.toByteArray() ;
output.close();
inputA.close();
inputB.close();
System.out.println(new String(data));
}
}
第五十二章:打印流(打印到文件)

3.2、打印流

为了解决输出数据时的功能不足,所以在java.io包里面又提供了一套专门用于输出数据的类:PrintStream(打印字节流)、PrintWriter(打印字符流)。
以PrintStream类为例,观察一下这个的继承结构与构造方法
java.lang.Object
java.io.OutputStream
java.io.FilterOutputStream
java.io.PrintStream
构造方法:public PrintStream(OutputStream out)
在PrintStream类里面提供有一系列的print()、println()方法,这些方法支持各种数据类型的输出,也就是说如果使用了PrintStream,那么就不会去使用write()方法了
但是整个操作过程之中,发现虽然操作形式不同了,但是本质依然是基于OutputStream类的方法完成的,那么这样的设计,在java之中称为装饰设计模式

范例:打印流
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class TestPrintStream {
public static void main(String[] args) throws Exception {
PrintStream pu = new PrintStream(new FileOutputStream(“e:” + File.separator + “demo” + File.separator + “my.txt”));
pu.print(“hello”) ;
pu.println(“world”);
pu.println(1 + 1);
pu.println(11.5 + 15.7) ;
pu.close();
}
}
范例:PrintWriter
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class TestPrintWriter {
public static void main(String[] args) throws Exception {
PrintStream pw = new PrintStream(new FileOutputStream(“e:” + File.separator + “demo” + File.separator + “my.txt”));
pw.println(“hello”);
pw.append(“world”) ;
pw.println(1+1);
pw.print(1.9+2.7);
pw.close();
}
}
在以后的开发过程之中,只要是由程序输出内容,都会采用打印流的模式完成,但是请一定要记住,打印流依然需要OutputStream的支持

3.3、JDK1.5的改进

所有的输出数据都要求使用打印流完成,但是在JDK1.5之后考虑到市场因素,所以增加了一种新的输出,称为格式化输出:public PrintStream printf(String format,Object… args)
如果要格式化输出就需要一些标记:整数(%d)、字符串(%s)、小数(%m.nf)、字符(%c)

范例:格式化输出
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class TestPrintStream {
public static void main(String[] args) throws Exception {
//格式化输出
String name = “张三” ;
int age = 19 ;
double score = 95.445 ;
PrintStream pu = new PrintStream(new FileOutputStream(“e:” + File.separator + “demo” + File.separator + “my.txt”));

	pu.printf("姓名:%s,年龄:%d,成绩:%5.2f",name,age,score) ;
	pu.close();
}

}

String类格式化方法public static String format(Locale l,
String format,Object… args)
范例:String类格式化
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class TestPrintStream {
public static void main(String[] args) throws Exception {
//格式化输出
String name = “张三” ;
int age = 19 ;
double score = 95.445 ;
String str = String.format(“姓名:%s,年龄:%d,成绩:%5.2f”,name,age,score) ;
System.out.println(str);
}
}

总结:
如果在日后进行程序输出数据操作的话,绝对要使用打印流完成功能

第五十三章 System类对io的支持

在System类里面为了支持IO操作专门提供有三个常量:
·错误输出:public static final PrintStream err
·输出到标准设备(显示器):public static final PrintStream out
·从标准输入设备读取(键盘):public static final InputStream in

3.1、错误输出

System.err是PrintStream类对象,此对象专门负责错误信息的输出操作
范例:输出错误信息
public class TestSystem {
public static void main(String[] args)throws Exception {
try {
Integer.parseInt(“abc”) ;
}catch (Exception e) {
System.err.println(e);
System.out.println(e);
}
}
}
java.lang.NumberFormatException: For input string: “abc”
java.lang.NumberFormatException: For input string: “abc”
严格来讲System.err和System.out的功能是完全一样的,之所以这样设计,主要的目的是不让用户看见错误信息,而out输的是可以让用户看见的信息,但是现在基本上没人在去分了

3.2、信息输出:System.out

System.out是在java之中专门准备的支持屏幕输出信息的操作(此对象由系统负责实例化)

范例:实现屏幕输出
import java.io.OutputStream;
public class TestSystem {
public static void main(String[] args)throws Exception {
OutputStream out = System.out ;
out.write(“hello world”.getBytes());
}
}

3.3、系统输入:System.in

在任何语言里面都有一种功能:键盘输入的操作,但是java本身并没有直接提供,在System类里面有一个in的对象。此对象的类型是InputStream。
范例:实现键盘数据输入
import java.io.InputStream;
public class TestSystem {
public static void main(String[] args)throws Exception {
InputStream input = System.in ;
byte data [] = new byte[1024] ;
System.out.println(“请输入数据:”);
int len = input.read(data) ;
System.out.println(“输入数据为 :” + new String(data,0,len));
}
}
与之前最大的不同只是更换了一个实例化对象。现在已经实现了键盘数据的输入操作,此时输入的时候开辟了一个数组,那么如果说数组的容量小于输入的长度?
那么现在会发现一个严重的问题,超过数组长度的数据将不会被保存,如果在实际的开发之中你永远无法知道用户可能输入的数据是多少,所以这种设置输入长度的的操作不可能使用
范例:
import java.io.InputStream;
public class TestSystem {
public static void main(String[] args)throws Exception {
InputStream input = System.in ;
StringBuffer buf = new StringBuffer() ;
System.out.println(“请输入数据:”);
int temp = 0 ;
while((temp = input.read()) != -1) {
if(temp == ‘\n’) {
break ;
}
buf.append((char)temp) ;
}
System.out.println(“输出的数据为 :” + buf);
}
}

第五十四章 缓冲输入流

缓冲输入是在工作之中,也会被经常大量使用到的工具类,其目的是解决数据乱码的问题
现在最直观的解决方式就是System.in所带来的问题

如果要进行中文数据的处理首先想到的一定是字符流,并且要想完整的处理数据,那么一定需要用到缓冲区,可是对于缓冲区的操作有两种流:
字符缓冲区流:BufferedReader、BufferedWriter
字节缓冲区流:BufferedInputStream、BufferedOutputStream
在给出的缓冲区数据输入流上有两个,其中最为重要的就是BufferedReader,因为在BufferedReader类里面提供有一个重要的读取方法:public String readLine()throws IOException,读取一行数据,以分隔符(换行)为界
继承结构:
java.lang.Object
java.io.Reader
java.io.BufferedReader
构造方法:public BufferedReader(Reader in)
但是如果要想使用BufferedReader类来处理System.in的操作就比较麻烦了,因为System.in是InputStream类型

范例:键盘输入数据的标准格式
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class TestBufferedReader {
public static void main(String[] args)throws Exception {
//System.in是InputStream类的对象
//BufferedReader的构方法需要接受Reader类对象
//利用InputStreamReader将字节流变为字符流
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.println(“请输入数据 :”);
String str = buf.readLine() ;//以回车作为换行
System.out.println(“输入的内容 :” + str);
}
}
此时的输入数据没有长度限制,并且得到的还是String型数据,那么这样就可以实现键盘输入的数据操作了,只不过这种操作一般意义不大。
一直强调使用BufferedReader是因为他可以实现字符串数据的接收,所以现在可以使用正则判断内容

范例:判断输入的内容
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class TestBufferedReader {
public static void main(String[] args) throws Exception {
// System.in是InputStream类的对象
// BufferedReader的构方法需要接受Reader类对象
// 利用InputStreamReader将字节流变为字符流
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
boolean flag = true;
while (flag){
System.out.println(“请输入年龄:”);
String sta = buf.readLine();
if (sta.matches("\d+{1,3}")) {
System.out.println(“年龄是 :” + Integer.parseInt(sta));
flag = false;
} else {
System.out.println(“年龄输入错误,应该由数字组成”);
}

	}
}

}
正是此处可以利用正则进行操作验证,所以在开发之中,只要能够接收的类型是String,那么是最方便的
除了接收输入信息之外,也可以利用缓冲区读取进行文件的读取

范例:读取文件
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class TestBufferedReaderFile {
public static void main(String[] args)throws Exception {
File file = new File(“e:” + File.separator + “demo” + File.separator + “my.txt”) ;
BufferedReader buf = new BufferedReader(new FileReader(file)) ;
String str = null ;
while((str = buf.readLine()) != null) {
System.out.println(str);
}
buf.close();
}
}
与直接使用InputStream(Reader)类相比,使用BufferedReader在进行文件信息读取的时候会更加的方便。

总结:
读取数据不在直接使用InputStream,就好比输出不在直接使用OutputStream一样。

扫描流:Scanner

如果要改进输出功能不足提供有打印流,随后又利用了BufferedReader解决了大文本数据的读取操作但是BufferedReader类有两个问题:
·它读取数据的时候只能够按照字符串返回:public String readLine()throws IOException
·所有的分隔符都是固定的
在JDK1.5之后提供有一个java.util.Scanner的类,这个类专门负责解决所有输入流的操作问题。
构造方法:public Scanner(InputStream source),接收有一个InputStream类对象,表示的是由外部设置输入的位置。
在Scanner类里面定义了以下的两大组方法:
·判断是否有指定数据:public boolean hasNextXxx()
·取出数据:public 数据类型 nextXxx()

范例:以键盘输入数据为例
import java.util.Scanner;

public class TestScanner {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in) ;//准备接受键盘输入数据
System.out.println(“请输入内容 :”);
if(scan.hasNext()) {
System.out.println(“输入内容 :” + scan.next());
}
scan.close();
}
}
Scanner与BufferedReader类相比,Scanner更加的容易,并且操作更为直观。
但是需要提醒的是,如果说现在输入的是字符串,是否存在有hasNext()意义不大,但是如果输入的是其他类型,这个hasNextXxx()就有意义了,为了保持操作的统一性,建议不管是否有用,都先加上hasNext()
判断
范例:输入一个double
import java.util.Scanner;

public class TestScanner {
public static void main(String[] args)throws Exception {
Scanner scan = new Scanner(System.in) ;//准备接受键盘 输入数据
System.out.println(“请输入成绩 :”);
if(scan.hasNextDouble()) {
double score = scan.nextDouble() ; //省略了转型
System.out.println(“输入内容 :” + score);
}else {
System.out.println(“输入的不是数字,错误”);
}
scan.close();
}
}
除了以上支持的各种类型外,也可以在Scanner输入数据的时候设置正则验证
范例:正则验证
import java.util.Scanner;

public class TestScanner {
public static void main(String[] args)throws Exception {
Scanner scan = new Scanner(System.in) ;//准备接受键盘输入数据
//正则验证
System.out.println(“请输入生日 :”);
if(scan.hasNext("\d{4}-\d{2}-\d{2}")) {
String bir = scan.next("\d{4}-\d{2}-\d{2}") ;
System.out.println(“生日是 :” + bir);
}else {
System.out.println(“输入的生日格式错误”);
}
scan.close();
}
}

在Scanner类的构造里面由于接收的是InputStream,所以此时依然可以设置一个文件的数据流,但是在文件读取的时候需要考虑到分隔符问题:public Scanner useDelimiter(String pattern)设置分隔符

范例:读取文件
import java.io.File;
import java.io.FileInputStream;
import java.util.Scanner;
public class TestScannerFile {
public static void main(String[] args)throws Exception {
Scanner scan = new Scanner(new FileInputStream(new File(“e:” + File.separator + “demo” + File.separator + “my.txt”))) ;
scan.useDelimiter("\n") ;//设置读取的分隔符
while(scan.hasNext()) {
System.out.println(scan.next());
}
scan.close();
}
}
现在使用Scanner读取数据的时候综合来讲的确要比BufferedReader简单一些,程序输出数据使用打印流,输入数据使用Scanner(如果发现Scanner不好用了,使用BufferedReader)。
总结:
InputStream类的功能不足已经被Scanner解决了
Reader类的功能不足被BufferedReader解决了
OutputStream类的功能不足被PrintStream解决了
Writer类的功能不足被PrintWriter解决了

对象序列化

3.1、对象序列化

所谓的对象序列化指的就是将保存在内存中的对象数据转换为二进制数据流进行传输的操作,但是并不是所有类的对象都可以序列化,如果要被序列化的对象,那么其所在的类一定要实现java.io.Serializable接口。但是这个接口里面并没有任何的操作方法存在,因为它是一个标识接口,表示一种能力。

第五十六章 类集框架
类集简介
类集就是一组java实现的数据结构。所谓的类集就是对象数组的应用
在之前讲解的时候强调过,如果要想保存多个对象应该使用对象数组,但是传统的对象数组有一个问题,长度是固定的(数组一般不会使用),后来使用链表来实现了一个动态的对象数组,但是对于链表来说有一个最大的感受:
·链表的开发是在是太麻烦了;
·如果要考虑到链表的性能太麻烦了;
·链表使用了Object类进行保存,所有的对象必须发生向上以及强制性的向下转型操作
得出结论:如果在一个项目里面由用户自己去实现一个链表,那么这种项目的开发难度实在是太高了。并且在所有的项目里面都会存在有数据结构的应用,那么在java设计之初就考虑到了此类问题,所以提供了一个与链表类似的工具类——Vector(向量),但是后来随着时间的推移,发现这个类并不能很好的描述出数据结构这一概念,所以从java2(JDK1.2之后)提供了一个专门实现数据结构的开发框架——类集框架,并且在JDK1.5之后由于泛型技术的引入,又解决了类集框架之中,所有的操作类型都是用Object所带来的的安全隐患
随后在JDK1.8里面,又针对于类集的大数据的操作环境下推出了数据流的分析功能
在整个类集里面一共有一下的几个核心接口:
·Collection、List、Set
·Map
·Iterator、Enumeration
总结:
类集就是java数据结构实现,类集就是动态的对象数组

3.2、Collection接口

Collection是整个类集之中单值最大的父接口。即:每一次可以向集合里保存一个对象
定义:public interface Collection extends Iterable

No 方法名称 类型 作用
1 public boolean add(E e) 普通 向集合里保存数据
2 public boolean addAll(Collection<? extends E> c) 普通 追加一个集合
3 public void clear() 普通 清空集合,根元素为null
4 public boolean contains(Object o) 普通 判断是否包含指定内容
5 public boolean isEmpty() 普通 判断是否是空集合(不是null)
6 public boolean remove(Object o) 普通 删除对象
7 public int size() 普通 取得集合中保存的元素个数
8 public Object[] toArray() 普通 将集合变为对象数组保存
9 public Iterator iterator() 普通 为Iterrator对象实例化
在所有的开发之中add()与iterato()两个方法使用的几率是最高的,其他方法机乎可以忽略,但是必须要知道。但是千万要记住,contains()与remove()两个方法一定要依靠equals()支持、
现在已经知道Collention接口的方法了,就应该使用使用子类为这个接口实例化,但是现在的开发由于要求的严格性,所以不会在直接使用Collection接口。而都会去使用它的两个子接口:List(允许重复)、Set(不允许重复)

3.3、List子接口

list子接口的常用子类(ArrayList、Vector)
List子接口(80%)是Collection中最为常用的一个子接口,但是这个接口对Collection接口进行了一些功能的扩充。

No 方法名称 类型 作用
1 public E get(int index) 普通 取得指定索引编号的内容
2 public E set(int index,E element) 普通 修改指定索引编号的内容
3 public ListIteraton listIterator() 普通 为listIterator接口实例化
而Lista本身也是属于接口,所以如果要想使用此接口进行操作,那么就必须存在有子类,可以使用ArrayList(90%)子类实现操作,Vector

3.1 新的子类:ArrayList

ArrayList类是List接口最为常用的子类,下面将用到此类来验证所学习到的方法
范例:List基本操作
import java.util.ArrayList;
import java.util.List;

public class TestList {
public static void main(String[] args)throws Exception {
//设置泛型,从而保证集合中所有的数据类型都一致
List all = new ArrayList() ;
System.out.println(“长度:” + all.size() + “,是否为空:” + all.isEmpty());
all.add(“hello”) ;
all.add(“hello”) ;//重复元素
all.add(“world”) ;
System.out.println(“长度:” + all.size() + “,是否为空:” + all.isEmpty());
//Collection接口定义了size()方法可以取得集合长队
//List子接口扩充了一个get()方法,可以根据索引取得数据
for(int x = 0 ;x < all.size() ;x ++) {
// Object sta[] = all.toArray() ;//将List集合变为Object 数组
// System.out.println(sta[x]);

		String str = all.get(x);//根据集合索引取得集合内容
		System.out.println(str);		
	}
}

}
通过演示可以发现,List集合之中所保存的数据是按照保存顺序存放的。而且允许存在有重复数据,但是一定要记住的是List子接口扩充有get()方法

范例:为Collection接口实例化
·ArrayList是List接口子类,而List由是Collection子接口,自然可以通过ArrayList为Collection接口实例化
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class TestCollection {
public static void main(String[] args)throws Exception {
Collection coe = new ArrayList() ;
coe.add(“hello”);
coe.add(“hello”);
coe.add(“world”);
System.out.println(“集合长度 :” + coe.size() + “,是否为空 :” + coe.isEmpty());
Object str[] = coe.toArray() ;
System.out.println(Arrays.toString(str));//将数组变为String直接输出

	for(int x = 0 ;x < str.length ;x ++) {
		System.out.println(str[x]);
	}
}

}
Collection接口与List接口相比,功能会显得有所不足,而且以上所讲解的输出方法并不是集合所会使用到的标准的输出结构,只是做一个基础展示

总结:
1、list中的数据保存顺序就是数据添加顺序
2、list集合可以保存重复元素
3、list接口比Collection接口扩充了get()方法
4、list选择子类就使用ArrayList子接口

3.2、Set子接口

在Collection接口下又有另外一个子接口为Set接口(20%),Set接口并不像List接口那样对于Collection接口进行了大量的扩充,而是简单的继承了Collection接口,也就没有之前List集合提供的get()方法了
Set接口下有两个常用子类HashSet、 TreeSet
范例:观察HashSet子类特点
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args)throws Exception {
Set all = new HashSet() ;
all.add(“csdn”) ;
all.add(“hello”) ;
all.add(“hello”) ;
all.add(“world”) ;
Object obj [] = all.toArray() ;
System.out.println(Arrays.toString(obj));
}
}
通过演示可以发现,Set集合下没有重复元素(这一点是Set接口的特征),同时发现在里面所保存的数据是没有任何顺讯的,即HashSet子类的特征属于无序排列。

范例:使用TreeSet子类
import java.util.Set;
import java.util.TreeSet;

public class TestTreeSet {
public static void main(String[] args) throws Exception{
Set all = new TreeSet() ;
all.add(“hello”) ;
all.add(“mldn”) ;
all.add(“csdn”) ;
all.add(“hello”) ;
System.out.println(all);
}
}
此时的程序使用了TreeSet子类,没有重复数据,以及所保存的内容自动排序

3.1、关于数据排序的说明

既然TreesSet子类保存的内容可以进行排序,那么下面就编写一个自定义的类来完成数据的保存
范例:排序
import java.util.Set;
import java.util.TreeSet;

class Book implements Comparable{
private String title ;
private double price ;
public Book(String title,double price) {
this.price = price ;
this.title = title ;
}
@Override
public String toString() {
return “书名 :” + this.title + ",价格 : " + this.price ;
}
@Override
public int compareTo(Book o) {
if(this.price > o.price) {
return 1 ;

	}else if(this.price > o.price) {
		return -1 ;
	}else {
		return this.title.compareTo(title) ;//调用了String累的commpareTo()方法
	}
}	

}
public class TestTreeSetBook {
public static void main(String[] args)throws Exception {
Set all = new TreeSet();
all.add(new Book(“java开发”,79.8));
all.add(new Book(“java开发”,79.8));
all.add(new Book(“JSP开发”,109.8));
all.add(new Book(“Android开发”,89.8));
System.out.println(all);
}
}
TreeSet保存的数据量减少了

3.2、关于重复元素的说明

很明显,Comparable接口只能够负责TreeSet子类进行重复元素的判断,他并不是真正能够进行重复元素验证的操作。如果要想进行重复元素的判断只能够依靠Object类中所提供的方法:
·取得哈希码:public int hashCode()
先判断对象的哈希码是否相同,依靠哈希码取得一个对象的内容;
·对象比较:public boolean equals(Object obj)
再将对象的属性进行依次比较

范例:hashcode进行去除重复元素
import java.util.HashSet;
import java.util.Set;

class Book {
private String title ;
private double price ;
public Book(String title,double price) {
this.title = title ;
this.price = price ;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(price);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((title == null) ? 0 : title.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;
Book other = (Book) obj;
if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
@Override
public String toString() {
return “书名 :” + this.title + ",价格 : " + this.price ;
}
}
public class TestHashSetBook {
public static void main(String[] args)throws Exception {
Set all = new HashSet();
all.add(new Book(“java开发”,79.8));
all.add(new Book(“java开发”,79.8));
all.add(new Book(“JSP开发”,109.8));
all.add(new Book(“Android开发”,89.8));
System.out.println(all);
}
}
以后在非排序的情况下,只要是判断重复元素依靠的永远都是HashCode()与equals()

集合输出

Collection、List、Set三个接口里面只有List接口是最方便进行输出操作的
集合在JDK1.8之前支持四种输出:Iterator(95%)、ListIterator、Enumeration(4.9%)、foreach。

3.1.迭代输出:Iterator

如果遇见了集合操作,那么一般而言都会使用Iterator接口进行集合的输出操作
public interface Iterator{
public boolean hasNext() ;
public E next();
}
Iterator本身是一个接口,如果要想取得本接口实例化只能够依靠Collection接口,在Collection接口定义有如下的一个操作方法:Iterator iterator();

范例:Set集合使用Iterator输出集合
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestIterator {
public static void main(String[] args) throws Exception{
Set all = new HashSet() ;
all.add(“张三”);
all.add(“是”);
all.add(“学生”);
Iterator iter = all.iterator() ;
while(iter.hasNext()) {
String str = iter.next() ;
System.out.print(str);
}
}
}

范例:List集合使用Iterator输出集合
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestIteratorList {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“张三”);
all.add(“是”);
all.add(“学生”);
Iterator iter = all.iterator() ;
while(iter.hasNext()) {
String str = iter.next() ;
System.out.print(str);
}
}
}
从今以后只要是集合输出就使用Iterator

3.2、双向迭代:ListIterator

Iterator本身只具备由前向后输出(99%的情况下都是这么做的),有些人认为应该可以由前向后,也可以由后向前输出。那么可以使用Iterator子接口ListIterator接口,有两个重要的方法:
·有没有前一个元素:public boolean hasPrevious() ;
·取得前一个元素:public E previous()
ListIterator是专门问List子接口定义的输出接口,使用的方法是:public ListIterator listIterator()

范例:完成双向迭代输出
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class TestListIterator {
public static void main(String[] args) throws Exception{
List all = new ArrayList() ;
all.add(“张三”);
all.add(“是”);
all.add(“学生”);
System.out.print(“由前向后输出 :”);
ListIterator iter = all.listIterator() ;
while(iter.hasNext()) {//由前向后
String str = iter.next() ;
System.out.print(str + “、”);
}
System.out.print("\n由后向前输出 😊;
while(iter.hasPrevious()) {//由后向前
System.out.print(iter.previous() + “、”);
}
}
}
如果要先实现由后向前输出操作之前,一定要首先发生由前向后输出

3.3、foreach输出

理论而言,foreach输出还是挺方便使用的,但是如果现在过多的使用foreach不利于理解程序。foreach可以方便的输出数组,集合也可以
范例:实现foreach输出
import java.util.ArrayList;
import java.util.List;

public class TestForeach {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“张三”);
all.add(“是”);
all.add(“学生”);
for(String str:all) {
System.out.print(str + “、”);
}
}
}

3.4、Enumeration输出

Enumeration是与Vector类一起在JDK1.0的时候推出的接口,即最早的Vector类要想输出就使用Enumeration接口完成
public interface Enumeration{
public boolean hasMoreElements();//等同于hasNext()
public E nextElement();//取出当前元素等同于next()
}
但是要想取得Enumeration接口实例化对象只能够依靠Vector子类完成,在Vector子类里面定义有如下的额操作方法
·取得Enumeration接口对象:public Enumeration elements()
范例:实现Enumeration输出
import java.util.Enumeration;
import java.util.Vector;

public class TestEnumeration {
public static void main(String[] args)throws Exception {
Vector all = new Vector() ;
all.add(“张三”);
all.add(“是”);
all.add(“学生”);
Enumeration enu = all.elements() ;
while(enu.hasMoreElements()) {
System.out.print(enu.nextElement() + “、”);
}
}
}
总结:
1、虽然集合的输出提供有四种输出方法,但是一定要以Iterator与Enumeration为主,一定要记住其操作形式

Map接口

Collection每一次都只会保存一个对象,而Map主要是负载保存一对对象的信息
Map接口常用的方法:
No 方法名称 类型 作用
1 public V put(K key,V value) 普通 向集合中保存数据
2 public V get(Object key) 普通 根据key查找对应的value数据
3 public Set<Map.Entry<K,V>> entrySet() 普通 将Map集合转化为Set集合
3 public Set keySet() 普通 取出全部的key
在Map接口下有两个常用子类:HashMap、Hashtable
范例:观察HashMap的使用
import java.util.HashMap;
import java.util.Map;

public class TestHashMap {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String , Integer>() ;
map.put(“壹”, 1) ;
map.put(“贰”, 2) ;
map.put(“叁”, 3) ;
map.put(“肆”, 4) ;
System.out.println(map);
}
}
通过以上的操作可以发现如下特点:
·使用HashMap定义的Map集合是无序存放的(顺序无用)
·如果发现出现了重复的key会进行覆盖,使用新的内容替换掉旧的内容
在Map接口里面提供有get()方法,这个方法的主要功能是根据key查找所需要的value
范例:查询操作
import java.util.HashMap;
import java.util.Map;

public class TestHashMap {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String , Integer>() ;
map.put(“壹”, 1) ;
map.put(“贰”, 2) ;
map.put(“叁”, 3) ;
map.put(“肆”, 4) ;
map.put(null, 4) ;
System.out.println(map.get(“壹”));
System.out.println(map.get(null));
System.out.println(map.get(“伍”));//如果key不存在,返回null
}
}
通过以上的代码可以发现,Map存放数据的最终目的是为了信息的查找,但是Collection存放数据的目的是为了输出

范例:取得全部的key
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TestHashMap {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String , Integer>() ;
map.put(“壹”, 1) ;
map.put(“贰”, 2) ;
map.put(“叁”, 3) ;
map.put(“肆”, 4) ;
map.put(null, 4) ;
Set set = map.keySet() ;
Iterator iter = set.iterator() ;
while(iter.hasNext()) {
System.out.println(iter.next());
}
}
}
在Map接口下还有一个Hashtable的子类,此类是在JDK1.0的时候提供的,属于最早的Map集合实现操作,在JDK1.2的时候让其多实现了一个Map接口,从而保存下来继续使用

范例:使用Hashtable
import java.util.Hashtable;
import java.util.Map;

public class TestHashtable {
public static void main(String[] args) throws Exception{
Map<String,Integer> map = new Hashtable<String , Integer>() ;
map.put(“壹”, 1) ;
map.put(“贰”, 2) ;
map.put(“叁”, 3) ;
map.put(“肆”, 4) ;
System.out.println(map);
}
}
现在发现Hashtable里面对于key和value的数据都不允许设置为null

3.1、关于Iterator输出的问题

在之前强调过,只要是集合的输出那么一定要使用Iterator完成,但是在整个Map接口里面并没有定义取得Iterator接口对象的方法,所以下面如果要想使用Iterator输出Map集合,首先必须要针对于Map集合与Collection集合保存的数据的特点进行分析后才能够实现
每当用户使用put()方法向Map集合里面保存一对数据的时候,实际上所有的数据都会被封装为Map.Entry接口对象,那么来观察一下Map.Entry接口的定义:
public static interface Map.Entry<K,V>
在这个接口里面定义了两个操作:
·取得key:public K getKey()
·取得value:public V getValue()
在Map接口里面定义有一个将Map集合转化为Set集合的方法:
public Set<Map.Entry<K,V>> entrySet()
Map集合利用Iterator接口输出的步骤:
·利用Map接口的entrySet()方法将Map变为Set集合,里面的泛型是Map.Entry
·利用Set集合中的iterator()将Set集合进行Iterator输出;
·每一次Iterator循环取出的都是Map.Entry接口对象,利用此对象进行key与value的取出

范例:
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class TestMapIterator {
public static void main(String[] args)throws Exception {
Map<String,Integer> map = new Hashtable<String , Integer>() ;
map.put(“壹”, 1) ;
map.put(“贰”, 2) ;
map.put(“叁”, 3) ;
map.put(“肆”, 4) ;
Set<Map.Entry<String,Integer>> set = map.entrySet() ;
Iterator<Map.Entry<String,Integer>> iter = set.iterator() ;
while(iter.hasNext()) {
Map.Entry<String,Integer> me = iter.next() ;
System.out.println(me.getKey() + “=” + me.getValue());
}
}
}

3.2、关于Map集合中key说明

在使用Map接口的时候可以发现,几乎可以使用任意的类型来作为key或value的存在,那么也就表示可以使用自定义的类型作为key和value

3.3、Stack子类

Stack表示的是栈操作,栈是一种先进后出的数据结构,而Stack是Vector的子类:public class Stack extends Vector
但是需要注意的是,虽然Stack是Vector的子类,可是他不会使用Vector的方法,它使用自己的方法,
·入栈:public E push(E item)
·出栈:public E pop()

范例:观察栈的操作
import java.util.Stack;

public class TestStack {
public static void main(String[] args) throws Exception {
Stack all = new Stack() ;
all.push(“A”);
all.push(“B”);
all.push(“C”);
System.out.println(all.pop());
System.out.println(all.pop());
System.out.println(all.pop());
}
}
在栈操作过程之中,如果栈已经没有数据了,那么无法继续出栈。

总结:
栈的操作现在唯一还算有点能够编程的应用,就是在Android上

3.4、Properties子类

Properties是Hashtable的子类,主要是进行属性的操作,(属性的最大特点是利用字符串设置key和value),首先来观察Properties类的定义结构:public class Properties extends Hashtable<Object,Object>
在我们使用Properties类的时候不需要设置泛型类型,因为从他一开始出现就只能够保存String,在Properties类里面主要使用如下的操作方法
·设置属性:public Object setProperty(String key,String value)
·取得属性:public String getProperty(String key,),如果key不存在返回null
·取得属性:public String getProperty(String key,String defaultValue),如果key不存在返回默认值

范例:属性的基本操作
import java.util.Properties;
public class TestProperties {
public static void main(String[] args) throws Exception{
Properties pro = new Properties () ;
pro.setProperty(“BJ”, “北京”) ;
pro.setProperty(“SH”, “上海”) ;
System.out.println(pro.getProperty(“BJ”));
System.out.println(pro.getProperty(“GZ”,“没有此记录”));
}
}
在Properties类里面提供有数据的输出操作;public void store(OutputStream out,String comments)throws IOException。

范例:将属性保存在文件里面
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
public class TestProperties {
public static void main(String[] args) throws Exception{
Properties pro = new Properties () ;
pro.setProperty(“BJ”, “北京”) ;
pro.setProperty(“SH”, “上海”) ;
System.out.println(pro.getProperty(“BJ”));
System.out.println(pro.getProperty(“GZ”,“没有此记录”));

	//一般而言后缀可以随意设置,但是标准来讲,既然是属性文件后缀必须是*.properties,这样做的目的是为了与国际化对应
	pro.store(new FileOutputStream(new File("e:" + File.separator + "demo" + File.separator + "info.properties")), "info");
}

}
也可以从指定的输入流中读取属性信息:public void load(InputStream inStream)throws IOException

范例:通过文件流读取属性内容
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

public class TestLoadProperties {
public static void main(String[] args) throws Exception {
Properties pro = new Properties () ;
pro.load(new FileInputStream(new File(“e:” + File.separator + “demo” + File.separator + “info.properties”)));
System.out.println(pro.getProperty(“BJ”));
}
}
对于属性文件(资源文件)而言,除了可以使用Properties类读取之外,也可以使用ResourceBundle类读取,这也就是将属性的属性文件统一设置的后缀为*.properties的原因所在

总结:
1、资源文件的特点:
key=value
value;
2、资源文件中的数据一定都是字符串

3.5、Collections工具类

在java提供类库的时候考虑到用户使用的方便性,所以专门提供了一个集合的工具类,——Collections,这个工具类可以实现List、Set、Map集合的操作
为集合追加数据:public static boolean addAll(Collection<? super T> c,T… elements);
范例:实现追加数据
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class TestCollections {
public static void main(String[] args)throws Exception{
List all = new ArrayList();
Collections.addAll(all, “A”,“B”,“C”,“D”) ;
Iterator iter = all.iterator() ;
while(iter.hasNext()) {
System.out.println(iter.next());
}

	Set<String> set = new HashSet<String>() ;
	Collections.addAll(set, "hello","world","hello","csdn");
	Iterator<String> iter1 = set.iterator() ;
	while(iter1.hasNext()) {
		System.out.println(iter1.next());
	}
}

}

Stream接口数据流

在JDK1.8开始发现整个类集里面所提供的接口都出现了大量的default或者static方法
除了使用Iterator迭代取出数据并处理之外,在JDK1.8里面又专门提供一个可以进行数据处理的类:java.util.Stream这个类的对象可以利用Collection接口提供的方法操作:default Stream stream()。
范例:取得Stream类的对象
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class TestStream {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“hello”) ;
all.add(“world”) ;
all.add(“csdn”) ;
Stream stream = all.stream() ; //取得Stream类的对象
System.out.println(stream.count());//取得数据个数
}
}
既然取得了Stream类的对象那么下面进行数据的加工处理操作
范例:取消重复数据
·在Stream类里面提供有一个消除重复的方法:public Stream distinct()
·收集器(最后使用收集):public <R,A> R collect(Collector<? super T,A,R> collector)
Collectors类:public static Collector<T,?,List> toList()
范例:消除集合中重复的内容形成新的集合
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestStream {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“hello”) ;
all.add(“hello”) ;
all.add(“world”) ;
all.add(“world”) ;
all.add(“csdn”) ;
all.add(“csdn”) ;
Stream stream = all.stream() ; //取得Stream类的对象
//System.out.println(stream.distinct().count());//取得数据个数
//去除掉所有的重复数据后形成新的集合数据,里面是不包含重复内容的集合
List all1 = stream.distinct().collect(Collectors.toList());
all1.forEach(System.out::println);
}
}
既然Stream接口是进行数据处理的,那么在数据处理过程之中就不可能不去思考数据的筛选问题(过滤),Stream类里面支持有数据的过滤操作:public Stream filter(Predicate<? super T> predicate)
范例:数据过滤
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestStreamFilter {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“Android”);
all.add(“java”);
all.add(“jsp”);
all.add(“oracle”);
all.add(“Ios”);
Stream stream = all.stream() ; //取得Stream类的对象
//System.out.println(stream.distinct().count());//取得数据个数
//去除掉所有的重复数据后形成新的集合数据,里面是不包含重复内容的集合
List all1 = stream.distinct().filter((x)->x.contains(“a”)).collect(Collectors.toList());
all1.forEach(System.out::println);
}
}
现在整个数据的操作已经成功的实现了过滤,但是有一个缺点,发现这个时候的过滤是区分大小写的,那么证明在对数据进行过滤之前需要对数据进行一些额外的处理,例如统一转大写或者转小写,在Stream接口里面提供有专门的数据处理方法:public Stream map(Function<? super T,? extends R> mapper)

范例:数据处理后过滤
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestStreamFilter1 {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“Android”);
all.add(“java”);
all.add(“jsp”);
all.add(“oracle”);
all.add(“Ios”);
Stream stream = all.stream() ; //取得Stream类的对象
//System.out.println(stream.distinct().count());//取得数据个数
//去除掉所有的重复数据后形成新的集合数据,里面是不包含重复内容的集合
List all1 = stream.distinct().map((x)->x.toLowerCase()).filter((x)->x.contains(“a”)).collect(Collectors.toList());
all1.forEach(System.out::println);
}
}
在Stream接口里面提供有进行集合分页的操作
·设置跳过的数据行数:public Stream skip(long n)
·设置取出的数据个数:public Stream limit(long maxSize)

范例:进行数据分页
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamFilterSkip {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“Android”);
all.add(“java”);
all.add(“jsp”);
all.add(“oracle”);
all.add(“Ios”);
Stream stream = all.stream() ; //取得Stream类的对象
List all1 = stream.distinct().map((x)->x.toLowerCase()).skip(2).limit(2).collect(Collectors.toList()) ;
all1.forEach(System.out::println);
}
}
在Stream接口里面还可以进行数据的全匹配或部分匹配;
·全匹配:public boolean allMatch(Predicate<? super T> predicate)
·匹配任意一个:public boolean anyMatch(Predicate<? super T> predicate)
范例:实现数据的匹配查询
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamMatch {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“Android”);
all.add(“java”);
all.add(“jsp”);
all.add(“oracle”);
all.add(“Ios”);
Stream stream = all.stream() ; //取得Stream类的对象
if(stream.anyMatch((x)->x.contains(“jsp”))) {
System.out.println(“数据存在”);
}
}
}
在实际操作之中有可能会出现多个匹配条件,在断言型的函数式接口提供有如下方法
·或操作:default Predicate or(Predicate<? super T> other)
·与操作:default Predicate and(Predicate<? super T> other)

范例:设置多个条件
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class StreaPredicate {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(“Android”);
all.add(“java”);
all.add(“jsp”);
all.add(“oracle”);
all.add(“Ios”);
Stream stream = all.stream() ;
Predicate p1 = (x)->x.contains(“jsp”);
Predicate p2 = (x)->x.contains(“Ios”);
if(stream.anyMatch(p1.or(p2))) {
System.out.println(“数据存在”);
}
}
}
利用这样的匹配条件,可以针对于数据进行方便的查询操作。
如果要想更好地发挥出Stream的操作优势,必须集合MapReduce一起观察
·数据分析方法:public Optional reduce(BinaryOperator accumulator):就是做数据统计使用的

范例:实现MapReduce
import java.util.ArrayList;
import java.util.List;
class ShopCar{
private String pname ;
private double price ;
private int amount ;
public ShopCar(String pname,double price,int amount) {
this.pname = pname ;
this.price = price ;
this.amount = amount ;
}
public String getPname() {
return pname;
}
public double getPrice() {
return price;
}
public int getAmount() {
return amount;
}
}
public class StreamMapReduce {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(new ShopCar(“干脆面”,0.5,60));
all.add(new ShopCar(“草鸡”,48.0,5));
all.add(new ShopCar(“鲫鱼”,8.0,7));
all.stream().map((x)->x.getAmount()*x.getPrice()).forEach(System.out::println);
}
}
此时已经针对于每一个数据进行处理。但是这个时候处理没有总价,于是要对于处理后的操作使用reduce()完成
范例:统计处理数据
import java.util.ArrayList;
import java.util.List;
class ShopCar{
private String pname ;
private double price ;
private int amount ;
public ShopCar(String pname,double price,int amount) {
this.pname = pname ;
this.price = price ;
this.amount = amount ;
}
public String getPname() {
return pname;
}
public double getPrice() {
return price;
}
public int getAmount() {
return amount;
}
}
public class StreamMapReduce {
public static void main(String[] args)throws Exception {
List all = new ArrayList() ;
all.add(new ShopCar(“干脆面”,0.5,60));
all.add(new ShopCar(“草鸡”,48.0,5));
all.add(new ShopCar(“鲫鱼”,8.0,7));
double sum = all.stream().map((x)->x.getAmount()*x.getPrice()).reduce((su,m)->su + m).get();
System.out.println(“花费总金额 :” + sum);
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值