JAVA入门万字总结
由于图片上传问题,我将文件转化为PDF,这样既可以查看文章图片,也可以下载保存
https://download.csdn.net/download/peterbearXY/15289857
文章目录
- 引言
- 什么是JAVA
- 第一个JAVA程序
- 结果
- JAVA的数据类型
- 内置数据类型
- 引用数据类型
- 内置数据类型
- 整型
- 浮点型
- 字符型
- 布尔型
- 引用数据类型
- 基础类型转换
- 自动类型转换
- 强制类型转换
- JAVA符号
- 算数运算符
- 关系运算符
- 逻辑运算符
- 补充
- JAVA逻辑判断
- if / else
- switch case
- JAVA循环
- for循环
- while循环
- break
- continue
- do while循环
- 判断与循环的应用
- 求最大公因数
- 求100以内的素数
- 不死神兔
- 水仙花数
- 99乘法表
- 求Pi的值
- JAVA函数
- 格式
- 作用域
- void关键字
- 函数调用其他函数
- JAVA数组
- 创建数组
- 访问数组元素
- 遍历数组
- 数组与函数
- 将数组作为参数传入函数
- 将数组作为返回值输出
- 多维数组
- 小案例 Tic-Tac-Toe (井字棋)
- 案例2,打印二维数组初始值
- JAVA类与对象
- 对象创建
- 构造方法
- 无参构造
- 有参构造
- 注意
- 对象方法
- this关键字
- 方法重载Overload
- 对象封装
- 对象继承
- 介绍
- 多态
- 向上转型
- 向下转型
- instanceof关键字
- super关键字
- 对象是引用类型
- 包装类
- JAVA字符串
- 常用方法
- JAVA修饰符
- static
- 静态方法
- 静态代码块
- 静态类
- final
- 最终类
- 最终变量
- 最终方法
- 对象常量
- abstract
- 抽象类
- 抽象方法
- JAVA接口
- 介绍
- interface关键字
- 注意
- 补充
- 案例
- JAVA内部类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
- JAVA泛型
- 泛型方法
- 泛型类
- 泛型接口
- 通配符
- JAVA集合
- Collection接口
- List接口
- ArrayList
- LinkedList
- Set接口
- HashSet
- TreeSet
- Map接口
- Map遍历
- HashMap
- TreeMap
- JAVA常用类
- Arrays类
- Date和Calendar类
- Date
- Calendar
- JAVA异常处理
- 常见异常
- 捕获异常
- Throws 关键字
- 自定义异常类
- JAVA IO处理
- 流的概念
- 流的分类
- 字节流
- 字符流
- 流的使用
- 字节流使用
- 对象流与序列化
- 字符流使用
- 字符流读取缓冲流
- 文件夹操作
- FileFilter接口
- Properties
- 参考文献
- FileFilter接口
- Properties
- 参考文献
引言
学习一门编程语言不是一件难事,在本书的前言我要郑重强调一下这件事。学习如逆水行舟,不进则退;只要大家坚持,相信最后定会有所收获。本书作为一本入门的工具书,会侧重讲解JAVA的基础知识,旨在引导读者进入JAVA的学习大门。
什么是JAVA
JAVA是一种面向对象的高阶编程语言,在JAVA中有句老话:万物皆对象。对于java的介绍我引用百科的一些解释。(Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 [2] 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等)
第一个JAVA程序
由于JAVA是一门面向对象的语言,在运行程序时我们需要单独建立一个类对象,在此类对象的main()函数中运行。废话不多说,直接上代码
public class hello_world
{public static void main(String[] args) {//这样我们就创立好了第一个程序的框架//在main函数里面,我们就可以书写一些需要的指令}
}
作为编程界的惯例,第一个程序当然是在console里面打印"Hello World"
public class hello_world
{public static void main(String[] args) {System.out.println("hello world");}
}
System.out.println() 是一条将程序中的数据打印在控制台,也就是console中的指令
在System.out.println后面有一对括号,在这个里面我们要传入想要打印在console中的内容,即函数的参数
因为要将”hello world“转化为计算机能看懂的语言,所以我们需要在"hello world"外加上双引号,将其转化为字符串类型
这样计算机就能读懂我们的语言,从而输出我们的指令。
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pfoSMW1z-1613061611808)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210128115153341.png)]
JAVA的数据类型
当我们运行JAVA程序时,我们会进行一系列的数学计算,此时拥有存贮数据的变量就尤为重要。在JAVA中为了拥有存储数据的变量,我们往往需要在内存中开辟一道空间,例如:
//在编辑器中的代码变量
int x =5;
int y =6;
//在内存中存储的变量数据, 变量名称我们可以自定义
JAVA的数据类型可以分为2大类
内置数据类型
引用数据类型
内置数据类型
Java 的内置数据类型一共有8种,8种中又可以分为4种。
- 整型: byte, short, int, long
- 浮点型: float, double
- 字符型: char
- 布尔型: boolean
整型
整型顾名思义,它是用来存储整数的
虽然byte, short, int和long都属于整型,但它们之间还是各有差异因为各自的取值不同。
数据类型 | 数据范围 | 数据大小(bit /位) | 默认值 |
---|---|---|---|
byte | -128~127 (-2^7 ~(2^7)-1) | 1 byte= 8 bits | 0 |
short | -32768~32767 (-2^15 ~(2^15)-1) | 2 bytes = 16 bits | 0 |
int | -2^31 ~ (2^31)-1 | 4 bytes = 32 bits | 0 |
long | -2^63 ~(2^63)-1 | 8 bytes = 64 bits | 0L |
一般情况下,我们使用int类型来定义整数,因为int的范围足以满足我们日常的需求
byte a =100;short b = 10000;int c = 100000;long d =10000000;
浮点型
与整型恰好相反,浮点型是用来存储小数的。浮点型分为float和double,两者的区别在于精度。
数据类型 | 数据范围 | 数据大小(bit /位) | 默认值 |
---|---|---|---|
float (单精度浮点型) | 1.4·10^-45 ~ 3.4·10^38 | 4 bytes = 32 bits | 0.0f |
double(双精度浮点型) | 4.9·10^-324 ~ 1.7·10^308 | 8 bytes = 64 bits | 0.0d |
虽然说浮点数可以表示小数,但是浮点数不能表示精确的数,例如货币。如果需要表示精确的数,需要借助其他java类例如Big Decimal来实现。例子: 1.40* 165 = 231 但是 计算机给出的计算是230.999999999997
通常浮点数在未声明的前提下都是double类型,
float f1 = 234.5f;
double d1 = 123.4;
字符型
char类型是一个单一的16位Unicode字符, 表示字符时用单引号。char的范围是0~65535,大小为16 bits
数据类型 | 数据范围 | 数据大小(bit /位) | 默认值 |
---|---|---|---|
char(字符) | 0~65535 | 2 bytes = 16 bits | ‘u0000’ |
对char变量赋值既可以使用数字,也可以使用字符,char可以存储任何字符
public class test {public static void main(String[] args) {char a =65;char b ='A';System.out.println(a);System.out.println(b);}
}
结果
布尔型
布尔类型指true和false,boolean数据只表示1位信息,可作为标志flag来记录true或false
数据类型 | 数据范围 | 数据大小(bit /位) | 默认值 |
---|---|---|---|
boolean | true / false | 1 bit | false |
引用数据类型
- 数组
- 类与对象
- 字符串
下面有一张图来表示引用类型数据
这张图上p1,p2,p3,p4作为类对象,当他们被创建时,他们实际上时作为指针指向一些数据
在本节引用类型暂时提一下,在后面的章节中会详细解释这些
基础类型转换
在运行程序时,我们有时需要将不同类型的数据转化为同一类型
类型转换又可分为自动类型转换与强制类型转换
自动类型转换
自动转换条件是转换前数据类型的位数低于转换后数据类型的位数
转化过程中可能会有精度损失
byte , short , char 可自动转化为int
int 可转化为 long
long 可转化为 float
float 可转化为 double
public class test {public static void main(String[] args) {char a =65;int b = a;System.out.println(a);System.out.println(b);}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWyg1G64-1613061611811)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210128175039057.png)]
强制类型转换
如果被转化数据类型位数大于要转化的数据类型的位数,此时需要用到强制类型转换,注意Boolean类型不能被强制转换
强制转换格式
public class test {public static void main(String[] args) {char a ='A';byte b = (byte)a; //强制将char类型转化为byte类型//其实将这些数据打印出来,也暗含了一层数据转换System.out.println(a);System.out.println(b);}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sf8WSxcn-1613061611813)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210128175841728.png)]
JAVA符号
既然JAVA作为一门计算机编程语言,它一定能像计算器一样为我们做一些运算,所以在本章我们将讲解JAVA的运算符号。
算数运算符
运算优先级和现实生活中一样,括号( ) > * 或 % 或 / > + 或 -
符号 | 含义 | 例子 |
---|---|---|
= | 赋值 | int i =5; 把5赋值给i |
+ | 加号 | int i = (5+6); |
- | 减号 | int j = (6-1); |
* | 乘号 | int k = (7*8); |
/ | 取整 | int a = (7/8); |
/ | 除号 | double c = 7.0 /8; |
% | 取余 | int b = (7%8); |
// | 转义字符 | 写注释用的 |
public class test {public static void main(String[] args) {int i = 5+6;int j = 6-1;int k = 7*8;int a = 9 / 8;double b = 9.0 / 8; //如果想用除法获得小数,必须要用double类型的数据int c = 9 % 8;System.out.println("5+6 = "+i);System.out.println("6-1 = "+j);System.out.println("7*8 = "+k);System.out.println("(整除)9/8 = "+a);System.out.println("(除以)9.0/8 = "+b);System.out.println("(取余)9%8 = "+c);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfkgjWuS-1613061611814)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129202007447.png)]
//优先级测试
public class test {public static void main(String[] args) {double a = (2+1)+3.0/5-6*7-(4/3);System.out.println("(2+1)+3.0/5-6*7-(4/3) = "+a); //注意(4/3) 是取整,结果是1 }
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ACH71YxL-1613061611816)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129202931197.png)]
关系运算符
在运行程序时,我们需要对一些数据进行判断,此时就需要关系运算符
关系运算符判断后,返回true 或 false
符号 | 含义 | 例子 |
---|---|---|
== | 等于 | (6 == 7) false |
!= | 不等于 | (6 != 7) true |
> | 大于 | (6 > 7) false |
< | 小于 | (6 < 7) true |
<= | 小于或等于 | (6 <= 7) true |
>= | 大于或等于 | (6 >= 7) false |
逻辑运算符
和电路图中的逻辑门类似, 逻辑运算符就是
与, 或,非
A为true
B为false
符号 | 含义 | 例子 |
---|---|---|
&& | 与,and,当左边与右边同时为true时返回true | (A && B) false |
|| | 或, or, 左边或右边任意一个满足即返回false | (A||B) true |
! | 非,与所选的条件相反 | !(A||B) false |
补充
看别人的源码时有时会碰到以下的几种符号
符号 | 含义 | 例子 |
---|---|---|
++ | 加一 | a++; a的值加1 |
– | 减一 | b–; b的值减1 |
+= | 加等于 | a += b; 意思是a= a + b; |
-= | 减等于 | a -= b; 意思是 a = a -b; |
/n | 换行 | “/n” |
/t | 水平制表符 | 从左往右数8个空格 |
JAVA逻辑判断
上文我们提到了逻辑运算符与关系运算符,这些符号会给我们返回boolean 类型的数据 :true 或 false
true / false便是用在逻辑判断中的
if / else
假如大家对其他语言,例如python有所了解, 判断通常会使用if else语句,格式如下
if(条件语句){//执行的指令
}
else if(条件语句){//执行的指令
}
//else指的是最终条件,即排除if与else if条件之后
else{//执行的指令
}
例子
在这个例子里面会用到用户输入指令,Scanner
import java.util.Scanner;
public class test {public static void main(String[] args) {Scanner input = new Scanner(System.in); //创建scanner对象,这样就可以从控制台输入System.out.print("a: ");int a = input.nextInt(); //nextInt()指输入的值是int类型数据,该方法是通过对象调用,后面会讲System.out.print("b: ");int b = input.nextInt();//比较a与b的大小if(a>b) {System.out.println("a大于b");}else if(a<b) {System.out.println("a小于b");}else {System.out.println("a等于b");}input.close();}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j6heCkcD-1613061611817)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129210114533.png)]
除此之外,还有嵌套式的if else
if(a > b){if(a > c){//当a大于b 同时 a大于c时,打印"a is MAX"System.out.println("a is MAX");}else{System.out.println("b < a <c ");}
}
switch case
switch case 类似于条件判断,通过switch的判断来选取对应的case,格式如下
switch(condition){case value://actionbreak;case value2://actionbreak;default: //当case中的value没有一个满足condition时,default中的指令才会执行//action
}
例子
//输出输入数字所对应的英文(1-9)
import java.util.Scanner;
public class switch{public static void main(String[] args) {System.out.print("NUM: ");Scanner num = new Scanner(System.in);int digit = num.nextInt();String digitName; //String是字符串类型,属于引用数据类型,在后面有提到switch (digit) {case 1: digitName = "one"; break;case 2: digitName = "two"; break;case 3: digitName = "three"; break;case 4: digitName = "four"; break;case 5: digitName = "five"; break;case 6: digitName = "six"; break;case 7: digitName = "seven"; break;case 8: digitName = "eight"; break;case 9: digitName = "nine"; break; //有时为了节省空间,可以连在一起写default: digitName = "I cannot distinguish this number"; break;}System.out.print(digitName);num.close();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MZpyKBrc-1613061611819)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130101525956.png)]
每个case后面都跟有一个break,用于阻止case1中的action执行完毕后再执行case2的action
反例
import java.util.Scanner;
public class switch2{public static void main(String[] args) {System.out.print("NUM: ");Scanner num = new Scanner(System.in);int digit = num.nextInt();String digitName;switch (digit) {case 1: digitName = "one"; break;case 2: digitName = "two"; break;case 3: digitName = "three"; break;case 4: digitName = "four"; case 5: digitName = "five";case 6: digitName = "six"; break; case 7: digitName = "seven"; break;case 8: digitName = "eight"; break;case 9: digitName = "nine"; break;default: digitName = "I cannot distinguish this number"; break;}System.out.print(digitName);num.close();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hbcY1AyX-1613061611820)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130101720253.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggRlfTKu-1613061611821)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130101740442.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DW41QtCF-1613061611822)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130101843945.png)]
由于没有在case 4和 case 5后面加上break, 无论输入的是4还是5,最终给予digitName的赋值始终是 “six”;
直白点说,break就是用来阻止程序继续向下运行的指令
JAVA循环
学完逻辑判断与基本的运算,接下来我们要了解一下java中的循环,
java的循环如同其他语言一样,包含
- for循环
- while循环
- do while循环
for循环
结构
for(初始值;循环结束条件;初始值变化){//action
}
在for循环中,初始值一般是我们自定义的,例子如下
//我们创造一个for循环,这个循环运行5次,每次打印我们定义的变量的值
for(int i=0;i<5;i++){System.out.println(i);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UxKmB9Ks-1613061611823)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130103416060.png)]
从输出的结果可以看出,当i的值等于5时,条件返回为false,循环终止
while循环
格式
//判断条件指的是满足这个条件时,程序循环运行
while(判断条件){//action
}
例子
//与上面for循环的案例类似
int i=0;
while(i <5) {System.out.println(i);i++; //前面计算符号补充部分有提及,i++指 i = i + 1
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e0XuzCEk-1613061611824)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130104404416.png)]
如果对这个不太明白,下面有一幅图可以解释
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-at8b94pM-1613061611825)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130105844321.png)]
总共运行了5次,在第6次时条件判断为false,所以循环停止
break
while循环还可以与之前switch case里面提到的break一起使用,例子如下
int i=0;
while(i < 7) {//当i 等于 5 时,循环中止if(i == 5) {break; //break的作用是中止循环}System.out.println(i);i++;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRjU0ohf-1613061611826)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130111831321.png)]
continue
与break对应的是continue,break是中止循环
而continue是跳过这一轮循环将要执行的语句,直接进入下一轮循环,例子如下
public class test {public static void main(String[] args) {int i=0;while(i <7) {System.out.println(i);i++;//当i 等于 5时,跳过输出这一轮的 "--------"//由于i++放在前面,所以输出i后, i的值+1, 即在第5轮,输出i=4过后跳过输出 "--------"if(i == 5) {continue;}System.out.println("--------");}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pjRHZxY4-1613061611827)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130112521021.png)]
do while循环
格式
do{//action
}while(判断条件);
do while循环和while循环的区别是:无论条件为何,do while循环都会将action部分执行一遍,例子如下
public class test {public static void main(String[] args) {int i=0;do {System.out.println(i);i++;}while(i<0);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LvRoK3o2-1613061611828)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130124327971.png)]
判断与循环的应用
前面几章我们学习了java的运算符,逻辑判断与循环,这一章举一些例子,灵活运用前面的知识
求最大公因数
题目:求出48与292的最大公因数与最小公倍数,
程序分析:使用辗转相除法
public class LargestFactor {public static void main(String[] args) {int m =48;int n = 292;int a = m; int b = n;int r = a%b;while (r!=0) {a = b;b = r;r = a%b;}int divisor = b; System.out.println("The Greatest Common Divisor:"+divisor);System.out.println("The Lowest Common Multiple:"+(m*n)/divisor);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S6scExTR-1613061611829)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130155438457.png)]
求100以内的素数
题目:输出100以内的素数?
程序分析:素数是大于1的正整数,只能除以它本身与1
public class isprime {public static void main(String[] args) {for(int i=2; i<=100; i++) {boolean isPrime = true;for (int j=2; j<i; j++) {if((i%j) == 0) {isPrime = false;break;}}if(isPrime) {System.out.println(i+" is prime");}}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wZUo3rXp-1613061611829)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130143041470.png)]
不死神兔
题目:古典问题:有一对兔子,从出生后第3个月起都生一对兔子,小兔子长到第3个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少(20个月内)?
程序分析:兔子的规律为数列1,1,2,3,5,8,13,21…(斐波那契数列)
public class Test{public static void main(String[] args){long a=1;long b=1;long c=0;System.out.print(a+"\t"+b);//for循环用来计数for(int i=3;i<=20;i++){//a,b,c交换数据c =a+b;a =b;b =c;System.out.print(c+"\t");}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-URMRdTWP-1613061611830)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130140249510.png)]
水仙花数
题目:打印出1000以内的水仙花数,所谓的“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:152是一个“水仙花数”,因为153 =1的3次方+5的3次方+3的3次方。
程序分析:需要用到for循环,每个数分解出个位,十位,百位
public class flower {public static void main(String[] args) {//水仙花数是三位数,从100开始,到1000结束for(int i=100; i<1000; i++ ) {//第一种获取每位的方法int a = i/100; //对i取整,获取百位的数字int b = (i-a*100)/10; // 减去1的百位上的数字,除以10,获取十位的数字int c = i-100*a-10*b; //个位就是排除十位与百位//第二种获取每位的方法//int a = i/100; //int b = (i%100)/10; //对i除以100取余,再通过10取整,获得百位//int c = (i%100)%10; //对i除以100取余,再通过10取余,获得个位int sum = a*a*a+b*b*b*b+c*c*c;if (sum==i) {System.out.println(i+"是水仙花数");}}System.out.println("Finish");}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXBkYWV8-1613061611831)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130133328919.png)]
99乘法表
题目:输出9*9口诀
程序分析:嵌套式for循环,注意换行
public class test {public static void main(String[] args) {for(int i=1;i<=9;i++) {for(int j=1;j<=i;j++) {System.out.print(j+"*"+i+"="+(i*j)+"\t");}System.out.println();}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eSlfSUmN-1613061611831)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130155506835.png)]
求Pi的值
题目:根据Gregory-Leibniz series, 我们可以计算Pi的值,要求算到第10000个级数
程序分析:Pi = (4/1) - (4/3) + (4/5) - (4/7) + (4/9) - (4/11) + (4/13) … 观察发现规律:分母为奇数,偶数-1,
public class test {public static void main(String[] args) {double rst=0.0;for(int i=1;i<=10000;i++){//判断是偶数还是奇数if(i%2==1){rst += 4.0/(2.0*i-1); //分母为奇数1,3,5,7……}else{rst -= 4.0/(2*i-1);}}System.out.println(rst);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EU9GcD7q-1613061611832)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130160022440.png)]
JAVA函数
函数,大家在初高中应该有所耳闻,例如f (x), f (x) 这个函数有名字f, 同时它也包含一个参数x。设置一个函数可以被我们连续调用,java或者说大部分主流的编程语言都继承了数学中函数的特点。
在本书的前面几章大家应该已经接触到了函数,System.out的println(""),这个就是一个系统类的函数(方法)
我们可以将想要打印在console(控制台)上的内容作为参数传入此函数(方法),它就将内容呈现出来
格式
java的函数(在类对象中也可以叫做方法)格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bTA4Pg2Z-1613061611834)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130182507127.png)]
- 函数返回值类型可以为任意数据类型,int, double, char, string等
- public static 都是修饰符,在后卖会讲到
- return 的值类型一定要与定义函数时一致
在函数或方法中参数还有另外一个名字,形参;而我们传入时的参数叫实参(实际的参数)
作用域
说到函数或方法,那一定要提及作用域,即我们创建的参数能够用在那些范围内
下面我们用一个例子来解释
public class test {public static void main(String[] args) {int a = 8;int b = 9;int c = add(a,b); //当要调用方法时,直接写该函数的名字与应该传入的参数System.out.println(a);System.out.println(b);System.out.println(c);}public static int add(int i, int j) {int a = i + j;return a;}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EZnODs2e-1613061611835)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130184251449.png)]
在上面的例子中,main主函数中的a, b, c是实参;而add函数中的i, j, a都是形参
我们可以看出虽然在main函数与add函数中a都是我们的参数,但是两者为什么都不冲突呢?
因为作用域的不同导致了两者的不同。在add函数中定义的参数的作用域仅仅在add函数中,不超过add,而main函数中定义的参数的作用域也仅仅在main中,无法扩散到add函数中。
假如main函数想要与add函数交换参数,就必须通过形参和return。
void关键字
有心的小伙伴也许已经发现了我们的main函数为什么没有返回值,且是返回值类型是void
void的英文意思是空,即什么也没有
同理,用在函数上时,表示该函数接收参数但不需要有返回值,这个函数就像一个方法一样,如下
//写一个比较大小的程序
public class test {public static void main(String[] args) {int a = 19;int b = 79;int c = 100;MAX(a, b, c); //此时调用MAX方法,没有返回值}public static void MAX(int a, int b, int c) {System.out.println("NUM: "+a+" "+b+" "+c);int max = a;if(a < b) {max =b;if(b < c) {max = c;}}System.out.println("MAX is "+max);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQRe1Svh-1613061611836)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210130190143049.png)]
函数调用其他函数
我们在一个函数中可以调用别的函数,例子如下
public class test {public static void main(String[] args) {int a = 19;int b = 79;int c = 100;MAX(a, b, c);}public static void MAX(int a, int b, int c) {System.out.println("NUM: "+a+" "+b+" "+c);int max = a;if(a < b) {max =b;if(b < c) {max = c;}}print(max); //直接输入函数名与参数就可以使用该函数}//通过print函数我们把max的值打印出来 public static void print(int max) {System.out.println("MAX is "+max);}
}
JAVA数组
上文提到了引用类型数据,在本章我将讲解其中一个引用类型数据:数组
对C语言或其他编程语言有所了解的伙伴应该听说过数组这个定义。数组,顾名思义,是将一系列统一的数据放在一起的组合。比如我们想将 ‘h’,‘e’,‘l’,‘l’,‘o’ 这几个字符放在一起之后再使用,此时我们就需要创建一个 字符类型的数组。
为什么说数组是引用类型的呢?
当我们创立一个数组并赋予其值,并不是在内存中直接开辟含有这些数据的数组,而是将数组的指针指向这些数据。直白点说,数组就像浏览器中的收藏夹,我们需要点击哪个链接(数据)时,就打开这个收藏夹(数组)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hiEMme8-1613061611837)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129163522377.png)]
以char类型的数组为例,接下来将介绍几种创建数组的方法
创建数组
//声明数组变量
char[] words;
char words[];//创建数组的几种方法
//1
//每一组括号前要先声明数组中存储数据的类型
words = new char[5]; //在后面的括号中放的数据是我们所定义的数组的大小//2
words2 = new char[5] //与上一个差不多
//当然声明与创建数组可以放在一起
char[] word = new char[5];//3
char[] words3 = {'h','e','l'.'l','o',};
当第1种和第2种数组创建完毕后,默认内部的5个元素都为’\u0000’(char 类型的默认值);
当第3种数组创建完毕后,默认的元素是初始化的那些元素
import java.util.Arrays;
public class test {public static void main(String[] args) {int[] words = new int[5];char words2[] = new char[5];char[] words3 = {'h','e','l','l','o'};//由于数组无法直接通过System.out.println打印出来,//我们需要调用Arrays包中的toString()方法System.out.println("words "+Arrays.toString(words));System.out.println("words2 "+Arrays.toString(words2));System.out.println("words3 "+Arrays.toString(words3));}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ougL3cAd-1613061611839)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129170236619.png)]
访问数组元素
创建数组是为了储存数据,所以我们应该要明白如何访问/调用数组中的元素
我们需要通过数组的下标来访问数组中的元素
在计算机编程语言中,数组下标几乎都是从0开始(数组中第一个元素),因为这样可以方便计算机的指针读取数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPnPsy1p-1613061611840)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129172730705.png)]
所以数组中第一个元素下标是0,第二个元素下标是1,依次类推。注意最后一个元素的下标必须是(数组长度-1),因为元素下标是从0开始的。
public class array2{public static void main(String[] args) {double[] values = {2,3,4,5};double one = values[0]; //注意获取数组中元素,接收的变量类型应与数组一致double two = values[1];System.out.println(one);System.out.println(two);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6IIEPOJg-1613061611840)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129173312581.png)]
有心的同学应该注意到了,我们存进去的元素是整数类型,为什么最后打印出来是double呢?
因为在存入double类型数组中时,编译器进行了自动类型转换,将整型转化为浮点double类型
遍历数组
为了读取数组中的元素,我们通常使用遍历的方法
通过一组for循环来获取数组中的每个元素
public class array2{public static void main(String[] args) {double[] values = {2,3,4,5};//public int length;是java数组中自带的方法,用于返回该数组的长度for(int i=0;i<values.length;i++) {System.out.println(values[i]);}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mNk9DjfS-1613061611840)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129174548429.png)]
我们还可以使用for-each(也叫增强for)来遍历数组
for(type element : array){System.out.println(element);
}
增强for允许我们在不访问下标的情况下读取数组,十分方便
public class array2{public static void main(String[] args) {double[] values = {2,3,4,5};for(double value: values) {System.out.println(value);}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbhNNukY-1613061611841)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129174548429.png)]
数组与函数
我们可以把数组作为一个返回值或参数放在函数中
将数组作为参数传入函数
public class array2{//add 将数组作为参数传入函数,返回数组中所有元素的和public static double add(double[] values) {double total = 0; for (double element : values){total = total + element;}return total;}public static void main(String[] args) {double[] values = {2,3,4,5};System.out.println(add(values));}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzZI0CFL-1613061611842)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129184602683.png)]
将数组作为返回值输出
import java.util.Arrays;
//将输入数组每个元素加1,并返回
public class array2{public static double[] add(double[] values) {for(int i=0;i<values.length;i++) {values[i] += 1;}return values;}public static void main(String[] args) {double[] values = {2,3,4,5};System.out.println(Arrays.toString(add(values)));}
}
多维数组
我们的现实世界是由多个维度所组成,一条线是一维, 一个平面是二维,我们所在的空间是三维
和现实世界类似,数组也可以创造多个维度
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-26KDN6dx-1613061611843)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129185959447.png)]
创建二维数组或多维数组的方式与一维数组类似
public class test {public static void main(String[] args) {int[][] num = new int[2][3]; //创建一个2行3列的二维数组num[0][0] = 1; //给第一行,第一列的元素赋值为1num[1][0] = 2; //给第二行,第一列的元素赋值为2//因为是二维数组,通过两个for循环来遍历打印for(int i=0;i<num.length;i++) {//num.length是获取二维数组的行数for(int j=0;j<num[0].length;j++) {//num[0].length是获取第一行数组的个数,即num二维数组的列数System.out.print(num[i][j]+" ");}System.out.println();}}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DgaM6fUI-1613061611843)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210129191554891.png)]
在本章中我们有运用到一个数组的工具类, Arrays,在后面常用类中,我们会有详细的解释。
小案例 Tic-Tac-Toe (井字棋)
import java.util.Scanner;
public class TiTaTu{public static void main(String[] args) {//用二维数组模拟棋盘, 0和1代表O和Xint [][] array = {{0,1,0,1},{1,0,0,1},{1,1,1,1},{0,1,0,1},};boolean rst_X = false;boolean rst_O = false;int numOfX_S = 0;int numOfO_S = 0;int numOfX_RS = 0;int numOfO_RS = 0;int k = array.length -1;for(int n=0;n<array.length;n++) {int numOfX_H =0;int numOfO_H =0;for(int m=0;m<array[n].length;m++) {if(array[n][m] == 1) {numOfX_H++;if(numOfX_H == array.length ) {rst_X = true;}}else if(array[n][m] == 0){numOfO_H++;if(numOfO_H == array.length){rst_O = true;}}}if(array[n][n] == 1) {numOfX_S++;if(numOfX_S == array.length ) {rst_X = true;}}else if(array[n][n] == 0) {numOfO_S++;if(numOfO_S == array.length ) {rst_O = true;}}//reverse diagonal lineif(array[n][k] == 1) {numOfX_RS++;if(numOfX_RS == array.length ) {rst_X = true;}}else if(array[n][k] == 0) {numOfO_RS++;if(numOfO_RS == array.length ) {rst_O = true;}}k--;}if(rst_X == true) {System.out.print("X win");}else if(rst_O == true) {System.out.print("O win");}else {System.out.print("Equal");}}
}
案例2,打印二维数组初始值
public class Print2DArray{public static void PrintOut(int[][] array) {for(int i=0; i<array.length;i++) {for(int j=0;j<array[i].length;j++) {System.out.printf("%3d", array[i][j]);}System.out.println();}}public static void main(String[] args) {int[][] a = new int[5][5];PrintOut(a);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9gpzHDwx-1613061611845)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131235733815.png)]
JAVA类与对象
不知道大家以前有没有听说过这样一句话“万物皆对象”。这句话出自Think in Java,一本今典的java书籍。在java中,任何东西都可以被描述成一个类,且每个类都能被用来实例化对象;因为周围的世界是由各种各样的对象所构成,所以我们可以利用java来模拟我们周围的世界,创建各种各样的类例如:学生类,老师类,汽车类,飞机类。
对象创建
创建一个对象的前提是有这个对象的类,我们先创建一个Animal类
package Class_Study;
public class animal {private int age; //private是修饰符,后面会讲public animal(){//action 我们可以在这里添加一些指令}public animal(int num) {age = num;}public void roar() {System.out.println("I am yelling.");}
}
拥有了animal这个类后,我们就可以实例化(创建)一个animal对象
animal Tom = new animal();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5iOegIrB-1613061611846)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131105309311.png)]
以后要是想对animal对象进行一些操作,直接通过Tom调用animal的内部方法(长得像函数的东西)即可。
构造方法
在类中的函数统一称作“方法”
有人也许注意到了在animal类中为什么还有与animal同名的方法呢?
这些方法叫做构造方法,也称构造函数。
无参构造
public animal(){ //public是修饰符System.out.println("I am an animal."); //在无参构造方法里面,我们可以写一些指令
}
像这一个构造方法,就是无参构造方法,当我们实例化对象时,可以不需要添加参数
animal Tom = new animal();
假如我们书写的类中没有写构造方法,如下
package Class_Study;
public class animal {public void roar() {System.out.println("I am yelling.");}
}
此时,编译器会自动给我们加上一个无参构造方法,等同于这样
package Class_Study;
public class animal {public animal(){}public void roar() {System.out.println("I am yelling.");}
}
有参构造
有参构造方法就是在无参构造的基础上增添了参数,方便我们将外部的参数传递给实例化的对象
我们第一个实例化对象的例子中除了有无参构造方法,还有有参构造方法
public animal(int num) {age = num; //将外部的参数num赋值给对象内部的ageSystem.out.println("My age is "+ age); //将age的值输出到控制台上
}
因为是有参构造方法,我们实例化时可以加参数
int age = 3;
animal Tom = new animal(age);
//由于作用域的不同,我们在main函数中定义的age并不与animal对象中的age相冲突
注意
当我们既没有写无参构造也没有写有参构造时,编译器会自动给我们加上一个无参构造方法。
但如果我们自己写了有参构造方法或无参构造方法任意一个以后,编译器就不会自动添加无参构造方法。
对象方法
上面也提到了,在类对象中函数叫做方法method, 除了叫法不同,各种功能与函数一致
package Class_Study;
public class animal {private int age;public animal(){}public animal(int num) {age = num;System.out.println("My age is "+ age);}public void roar() {System.out.println("I am yelling.");}
}
在animal类中,roar就是对象方法。使用roar方法必须通过animal的实例化的对象来调用
public class animalTest {public static void main(String[] args) {animal Tom = new animal(3);Tom.roar();}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pGFaF1y5-1613061611847)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131113112130.png)]
因为在实例化过程中使用了有参构造方法,有参构造方法中有一行指令是打印age: "System.out.println("My age is “+ age);” 所以在控制台中出现 My age is 3
我们通过Tom来调用类方法
Tom.roar();
所以程序执行此方法,在控制台中打印 “I am yelling”
this关键字
this关键字可以用于在本类中调用,本类方法或实例变量; 它也可以用于调用本类中其他构造方法;
this可以理解为当前对象
一个一个分析;
- 实例变量
当我们方法中的形参与类对象中的参数名字一样时,使用this关键字可以避免运行时的error,如下
没有使用this 关键字时
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {age = age;}public void printAge() {System.out.println("My age is "+ age);}public void roar() {System.out.println("I am yelling.");}}
public class animalTest {public static void main(String[] args) {animal Tom = new animal(3);Tom.printAge();}
}
此时的编译器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EtV3iFye-1613061611848)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131115030599.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uVx1YGRR-1613061611849)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131184425189.png)]
为什么我们输的是3,而打印的却是0 ?因为我们并没有将值真正赋给对象的age
为了避免这种无效赋值的情况,我们需要使用this
this的作用相当于告诉编译器,你要把我传进的参数age赋值给类对象的age,然后调用类对象的age打印输出
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this.age = age;}public void printAge() {System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");}}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dchxMTLs-1613061611850)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131184639113.png)]
- 本类方法
为了表示方便,在本类中调用本类方法,可以在调用的方法前加上this
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this.age = age;System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");this.Hungry(); }public void Hungry() {System.out.println("I am hungry!!");}}
这个this加或不加都没关系,编译器会帮我们自动加上
- 调用本类的其他构造方法
this可以调用构造方法,这样能避免相同初始化代码
this()是用来调用无参构造方法的
没加this()
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this.age = age;}public void printAge() {System.out.println("My age is "+ this.age);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvACJehR-1613061611851)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131185804560.png)]
加上this();
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this(); //必须方法构造方法最前面this.age = age;}public void printAge() {System.out.println("My age is "+ this.age);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZwmzIw2j-1613061611852)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131185909356.png)]
可见,加上this()就调用了animal的无参构造方法
注意,this();必须在调用的方法最前面
this(a); 可以调用有参构造方法, a是有参构造需要的参数,例子如下
public class animal {private int age;public animal(){this(3);System.out.println("I am an animal.");}public animal(int age) {this.age = age;}public void printAge() {System.out.println("My age is "+ this.age);}
}
//测试类
public class animalTest {public static void main(String[] args) {animal Tom = new animal();Tom.printAge();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-apcvmb6p-1613061611853)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131190535142.png)]
我们直接调用animal的无参构造,但是age是有初始值的,就是我们在无参构造中this(3);传入的age。
方法重载Overload
方法可以重载,当然之前学习的函数也可以重载;重载后的方法可以接收不同参数
所谓的重载Overload针对同一个类,在这个类里面可以包含名字相同但是接收参数不同的的方法。例子如下。
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this();this.age = age;}public void printAge() {System.out.println("My age is "+ this.age);}//对printAge进行Overloadpublic void printAge(int year) {this.age += year;System.out.println("After "+year+" years. My age is "+this.age);}
}
public class animalTest {public static void main(String[] args) {animal Tom = new animal(3);Tom.printAge();Tom.printAge(4);}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9I3kwb1h-1613061611854)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131195018061.png)]
其实方法的重载就像无参构造方法与有参构造方法一样
对象封装
封装,顾名思义将数据封起来,不让外界轻易访问。在java开发时,我们有时不希望外界访问或改变我们设计好的数据,此时需要将这些数据封装起来。
为了封装数据,我们需要一些访问修饰符,例如public, private(这些在前面大家应该已经遇到了,但是不知道是什么)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vVjr7yf7-1613061611855)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131201852288.png)]
一般用访问修饰符时,都用public 或 private ,public定义的数据都可以访问,但是private的只有本类才能访问
封装可以使数据更安全,假如说想要获取或改变数据,可以使用get, set, 例子如下
public int getAge() {return age;
}
public void setAge(int age) {//有set的好处就是,假设在给age赋值时传入的时string类型或其他类型,set里面可以加上判断this.age = age;
}
对象继承
介绍
聊完上面几章,我们进入对象中比较重要的环节,对象继承,这就像儿子与父亲一样,所以被继承的类大家称为父类,继承的类称之为子类
子类对于父类的继承
- 子类继承父类所有public方法与属性, 也可以添加自己独有的方法
- JAVA继承遵循单一继承关系, 即一个子类只能继承一个父类
- 当子类添加自己方法时可以对父类方法进行覆盖, override。 例如父类可以使用a方法,子类继承a方法,可以再写一遍a方法,使a方法实现另一种
//继承语法: class B extends A{ } //B是子类, A是父类, 子类继承父类
例子
package Class_Study;
//animal是父类
public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this.age = age;System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");}}
package Class_Study;public class TestForAnimal {public static void main(String[] args) {Dog kit = new Dog();kit.roar();}
}
class Dog extends animal{Dog(){System.out.println("I am a dog.");}//方法覆盖overridepublic void roar() {//super.roar();这个super关键字后面再讲System.out.println("I am hungry. I need meat");}
}
在实例化子类对象时,我们会先调用父类的默认构造方法,再调用子类的构造方法,
这就是为什么会出现"I am an animal"
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zzGaJQ6b-1613061611856)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210131234622162.png)]
在上面这个例子中,dog类是animal类的子类,它继承了父类的方法
Dog kit = new Dog(); //实例化子类对象,调用子类的无参构造方法
在具有继承关系的创建中,系统先创建父类再创建子类。 如果有默认的构造方法, 先调用父类A的默认无参构方法,再调用子类B的所属构造方法。 这就是为什么我们调用dog类的无参构造方法时,先打印“I am an animal.”,再打印“I am a dog.”
//方法覆盖overridepublic void roar() {System.out.println("I am hungry. I need meat");}
在子类中,子类拥有与父类相同的方法,这样可以对父类的方法进行覆盖,(方法的Override必须是方法一样)(即访问修饰符+返回值类型+名称+传入参数类型一样)
多态
世间万物都有属于自己的类,这些类之间又可以进行分类,例如汽车,飞机等可以被分在(继承)交通工具类里面;老师,学生,家长可以被分在(继承)人这个类里面。我们可以用交通工具类或人类来作为汽车或学生宽泛的表示方法。
- 使用父类作为方法形参实现多态, 使方法参数类型更为宽泛
- 使用父类作为方法返回值实现多态, 使方法可以返回不同子类对象
例子: A a = new B(); A是B的父类
使用多态时,只能使用父类的方法或子类覆盖父类的方法, 例如
//例子
package Class_Study;public class animal {private int age;public animal(){System.out.println("I am an animal.");}public animal(int age) {this.age = age;System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");}}
package Class_Study;public class TestForAnimal {public static void main(String[] args) {animal kit = new Dog();kit.roar(); // 作为父类的kit只能调用子类覆盖后的方法或自己本身的方法}
}
class Dog extends animal{ //狗类继承了父类animal类,覆盖了roar()这个方法Dog(){System.out.println("I am a dog.");}//方法覆盖overridepublic void roar() {System.out.println("I am hungry. I need meat");}public void run() {System.out.println("I can use four legs to run!!");}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R2PomW1Q-1613061611856)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202104457940.png)]
假设我们作为父类,再调用子类的方法,例如这个:用kit animal类调用dog子类的run方法,出现错误
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I5o8Lhwj-1613061611857)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202104550114.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OCuMepQD-1613061611858)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202104646229.png)]
向上转型
格式
//Animal类是Dog类的父类
Animal a = new Dog()
刚才上面那个例子就使用了向上转型的方法(子类转为父类)。
向下转型
向下转型前提是 原来实例是子类(先向上转型):
Animal a = new Dog()
Dog dog = (Dog) a //利用强转向下转型
多态的好处是有很强的扩展性,例如这样
speak(new Cat());
speak(new Dog());//此时我们将cat类与dog类作为参数传进去
public void speak(Animal a){a.roar(); //函数会自动向上转型,调用cat与dog类中Override父类Animal的roar方法
}
instanceof关键字
向下转型前,应判断引用中对象的真实类型,以达到准确性
语法, (dog instanceof animal)//返回结果为boolean
if (args instanceof type) {type new_name = (type) args;
}
package Class_Study;public class TestForAnimal {public static void main(String[] args) {animal animal = new Dog();if (animal instanceof Dog) { //判断animal的真实类型是否是Dog类,是的话进行向下转型Dog dog = (Dog) aanimal;dog.run();}}
}class Dog extends animal{Dog(){System.out.println("I am a dog.");}//方法重写overridepublic void roar() {System.out.println("I am hungry. I need meat");}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQxxYVnP-1613061611859)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202115137520.png)]
super关键字
作为子类,我们继承了父类的方法,但当我们继承父类后并Override父类方法后,我们就不能再使用父类的方法,为了能再次使用,我们需要使用super关键字
和this()一样,super()必须是第一条语句
可以调用父类的属性和方法
super.upload() // 父类的方法
super.value //父类的属性,注意这个属性必须是public公共属性,私有属性无法继承
例子,调用父类属性
public class Value {public static void main(String[] args) {B b =new B();b.print();}
}
class A{int value =10;
}class B extends A{int value = 20;public void print() {int value =30;System.out.println(value); //就近原则,选取本方法中的valueSystem.out.println(this.value); //this调用本类中的valueSystem.out.println(super.value);//super调用父类中的value}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rhj3h0qR-1613061611859)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202121542748.png)]
例子,调用父类的方法
package Class_Study;
//父类
public class animal {private int age;public animal(){}public animal(int age) {this.age = age;System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");}}
package Class_Study;
//子类
public class TestForAnimal {public static void main(String[] args) {Dog dog = new Dog();dog.roar(); }
}class Dog extends animal{Dog(){System.out.println("I am a dog.");}//方法重写overridepublic void roar() {super.roar(); //通过super调用父类的roar方法System.out.println("I am hungry. I need meat");}public void run() {System.out.println("I can use four legs to run!!");}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ObOJS1cO-1613061611860)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202122338431.png)]
super也可以调用父类构造方法
super() // 调用无参构造方法
super(5, 6) //调用有参构造方法
在继承章节开头我们碰见的那个例子里面,当调用我们调用子类构造方法时,系统会自动调用父类的无参构造方法,即在子类无参构造之前加上super();如下
package Class_Study;
//父类
public class animal {private int age;public animal(){//父类的无参构造System.out.println("I am an animal.");}public animal(int age) {this.age = age;System.out.println("My age is "+ this.age);}public void roar() {System.out.println("I am yelling.");}}
package Class_Study;
//子类
public class TestForAnimal {public static void main(String[] args) {Dog dog = new Dog();}
}class Dog extends animal{Dog(){super();System.out.println("I am a dog.");}//方法重写overridepublic void roar() {super.roar();System.out.println("I am hungry. I need meat");}public void run() {System.out.println("I can use four legs to run!!");}
}
加上super()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Ggqw58j-1613061611862)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202122732411.png)]
没加super()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnFoirY4-1613061611862)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202122802897.png)]
编译器默认调父类无参构造方法(在没加super()的前提下),不管子类调用的是否是无参还是有参构造
当C对象继承B对象,B对象继承A对象时,实例化C对象,先调用A的无参构造,然后调用B的无参构造,最后调用C的无参构造
//子类调用父类的有参构造
Dog(){super(3); //在Dog子类的无参构造方法中,调用父类的有参构造System.out.println("I am a dog.");
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZfTYONx-1613061611862)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202123738106.png)]
对象是引用类型
为什么说对象是引用类型?
我们new一个对象,其实是用一个指针指向这个部分数据集合,例子如下
//创建一个Point类,有x,y值
public class Point {private int x;private int y;public void SetPoint(int x, int y){this.x =x;this.y =y;}public void show() {System.out.println("("+this.x+" , "+this.y+")");}
}
public class TestPoint {public static void main(String[] args) {//实例化一个Point类Point a = new Point();//将a点的地址传入SetPoint函数SetPoint(a);//如果对象不是引用类型,a点的x,y值就不会改变a.show();}public static void SetPoint(Point b) {b.SetPoint(5, 5);}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ko0rP80P-1613061611862)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202215944627.png)]
上面例子的box diagram
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQCsyKc1-1613061611863)(C:\Users\23881\OneDrive - Rose-Hulman Institute of Technology\未命名.jpg)]
包装类
由于基本类型不是对象,在万物皆对象的JAVA中,我们有时需要将这些数据封装成对象,这就是包装类
基本数据 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
基本类型封装的好处
- 方便进行对象操作
- 便于数据与字符串之间的转换
例如:将数字1转为字符串1,再将字符串1转为数字1
public class NumDemo1
{public static void main(String[] args) {int i =1;//把基本数据int封装成IntegerInteger num = new Integer(i);//数字转为字符串String word = num.toString();//打印转成的类型System.out.println(word.getClass());//将字符串转为数字,打印转成的类型System.out.println(Integer.valueOf(word).getClass());}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ikgqHyJ3-1613061611864)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210209194231137.png)]
JAVA字符串
在前面大家已经不止一次接触到了字符串String类型数据,String字符串是一个功能强大的类,它可以将多个字符放在一起,如下
char word = 'h';
String words = "hello world";
字符串与字符有一点区别:字符串内容放在双引号内,而字符则是单引号。
特点
- 字符串是常量,创建后不可改变
- 字符串字面值储存在字符串池中,可以共享
- String str = new String(“Java”)在堆里面创建一个对象
常用方法
public int length() //返回字符串长度
public char charAt(int index) //根据下标获取字符
public boolean contains(String str) //判断当前字符串是否包含传进去的字符str
public int indexOf(String str)//查找str首次出现的下标,存在则返回该下标,不存在则返回-1
public int lastIndexOf(String str)//查找字符串当中最后出现的下标索引
public String trim()//去除字符串前后的空格
public String toUpperCase()//全部转为大写
public boolean endWith(String str)//判断字符串是否是以str结尾
public boolean startWith(String str)//同样,也有以str开头的判断
public String replace(char oldChar, char newChar)//将原来旧的字符串替换为新的字符串
public String concat(String s)//返回连接后的字符串, s是加在后面的字符串
public String substring(int beginIndex, int endIndex)//返回一个分割过后的字符串
public char[] toCharArray()//将字符串转换成数组
Arrays.toString(char[] string)//为了将数组内的字符打印出来,调用Arrays工具类
下面用一串代码来演示如何使用这些方法
package StringStudy;import java.util.Arrays;//为了把数组中的内容转成字符串并打印出来public class Demo1 {public static void main(String[] args) {String words = "hello";System.out.println(words);words = "world";System.out.println(words);String str = new String("Java");String str2 = new String("Java");System.out.println("str与str2是否在同一地址:"+(str == str2));System.out.println("str与str2是否内容完全相同"+str.equals(str2));System.out.println("words在第一个的字符串是:"+words.charAt(0));System.out.println("将words转化为数组后的 Array:"+Arrays.toString(words.toCharArray()));System.out.println("将words转化为数组后的Array[0]:"+words.toCharArray()[0]);System.out.println("判断words中是否含有w:"+words.contains("w"));System.out.println("判断words中是否含有wd:"+words.contains("wd"));System.out.println("返回对应字符串rd的下标:"+words.indexOf("rd"));words = "hello";System.out.println("返回对应字符串l的下标:"+words.indexOf("l"));System.out.println("返回对应字符串l最后的下标:"+words.lastIndexOf("l"));String student = " Peter Bear ";System.out.println("After deleting SPACE in String----"+student.trim()+"----");System.out.println("将字母全部改为大写:"+student.toUpperCase());System.out.println("将原来的字符串中的内容进行替换:"+student.replace("ear", "ear is 18 years old."));String website = "www.peterbear.com";System.out.println("返回在原来的字符串后面增添内容的字符出:"+student.concat("'s website: ").concat(website));}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPyl6PwK-1613061611865)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210202231723332.png)]
JAVA修饰符
再类对象封装中我们提到的private, public属于JAVA的访问修饰符;在本章我们将介绍其他的修饰符:非访问修饰符
static
static中文翻译是静态,所以关于static 的方法和属性叫做静态属性和静态方法
使用静态修饰符后程序会发生哪些变化?
静态属性和方法利用类名进行调用(假如说一个类仅含有static成员,那么这个类被称作工具类)
静态成员是全类所共享的成员
static 关键字用来声明独立于对象的静态变量(静态属性),无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
//静态属性
static int count=10;
例子如下
package modifier;
//创建一个类,这个类有静态属性与非静态属性,含静态方法与非静态方法
public class StaticStudy {public int cnt=0; //非静态属性public static int cnt2=0; //静态属性,静态变量public void add() {cnt++;}public static void add2() {cnt2++;}public void show() {//因为静态成员是全类所共享的成员,所以非静态方法可以调用静态成员变量System.out.println("非静态计数器"+cnt);System.out.println("静态计数器: "+cnt2);}
}
package modifier;public class TestStatic {public static void main(String[] args) {StaticStudy num = new StaticStudy();//实例化一个类对象num.show();//初始值,调用show非静态方法num.add();StaticStudy.add2();//通过类名调用静态方法num.show();//add后的值System.out.println("类名调用静态属性: "+StaticStudy.cnt2);//类名调用静态属性System.out.println("----实例化第二个对象"+"----");StaticStudy num2 = new StaticStudy();//再实例化一个类对象num2.add();StaticStudy.add2();num2.show();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3pDt1S75-1613061611866)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203133932014.png)]
从上面例子我们不难发现无论一个类实例化多少对象,它的静态变量只有一份拷贝。
静态方法
特点
- 静态方法可以直接访问静态成员
private static int cnt3=0;
public static int cnt2=0; //静态属性,静态变量
public static void add2() { //静态方法给cnt2加一cnt2++;}
- 但是静态方法不能直接访问非静态成员
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sc5hPlgF-1613061611867)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203125411520.png)]
- 静态方法不能使用this和super关键字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ARoVq8mg-1613061611867)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203134731231.png)]
- 静态方法不能重写,只能继承,没有多态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PGG1TWGV-1613061611868)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203135945647.png)]
静态代码块
static{ }
//整个程序执行过程中,只执行一次
//可以执行一些必要的初始化行为//与其相反的是非静态代码块
{}
静态代码块中只能放静态成员
系统初始化过程:静态代码块---->main函数---->非静态代码块---->构造函数
这里请参考下面的链接
静态类
倘若一个类是静态的,它一定是静态内部类//这个在讲到内部类的时候再具体分析
final
final意为最终的,最后的,即不可变的
最终类
final修饰的不能被继承, 例如String, Math,System类,这些类的均无法被继承
当FinalStudy准备继承Point类时,由于Point类是被final修饰,所以无法被继承
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-op8xRSgo-1613061611868)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203144245874.png)]
最终变量
final int num = 10;
final static string address = "school";
只能被赋值一次(常量)
1. 在构造方法中赋值
如果有一个对常量赋值,其他的构造方法都要对其进行赋值
2. 创建常量时直接赋值
我们创建了一个Point类,使用final修饰了原点,当我们想要改变原点数据时,失败
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvHcb2d3-1613061611870)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203145808713.png)]
对于最终变量有两种初始化方法,
第一种:直接创建时就赋值
final int Origion_x=0;
final int Origion_y=0;
第二种:使用代码块进行赋值
final int Origion_x;
final int Origion_y;
{Origion_x=0;Origion_y=0;
}
第三种:在构造方法中
final int Origion_x;
final int Origion_y;
Point(){Origion_x=0;Origion_y=0;
}
倘若变量用static + final修饰,为静态常量,初始化要在静态代码块中进行
第一种:直接创建时就赋值
static final int Origion_x=0;
static final int Origion_y=0;
第二种:使用代码块进行赋值
static final int Origion_x;
static final int Origion_y;
static{Origion_x=0;Origion_y=0;
}
最终方法
不能被子类覆盖或者重写,只能继承
我们给父类的Print方法加上final修饰后,子类FinalStudy无法Override Print方法,所以只能继承该方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfanjxGD-1613061611870)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203144655295.png)]
例子如下
package modifier;public class FinalStudy extends Point{}class Point{private int x;private int y;public void SetPoint(int x, int y) {this.x =x;this.y =y;}public final void Print() {System.out.println("( "+this.x+", "+this.y+" )");}
}
package modifier;
//测试
public class TestFinal {public static void main(String[] args) {FinalStudy point = new FinalStudy();point.SetPoint(1, 2);point.Print();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jlc1QG5v-1613061611871)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203145143119.png)]
对象常量
final修饰基本类型:值不可变
final 修饰引用类型:地址不可改变
例子如下
class Point{private int x;private int y;static final int Origion_x;static final int Origion_y;static{Origion_x=0;Origion_y=0;}public void SetPoint(int x, int y) {this.x =x;this.y =y;}public void Print() {System.out.println("原点: "+"( "+Origion_x+", "+Origion_y+" )");System.out.println("( "+this.x+", "+this.y+" )");}
}
package modifier;import java.util.Arrays;public class TestFinal {public static void main(String[] args) {final int[] nums = new int[] {1,3,5,7};System.out.println(Arrays.toString(nums));
// nums = new int[] {5,6,7};//此时不能对nums再进行赋值,因为已经nums已经变成了常量nums[0] = 9; //但是nums内部的数据可以进行更改,因为nums是引用类型System.out.println(Arrays.toString(nums));final Point p1 = new Point();p1.SetPoint(6, 6);p1.Print();p1.SetPoint(10, 10);p1.Print();}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vMvOHovl-1613061611871)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203154357345.png)]
abstract
abstract中文意思是抽象,抽象即为不具体
抽象类
一个类不能同时被abstract和final修饰
当类对象没有具体的含义,可以将该类改为抽象类
例如Animal类,它本身没有任何意义各种方法比较抽象,但是继承Animal类的子类Dog类和Cat类有意义,所以要把Animal类改为抽象类
作用:
- 可以被子类继承,提供共性的属性和方法
- 可以声明为引用,更自然的使用多态
抽象类当中可以包含抽象方法,也可以包含非抽象方法
//语法:
public abstract class Animal{ }
如果一个类被改为抽象类,该类就不可以被实例化, 即不能new 对象;但是我们能够用这个类来作为引用,就像多态向上转型一样
下面是一个关于抽象类的例子
package modifier;public class TestAbstract {public static void main(String[] args) {Dog dog = new Dog();dog.speak();Animal bird = new Bird(); //可以声明为引用,更自然的使用多态bird.speak();//dog和bird调用父类的walk方法dog.walk();bird.walk();}
}abstract class Animal{public abstract void speak();public abstract void move();//抽象类中包含非抽象方法public void walk() {System.out.println("I am walking");}
}class Dog extends Animal{@Overridepublic void speak() {System.out.println("Wang Wang Wang……");}@Overridepublic void move() {System.out.println("Dog uses his four legs to run");}
}class Bird extends Animal{@Overridepublic void speak() {System.out.println("Yin Yin Yin……");}@Overridepublic void move() {// TODO Auto-generated method stub}}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5xEga0Yh-1613061611872)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203162947766.png)]
抽象方法
一但类当中包含抽象方法,此类必须是抽象类
父类对象的方法本身没有意义,但为了实现多态(向上转型)又不得不保留
Animal dog = new Dog();
dog.eat();
抽象方法只有方法的声明,没有方法实现,此外抽象方法只能在抽象类当中
//格式
public abstract void eat();
子类继承父类,子类必须重写父类的抽象方法,否则子类必须是抽象类
//抽象的felid猫科动物类继承抽象的动物类,其中增添了抽象的猫科动物捕猎方法
abstract class felid extends Animal{abstract void hunt();
}
抽象类与抽象方法的小案例:
建立一个Vehicle的交通工具抽象类和一个主人类,打印主人回家时开的什么车,是什么品牌
package Polymophic_And_Abstract;public class Master {private final String name; //将主人的名字封装起来public Master(String name) {this.name = name;}public String getName() {return name;}public void GoHome(Vehicle vehicle) {System.out.println(this.getName()+"回家了");vehicle.run();}
}
package Polymophic_And_Abstract;public class TestForVehicle {public static void main(String[] args) {Master jim = new Master("Jim");Vehicle car = new Car("奔驰");jim.GoHome(car);}
}//创建一个抽象的Vehicle类
abstract class Vehicle {private final String band;public Vehicle(String band) {this.band = band;}public String getBand() {return band;}//一个抽象方法public abstract void run();}
//Car继承抽象的Vehicle交通工具类
class Car extends Vehicle{public Car(String band) {super(band);}
//implements 实现run()方法@Overridepublic void run() {System.out.println(super.getBand()+"牌的车在路上跑");}}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LD8zFs2k-1613061611872)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203170116415.png)]
JAVA接口
介绍
接口相当于是特殊的抽象类,定义方法,组成部分与抽象类类似
接口没有构造方法,所以不能创建对象但是可以implements,一个类可以实现多个接口,例如
C extends A implements B implements C
接口也可以和父类一样实现多态(向上转型)
仅可调用接口中实现的方法,不能调用实例化对象所独有的方法
接口往往可以代表一种能力,一但类对象实现了该接口,它也具备了这种能力
实现接口时,访问修饰符必须是public
接口与抽象类相同之处:
- 可编译成字节码文件
- 不能创建对象
- 可以作为引用类型 // 当作为引用类型时,仅可调用实现了的接口;
- 具有Object类中定义的方法(Object类是所有类对象的父类)
不同之处:
- 接口所有属性都是用public static final修饰
- 接口所有方法都是用public abstract 修饰
- 接口没有构造方法,动态代码块和静态代码块
类无法使用多继承,但是接口可以实现多继承接口
package Interface;public interface Ability extends flyable, swimmable{public abstract void fire();
}interface flyable{public abstract void fly();
}interface swimmable{public abstract void swim();
}
interface关键字
类对象是class,而接口则是interface
public interface A{ public static final String FIELD = "Value" public abstract void method();
}
注意
接口只能定义:公开静态常量 和***公开抽象方法***
public static final String FIELD="Value"; //公开静态常量,使用时,直接用接口进行调用
public abstract void method();//公开抽象方法只用写返回值类型和方法名
类一但implement就必须实现覆盖接口中全部抽象方法,此类就是该接口的实现类
补充
标记接口,例如Serializable接口
public interface Serializable{}; //表示实现这个接口的对象可以被序列化和克隆
public interface Cloneable{};
案例
- 给人实现飞的能力
//先创建fly的接口
package Interface;public interface fly {public abstract void fly();
}
//然后创建一个人类,来实现fly接口
package Interface;public class Person implements fly{String name;int age;Person(String name, int age){this.name= name;this.age = age;}public void eat() {System.out.println(this.name+" 在吃饭……");}public void sleep() {System.out.println(this.name+" 在睡觉……");}//由于继承了接口,我们必须实现接口的方法@Overridepublic void fly() {System.out.println(this.name+" can fly");}
}
//写一个测试类
package Interface;public class TestPerson {public static void main(String[] args) {Person jim = new Person("Jim",20);jim.fly();//利用接口作为引用类型fly baby = new Person("baby", 30);baby.fly();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKnAsRfa-1613061611874)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203194232960.png)]
- USB案例
USB接口是大家熟知的一种接口,风扇,U盘,都是USB接口,我们要将USB接口插入电脑
//1先创建USB接口
package USB_Interface;public interface USB {public abstract void Service();
}
//2实现Fan,U盘的接口
//U盘
public class USB_Flash implements USB {@Overridepublic void Service() {System.out.println("USB-Flash has connected to the computer");}}
//风扇
public class Fan implements USB{@Overridepublic void Service() {System.out.println("Fan starts to run");}}
//3由于我们要将U盘和风扇插入电脑中,所以要创建一个电脑类
package USB_Interface;public class Computer {private USB usb1;private USB usb2;public USB getUsb1() {return usb1;}public void setUsb1(USB usb1) {this.usb1 = usb1;}public USB getUsb2() {return usb2;}public void setUsb2(USB usb2) {this.usb2 = usb2;}public void Run() {System.out.println("Computer starts to work!!");if(this.getUsb1() != null) {usb1.Service();}if(this.getUsb2() != null) {usb2.Service();}}}
//4最终的测试类
package USB_Interface;public class Test_USB {public static void main(String[] args) {Computer Windows = new Computer();Windows.setUsb1(new Fan());Windows.setUsb2(new USB_Flash());Windows.Run();}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MSfafuL-1613061611874)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210203200029587.png)]
JAVA内部类
创建在类内部的类叫做内部类,
class Outer{//外部类class Inner{//内部类}
}
内部类拥有和普通类一样的属性,可以拥有方法,能够去实现接口,继承
如果外部类与内部类成员属性名字相同,则优先访问内部类成员
如果想要访问同名外部类成员,需要先写上外部类名字,再this.name,或直接Outer.this.name
既然已经有了外部类,那为什么还要内部类呢?
好处
- 内部类可以对外部类全部内容进行访问
- 方便访问外部类的私有属性(内部类可直接访问外部类的私有成员而不破坏封装)
成员内部类
package InnerClass;import InnerClass.OuterClass.InnerClass;public class NormalInnerTest {public static void main(String[] args) {//1. 第一种实例化内部类的方法//OuterClass outer = new OuterClass();//InnerClass inner = outer.new InnerClass();//2. 第二种实例化内部类的方法,一步到位InnerClass inner = new OuterClass().new InnerClass();inner.print();}
}class OuterClass{private String words="Outer Class";class InnerClass{public void print() {System.out.println(OuterClass.this.words);new OuterClass().print();System.out.println("Inner Class: Hello World");}}public void print() {System.out.println(words+": Hello World");}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hkMTS7sx-1613061611875)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210204213254151.png)]
成员内部类不能定义静态成员
静态内部类
静态内部类可以不依赖外部类对象实例化对象
只有静态内部类可以用static修饰
//实例化静态内部类
Outer.Inner StaticInnerDemo =new Outer.Inner();
案例
package InnerClass;class Outer{//外部类中包含静态成员变量与非静态成员变量private static String inf = "Hello World";private String inf2 = "GoodBye World";//创建静态内部类public static class Inner{//静态内部类里面包含静态方法与非静态方法private static void print() {System.out.println("\t静态成员变量: "+inf);//静态内部类无法直接调用非静态变量
// System.out.println(inf2);
//由于外部类成员变量为私有,需要借助外部类来访问Outer out = new Outer(); System.out.println("\t非静态成员变量: "+out.inf2);}//非静态方法public void print2() {System.out.println("\t非静态方法调用静态成员变量: "+inf);}}//普通内部类public class Inner2{//普通成员内部类无法创建静态方法public void print() { //但是可以调用外部类中的静态成员变量System.out.println("\t静态成员变量: "+inf);System.out.println("\t非静态成员变量: "+inf2);}}//外部类能够创建非静态方法public void fun() {//在外部类的方法中实例化内部类Inner innerDemo = new Inner();System.out.println("静态内部类的静态方法");//直接通过内部类类名访问静态方法Inner.print();System.out.println("静态内部类的非静态方法");//访问内部类非静态方法需要通过实例化的对象来访问innerDemo.print2();}}
public class InnerClassDemo1 {public static void main(String[] args) {//实例化静态内部类Outer.Inner StaticInnerDemo =new Outer.Inner();//实例化普通内部类Outer shell = new Outer();shell.print();Outer.Inner2 NormalInnerDemo = shell.new Inner2();System.out.println("静态内部类的非静态方法");StaticInnerDemo.print2();System.out.println("普通内部类的方法");NormalInnerDemo.print();}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-470Blw7C-1613061611875)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210204215906597.png)]
局部内部类
把一个类定义在方法内部,这个类叫做局部内部类,就像定义在方法中的变量叫局部变量一样
局部内部类不能定义访问修饰符,即不能定义为static
但是可以包含静态常量,private final static int count =2000;
public void fun(final String temp){class Inner{public void print(){System.out.println(info);System.out.println(temp);}}//实例化内部类,调用内部类方法new Inner().print();
}
匿名内部类
在java中处理内部类之外,还有一种匿名内部类。
匿名内部类就是指没有一个具体名称的类,此概念是在接口和抽象类的应用上发展起来的,
有时这种类只用一次,命名又可惜,所以就使用匿名内部类
以之前写的Ability接口为例
//接口
package InnerClass;public interface Ability extends flyable{public abstract void swim();
}interface flyable{public abstract void fly();
}
package InnerClass;import Interface.Ability;public class AnonymousInnerClass {public static void main(String[] args) {Ability SuperMan = new Ability(){@Overridepublic void swim() {// TODO Auto-generated method stubSystem.out.println("I can swim");}@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("I can fly");}};SuperMan.swim();SuperMan.fly();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fPyxVxD5-1613061611875)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210204225913164.png)]
使用匿名内部类时,必须继承一个父类或实现一个接口
JAVA泛型
JAVA泛型英文generics,
本质是参数化类型,就是把类型作为参数传递,泛型对象不能被实例化:T type = new T();
这么说大家估计还是觉得这个定义比较抽象,
举个例子:我们要写一个排序方法,这个方法能够对int类型,String类型,double类型都进行排序,此时要使用泛型方法
泛型可以提高代码的重复性,防止类型转换异常,提高代码的安全性
泛型字母含义
E - Element:指集合中的元素
T - Type:Java类型,种类
K - Key:键
V - Value:值
N - Number:数值类型
格式
<T,...> //T是类型占位符,是一种引用类型
泛型方法
泛型方法可以接收不同类型的参数,根据传进去的参数做适当的处理,格式如下
//<T> 声明此方法为泛型方法, T指出返回值是泛型T
//Class<T> 指明泛型T的具体类型, c用来创建泛型T代表的类对象
public <T> T getObject(Class<T> c){//创建一个泛型对象T t = c.newInstance();return t;
}
例子,有三个不同类型的数组,分别打印出其中的值
package GenericsStudy;public class GenericDemo1 {//泛型方法public static < E > void printArray(E [] inputArray) {//输出数组元素for (E element : inputArray) {System.out.printf("%s ", element);}System.out.println();}public static void main(String[] args) {//创建不同类型数组Integer[] intArray = {1, 2, 3, 4, 5};Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};Character[] charArray = {'H', 'E', 'L','L','O'};System.out.println("整型数组元素为:");//因为是写在本类里面,所以可以直接调用//如果是测试类写在本类外面,需要通过类名来调用静态方法,printArray(intArray);System.out.println("\n双精度型数组元素:");printArray(doubleArray);System.out.println("\n字符串数组元素:");printArray(charArray);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bNTFMXgx-1613061611876)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210205114935980.png)]
案例2
编写一个add方法,传入不同类型的数字类型,并返回相加的值,相加的值是double类型
package GenericsStudy;public class GenericsDemo5 {//extends是为了做泛型界定,即泛型T必须是Number的子类public static <T extends Number> double add(T num1, T num2) {double sum=0.0;sum = num1.doubleValue() + num2.doubleValue();return sum;}public static void main(String[] args) {System.out.println("double 类型相加:5.5 + 6.7 ="+add(5.5, 6.7));System.out.println("int 类型相加:5 + 7 ="+add(5, 7));System.out.println("double 与 int 类型相加:5.5+6 ="+add(5.5, 6));}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h5bQ1WUk-1613061611876)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210205211611985.png)]
泛型类
既然方法可以定义为泛型,类也可以定义成泛型
泛型类中可以包含泛型方法,多个类型参数
package GenericsStudy;public class GenericDemo3<T> {private T t;public void add(T t) {this.t = t;}public T get() {return this.t;}public static void main(String[] args) {GenericDemo3<Integer> one = new GenericDemo3<Integer>();GenericDemo3<String> two = new GenericDemo3<String>();one.add(1);two.add("Hello World");System.out.println(one.get());System.out.println(two.get());}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I2ZSAv5l-1613061611877)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210205214226660.png)]
上面提到了,泛型可以存储多个类型,下面我们来写一个简易字典,仅包含一对key和value
package GenericsStudy;public class GenericDemo6 {public static void main(String[] args) {Dictionary<String, Integer> dic1 = new Dictionary<String, Integer>();dic1.put("Peter",110);System.out.println(dic1.getKey());System.out.println(dic1.getValue());System.out.println(dic1.getAll());}
}class Dictionary<K, V>{private K key;private V value;public void put(K key, V value) {this.key = key;this.value = value;}//获取keypublic K getKey() {return key;}//获取valuepublic V getValue() {return value;}//获取key与value的字符串public String getAll() {return key.toString()+":"+value.toString();}}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJEknvNO-1613061611878)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210205215953250.png)]
泛型接口
继承了泛型接口的类会变成泛型类
package GenericsStudy;public class GenericDemo7 {public static void main(String[] args) {ImpleData<String> Imple = new ImpleData<String>();Imple.print("Hello World");}
}//创建一个泛型接口
interface Data<T>{T getData(T t1);
}//ImpleData实现了Data接口
class ImpleData<T> implements Data<T>{@Overridepublic T getData(T t1) {return t1;}public void print(T t1) {System.out.println("Print: "+this.getData(t1));}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S8qvVnlv-1613061611879)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210205221855579.png)]
通配符
通配符是指这个 问号:?,
List <?> seq = new ArrayList<>();
- <? extends T>表示该通配符所代表的类型是T类型的子类。
? extends通常与List一起用,List是一种存储数据的容器和Array数组类似,在后面的章节有介绍
package GenericsStudy;
import java.util.List;public class GenericDemo4 {public static void main(String[] args) {/*由于我们extends Number了,种类只能是Number类或Number的子类如果使用String类型,会报错 */List<Number> sequence = new ArrayList<>();sequence.add(1);sequence.add(2);sequence.add(1.4);sequence.add(7.9f);getDate(sequence);}public static void getDate(List<? extends Number> data) {for(Object i : data) {System.out.println(i);}}
}
- <? super T>表示该通配符所代表的类型是T类型的父类。
不能同时声明泛型通配符上界和下界
JAVA集合
我们Java后端一般要进行数据处理,假设所有数据都是储存在数组里面,大小长度受限,不方便;所以我们在本章将引进集合的概念,集合是对象的容器,定义了对多个对象进行操作的常用方法,可实现数组的功能,但比数组更灵活。注意:数组可以存储基本类型,如int,但是集合只能存储引用类型,如String,所以在集合中存数字时,要将int类型转化为Integer类型
对于集合中的元素我们想要遍历有2种方法
- 增强for(for each循环)
for(Object i :container1) {System.out.println(i);
}
- 通过迭代器来遍历
//迭代器是通过集合内部的方法来获得的
Iterator<Object> itr = container1.iterator();
//itr.hasNext()是判断是否还有下一个元素,如果是,该循环开始执行
while(itr.hasNext()) {//打印出下一个元素System.out.println(itr.next());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5kVeBFEv-1613061611880)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210207164038116.png)]
Collection接口
Collection接口是众多集合的父接口,List接口,Set接口都是继承Collection接口,然后通过实现类实现其中的方法。由于Collection,Set, List都是接口,创建时必须要用实现类;比如List的实现类ArrayList,Set的实现类HashSet.
//引入集合模块
import java.util.Collection
//创建集合,由于Collection是接口,我们用Collection的实现类ArrayList来实现
//Collection集合是泛型集合,< >中我们要添加存储的数据类型, Object类是所有类的父类
Collection<Object> container1 = new ArrayList<>();
由于集合是无法储存基本类型的,当我们存入基本类型时,集合会自动装箱
list.add(20); 实际上是list.add(new Integer(20));
如果有一些方法解释不全,可以参考以下API链接
API: https://www.runoob.com/manual/jdk1.6/
常用方法 | 作用 | 例子 |
---|---|---|
boolean add(E e) | 添加元素,添加成功返回true | container1.add(“apple”); |
void clear() | 移除collection中的所有元素 | container1.clear(); |
int size() | 返回集合中元素的个数 | int size = container1.size(); |
boolean contains(Object o) |
如果此 collection 包含指定的元素,则返回 true
|
container1.contains(“apple”); |
Iterator iterator() | 返回collection的所有元素的迭代器 | Iterator itr = container1.iterator(); |
boolean isEmpty() | 判断此集合是否为空 | container1.isEmpty(); |
boolean remove(Object o) | 移除集合中的某对象 | container1.remove(1); |
Object[] toArray | 将此集合转为数组 | Object[ ] arrray = container1.toArray(); |
例子1
package CollectionStudy;import java.util.ArrayList;//引入ArrayList
import java.util.Collection;//引入Collection
import java.util.Iterator; //引入迭代器public class CollectionDemo1 {public static void main(String[] args) {//使用多态Collection<Object> container1 = new ArrayList<>();//添加元素container1.add("apple");container1.add(1);//增强for遍历元素System.out.println("----增强For----");for(Object i :container1) {System.out.println(i);}//迭代器遍历元素System.out.println("----Iterator----");Iterator<Object> itr = container1.iterator(); while(itr.hasNext()) {System.out.println(itr.next());}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0fxJJdV0-1613061611880)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210207115019530.png)]
例子2
Collection集合可以存储其他引用数据类型,我们创建一个学生类,并将学生类添加进ArrayList集合(Collection的实现类)
package CollectionStudy;
//Students类
public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}//重写toString方法,按照我们的规定返回字符串@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}
}
//测试类
package CollectionStudy;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class CollectionDemo2 {public static void main(String[] args) {Students Tom = new Students(18, "Tom");Students Jimmy = new Students(22, "Jimmy"); //先实例化2个students对象Collection<Students> container = new ArrayList<Students>();container.add(Tom);container.add(Jimmy);//遍历 1for(Object student : container) {System.out.println(student);}System.out.println("\t----Line-----");//遍历 2Iterator<Students> itr = container.iterator();while(itr.hasNext()) {System.out.println(itr.next());}}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vVj96uo-1613061611881)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210207165739022.png)]
我们想用集合的contains方法,来判断是否包含某引用元素
Students Jimmy = new Students(22, "Jimmy");
Collection<Students> container = new ArrayList<Students>();
container.add(Jimmy);
System.out.println(container.contains(Jimmy));
结果是:true
假设我们传进去的不是Jimmy,而是: new Students(22, “Jimmy”)
结果是:false
为了避免这个问题,我们需要重写students类中的equals方法
//在Students类中重写此方法 @Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(obj == null) {return false;}if(obj instanceof Students) {Students students = (Students) obj;if(this.name.equals(students.name)&&this.age == students.age) {return true;}}return false;}
再次调用测试类
结果为:true
List接口
List是有序(添加顺序与遍历顺序一致),有下标,元素可重复的集合
List的独有方法
如果有一些方法解释不全,可以参考以下API链接
API: https://www.runoob.com/manual/jdk1.6/
方法 | 解释 | 例子 |
---|---|---|
void add(int index, Object o) | 在index位置插入对象o | conatiner2.add(0, “Hello”); |
boolean addAll(int index, Collection c) | 将一个集合元素增添到index位置 | container2.addAll(0,container1); |
Object get(int index) | 返回集合中指定位置的元素 | container2.get(0); |
List subList(int fromIndex, int toIndex) | 返回fromIndex与toIndex之间的元素 | container2.subList(0, 5); |
ArrayList
ArrayList是由数组结构实现的,查询快,增删慢
增添包:import java.util.ArrayList;
构造方法:ArrayList container = new ArrayList<>();
E为泛型即ArrayList可以增添任何类
常用方法 | 解释 |
---|---|
public boolean add(E e); | 添加元素 |
public E get(int index) | 按照索引获取元素,从0开始 |
public E set(int index, E element) | 可以替换指定元素 |
public boolean remove(Object 0) | 根据内容删除元素 |
public E remove(int index) | 根据index删除元素,返回删除元素 |
例子
我们要创建一个Students类,将几个students对象存入ArrayList类中
package CollectionStudy;public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}}
package CollectionStudy;import java.util.ArrayList;
import java.util.Arrays;public class ArrayListCollection {public static void main(String[] args) {ArrayList<Students> container = new ArrayList<>();Students Jim = new Students(18, "Jim");Students Tom = new Students(20, "Tom");//成功add元素后,返回是否成功System.out.println("是否增添了Jim:"+container.add(Jim));container.add(Tom);System.out.println("获取第一个元素:"+container.get(0));//把第2个元素设置为Alexcontainer.set(1, new Students(78, "Alex"));System.out.println("第2个元素是:"+container.get(1));//container包含的元素个数System.out.println("元素个数:"+container.size());//将ArrayList转化为数组Object[] array = container.toArray();System.out.println("将ArrayList转化为数组:"+Arrays.toString(array));//删除元素,删除Jim的信息System.out.println("删除: "+container.remove(Jim));System.out.println("删除后个数:"+container.size());}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f4FSI5pI-1613061611882)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208192224042.png)]
假如我们增添,删除时用的不是Jim, 而是new Students(18, “Jim”); ?
package CollectionStudy;import java.util.ArrayList;
import java.util.Arrays;public class ArrayListCollection {public static void main(String[] args) {ArrayList<Students> container = new ArrayList<>();Students Jim = new Students(18, "Jim");
// Students Tom = new Students(20, "Tom");System.out.println("是否增添了Jim:"+container.add(Jim));container.add(new Students(20, "Tom"));System.out.println("获取第一个元素:"+container.get(0));//把第2个元素设置为Alexcontainer.set(1, new Students(78, "Alex"));System.out.println("第2个元素是:"+container.get(1));//container包含的元素个数System.out.println("元素个数:"+container.size());//将ArrayList转化为数组Object[] array = container.toArray();System.out.println("将ArrayList转化为数组:"+Arrays.toString(array));//删除元素,注意,此时我们new Students(18,"Jim");System.out.println("删除: "+container.remove(new Students(18, "Jim")));System.out.println("删除后个数:"+container.size());}
}
结果
即使我们删除new Students(18,“Jim”);(内容相同),但是还是无法完全删除,删除返回为false
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aiks5UEV-1613061611882)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208192723418.png)]
所以此时我们需要重写Students里面的equals方法(ArrayList判断remove时调用的方法)
@Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(obj == null) {return false;}if(obj instanceof Students) {Students students = (Students) obj;if(this.name.equals(students.name)&&this.age == students.age) {return true;}}return false;}
结果,成功删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CODsJJaJ-1613061611883)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208193019582.png)]
LinkedList
Link意思为链,链表集合就像所以数据被链子连接在一起一样
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7g0GKYZ-1613061611884)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208193746827.png)]
特点:链表结构实现,增删快,查询慢
使用方法与ArrayList类似
例子
继续用LinkedList存储Students类的信息
同样,我们先不重写equals方法
package CollectionStudy;public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}}
package CollectionStudy;import java.util.LinkedList;public class LinkedListDemo1 {public static void main(String[] args) {LinkedList<Students> container = new LinkedList<>();System.out.println("增添Tom: "+container.add(new Students(20, "Tom")));container.add(new Students(18, "Jim"));//pop从container中弹出元素System.out.println("Pop第一个元素:"+container.pop());container.add(new Students(18, "Jim")); container.add(new Students(72,"Trump"));System.out.println("删除元素Jim:"+container.remove(new Students(18, "Jim")));//遍历for(Object i :container) {System.out.println(i);}}
}
结果Jim无法被删除,同时***我们还发现List可以存储相同的元素***
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vsjNqaj3-1613061611885)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208200323333.png)]
此时,我们再重写Students的equals方法
@Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(obj == null) {return false;}if(obj instanceof Students) {Students students = (Students) obj;if(this.name.equals(students.name)&&this.age == students.age) {return true;}}return false;}
结果,成功删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNaB7hId-1613061611885)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208200612292.png)]
Set接口
上文我们介绍了List接口与其的实现类,现在我们开始讲Set接口
Set是无序(添加顺序与遍历顺序不一致),无下标,***元素不可重复***的集合
但是使用new可以插入内容相同的元素,因为Set判断的依据是equals方法,如果equals方法未重写则根据地址判断.
例子引入
package setStudy;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class SetIntroduction {public static void main(String[] args) {//我们使用Set集合的实现类HashSet来创建集合Set<Object> container = new HashSet<>();container.add("Hello");container.add("World");container.add("Hello");container.add("My Friend");Iterator<Object> itr = container.iterator();while(itr.hasNext()) {System.out.println(itr.next());}}
}
这里由于是字符串,系统内部有equals方法,所以第二个"Hello"无法加入Set集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rxbghmdD-1613061611886)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208202251947.png)]
HashSet
HashSet是Set集合的一个实现类
存储结构:哈希表(数组+链表+红黑树)
存储过程
(1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空,则执行第二步
(2) 再执行equals方法,如果equals方法为true,则认为重复,否则形成链表,即添加到HashSet容器中
因为HashSet是以equal与hashcode进行比较,所以要重写hashcode与equals,这样就可以排除new的干扰。
构造方法
//E为任意种类的数据
HashSet<E> container = new HashSet<>();
基本操作与List / Set / Collection类似
增添元素:add(E e);
删除元素:remove(E e);
也有迭代器:Iterator iterator();
package setStudy;import java.util.HashSet;public class HashSetStudy {public static void main(String[] args) {HashSet<String> container = new HashSet<>();container.add("tim");container.add("Ketty");container.add("Yellow");System.out.println("HashSet中的内容:"+container.toString());System.out.println("HashSet的大小:"+container.size());System.out.println("此HashSet中是否含有Ketty数据:"+container.contains("Ketty"));}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvBItWvM-1613061611887)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208203127750.png)]
案例2
像ArrayList一样,我们创建Students类,增添Students元素
package setStudy;public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {return "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}
}
package setStudy;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class HashSetDemo2 {public static void main(String[] args) {HashSet<Object> container = new HashSet<>();System.out.println("添加成功:"+container.add(new Students(18, "Jim")));System.out.println("添加成功:"+container.add(new Students(19, "Jone")));System.out.println("添加成功:"+container.add(new Students(18, "Alex")));System.out.println("添加成功:"+container.add(new Students(18, "Jim")));Iterator<Object> itr = container.iterator();while(itr.hasNext()) {System.out.println(itr.next());}}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INqkJjIu-1613061611888)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208204141673.png)]
当我们增添内容相同的元素new Students(18, “Jim”)时,系统先判断是否是同一地址,如果没有看是否重写了equals和hashcode方法。因为判断地址不一样又没重写equals方法(照系统默认的equals方法),所以添加成功
现在我们重写Students类的equals和hashcode方法
@Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(obj == null) {return false;}if(obj instanceof Students) {Students students = (Students) obj;if(this.name.equals(students.name)&&this.age == students.age) {return true;}}return false;}@Overridepublic int hashCode() {//第一种转换string的方法
// String age = String.valueOf(this.age);//第二种
// String age = this.age+"";String age = Integer.toString(this.age);return age.hashCode()*this.name.hashCode();}
结果,相同内容的数据添加失败
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GX7opgtZ-1613061611888)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208204223172.png)]
TreeSet
实现Set接口的还有一个类,TreeSet,基于排列顺序实现元素不重复
此实现为基本操作(add
、remove
和 contains
)
实现了SortedSet接口,对集合元素自动排序
传入TreeSet的元素对象类型必须实现Comparable接口(指定排序规则)
因为TreeSet是通过ComparaTo方法确认是否为重复元素,所以可以通过内部类来override比较方法
使用TreeSet时,最好不要用Object类
package setStudy;import java.util.TreeSet;public class TreeSetStudy {public static void main(String[] args) {TreeSet<String> container = new TreeSet<>();container.add("Hello");container.add("xyz");container.add("world");container.add("hello");container.add("99");System.out.println(container.toString());}
}
String类型,(0,1,2…)默认数字在前–>大写–>小写(a,b,c…z)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qX8419Ic-1613061611889)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208204509037.png)]
案例2
还是Students的案例
package setStudy;public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {return "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}
}
package setStudy;import java.util.Iterator;
import java.util.TreeSet;public class TreeSetStudy {public static void main(String[] args) {TreeSet<Students> container = new TreeSet<>();System.out.println("添加成功:"+container.add(new Students(18, "Jim")));System.out.println("添加成功:"+container.add(new Students(19, "Jone")));System.out.println("添加成功:"+container.add(new Students(18, "Alex")));System.out.println("添加成功:"+container.add(new Students(18, "Jim")));//遍历Iterator<Students> itr = container.iterator();while(itr.hasNext()) {System.out.println(itr.next());}}
}
由于我们再Students类中没有重写CompareTo方法,报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NIbDItbe-1613061611890)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208205925362.png)]
继承Comparable接口重写CompareTo方法
package setStudy;public class Students implements Comparable<Object>{private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}@Overridepublic int compareTo(Object obj) {Students stu = (Students) obj;return (stu.name.hashCode() - this.name.hashCode());}}
此时TreeSet根据我们重写的compareTo方法来判断Object是否重复,我们的判断依据是students的名字的hashcode。
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9iik1hVF-1613061611890)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208211200435.png)]
Map接口
Map是一种将Key与value(键对象与值对象)相互映射的集合
Key | Value |
---|---|
1 | Biden |
2 | Trump |
有时能用Map就不要用List,查找信息Map使用效率有时比List要高
//通过HashMap这个实现类来创建一个Map对象
//Students是传入Key的类型, String是value的类型
Map<Students, String> container = new HashMap<>();
常用方法 | 解释 |
---|---|
V put(K key, V value) | 放入键值对 |
Object get(Object Key) | 通过key来获取值value |
Set KeySet() | 返回所有的Key的Set集合 |
Collection values() | 返回包含所有值的collection集合 |
boolean containsKey(Object key) | 如果此映射包含对于指定键的映射关系,则返回 true |
boolean containsValue(Object Value) | 如果此映射将一个或多个键映射到指定值,则返回 true |
V remove(Object key) | 如果存在,根据key移除此键值对 |
如果有一些方法解释不全,可以参考以下API链接
API: https://www.runoob.com/manual/jdk1.6/
实现Map接口的类有HashMap, TreeMap等
Map遍历
- KeySet()
Map <String, String> map = new HashMap<>();
Set<String> key = map.KeySet(); //是所有的Key的集合. 随后可以使用增强for 或迭代器去遍历
System.out.println("\tKeySet");
for( Students i : container.keySet() )
{System.out.println(i.getName()+"----"+container.get(i));
}
- EntrySet()
EntrySet()的效率要略高于KeySet()
for(Entry<Students, String> i :container.entrySet())
{System.out.println(i.getKey().getName()+"----"+i.getValue());
}
HashMap
HashMap和HashSet类似,也是存储数据的集合;HashSet是存储值数据,而HashMap是存储键值对数据
在HashMap中Key的数据是根据hashcode来存的
HashMap是无序的,即我们插入和取出的顺序是不一样的
Students案例
由于是根据hashcode来存储key,我们需要重写students中的hashcode和equals方法
package Map_Key_Value;public class Students {private int age;private String name;public Students(int age, String name) {super();this.age = age;this.name = name;}public int getAge() {return age;}public String getName() {return name;}@Overridepublic String toString() {// TODO Auto-generated method stubreturn "Student [ name: "+this.getName()+", age: "+this.getAge()+" ]";}@Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(obj == null) {return false;}if(obj instanceof Students) {Students students = (Students) obj;if(this.name.equals(students.name)&&this.age == students.age) {return true;}}return false;}@Overridepublic int hashCode() {// TODO Auto-generated method stub//第一种转换string的方法
// String age = String.valueOf(this.age);//第二种
// String age = this.age+"";String age = Integer.toString(this.age);return age.hashCode()*this.name.hashCode();}}
package Map_Key_Value;import java.util.HashMap;
import java.util.Map.Entry;public class OriginalMap {public static void main(String[] args) {HashMap<Students, String> container = new HashMap<>();
// Students Jim = new Students(18, "Jim");
// container.put(Jim, "CSSE120");container.put(new Students(18, "Jim"), "CSSE120");container.put(new Students(20, "John"), "CSSE220");container.put(new Students(17, "Alex"), "MA112");container.put(new Students(20, "Eric"), "ESL102");System.out.print("获取 Students(18, \"Jim\") 的值:");System.out.println(container.get(new Students(18, "Jim")));//get value//遍历//使用KeySet方法System.out.println("\tKeySet遍历");for(Students i:container.keySet()) {System.out.println(i.getName()+"----"+container.get(i));}//使用EntrySet方法System.out.println("\tEntrySet遍历");
// Set<Map.Entry<Students, String>> entrys = container.entrySet();for(Entry<Students, String> i : container.entrySet()) {System.out.println(i.getKey().getName()+"----"+i.getValue());}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rtUa3yt3-1613061611892)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210208215330562.png)]
TreeMap
TreeMap存储数据根据compareTo方法,对于自定义对象需要override比较方法,这个与TreeSet类似
下面就不多解释了,不懂可以查看API
API: https://www.runoob.com/manual/jdk1.6/
JAVA常用类
java中还有一些常用的工具类,这些类都是日常开发时可能会用到的
Arrays类
Arrays是数组的意思,Arrays是为数组所开发的工具类(方法是静态static方法)
arrays能处理的类型有int, double, long, char等
常用方法 | 解释 |
---|---|
static boolean equals(int[ ] a, int[ ] a2) | 如果两个int类型数组相等,则返回true |
static int hashCode(int[ ] a) | 返回指定数组的哈希值 |
static void sort(double[ ] a) | 对指定数组进行升序排序 |
static String toString(char[ ] a) | 将数组内容转化为字符串 |
static void sort(T[ ] a, Comparator<? super T> c ) | 根据指定比较器的顺序对指定对象数组进行排序 |
Date和Calendar类
Data和Calendar是java中表示时间的两个类,它们能返回当前的时间的毫秒值
毫秒值表示自 1970 年 1 月 1 日 00:00:00 GMT 以来经过的毫秒数。
Date
构造方法
//以当前时间来初始化对象
Date date = new Date();//构造函数接收一个参数,这个参数是从1970年起的毫秒数
Date date = new Date(long millisec)
常用方法 | 解释 |
---|---|
String toString() | 格式化日期转义形式yyyy-mm-dd的日期 |
int getHours() | 获取此刻的小时 |
String toLocaleString() | 返回当前本地格式的时间(方法已过时) |
package DateAndCalendar;
import java.util.Date;
public class DateDemo1 {public static void main(String[] args) {Date date = new Date();System.out.println(date.toString());System.out.println(date.toLocaleString());}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZHhV2f1Y-1613061611892)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210209130751457.png)]
我们可以使用SimpleDateFormat将日期输出格式化
格式 | 含义 | 例子 |
---|---|---|
yyyy | 年 | 2020 |
MM | 月 | 1 |
dd | 日 | 22 |
HH | 24小时制 | 13 |
hh | 12小时制 | 1 |
ss | 秒 | 07 |
S | 毫秒 | 7000 |
E | 星期几 | Monday |
D | 一年中的第几天 | 365 |
F | 一个月中的第几周的周几 | 2 |
w | 一年中的第几周 | 7 |
W | 一个月中的第几周 | 2 |
a | AM / PM | PM |
z | 时区 | CST |
package DateAndCalendar;
import java.text.SimpleDateFormat;
import java.util.Date;public class DateDemo1 {public static void main(String[] args) {Date date = new Date();
// System.out.println(date.toString());
// System.out.println(date.toLocaleString());SimpleDateFormat Df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(Df.format(date));}
}
我们还能用时间来做一个定时器
package DajavateAndCalendar;
//在10s之内,持续打印hello, 结束时打印world
public class DateDemo1 {public static void main(String[] args) {long start = System.currentTimeMillis();while(true) {long end = System.currentTimeMillis();if((end-start)>10000) {System.out.println("world");break;}System.out.println("hello");}}
}
Calendar
通过Calendar我们可以获取时间中特定的数据
Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些。
由于Calendar是protected类型,只能通过其他方法进行构建
static Calendar getInstance()
//使用默认时区获取日历Calendar date = Calendar.getInstance();
在Calendar中,系统定义了一些常量
Calendar.YEAR 年
Calendar.MONTH 月
Calendar.DATE 日期
Calendar.HOUR 小时
Calendar.MINUTE 分钟
Calendar.SECOND 秒
Calendar.DAY_OF_WEEK 星期几
常用方法
int get(int field)
calendar.get(Calendar.YEAR)//可用于获取calendar特定的年-月-日
abstract void add(int field, int amount) //根据日历给特定的字段增减时间量
void set(int year, int month, int day, int hourOfDay, int minute, int second)//设置特定值
例子
package DateAndCalendar;
import java.util.Calendar;
import java.util.Date;
public class CalendarDemo1 {public static void main(String[] args) {Calendar calendar = Calendar.getInstance();System.out.println(calendar.getTime());int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH)+1;int day = calendar.get(Calendar.DAY_OF_MONTH);System.out.println("Today is "+year+"-"+month+"-"+day);}
}
JAVA异常处理
在写程序时我们可能会遇到程序报错的情况,此时编译器会出现红色的提示,如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgGqCjwp-1613061611893)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210209194701662.png)]
这就是异常Exception
所有的异常都是从java.lang.Exception中继承的,Exception类是Throwable类的子类,Throwable还有一个子类Error
常见异常
- 用户输入了非法数据
- 要打开的文件不存在
- 网络连接通信时中断,或者JVM内存溢出
三大类异常
1. 检查性异常(checked exception)
如用户输入异常或者打开一个不存在的文件(这些异常在编译时不能被简单地忽略)
2. 运行时异常
运行时可能被程序员避免的异常
3. 错误
错误不是异常,通常是摆脱程序员控制的问题,例如当内存溢出时,会报错误
检查性异常
- InterruptedException
一个线程被另一个线程中断,抛出该异常。 - NoSuchFieldException
请求的变量不存在
非检查性异常
1. ArithmeticException
2. NumberFormatException
当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常
3. NullPointerException
4. IndexOutOfBoundsException
遍历超过
5. UnsupportedOperationException
捕获异常
//捕获异常的基础语法
try{}catch(IOException e1){//如何处理该异常,异常e1的类型可以为Exception的子类或Exception;
}catch(ArithmeticException e2){}finally{//finally可加可不加//如果加了,无论是否发生异常,finally 代码块中的代码总会被执行。 //一般这里用于释放内存,如input.close()
}
例子
我们要用户输入两个数并互除,在除法中,被除数不能为0,所以我们要捕获这个异常
package Exception;import java.util.Scanner;public class ExceptionStudyDemo1 {public static void main(String[] args) {Scanner input = new Scanner(System.in);try {System.out.print("Num1: ");int num = input.nextInt();System.out.print("Num2: ");int num2 = input.nextInt();//注意此时num/num2得出的数字是整数System.out.println("Num1 / Num2 = "+num/num2);}catch(ArithmeticException a) {System.out.println(a.getMessage()); //获取为什么错误}finally {input.close();}}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HCb0goWT-1613061611894)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211155159674.png)]
解决方法
添加一个
double rst = num*1.0/num2;java
package Exception;import java.util.Scanner;public class ExceptionStudyDemo1 {public static void main(String[] args) {Scanner input = new Scanner(System.in);try {System.out.print("Num1: ");int num = input.nextInt();System.out.print("Num2: ");int num2 = input.nextInt();double rst = num*1.0/num2;System.out.println("Num1 / Num2 = "+rst);}catch(ArithmeticException a) {System.out.println(a.getMessage());}finally {input.close();}}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNDO2WYq-1613061611895)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211155458450.png)]
Throws 关键字
throws中文意思是抛出,当一个函数有一个异常,此时我们不想处理时,我们可以throws这个Exception,交给函数外的部分处理
还是刚才num / num2的例子
package Exception;import java.util.Scanner;public class ExceptionStudyDemo1 {public static void main(String[] args) {Scanner input = new Scanner(System.in);try {System.out.print("Num1: ");int num = input.nextInt();System.out.print("Num2: ");int num2 = input.nextInt();divide(num, num2);}catch(ArithmeticException a) {System.out.println(a.getMessage());}finally {input.close();}}public static void divide(int num, int num2) throws ArithmeticException{System.out.println("Num1 / Num2 = "+num/num2);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOPcrIp5-1613061611895)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211160006853.png)]
自定义异常类
所有异常必须是Throwable的子类。如果希望写一个检查性异常,则需要继承Exception类;如果是运行时异常,则继承RuntimeException类
继承语法
class CustomException extends Exception{ //里面根据编译器自动生成
}package Exception;
import java.util.Scanner;
public class ExceptionStudyDemo1 {public static void main(String[] args) {Scanner input = new Scanner(System.in);try {System.out.print("Num1: ");int num = input.nextInt();System.out.print("Num2: ");int num2 = input.nextInt();divide(num, num2);}catch(CustomException a){ //捕获自定义异常 }
public static void divide(int num, int num2) throws CustomException{ //在方法中抛出异常if(num2 == 0) {throw new CustomException(); //在方法中加入此语句,即为判断那种情况下抛出自定义异常}}
}
自定义异常有什么用呢?
当我们自己开发时,有时需要自己定义一些异常(别人能看懂的异常类名字),这样可以方便开发
JAVA IO处理
我们每次运行一个程序,此时我们输入的数据仅仅是存在缓存中的,倘若我们关掉程序,数据就会随之消失。为了把数据存起来,我们需要学习IO处理(Input Output),这样数据才可以写入内存硬盘里面。
流的概念
流stream可以为数据与目的之间建立通道。通过流我们可以把在内存中的信息写入到硬盘中;同理,我们也可以将硬盘中的数据读取,print在控制台里面
通过流读取的不管是字节还是字符,一般返回的都是int值
流的分类
流有很多种类,按照处理数据侧重点的不同可以分为输入/输出字节流与输入/输出字符流;
这里我引用某位博主的图片来解释:https://blog.csdn.net/mu_wind/article/details/108674284
字节流
字节流每次读取或写入一个字节,2字符=1字节, 1字节(Byte) = 8位 (bit)。字节流可以处理图像,视频等
一般英文字母一个字母为一个字节(字节是以int类型表示而字母则是以char类型表示)
字符流
字符流每次读取或写入一个字符。字符流只能用于处理文字信息
中文与英文有点区别,1个中文代表1个字符(char),1个字符 = 2个字节, 加入用字节流读取中文字符会出现乱码
流的使用
字节流使用
输入字节流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wjOhF8K1-1613061611896)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211224816778.png)]
//实例化对象
FileInputStream file = new FileInputStream("E:\\java程序\\ReadFile.txt");//读取文件内容
//读取出来的是字节流信息,要转化成char或string才能打印
//file.read()一次读取一个字节,如果有返回此字节,若没有返回-1
int data;
while((data = file.read()) != -1) {System.out.print((char)data);
}//使用自制缓冲区读取数据
byte[] buffer = new byte[3];//自制的一次能储存3个字节的缓冲区
int count=0;
while((count = file.read(buffer))!=-1) {System.out.print(new String(buffer,0,count));
}//注意打开的文件使用后要关闭
file.close();
输出字节流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSBb74TV-1613061611898)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211224920029.png)]
//实例化对象
//true表示如果给出的文件地址已存在,则在此文件的基础上再写如内容
FileOutputStream Out = new FileOutputStream("E:\\java程序\\OutPutFile.txt",true);//写入内容
String words = "HELLO WORLD ";
Out.write(words.getBytes()); //通过字节流来写入,必须是字节形式//同样,写完记得关闭
Out.close();
由于普通的输入输出字节流效率不高,一般需要与缓冲流相互配合
文件内容先读入缓冲区,接着被程序访问,这样可以减少程序访问硬盘的次数
缓冲输入输出流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tZ7vrIER-1613061611899)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211225026578.png)]
//使用缓冲区读取数据
FileInputStream file = new FileInputStream("E:\\java程序\\ReadFile.txt");
BufferedInputStream buf = new BufferedInputStream(file);
int data;
while((data = buf.read()) != -1) {System.out.print((char)data);
}//缓冲区用完也最好记得关闭
buf.close();
//使用缓冲区输出数据
package IOStudy;import java.io.BufferedOutputStream;
import java.io.FileOutputStream;public class buf {public static void main(String[] args) throws Exception {System.out.println("hello world");FileOutputStream file = new FileOutputStream("E:\\java程序\\BufferOutput.txt",true);BufferedOutputStream buf = new BufferedOutputStream(file);for(int i=0;i<4;i++) {buf.write("hello world ".getBytes());buf.flush(); //使用缓冲区每写入一次数据要刷新一遍}System.out.println("Finish");buf.close();}
}
对象流与序列化
字节流可以传输任何数据类型,包括对象,由此产生了另一个流,对象流
创建方法
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(source, true));
ObjectInputStream 读取Obj数据顺序根据写入顺序来,先进先出
在使用对象流写入对象数据时,该对象必须实现Serializable接口
之前接口部分有提到Serializable没有任何方法和常量,它是一个标记类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMPV6LNC-1613061611899)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211225831552.png)]
下面我们要将两个学生类的信息储存到硬盘中,再通过一个程序将内容读取出来
//学生类,要实现Serializable接口
package IOStudy;import java.io.Serializable;public class Student implements Serializable{/*** */private static final long serialVersionUID = -4870784691100550826L;private String name;private int age;public Student(String name, int age) {super();this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "["+this.getName()+" , "+this.getAge()+"]";}}
//写入信息
package IOStudy;import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;public class ObjectWrite {public static void main(String[] args) throws Exception{String source = "E:\\java程序\\ObjWriter.bin";ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(source));Student Biden = new Student("Biden", 78);Student Trump = new Student("Trump", 72);obj.writeObject(Trump);obj.writeObject(Biden);obj.writeObject(null);obj.close();System.out.println("Finish");}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3t55wuuK-1613061611900)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212000040489.png)]
//读取信息
package IOStudy;import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;public class ObjectRead {public static void main(String[] args) throws Exception{String source ="E:\\java程序\\ObjWriter.bin";ObjectInputStream obj = new ObjectInputStream(new FileInputStream(source));Object stu;while((stu=obj.readObject())!= null) {System.out.println(stu);}obj.close();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5g4mgD9P-1613061611901)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212000057958.png)]
字符流使用
字符流输入输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0B1QXiv-1613061611901)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211225130652.png)]
//实例化对象
FileReader read = new FileReader(Source);
//读取操作与字节流类似//案例(反例),我们使用默认的解码格式读取数据
package IOStudy;import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;public class ReadFile2 {public static void main(String[] args) throws Exception{String Source = "E:\\java程序\\字符Reader.txt";FileReader read = new FileReader(Source);int count =0;while((count = read.read())!= -1) {System.out.print((char)count);}read.close();}
}
结果,中文出现乱码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Mfg0ljR-1613061611903)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211232655649.png)]
由于英文一个字母只占一个字节,默认的GBK解码没有问题。但是中文一个字占3个字节,使用GBK解码(与文本保存的格式不同)出现了乱码。
为了保证能正确解码,我们读取字符文件时要指定解码格式,例如UTF-8
//下面是对上面例子的修改
package IOStudy;import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;public class ReadFile2 {public static void main(String[] args) throws Exception{String Source = "E:\\java程序\\字符Reader.txt";InputStreamReader read = new InputStreamReader(new FileInputStream(Source),"UTF-8");int count =0;while((count = read.read())!= -1) {System.out.print((char)count);}}
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmLS8dzw-1613061611903)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211233135453.png)]
中文字符流写出时,不用担心上面编码的问题,系统默认是GBK编码,例子如下
package IOStudy;import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;public class WriteFile2 {public static void main(String[] args) throws Exception{String Source = "E:\\java程序\\字符Writer.txt";FileWriter file = new FileWriter(Source);file.write(" 世界你好 ");System.out.println("Finish");file.close();}
}
写入的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fl8HL4f9-1613061611903)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211233838187.png)]
ANSI就是GBK编码格式
当然,我们也可以指定输出格式,像输入一样
package IOStudy;import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;public class WriteFile2 {public static void main(String[] args) throws Exception{String Source = "E:\\java程序\\字符Writer.txt";OutputStreamWriter file = new OutputStreamWriter(new FileOutputStream(Source,true), "UTF-8");
// FileWriter file = new FileWriter(Source);file.write(" 世界你好 ");System.out.println("Finish");file.close();}
}
结果:文件使用UTF-8编码格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yYUtAIF2-1613061611904)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210211234107217.png)]
字符流读取缓冲流
package IOStudy;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;public class BufferCharRead {public static void main(String[] args) throws Exception{String source = "E:\\编程.txt";BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(source), "GBK"));for(int i=0;i<20;i++)//打印缓冲区中的前20行//buf.readLine()指读一行数据System.out.println(buf.readLine());buf.close();}
}
文件夹操作
java的IO处理还包括文件夹的一些操作,例如文件夹的创建,删除等
//构造方法
//--1--
File file = new File(String parent_path, String child_path);
//--2--
File file = new File(String absolute_path)
目录操作 | 解释 |
---|---|
createNewFile() | 创建一个新文件,不是文件夹 |
mkdir() | 创建一个新目录 |
delete() | 删除文件或空目录 |
exists() | 判断File对象所表示的对象是否存在 |
getAbsolutePath() | 获取文件的绝对路径 |
getName() | 获取目录的名字 |
getParent() |
获取文件/目录所在的目录, 该文件夹所在绝对路径E:\java程序\PicSource\Summer_Pocket Parent就是E:\java程序\PicSource Child就是Summer_Pocket |
isDirectory() | 判断是否是目录 |
isFile() | 判断是否是文件 |
length() | 获取文件的长度,以字节为单位 |
renameTo() | 修改文件名为 |
listFiles() |
列出目录中的所有内容 File[] files = file.listFiles(); 返回的是File类型数组 File[] file2 = file.listFiles(FileFilter filter);//可以通过Filefilter进行过滤文件的目的 |
FileFilter接口
public interface FileFilter
//需要实现的方法
boolean accept(File pathname)
案例
存了一些图片在某个文件夹中,我们要将这些图片重命名,按1-50的顺序重命名
package IOStudy;import java.io.File;
import java.io.FileFilter;
import java.util.Scanner;public class FileOperator {public static void main(String[] args) throws Exception {File file = new File("E:\\java程序\\PicSource");System.out.println("dictory's name: "+file.getName());File[] files = file.listFiles();Integer count =0;for(File pic:files) {File image = new File(file.getAbsolutePath(),count.toString()+".jpg");if(pic.isFile()) {pic.renameTo(image);count++;}}File[] file2 = file.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {if(pathname.getName().endsWith(".jpg"))return true;return false;}});for(File pic:file2) {System.out.println(pic.getName());} }
}
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fqe9AdYz-1613061611905)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212002426056.png)]
Properties
properties是一个属性集合,继承HashTable,是一个线程安全的集合;properties可以储存键值对,同时键值对是字符串类型,它没有泛型。
//构造方法
Properties container = new Properties();//常用方法
container.setProperty("Trump","72");//使用迭代器遍历properties中的键值对
Iterator<Entry<Object, Object>> itr = container.entrySet().iterator();
while(itr.hasNext()) {Entry<Object, Object> set = itr.next();System.out.println(set.getKey()+"=====>"+set.getValue());
}//使用Set遍历键值对
Set<String> set = container.stringPropertyNames();
for(String pro:set) {System.out.println(pro+"=====>"+container.getProperty(pro));
}//load加载存储在硬盘中property的内容
container.load(FileInputStream fis);//以适合的方法将键值对写入到输出流,可以保存注释
container.store(FileOutputStream fos, String comment);
//-----////store方法,以适合的方法将键值对写入到输出流,可以保存注释FileOutputStream fos = new FileOutputStream("E:\\java程序\\properties_save.txt");container.store(fos, "American President");fos.close();
//----////将属性列表输出到指定的输出流
container.list(PrintWriter file);
举一个储存properties的例子
package IOStudy;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;public class PropertyStudy {public static void main(String[] args) throws Exception {Properties container = new Properties();container.setProperty("Trump", "72");container.setProperty("Biden", "74");System.out.println(container.getProperty("Trump"));//使用迭代器遍历Iterator<Entry<Object, Object>> itr = container.entrySet().iterator();while(itr.hasNext()) {Entry<Object, Object> set = itr.next();System.out.println(set.getKey()+"=====>"+set.getValue());} //将属性列表输出到指定的输出流PrintWriter file =new PrintWriter(new FileOutputStream("E:\\java程序\\properties_save.txt"));container.list(file);file.close();}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPwJjFAh-1613061611907)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212000516493.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rRe7NZqH-1613061611908)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212000544377.png)]
读取properties在硬盘中的内容
//load加载properties内容FileInputStream fis = new FileInputStream("E:\\java程序\\properties_save.txt");container.load(fis);fis.close();Set<String> set = container.stringPropertyNames();for(String pro:set) {System.out.println(pro+"=====>"+container.getProperty(pro));}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2oIxvIii-1613061611908)(C:\Users\23881\AppData\Roaming\Typora\typora-user-images\image-20210212000811298.png)]
参考文献
API:https://www.runoob.com/manual/jdk1.6/
菜鸟教程:https://www.runoob.com/java/java-tutorial.html
JAVA final关键字:https://blog.csdn.net/PickUpOldDriver/article/details/80566628
JAVA static block:https://blog.csdn.net/qq_35868412/article/details/89360250
JAVA this关键字:https://blog.csdn.net/qq_43555323/article/details/84993460
JAVA IO:https://blog.csdn.net/baobeiSimple/article/details/1713797
BufferedReader(new InputStreamReader(new FileInputStream(source), “GBK”));
for(int i=0;i<20;i++)//打印缓冲区中的前20行
//buf.readLine()指读一行数据
System.out.println(buf.readLine());
buf.close();
}
}
### 文件夹操作java的IO处理还包括文件夹的一些操作,例如文件夹的创建,删除等```java
//构造方法
//--1--
File file = new File(String parent_path, String child_path);
//--2--
File file = new File(String absolute_path)
目录操作 | 解释 |
---|---|
createNewFile() | 创建一个新文件,不是文件夹 |
mkdir() | 创建一个新目录 |
delete() | 删除文件或空目录 |
exists() | 判断File对象所表示的对象是否存在 |
getAbsolutePath() | 获取文件的绝对路径 |
getName() | 获取目录的名字 |
getParent() |
获取文件/目录所在的目录, 该文件夹所在绝对路径E:\java程序\PicSource\Summer_Pocket Parent就是E:\java程序\PicSource Child就是Summer_Pocket |
isDirectory() | 判断是否是目录 |
isFile() | 判断是否是文件 |
length() | 获取文件的长度,以字节为单位 |
renameTo() | 修改文件名为 |
listFiles() |
列出目录中的所有内容 File[] files = file.listFiles(); 返回的是File类型数组 File[] file2 = file.listFiles(FileFilter filter);//可以通过Filefilter进行过滤文件的目的 |
FileFilter接口
public interface FileFilter
//需要实现的方法
boolean accept(File pathname)
案例
存了一些图片在某个文件夹中,我们要将这些图片重命名,按1-50的顺序重命名
package IOStudy;import java.io.File;
import java.io.FileFilter;
import java.util.Scanner;public class FileOperator {public static void main(String[] args) throws Exception {File file = new File("E:\\java程序\\PicSource");System.out.println("dictory's name: "+file.getName());File[] files = file.listFiles();Integer count =0;for(File pic:files) {File image = new File(file.getAbsolutePath(),count.toString()+".jpg");if(pic.isFile()) {pic.renameTo(image);count++;}}File[] file2 = file.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {if(pathname.getName().endsWith(".jpg"))return true;return false;}});for(File pic:file2) {System.out.println(pic.getName());} }
}
结果
[外链图片转存中…(img-fqe9AdYz-1613061611905)]
Properties
properties是一个属性集合,继承HashTable,是一个线程安全的集合;properties可以储存键值对,同时键值对是字符串类型,它没有泛型。
//构造方法
Properties container = new Properties();//常用方法
container.setProperty("Trump","72");//使用迭代器遍历properties中的键值对
Iterator<Entry<Object, Object>> itr = container.entrySet().iterator();
while(itr.hasNext()) {Entry<Object, Object> set = itr.next();System.out.println(set.getKey()+"=====>"+set.getValue());
}//使用Set遍历键值对
Set<String> set = container.stringPropertyNames();
for(String pro:set) {System.out.println(pro+"=====>"+container.getProperty(pro));
}//load加载存储在硬盘中property的内容
container.load(FileInputStream fis);//以适合的方法将键值对写入到输出流,可以保存注释
container.store(FileOutputStream fos, String comment);
//-----////store方法,以适合的方法将键值对写入到输出流,可以保存注释FileOutputStream fos = new FileOutputStream("E:\\java程序\\properties_save.txt");container.store(fos, "American President");fos.close();
//----////将属性列表输出到指定的输出流
container.list(PrintWriter file);
举一个储存properties的例子
package IOStudy;import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;public class PropertyStudy {public static void main(String[] args) throws Exception {Properties container = new Properties();container.setProperty("Trump", "72");container.setProperty("Biden", "74");System.out.println(container.getProperty("Trump"));//使用迭代器遍历Iterator<Entry<Object, Object>> itr = container.entrySet().iterator();while(itr.hasNext()) {Entry<Object, Object> set = itr.next();System.out.println(set.getKey()+"=====>"+set.getValue());} //将属性列表输出到指定的输出流PrintWriter file =new PrintWriter(new FileOutputStream("E:\\java程序\\properties_save.txt"));container.list(file);file.close();}
}
[外链图片转存中…(img-qPwJjFAh-1613061611907)]
[外链图片转存中…(img-rRe7NZqH-1613061611908)]
读取properties在硬盘中的内容
//load加载properties内容FileInputStream fis = new FileInputStream("E:\\java程序\\properties_save.txt");container.load(fis);fis.close();Set<String> set = container.stringPropertyNames();for(String pro:set) {System.out.println(pro+"=====>"+container.getProperty(pro));}
[外链图片转存中…(img-2oIxvIii-1613061611908)]
参考文献
API:https://www.runoob.com/manual/jdk1.6/
菜鸟教程:https://www.runoob.com/java/java-tutorial.html
JAVA final关键字:https://blog.csdn.net/PickUpOldDriver/article/details/80566628
JAVA static block:https://blog.csdn.net/qq_35868412/article/details/89360250
JAVA this关键字:https://blog.csdn.net/qq_43555323/article/details/84993460
JAVA IO:https://blog.csdn.net/baobeiSimple/article/details/1713797
JAVA入门万字总结相关推荐
- 两万字长文总结,梳理 Java 入门进阶那些事
两万字长文总结,梳理 Java 入门进阶那些事 先给大家看下完整的思维导图,也是这篇文章的主要脉络. Java从入门到进阶学习路线 主导三个项目,让我独当一面 能力提升你要怎么学 全篇总结 Java ...
- 两万字长文总结,梳理 Java 入门进阶哪些事(推荐收藏)
两万字长文总结,梳理 Java 入门进阶哪些事(推荐收藏) 程序员小跃 2021-01-12 13:19:09 23 收藏 分类专栏: Java学习之路 文章标签: java 数据库 redis ...
- 两万字梳理 Java 入门进阶那些事
大家好,我是石头哥,今天跟大家分享一篇 Java 入门到进阶的文章,配合之前我写的[经验分享 -- 程序员编程如何入门.进阶]一起食用更佳哦. 作者是一名在职场已经写了6年程序的老程序员,从一开始的菊 ...
- Java入门到架构师知识点整理,P8的技术大咖是这样通关的
一个人最怕的不是路途遥远,而是看不到胜利曙光.我希望下面这篇文章能给你的学习之路带来一丝曙光,大家不妨试着读一下吧,如果有收获给我点个赞哟. 温馨提醒:这篇文章写着写着就一万字了,建议大家关注后再收藏 ...
- Java入门培训班怎么选择
想要学习java技术,小编一直给小伙伴推荐的是报班学习,目前市面上的java培训机构有很多,对于java培训班的选择很多小伙伴都比较迷茫,下面小编就为大家详细的介绍一下Java入门培训班怎么选择的问题 ...
- Java入门学习注意事项有哪些?
想要学好java技术,做好学习规划路线和注意事项是非常重要的,尤其是零基础学员,Java涉及到的知识点非常多,我们需要制定合理的Java学习路线图,这样会事半功倍,下面小编和大家总结一下Java入门学 ...
- Java实用教程笔记 Java入门
Java入门 JDBC Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新 ...
- Java入门(一):Hello World !
前言 从今天开始,准备写Java Web开发的系列文章,毕竟自己主攻的还是Java方向,Python只是业余学习的兴趣使然,在第二技能还没有培养成熟前,做好第一技能的巩固和提高是很有必要的.从正式入行 ...
- 《Java入门经典(第7版)》—— 6.11 练习
本节书摘来异步社区<Java入门经典(第7版)>一书中的第6章,第6.11节,作者:[美]Rogers Cadenhead(罗格斯 卡登海德),更多章节内容可以访问云栖社区"异步 ...
最新文章
- 无招胜有招之Java进阶JVM(八)类加载机制
- 用Intel跟AMD CPU烤肉,哪个更香,你们猜猜结果?
- 【摘抄】百度分词算法详解:查询处理以及分词技术
- java安装版本哪种好_我怎么知道我安装了哪个版本的Java?
- Mysql调优你不知道这几点,就太可惜了
- 架构师之路:从码农到架构师你差了哪些
- 借力阿里云存储产品 延锋彼欧加速数字化重塑
- Linux 正则表达式 流编辑之sed awk
- 马云:不能把孩子放在温室里,光给孩子知识是不够的
- 10.28-11.1-广州软件所-实习工作日记
- 什么是Code Review
- Google验证码ReCaptcha V3
- OpenCV人脸识别
- 健康猫涉嫌非法吸收公众存款被立案侦查 9名犯罪嫌疑人被抓
- java工程师青春饭吗_Java工程师是青春饭吗?
- “你打篮球像蔡徐坤”:微信翻译这个bug是怎么回事?
- 产品经理数据分析入门指南
- USB 检测外接摄像头
- 李嘉诚汕头大学毕业典礼上致辞:无心睡眠
- excel数据透视表中插入一列新数据