导语:

本系列文章仅仅用于自己的复习以及分享交流。它随着时间的推移,内容也会有所改变,假设这系列文章获得了一些回复,那我应该也会将其中有价值的内容做一些补充附录之类的东西。

目前这系列文章暂无明确的标题,等到它的结构较为明确的展现出来之后会再次补充。

一、了解JAVA

Java是什么?

是一门高级编程语言。

Java是哪家公司研发的,现在属于哪家公司?

sun公司、Oracle公司。

Java之父是谁啊?

詹姆斯.高斯林 Java能做什么?

基本上什么都可以干,主要做互联网系统的开发。

Java有哪些技术平台?

JavaSE(标准版)、JavaEE(企业版)、JavaME(小型版)

二、使用JAVA语言的前置条件

2.1 JDK的相关知识

1.什么是JDK?

JDK(Java Development Kit): Java开发工具包

2.JDK的作用?

必须安装JDK才能使用Java语言

PS.JDK中的LTS指的是?

long-term support:长期支持版

3.JDK的组成?

JDK由JVM,核心类库,开发工具组成。


1.JVM是什么?

Java Virtual Machine:Java虚拟机, 真正运行Java程序的地方。

2.核心类库是什么?

Java自己写好的程序,给程序员自己的程序调用的。

PS.JVM与核心类库构成了JRE。

JRE(Java Runtime Environment): Java的运行环境。

PSS.理解记忆的思路是:

因为“虚拟机”这东西在日常生活中可以拿来尝试运行一些不知是否安全的app什么的,因此自己搞出来的JAVA程序先在虚拟机(JVM)里运行一下也没什么问题。在学习的过程中会调用各种人家准备好的方法,例如Scanner之类的,所以在运行环境JRE中,核心类库也得有

3.开发工具是什么

java,javac等

PSSS.这里需要提到JAVA开发的三个步骤:编写代码,编译代码和运行代码

具体过程:

首先编写代码,生成一个源代码文件(.java),之后使用javac编译代码,得到一个字节码文件(.class)然后使用java运行代码。

也因此,JAVA能够跨平台是因为不同的操作系统能够提供不同的JVM。

三、JAVA语言的基础

3.1 JAVA中的注释

名称 单行注释 多行注释 文档注释
样式 //内容 /*内容*/ /**内容 */
快捷键(IDEA) ctrl+/ ctrl+shift+/ /**+enter

PS.注释在编译后的class文件中不存在。

3.2 JAVA中的变量

1.变量是什么,有什么作用?

变量是内存中的一块区域。

其作用是存储一个数据的,且存储的数据可以被替换。

2.变量的格式是什么?

数据类型 变量名称 = 初始值;

3.变量的分类

1.局部变量
2.成员变量2.1 实例成员变量2.2 静态成员变量

数据类型

1.数据类型的分类:

引用数据类型:String,自己写的类

基本数据类型:

数据类型 关键字
整数 byte
short
int(默认)
long
浮点数 float
double(默认)
字符 char
布尔 boolean

2.类型之间的转换

(1)自动类型转换

类型范围小的变量,可以直接赋值给类型范围大的变量。

【byte<short/char<int<long<float<double】

其中:int类型 , 加上L/l就是long类型,double类型,加上F/f就是float类型

在表达式中,小范围类型的变量会自动转换成当前较大范围的类型再运算。

表达式的最终结果类型由表达式中的最高类型决定。

在表达式中,byte、short、char 是直接转换成int类型参与运算的。

(2)强制类型转换

类型范围大的数据或者变量,不能直接赋值给类型范围小的变量,会报错。

格式:数据类型 变量2 = (数据类型)变量1、数据

强制类型转换可能造成数据(丢失)溢出;

浮点型强转成整型,直接丢掉小数部分,保留整数部分返回。


3.变量的基本特点是什么?

(1)变量中只能存一个值

(2)变量中存的值是可以替换的

PS.定义变量时需要注意的是:

(1)变量要先声明再使用

(2)变量声明后,不能存储其他类型的数据。

比如假设int类型的变量不能存double类型的数据。

(3)变量定义的时候可以没有初始值,但是使用的时候必须给初始值。

比如说先随便定义一些 int a; int b; 之类的,但我想用a的时候它得有个值。

(4)变量存在访问范围、同一个范围变量名不能重复。

3.3 JAVA中的关键字

定义:在JAVA中有特殊作用的词。

比如public之类的

3.4 JAVA中的标识符

定义:说白了就是名字

取名规则:

(1)由数字、字母、下划线(_)和美元符($)等组成

(2)不能以数字开头、不能是关键字、区分大小写

ps有关于什么驼峰模式我去找找看怎么弄比较好记

四、JAVA语言比基础稍微高一点的东西

4.1 各种进制的转换

(1)十进制转二进制的算法:除二取余法

4.2 计算机中数据的存储

除了1B = 8b这种单位之外,我们还要了解一下,计算机中会有很多文件形式,比如文本,声音与图像

字符在计算机中的存储有例如ASCII编码表的方式

PS字符’A’对应的数字是 65 ,字符’a’对应的数字是 97 ,字符’0’对应的数字是 48。这些可以记一记,说不定有用(?)

图片由像素点组成,像素点的颜色的表示也有很多方法,比如百分之几,或者0 - 255*255*255

声音的波纹每一点可由二进制的数据表示

4.3 数据的运算

4.3.1 运算符

4.3.1.1 通用内容

定义:对字面量或者变量进行操作的符号。

内容:+,-,*,/,%

PS.如果两个整数做除法,其结果一定是整数,因为最高类型是整数。

小案例题(后期案例应该也会整理出来)

Q:请将一个三位数的个位,十位,百位拆分开,打印在控制台

解题思路:这个题就是要利用数据类型的特点和运算符来算

以574举例

对于百位来说,574/100得到的是5.74,但是因为int类型是整数,所以5就有了

对于个位来说,574%10得到的是(商570)余4

把十位先整到个位的位置上,再用个位的计算方法来算就好了

最后总结一下:

个位 :数值 % 10

十位 :数值 / 10 % 10

百位 :数值 / 10 / 10 % 10

千位 :数值 / 10 / 10 / 10 % 10;

...

4.3.1.2 “+”用法

对于数字而言,就是数学的简单运算,而出现字符串的时候,就会变成连接运算

小案例题

Q:请写出以下输出语句的结果(大家复制IDE中的时候不要忘记写main方法,笑死。另外右键控制台的选项卡,在move  to中可以把运行结果放右边,更好对比)

int a = 5;System.out.println("abc" + 'a');System.out.println("abc" + a);System.out.println(5 + a);System.out.println("abc" + 5 + 'a');System.out.println(15 + "abc" + 15);System.out.println(a + 'a');System.out.println(a + "" + 'a');System.out.println(a + 'a' + " abc");System.out.println("abc" + a + 'a');System.out.println("abc" + (a + 'a'));

在结果中我们可以发现,'a'在能够计算的时候,是按照97这个ASC2值来计算的,而字符串就单纯的被连接了起来。

4.3.1.3 自增自减运算符

符号 名称 作用
++ 自增运算符 写在变量的前面或后面,使变量自身的值加1
-- 自减运算符 写在变量的前面或后面,使变量自身的值减1

举例:int i = 0; i++

具体实用的案例:点一下大拇指,就多一个赞。

注意:

(1)++ 、-- 只能操作变量

(2)++、--如果不是单独使用(如在表达式中、或者同时有其它操作),放在变量前后会存在明显区别:

放在变量的前面,先对变量进行+1、-1,再拿变量的值进行运算.

放在变量的后面,先拿变量的值进行运算,再对变量的值进行+1、-1.

这个比较好记

比如我先设定一个 int i = 3;

然后让 int j = i++;

在看的时候,就是先看到i,我们把i先赋值给j,然后再让i自加,

那么此时的j=3,i=4;

而假设int j = ++i;

先看到的是++,那就给i先自加再说

最后j=4,i=4;

小案例题

请写出此代码的运算结果

int c = 10;
int d = 5;
int rs3 = c++ + ++c - --d - ++d + 1 + c--;
System.out.println(rs3);
System.out.println(c);
System.out.println(d);

在计算的时候应该做好笔记,这样不容易出错

例如画上表格

c 10(初始值) (2)11 (3)12 (11)11
d 5(初始值) (5)4 (7)5
rs3 不知道 (1)10+ (4)10+12 (6)10+12-4 (8)10+12-4-5 (9)10+12-4-5+1 (10)10+12-4-5+1+12

把变量名和初始值都写好

第一步(1):算的是c++,因为加号写在后面,所以先运算再自增,所以是10+

第二步(2):c的值变为11

大概这样理解

4.3.1.4 赋值运算符

即“=”

扩展:

符号

作用

说明

+=

加后赋值

a+=b 等价于 a = (a的数据类型)(a+b); 将a + b的值给a

-=

减后赋值

a-=b 等价于 a = (a的数据类型)(a-b); 将a - b的值给a

*=

乘后赋值

a*=b 等价于 a = (a的数据类型)(a*b); 将a * b的值给a

/=

除后赋值

a/=b 等价于 a = (a的数据类型)(a/b); 将a / b的商给a

%=

取余后赋值

a%=b 等价于 a = (a的数据类型)(a%b); 将a % b的商给a

PS.扩展的赋值运算符隐含了强制类型转换。

比如大的类型要强转才能赋值给小类型,下面的代码一个出错一个不出错

byte a = 2;
int b = 5;
a = a/b;
a /= b;

4.3.1.5 关系运算符

符号

说明

==

a==b,判断a和b的值是否相等,成立为true,不成立为false

!=

a!=b,判断a和b的值是否不相等,成立为true,不成立为false

>

a>b,  判断a是否大于b,成立为true,不成立为false

>=

a>=b,判断a是否大于等于b,成立为true,不成立为false

<

a<b,  判断a是否小于b,成立为true,不成立为false

<=

a<=b,判断a是否小于等于b,成立为true,不成立为false

关系运算符得到的值是布尔类型

4.3.1.6 逻辑运算符

功能:可以把多个条件的布尔结果放在一起运算,最终返回一个布尔结果。

符号

介绍

说明

&

逻辑与

必须都是true,结果才是true; 只要有一个是false,结果一定是false。

|

逻辑或

只要有一个为true、结果就是true

逻辑非

你真我假、你假我真。 !true=false 、 !false= true

^

逻辑异或

如果两个条件都是false或者都是true则结果是false。两个条件不同结果是true。

短路逻辑运算符

符号

介绍

说明

&&

短路与

判断结果与“&”一样。过程是左边为 false,右边则不执行。

||

短路或

判断结果与“|”一样。过程是左边为 true, 右边则不执行。

对比:

逻辑与 “&” 、逻辑或“|”:   无论左边是 false还是 true,右边都要执行。

实际开发中、常用的逻辑运算符还是:&& 、 || 、 !

4.3.1.7 三元运算符(我记得也叫三目运算符)

写法:条件表达式 ?  值1 : 值2;

运算流程:先计算表达式,若值为true就得到值1,false得到值2

小案例题

Q:请找出三个数中的最大值。

int a = 2;
int b = 5;
int c = 4;
int d = a > b ? a:b;
int max = d>c?d:c;
System.out.println(max);

不要忘了找个变量接一下结果。

4.3.1.8 运算符的优先级

因为网络上很好查到,所以我这里就来整理一下记忆的思路

优先级最高的是括号,这个很好理解,就是肯定先括起来谁就先算谁,我们一般的习惯也是这样

第二高的是!非,~取反,++,--。也就是对这个数据本身有变化意涵的都会更先执行。

第三高的是乘除取余,数学规律

第四是加减,数学规律

小案例题

Q:请写出代码的输出结果

System.out.println(10 > 3 || 10 > 3 && 10 < 3);
System.out.println( (10 > 3 || 10 > 3 ) && 10 < 3);

4.4 程序流程控制

程序执行的常见形式有顺序结构,分支结构,循环结构

顺序结构是默认的执行流程

4.4.1分支结构

分支结构是通过判断某条件是否成立来选择某段程序执行

4.4.1.1 if语句

if语句的格式与执行流程:

格式1:

if (条件表达式) {

语句体;

}

执行流程:首先判断条件表达式的结果,如果为true执行语句体,为 false 就不执行语句体。

PS.if 语句中,如果大括号控制的只有一行代码,则大括号可以省略不写。


格式2:

if (条件表达式) {

语句体1;

} else {

语句体2;

}

执行流程:首先判断条件表达式的结果,如果为true执行语句体1,为 false 就执行语句体2。


格式3:

if (条件表达式1) {

语句体1;

} else if (条件表达式2) {

语句体2;

} else if (条件表达式3) {

语句体3;

} . . . else {

语句体n+1;

}

执行流程:先判断条件1的值,如果为true则执行语句体1,分支结束;如果为false则判断条件2的值 如果值为true就执行语句体2,分支结束;如果为false则判断条件3的值 ... 如果没有任何条件为true,就执行else分支的语句体n+1。


小案例题

1.设置几个考试成绩分数段,不同成绩打印出不同的奖惩结果。

2.设置一个正确的密码,让用户输入密码,当用户输入密码正确时打印“正确”,错误时打印“错误”

4.4.1.2 switch语句

相比起if语句,它的结构和格式更好看一些,适合做值匹配的分支

格式:

switch(表达式){

case 值1:

执行代码...;

break;

case 值2:

执行代码...;

break;

case 值n-1:

执行代码...;

break;

default:

执行代码n;

}

这里的default还挺容易被忘掉的。

执行流程:先执行表达式的值,拿着这个值去与case后的值进行匹配。 匹配哪个case的值为true就执行哪个case,遇到break就跳出switch分支。 如果case后的值都不匹配则执行default代码。

注意:

(1)表达式类型只能是byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String、不支持double、float、long。

这是因为假设设定一个double类型的变量,double a = 0.1+0.2;它输出的结果会是0.30000000……这样

(2)case给出的值不允许重复,且只能是字面量,不能是变量。

(3)不要忘记写break,否则会出现穿透现象。

就是判断符合结果却没有跳出这个分支,而是继续向下走。

但穿透其实也可以利用

例如case1和case2要执行的代码一样的话,我们可以写成这样,就会更加简单

switch(表达式){

case 值1:

执行代码1;

case 值2:

执行代码2;

case 值n-1:

执行代码n-1;

break;

default:

执行代码n;

// break;

}

4.4.2 循环结构

循环结构是重复执行某段程序多次

4.4.2.1 for循环

格式:

for (初始化语句; 循环条件; 迭代语句)  {

循环体语句【也就是重复执行的代码】;

}

案例:

输出3次HelloWorld

for (int i = 0; i < 3; i++) {

System.out.println("Hello World");

}

执行的流程:

循环一开始,执行int i = 0 一次。 然后判断循环条件:0 < 3 返回true ,进入到循环体中执行输出 :helloWorld ,

然后执行迭代语句i++ , 此时i=1了。

然后判断循环条件:1 < 3 返回true ,进入到循环体中执行输出 :helloWorld ,

然后执行迭代语句i++ , 此时i=2了。

然后判断循环条件:2 < 3 返回true ,进入到循环体中执行输出 :helloWorld,

然后执行迭代语句i++ , 此时i=3了。

然后判断循环条件:3 < 3 返回false, 循环立即结束


小案例题

(1)求1-5之间的数字和,并把求和结果在控制台输出。

解题思路:

写循环语句循环1-5

并设置一个变量来累加数据

(2)求1-10之间的奇数和,并把求和结果在控制台输出。

解题思路:判断是否为奇数,就是看这个数字除以二的余数是一还是零

(3)在控制台输出所有的“水仙花数”

【水仙花数是一个三位数。水仙花数的个位、十位、百位的数字立方和等于原数】

解题思路:之前我们已经练习过如何得到三位数的个位,十位,百位。然后通过循环语句遍历所有的三位数,再使用if语句判断它是否是水仙花数,如果是的话输出就好了

(4)在控制台输出所有的“水仙花数”,输出水仙花数的个数

解题思路:要知道个数,只需要再设置一个变量,让它自增


4.4.2.2 while循环

格式:

初始化语句;

while (循环条件) {

循环体语句【被重复执行的代码】;

迭代语句;

}

什么时候用for循环,什么时候用while循环?

它们在功能上是完全一样的,for能解决的while也能解决。

使用规范是:知道循环几次:使用for;不知道循环几次建议使用:while。


小案例题

世界最高山峰是珠穆朗玛峰(8848.86米=8848860毫米),假如我有一张足够大的纸,它的厚度是0.1毫米。请问,折叠多少次,可以折成珠穆朗玛峰的高度。

解题思路:

不知道循环几次所以使用while。

纸的初始厚度为0.1,对折一次翻一倍。


4.4.2.3 do  while循环

do-while循环的特点:一定会先执行一次循环体。

格式:

初始化语句;

do {

循环体语句;

迭代语句;

} while (循环条件);

使用案例 :先执行的这种循环在实际使用案例中就像抢票一样,抢了之后判断一下抢到没有。

三种循环的对比

for循环 和 while循环(先判断后执行)

do...while (第一次先执行后判断)

for循环中,控制循环的变量只在循环中可以使用。While循环中,控制循环的变量在循环后还可以继续使用。

4.4.2.4 死循环

定义:一直循环的执行下去,如果没有干预不会停止下来。

格式:

for(;;) {

System.out.println("Hello World"); }

【while的最为常用】

while(true) {

System.out.println("Hello World");

}

do {

System.out.println("Hello World");

} while (true);

PS.在IDEA中,添加死循环的快捷键是Ctrl+alt+t


小案例题:

设定一个系统密码,请用户不断的输入密码验证,如果验证不对就输出:密码错误,验证成功输出:欢迎进入系统,并停止程序。

解题思路:

将输入与验证都包含进死循环当中,if判断正确的话使用break跳出循环


4.4.2.5  循环嵌套

循环之间是可以嵌套的,例如:

for(int i = 0; i < 3; i++) {

for(int j = 0; j < 5; j++) {

System.out.println("这是一个循环嵌套");

}

}  ​​​​​​

嵌套循环的特点:外部循环每循环一次,内部循环全部执行完一次。


小案例题:

在控制台输入5行5列的*号组成的矩形

解题思路:

内循环负责打出5列的*,外循环负责换行


4.4.3 跳转控制语句

break   :  跳出并结束当前所在循环的执行。 只能用于结束所在循环, 或者结束所在switch分支的执行。

continue:  用于跳出当前循环的当次执行,进入下一次循环。只能在循环中进行使用。


小案例题:

你是一位攘夷志士,为了成为桂先生的心腹每天兢兢业业,这一天,桂先生安排你在未来五天每天去江户公园投喂六只猫咪,你领命,每天认真撸猫并拍摄照片上传到攘夷志士公众号做宣传。

(1)你投喂到了第三天,可恶的税金小偷最近四处巡逻,桂先生为了你的安全着想,让你不要去了。

解题思路:外循环是控制五天的,内循环是控制投喂六只猫咪的。但由于第四天的时候不能继续投喂了,因此当i等于4时使用break跳出循环。

(2)你投喂到了第三天,家里的速食荞麦面吃光了,需要进行补充,而超市特价还能顺便买些牛肉来吃火锅,桂先生派你去抢购食材,这一天就别去投喂猫咪了。

解题思路:外循环是控制五天的,内循环是控制投喂六只猫咪的。但由于第四天的时候有事,无法投喂了,因此当i等于4时使用continue跳出本次循环,明天继续投喂。


4.5 随机数Random

功能:用于在程序中生成随机数

使用方法:

(1)导包:告诉程序去JDK的哪个包中找随机数技术【至少IDEA会帮我们导进来,我们不用管】

(2)new一个随机数对象

Random r = new Random();

(3)调用随机数的功能来获取随机数。

int number = r.nextInt(10);

用int来接的话就调用nextInt,并且nextInt(n) 功能只能生成: 0 至 n-1之间的随机数,不包含n。

如果想生成3到15之间的随机数要怎么做呢?

解法:

先给3和15都减3,就会变成0到12,然后写

int number = r.nextInt(13);

这样就能得到0到12的随机数了

然后再加上3

int number = r.nextInt(13)+3;

小案例题:

随机生成一个1-100之间的数字,让用户来猜,猜大提示过大,猜小提示过小,直到猜中结束游戏

解题思路:先随机生成一个符合条件的数字,然后把整个输入和if判断都放进死循环里,猜到了的话就break跳出循环。

4.6 数组

定义:用来存储一批同种类型数据的容器。

例如我定义一个int类型的数组

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

里面只能存储int类型的数据

PS.这个[]写在int后面或者数组名后面都行,因为我最开始学的C语言,所以写后面比较习惯

4.6.1 静态化初始数组

也就是:定义数组的时候直接给数组赋值。

4.6.1.1 数组基本知识

书写格式:数据类型[]  数组名 = new 数据类型[]{元素1,元素2 ,元素3… };

eg.     int[] ages = new int[]{12, 24, 36};

简化后的书写格式:数据类型[] 数组名 = { 元素1,元素2 ,元素3,… };

eg.     int[] ages = {12, 24, 36};


数组的原理

以int[] ages = {12, 24, 36};这个数组为例

首先在内存中开辟一块存储数组变量ages的区域,然后再开辟一块连续的区域存储对象{12, 24, 36}【可以想象他们一人一个房间】它们有一个地址【门牌号】

int[] ages = {12, 24, 36};语句是从右往左执行的,这个等于号就会把【门牌号】交给变量来存储。

在使用过程中,变量可以通过地址找到数组,访问数据

PS.数组也是引用类型。【就是其中装着地址】


4.6.1.2 数组的访问

访问数组中元素的格式:数组名称[索引]

为数组赋值:数组名称[索引] = 数据;

数组的最大索引值为:数组名. length – 1

PS.在元素个数大于零的情况下才能使用。

补充:数组一旦定义出来,长度、类型就固定了。

4.6.2 动态化初始数组

也就是:定义数组的时候只确定元素的类型和数组的长度,之后再存入具体数据。

书写格式:数据类型[]  数组名 = new 数据类型[长度];

eg.   int[] arr = new int[3];

对比:两种数组定义时的特点和场景有什么区别?

当前已经知道存入的元素值,用静态初始化。

当前还不清楚要存入哪些数据,用动态初始化。

两种格式的写法是独立的,不可以混用。

eg.  int[] arrs = new int[3]{30,40,50}; 这样是错的。

两个数组变量可以同时指向一个数组对象,也就是两个数组变量保存着同一个数组地址

4.6.3 数组使用时可能存在的问题

如果访问的元素位置超过最大索引,执行时会出现ArrayIndexOutOfBoundsException(数组索引越界异常)

如果数组变量中没有存储数组的地址,而是null, 在访问数组信息时会出现NullPointerException(空指针异常)


元素默认值规则

数据类型 具体类型 默认值
基本类型 byte、short、char、int、long 0
float、double 0.0
boolean false
引用类型 类、接口、数组、String null

4.6.3 数组遍历

用案例来展示如何遍历数组

eg.int[] ages = {20, 30, 40, 50};

for (int i = 0; i < ages.length; i++) {

System.out.println(ages[i]);

}

小案例题:

(1)在本周壁外调查的过程中,让宝的巨人击杀数量分别是:3,4,2,0,5匹,请计算出让宝本周击杀数量的总和。

解题思路,先将击杀数量存进数组中,对数组进行遍历,将各个索引中的数据累加起来。

(2)训练兵吃晚饭的时候在聊天,说到各自的身高,大家公认贝贝(190)最高,阿尼(153)翻白眼不想理他们,让宝(175)撑着脸道:“我也就比某个赶着去死的家伙高5厘米而已”。而对方反击“确实比不了你,脸上额外增加了五厘米。”此时利歪(只是想迫害一下小矮子)踹门而入。

请通过数组求以上角色的身高最大值。

解题思路:先将大家的身高放进数组里{190,153,175,170,160,},设定一个max变量存储数组中第一个元素,遍历数组进行比较,将最大值存入max中,最后输出max

(3)写一个小游戏,后台随机生成1-30之间的五个数字,用户可以输入数字来猜,未猜中提示:“未命中”,并继续猜测。猜中提示:“运气不错,猜中了”,并输出该数据第一次出现的索引位置,最后把数组中的5个数据都输出, 然后结束本游戏。

解题思路:使用Random生成五个随机数存储进数组里。在死循环中让用户输入数字,遍历数组寻找是否与用户输入的数字匹配,假设匹配就break

(4)同人大手大发慈悲准备给每位S级英雄画同人图,(为了简单大家可以挑一些自己喜欢的英雄,比如油腻假面,刘海大婶,邦古老头什么的),但是大手说要随机,根据S级英雄的等级数字来随机摇号,最后输出一组随机的排名。

解题思路:先将s级英雄的排名存入数组,遍历数组,并通过Random随机索引值,让i位置的数据与随机的索引位置的数据交换,最终得到新的数组。

【随机交换排名也可以用在洗牌当中】


对元素交换来一点小小的补充

比如要交换的是 int a = 1;int b  = 2;

我们可以创建一个int c = 0;

然后:

c = a;

a = b;

b = c;

也可以:

a = a+b;

b = a-b;

a = a-b;


4.7 java内存的分配

JAVA中的内存可以分为五块区域

方法区

本地方法栈

寄存器

就像家里有客厅厨房一样,每个地方有每个地方的用途,易于管理和维护,提高性能

方法区:是字节码文件加载时进入的内存【.class文件】

栈内存:方法运行时进入的内存,变量也在其中

堆内存:new的那些对象,在这块内存中开辟空间并分配地址

4.8 方法

定义:方法是一种语法结构,它可以把一段代码封装成一个功能,以方便重复调用。

例如 main方法

为什么要使用方法?

(1)提高了代码的复用性。

假如一个功能,在这个地方也要用,那个地方也要用,只写一遍就更简单一些

(2)让程序的逻辑更清晰。

对一个庞大的系统而言,会有许许多多的方法,要是不调用方法,而是将这些代码放在例如switch语句中,就显得非常凌乱,而调用某个方法则只需要一行。

4.8.1 定义方法

书写格式:

修饰符  返回值类型  方法名( 形参列表 ){

方法体代码【需要执行的功能代码】

return 返回值;//可能有可能没有

}

定义方法时真正需要关注的就两点:1、分析方法是否需要申明返回值类型;2、分析方法是否需要接收参数

PS.形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值。

如果方法不需要返回结果,返回值类型必须申明成void(无返回值),  此时方法内部不可以使用return返回数据。

方法如果没有参数,或者返回值类型申明为void可以称为无参数、无返回值的方法,依次类推。

举例:一个求和的方法:

public static int add ( int a , int b ){

int c = a + b;

return c;

}

返回值类型和返回值的类型要一致

4.8.2 调用方法

书写格式:

方法名(假如有要传递的参数就写在这里);

举例:调用求和的方法:

int sum = add(10, 20); //用一个int类型的变量接一下返回值

4.8.3 具体使用方法的注意事项

(1)方法的编写顺序无所谓。

假如你先写main方法,再写别的方法也可以。

(2)方法与方法之间是平级关系,不能嵌套定义。

也就是方法里面不能写别的方法。

(3) return语句下面,不能编写代码,因为永远执行不到,属于无效的代码。

return了就直接把值返回了,后面就执行不下去了。

(4)方法不调用就不执行,  调用时必须严格匹配方法的参数情况。

就像你不叫别人别人也不理你,然后你给人家寄信也得把地址写对,人家是int类型,你别传double类型

(5)有返回值的方法调用时可以选择定义变量接收结果,或者直接输出调用,甚至直接调用;无返回值方法的调用只能直接调用。


小案例题:

(1)定义一个方法,方法中计算出 1到n的和并返回。

解题思路:它说了要返回,就肯定有返回值,它有n,说明肯定要传参。计算用for循环来累加就行了。

(2)写一个能判断某数是奇数还是偶数的方法。

解题思路:某数肯定还是让你输入的,所以要传参,但是返回不返回都可以,因为在本方法里面输出和在main方法(或调用本方法的方法)里面输出都行。

(3)给一个数组求最大值的例题,也可以把求最大值的过程单独成一个方法。

解题思路:传参要把数组传过去,最大值应该返回


4.8.4 调用方法在内存中是怎么弄的?

方法是放在方法区中的,被调用的时候,需要进入到栈内存中运行

方法没有被调用的时候,在方法区中的字节码文件中存放

被调用需要进入栈内存中运行

所以可以将弹夹看做方法区,子弹看做方法,枪膛看做栈内存

4.8.5 方法的参数传递

4.8.5.1 基本类型的参数传递

值传递 : 在传输实参给方法的形参的时候,并不是传输实参变量本身, 而是传输实参变量中存储的值,这就是值传递。

实参:如在方法内部定义的变量。

形参:如在定义方法时,“()”中所声明的参数

4.8.5.2 引用类型的参数传递

也是值传递,但传递的是参数传输存储的地址值。


小案例题:

(1)写一个方法,要求将数组输出成:“该数组内容为:[1, 2, 3, 4, 5]”这样

解题思路:它肯定要得到一个数组才能输出,所以需要传参,但是可以不返回

需要遍历数组才能拿到数据

输出时,假设不是最后一个数,就输出数字加逗号,如果是最后一个数字应该输出数字+反中括号。

(2)设计一个方法可以接收整型数组,和要查询的元素值;最终要返回元素在该数组中的索引,如果数组中不存在该元素则返回 -1。

解题思路:要传参,要返回值。遍历数组,先展示一下有哪些元素,然后遍历数组,让用户输入的数据和数组中的数据进行匹配,把i返回回来。

(3)设计一个方法比较两个整型数组是否一样。【如果两个数组的类型,元素个数,元素顺序和内容是一样的我们就认为这2个数组是一模一样的。】返回true或者false。

解题思路:需要传参,需要返回值。可以定义一个方法先比较他们的元素个数是否相等,再比较相同位置的元素是否相等,如果两个都是true那么证明他们相等。


4.8.6 方法的重载

定义:同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。

举例:利根川老师每天的工作量很大,可能要给黑服们开会,可能要被兵藤会长制裁,偶尔有空去打高尔夫球。

public class Tonegawa {

/**(1)默认被制裁。*/

public static void work(){

System.out.println(“默认被兵藤会长制裁!");

}

/** (2)还要开会。 */

public static void work(String location){

System.out.println("在"+location+"给黑服开会");

}

/**(3)开会之后去打高尔夫*/

public static void work(String location ,double times){

System.out.println("在"+location+"给黑服开会.打"+times+"小时高尔夫球");

}

}

方法重载的作用 :可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计。

方法重载的识别技巧 :只要是同一个类中,方法名称相同、形参列表不同,那么他们就是重载的方法,其他都不管!(如:修饰符,返回值类型都无所谓)

形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。


return关键字单独使用

效果 :可以立即跳出并结束当前方法的执行。

对比记忆:

  • return; 跳出并立即结束所在方法的执行。
  • break; 跳出并结束当前所在循环的执行。
  • continue; 结束当前所在循环的当次继续,进入下一次执行。

五、面向对象

在学习面向对象的时候,可以把面向对象和面向过程做一个对比

面向过程,就像我们之前做过的很多练习,桂先生让你去投喂猫咪,你先干了前三天,第四天出事了,那我们就得用continue跳出来。每一步都很明确。

面向对象,是将自己作为一个旁观者,我来命令谁干什么事情,他们自己去做事。也就是可以把面向看做“找”,把对象看做“谁”,找谁来干活。

在这种情况下,面向对象与面向过程的优缺点是什么?

优点 缺点
面向过程 简单 维护性差
面向对象 可扩展性强,维护成本低 新手上手难

在之前做例题的时候,我们已经使用过例如:

System.out.println();

Scanner

Random

这其实就是一种面向对象

5.1 类

定义:是对象共同特征的描述;

我们可以将类想象成一个设计图,根据这个设计图可以制造出具体的对象,也就是真实存在的具体实例。

例如

Random r = new Random();

Random就是一个类型,根据Random这个设计图,new一个新的r对象出来

5.1.1 设计类

总体格式:

public class 类名 {

1、成员变量Field(代表属性,一般是名词)

2、成员方法Method(代表行为,一般是动词)

3、构造器Constructor  (初始化一个类的对象并返回地址)

4、代码块

5、内部类

}

我们可以用一个案例来学习

今天是5.26日,还有一个月就是桂先生的生日了,我想整一张猫咪设计图,生成许多猫咪送给桂先生做生日礼物。

public class Cat{

}

这里就是一个cat类。

猫咪存在一些共同特征。

public class Cat{

String name;//人类为了区分猫咪,会给它们起名字

String color;//每只猫咪都有不同的花色

int age;//至少按周岁比较好区分年龄

}

猫咪可能会有一些行为

public class Cat{

String name;//人类为了区分猫咪,会给它们起名字

String color;//每只猫咪都有不同的花色

int age;//至少按周岁比较好区分年龄

public  void play(){

}//动物有玩耍的天性

public  void eat(){

}//猫咪至少要吃饭

}

有了设计图之后,我们就可以生成猫咪对象了

书写格式:类名 对象名 = new 类名();

也就是:Cat c = new Cat();

生成一只猫咪之后,我们可以看看它长什么样子,看看它在做什么

访问属性:   对象名.成员变量

c.color

访问行为:   对象名.方法名

c.play


补充:

类名首字母建议大写,且有意义

一个Java文件中可以定义多个class类,但只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。 实际开发中建议还是一个文件定义一个class类。

成员变量的完整定义格式是:修饰符 数据类型 变量名称 = 初始化值; 一般无需指定初始化值,存在默认值。

修饰符比如 private。默认值就是之前数据类型的默认值。

1.对象是放在哪个位置的?

堆内存中

2. Cat c = new Cat();  c变量名中存储的是什么?

存储的是对象在堆内存中的地址。

3.成员变量的数据放在哪里,存在于哪个位置?

对象中,存在于堆内存中。

4.当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。Java存在自动垃圾回收器,会定期进行清理。


5.1.2 构造器

定义:定义在类中的,可以用于初始化一个类的对象,并返回对象的地址。

书写格式:

修饰符 类名(形参列表){

...

}

当形参列表存在的时候,称为有参数构造器。不存在称为无参数构造器

无参数构造器(默认存在的):初始化对象时,成员变量的数据均采用默认值。

有参数构造器:在初始化对象的时候,同时可以接收参数为对象进行赋值。

PS.至少在IDEA中,构造器是可以右键一下自动生成的

调用构造器得到对象

书写格式:类 变量名称 = new 构造器;

也就是之前写过的:Cat c = new Cat();

如果要传参的话:Cat c = new Cat("咪咪","玳瑁",1);

补充:

任何类定义出来,默认就自带了无参数构造器,写不写都有。

一旦定义了有参数构造器,那么无参数构造器就没有了,如果还想用无参数构造器,此时就需要自己手写一个无参数构造器了。


防忘记,稍微整理一下

public class Cat {

...

// 无参数构造器(需要写出来了)

public Cat(){

}

// 有参数构造器

public Cat(String n,String c,int a){

}

}

构造器的写法也就是比类少一个class而已


5.1.3 this关键字

作用:代表当前对象的地址。

在何处使用:可以出现在构造器、方法中

举一个例子

public class People{

String name;

public void doSth(String name){

sout(this.name+"和"+name+"干活去了");

}

}

this.name指的是对象的名字,name指的是传来的名字

5.2 封装

封装是干什么的:告诉我们如何正确设计对象的属性和方法。

封装的原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为。

举一个例子

学生写作业

应该有一个学生类

public class Student {

...

}

有一个作业类

public class Homework {

...

}

那么是不是要再定义一个写的方法?

但由于:对象代表什么,就得封装对应的数据,并提供数据对应的行为。

所以作业类应该提供“写”这个行为

public class Homework {

String subject;

sout("写"+suject+"作业");

}

PS.这种作业自己写自己也太爽了(x)

封装的好处:

让编程变得很简单,有什么事,找对象,调方法就行。

降低我们的学习成本,不用记对象的那么多方法,有需要时去找就行。

如何进行封装更好?

一般建议对成员变量使用private(私有、隐藏)关键字修饰进(private修饰的成员只能在当前类中访问)。

为每个成员变量提供配套public修饰的的getter、setter方法暴露其取值和赋值。

PS.getter、setter方法至少在IDEA中也能右键自动生成

案例:

public class Cat{

private String name;

private String color;

private int age;

}

5.2 JavaBean

定义:也可以称为实体类,其对象可以用于在程序中封装数据。

举例:是创建的猫咪类,学生类,作业类,却不是测试类

书写要求:

成员变量使用 private 修饰。

提供成员变量对应的 setXxx() / getXxx()方法。

必须提供一个无参构造器;有参数构造器是可写可不写的。


成员变量和局部变量的区别

区别

成员变量

局部变量

类中位置不同

类中,方法外

常见于方法中

初始化值不同

有默认值,无需初始化

没有默认值,使用之前需要完成赋值

内存位置不同

堆内存

栈内存

生命周期不同

随着对象的创建而存在,随着对象的消失而消失

随着方法的调用而存在,随着方法的运行结束而消失

作用域

在所归属的大括号中


小案例题:

使用面向对象编程来展示番剧。

解题思路:比如选择自己喜欢的番剧《银魂》《xx的巨人》【对不起我还是觉得前期角色都很棒呜呜作者不是人】《一拳超人》

那么一部番就是一个java对象了,我们设计番剧类,创建对象就好了

番剧的成员变量可以有:名称,评分,主要角色之类的

创建好的番剧对象可以存储在数组中,通过遍历数组来展示番剧信息。

在这里有一个新手可能会懵的地方。

因为一部番剧一般会有两三个主要角色,所以我们应该把角色姓名存进数组里。

但是数组要怎么样Get和set呢?

Movie2 m = new Movie2();
m.setName("银魂");
m.setScore(9.8);
String actor[] = {"桂小太郎", "河上万齐"};
m.setActor(actor);//因为角色是一个数组类型,所以要先把数组定义出来才能传值
-----------------------------------------------------------------------
要读取数组中的元素仍然需要遍历
Movie2 m3[] = {m, m1, m2};//将三个番剧对象存入数组中
for (int i = 0; i < m3.length; i++) {Movie2 a = m3[i];System.out.print("番剧名称" + a.getName() + "评分" + a.getScore() + "重要角色");String arr[] = a.getActor();//用一个叫arr的数组接get到的重要角色数组for (int i1 = 0; i1 < arr.length; i1++) {//遍历arr数组拿到角色String b = arr[i1];if (i1 < arr.length - 1) {System.out.print(b + ",");} else {System.out.print(b + "。");//这个if判断是为了写出来好看,所以你想怎么写就怎么写吧}}System.out.print("\n");
}

六、API

全程:Application Programming Interface,应用程序编程接口

本质:Java写好的程序(功能),可以直接调用。

通过查询API文档可以全面的了解代码的功能

6.1 常用API之String

定义:java.lang.String 类代表字符串,String类定义的变量可以用于指向字符串对象,然后操作该字符串。

Java 程序中的所有字符串文字(例如“abc”)都为此类的对象。

特点:String被称为不可变字符串类型,它的对象在创建后不能被更改。

PS.通过拼接改变的字符串其实都是产生并指向了新的字符串对象。这些字符串对象存储在字符串常量池中。

6.1.1 String常用API

方法名

含义

public boolean equals (Object anObject)

将此字符串与指定对象进行比较。只关心字符内容是否一致

public boolean

equalsIgnoreCase (String anotherString)

将此字符串与指定对象进行比较,忽略大小写比较字符串。

只关心字符内容是否一致

方法名

含义

public int length​()

返回此字符串的长度

public char charAt​(int index)

获取某个索引位置处的字符

public char[] toCharArray​():

将当前字符串转换成字符数组返回

public String substring(int beginIndex, int endIndex)

根据开始和结束索引进行截取,得到新的字符串

(包前不包后)

public String substring(int beginIndex)

从传入的索引处截取,截取到末尾,得到新的字符串

public String replace(CharSequence target,

CharSequence replacement)

使用新值,将字符串中的旧值替换,得到新的字符串

public String[] split(String regex)

根据传入的规则切割字符串,得到字符串数组返回


小案例题:随机产生一个5位的验证码,每位可能是数字、大写字母、小写字母。

解题思路:设置一个字符串存放数字,大小写字母。使用Random生成一个用length​()得到的符合条件的随机索引值。

在循环中,使用charAt​()方法得到随机出的字符,然后拼接起来,得到一个验证码。

用户输入验证码,使用equalsIgnoreCase方法判断是否符合条件。

6.2 常用API之ArrayList

集合的定义:是一种容器,用于装数据。与集合类似。集合中存储的元素并不是对象本身,而是对象的地址。

与数组的差异:数组定义完成并启动后,类型确定、长度固定。

集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。

集合更适合做元素个数不确定,且要进行增删操作的业务场景。

相比起数组来说,集合的功能更多。

在实际的应用中,类似于“购物车”这个场景就可以使用集合来实现

6.2.1集合之中的ArrayList集合

ArrayList是集合中的一种,它支持索引。

构建ArrayList集合

public ArrayList​()

向集合中添加元素

方法名

含义

public boolean add(E e)

将指定的元素追加到此集合的末尾

public void add(int index,E element)

在此集合中的指定位置插入指定的元素

泛型

定义:泛型就是指在类定义时不会设置类中的属性或方法参数的具体类型,而是在类使用时(创建对象)再进行类型的定义。会在编译期检查类型是否错误。

ArrayList<E>:是一个泛型类,可以在编译阶段约束集合对象只能操作某种数据类型

案例:ArrayList<String> :此集合只能操作字符串类型的元素。

ArrayList<Integer>:此集合只能操作整数类型的元素。

由于泛型只能支持引用数据类型,不支持基本数据类型。

使用的时候也和之前一样,没什么区别

例如:ArrayList<String> list1 = new  ArrayList();

6.2.3 ArrayList集合的常用API

方法名称

含义

public E get(int index)

返回指定索引处的元素

public int size()

返回集合中的元素的个数

public E remove(int index)

删除指定索引处的元素,返回被删除的元素

public boolean remove(Object o)

删除指定的元素,返回删除是否成功

public E set(int index,E element)

修改指定索引处的元素,返回被修改的元素


小案例题:

(1)背景:上一次的身高比较。要求将身高不大于一米六的身高去掉

解题思路:将五位的身高存储进ArrayList集合中,用get方法遍历集合中的元素。将小于等于一米六的身高从集合中删除remove

(2)将番剧展示的题用集合做一遍

(3)设计一个图书管理工具。要求显示书籍的编号,名称,作者,价格,并且能根据编号查询书籍

解题思路:创建一个图书类,将各个属性定义好,getset方法构造器都定义好。

创建一些图书对象,并将这些图书对象都存入一个集合中。

遍历集合展示所有的图书信息。

将查询单独创建为一个方法,先展示图书信息,然后用户输入图书编号,遍历图书信息进行查询,假设查到了返回那一条数据,假设没查到返回空。

七、static静态关键字

定义:指静态

作用:

称呼变为 效果变为
修饰成员变量 静态成员变量(类变量) 该成员变量只在内存中存储一份,可以被共享访问,修改
修饰成员方法 静态成员方法(类方法)

具体使用举例:

例如视频的观看人数只需要存储一份即可

例如写为 public static int onlineNumber = 13;

静态成员变量的访问方式

类名.静态成员变量      【较为推荐】

对象.静态成员变量      【不太推荐】

7.1 成员变量

分类:静态成员变量和实例成员变量

特点 使用 访问方式
静态成员变量 有static修饰,属于类,加载一次,内存中只有一份 常用于表示在线人数等需要被共享的信息

类名.静态成员变量(推荐)

对象.静态成员变量(不推荐)

实例成员变量 无static修饰,属于对象,有多个 常用于表示姓名年龄等特有的信息  对象.实例成员变量

PS.假设在这个类中调用这个类的静态成员变量可以不写类名

举例:在User类中调用在线人数可以直接写onlineNumber

更加具体的案例展示

//    定义的静态成员变量public static int onlineNumber = 161;//    定义的实例成员变量private String name;private  int age;public static void main(String[] args) {//        调用静态成员变量System.out.println(User.onlineNumber);System.out.println(onlineNumber);//        调用实例成员变量User user = new User();user.age = 10;user.name = "小酒窝";
}

而在其他类中的调用就需要用类名来调用了,调用之后的运算与曾经我们学习过的成员变量都很类似

//        类名.静态成员变量System.out.println(User.onlineNumber);//161//        对象名.静态成员变量User user = new User();user.onlineNumber++;//新来了一个人System.out.println(user.onlineNumber);//162

待补充上面的笔记

static访问注意事项

1.静态方法只能访问静态成员变量,不可以直接访问实例成员变量

2.实例方法可以访问静态成员变量,也可以访问实例成员变量

3.静态方法中不能出现this关键字

【对上述注意事项的理解】

因为实例成员是属于对象的,那么我们应该用一个对象来"."一下,我们必须知道是“谁的变量”才能准确得到属于这个人的属性。

而静态成员变量因为大家都能用,就像在线人数一样,对你和对我都是同样的人数。

this关键字表示的是当前对象,那么静态方法不一定用对象去调用,所以不能使用。

7.2 工具类

定义:类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员共同使用的。

优点:例如我们之前学习设计过的生成验证码的功能,可能在登录和修改密码时都需要输入验证码,如果每一次使用都要写一遍,代码的重复率就会很高,因此

使用工具类的好处: 一是调用方便,二是提高了代码复用

为什么工具类中的方法是静态方法二不是实例方法?

实例方法需要创建对象调用。 此时用对象只是为了调用方法,这样只会浪费内存。

所以建议工具类的构造器进行私有,这样就无法使用构造器构造对象,只能通过类名调用了。

举例:

public class xuexiUtil {private xuexiUtil(){}
}

小案例题:

需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils :

我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10, 20, 50, 34, 100](只考虑整数数组,且只考虑一维数组)

:经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组)

:定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。

解题思路:

一个一个慢慢写

我们已经知道了第一个方法名是“toString”,定义静态方法所以写public static,因为它说返回字符串,所以返回值写String。将所要展示的数组传过来

具体的内容就是遍历数组,然后将结果累加进一个定义好的空字符串中。

我们已经知道了第二个方法名是“getAerage”,定义静态方法所以写public static,因为它说返回平均值,所以返回值写double,将所要计算的数组传过来

遍历数组,用各种方式都可以去掉最大值最小值,再计算平均值,返回平均值即可

在测试类TestDemo中,通过类名调用工具类中的方法即可。


7.3 代码块

定义:在Java类下,使用 { } 括起来的代码被称为代码块 。

在程序中的位置:定义在类中方法外。

分类:

静态代码块:

格式:static{}

特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次

使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。  【也就是:如果要在启动系统时对静态资源进行初始化,则建议使用静态代码块完成数据的初始化操作。】

构造代码块(了解,见的少):

格式:{}

特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行

使用场景:初始化实例资源。


小案例题:

在斗地主游戏中,开启游戏房间之前应该提前准备好54张牌,方便后续的使用

解题思路:

在这个案例中,一个房间只需要一副牌,而且要提前准备,因此就采用静态代码块来构建。

用集合来存放扑克牌

可以定义一个数组a存放扑克牌的数字,定义一个数组b存放扑克牌的花色。

利用嵌套循环,将组合的扑克牌数字与花色存放进集合中。

大小王单独存放进去,就可以得到装着54张牌的扑克牌集合了。

将上述代码写在“static{}”里面即可


学到目前为止所有长相相似的东西的对比

1.类

public class HelloWorld {}
class HelloWorld {}

实际上public是修饰符,所以不写public只是表明一种其他权限的类罢了

2.主方法

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

主方法就是公开,静态,返回值为空,传值是名为args的字符串类数组

3.getter,setter

public int getAge() {return age;}

get方法就是公开,实例方法,有返回值,无传值的名为get的方法

public void setAge(int age) {this.age = age;}

set方法就是公开,实例方法,返回值为空,有传值的名为set的方法

4.构造器

public constructor(){}
//        这是一个无参数构造器public constructor(String name,double price){}
//        这是一个有参数构造器private constructor(){}

构造器仅仅由修饰符和类名构成。当不想被拿来随便创造对象时就私有,想的话就公开

5.同一个类中不是主方法的其他方法

public static void chu(int a,int b){}

公开的,静态的,返回值为空(当然这里也可以有返回值),名称为除,计算传来的两个数值的某个方法

6.成员变量所在类中的方法【实例成员方法】

public void goWith(String name) {System.out.println(this.name + "正在和" + name + "比赛");}

公开的,无返回值,方法名为gowith,传入name的方法

7.成员变量的对比

//    定义的静态成员变量public static int onlineNumber = 161;
//    定义的实例成员变量private String name;private  int age;

静态成员变量是公开,静态的

之前我们写的实例成员变量是私有的。

该写什么类型写什么类型

调用也是同样的道理,之前写的静态方法没有被谁调用就直接写方法名,这里的静态成员变量也可以

//        调用静态成员变量System.out.println(User.onlineNumber);System.out.println(onlineNumber);

用不用类名调用都可以

8.静态成员方法和实例成员方法看起来就是有没有static的区别

  public static void test1() {System.out.println("==test1==");}//    实例成员方法public void run() {System.out.println(name + "跑得快");}

9.静态代码块

static {}

光写一个静态就可以

10.构造代码块【实例代码块】

{}

甚至连静态都不用写

ps.实例代码块优先于无参构造器执行

8 设计模式

定义:在开发中,一个问题常常有n种解法,其中会存在最优解,最优解就是设计模式。

学习设计模式时应该重点关注:

第一:这种模式用来解决什么问题。

第二:遇到这种问题了,该模式是怎么写的,是如何解决这个问题的。

8.1 单例模式

含义:一个类永远只能创建一个对象。

作用:可以保证系统中,应用该模式的这个类永远只有一个实例。

例如任务管理器对象我们只需要一个就可以解决问题了。

优点:可以节省内存空间。

8.1.1 饿汉单例设计模式

含义:在用类获取对象的时候,对象已经提前创建好了。

案例:

/** a、定义一个单例类 */
public class SingleInstance {/** c.定义一个静态变量存储一个对象即可 :属于类,与类一起加载一次 */ public static SingleInstance instance = new SingleInstance ();/** b.单例必须私有构造器*/   private SingleInstance (){       System.out.println("创建了一个对象");}
}

设计步骤:

1.定义一个类,把构造器私有。

2.定义一个静态变量存储一个对象。

8.1.2 懒汉单例设计模式

含义:在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。

案例:

/** 定义一个单例类 */
public class SingleInstance{
/** 定义一个静态变量存储一个对象即可 :属于类,与类一起加载一次 */   public static SingleInstance instance ; // null
/** 单例必须私有构造器*/   private SingleInstance(){}
/** 必须提供一个方法返回一个单例对象  */public static SingleInstance getInstance(){if(instance == null){
//            如果第一次创建对象的话,就允许创建对象instance = new SingleInstance();}       return instance; }
}

设计步骤:

1.定义一个类,把构造器私有。

2.定义一个静态变量。

3.提供一个返回单例对象的方法。


对比饿汉单例和懒汉单例的设计思路:

1.都要先定义一个类然后将构造器私有。

2.都要定义一个静态变量,饿汉单例直接创建一个对象,懒汉单例则不用。

3.饿汉单例要提供一个方法返回一个对象。


9 继承

定义:继承可以让子类直接谁用父类的公共属性与方法。

关键字:extends

举例:

public class Student extends People {}

也就是创建一个学生类,继承,人类的东西

Student称为子类(派生类),People称为父类(基类 或超类)。

优点:可以提高代码的复用性。

PS.因此,在JAVA中,子类更加强大

9.1 继承的设计规范

子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的的属性和行为应该定义在子类自己里面。

这样设计的理由:

如果子类的独有属性、行为定义在父类中,会导致其它子类也会得到这些属性和行为,这不符合面向对象逻辑。


小案例题:

假设在学校中,有老师和学生这两种类。

学生信息和行为有:名称,年龄,所在班级,查看课表,填写听课反馈

老师信息和行为有:名称,年龄,部门名称,查看课表,发布问题

请用继承的思想来设计一下类

解题思路:

根据题目,我们明确知道要设计三个类,学生类和老师类还有一个父类,我们可以把它叫角色类或者人类都行。

并且老师和学生的共同属性和行为有:名称,年龄,查看课表,这些就要定义来角色类中

剩下的分别定义在学生类和老师类中

PS. 这里需要注意,即便是角色类这种父类,他的属性也可以是私有的。

9.2 继承的特点

继承的特点 :

1.子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。

1.1 子类是否可以继承父类的构造器?

答:不可以,子类有自己的构造器,不需要继承别人的。

1.2 子类是否可以继承父类的私有成员?(有争议)

答:在内存中,子类对象包含父类成员空间,子类成员空间,调用一个公开的方法可以,调用一个私有的方法会报错,但这不能说明没有继承,只能说明不能直接访问而已。

1.3 子类是否可以继承父类的静态成员?(有争议)

答:虽然子类可以直接使用父类的静态成员,但这属于一种共享,而并非继承

2.Java是单继承模式:一个类只能继承一个直接父类。

原因:例如父类1和父类2中有同名方法,那么子类在调用时究竟调用的是谁,这个说不清楚

3.Java不支持多继承、但是支持多层继承。

【多层继承也就是说父类也可以有自己的父类。假设父类和祖父类有同名方法就会就近】

4.Java中所有的类都是Object类的子类。

【有可能直接继承,有可能间接继承,但都继承了】

9.3 继承后的访问

在子类方法中访问成员变量或成员方法,依据就近原则

也就是:

先子类局部范围找 【在子类这个方法中看一下是否定义过】

然后子类成员范围找 【在子类成员变量、成员方法中看一下是否定义过】

然后父类成员范围找,如果父类范围还没有找到则报错。

如果子父类中,出现了重名的成员,会优先使用子类的

如果一定要在子类中使用父类的,可以通过super关键字,指定访问父类的成员。

例如:super.父类成员变量/父类成员方法

在脑子里把super当做变量去调用xxx就好

9.4 继承后的方法重写

定义:在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。

也就是说,方法左括号左边那一堆和父类一模一样的话,就是重写。

作用:当子类需要父类的功能,但父类的该功能不完全满足自己的需求时, 子类可以重写父类中的方法。

举例:假设设定两个类,一个新手机类,一个旧手机类。

旧手机类的发短信方法只能发送文字

新手机类的发短信方法除了发送文字还能够发送图片和音频,视频。

那么新手机类就可以重写旧手机的发短信方法,在此基础上加入一些其他功能

public void sendMsg() {System.out.println("发短信");}
//父类中的发短信方法@Override
public void sendMsg() {super.sendMsg();//用super表示调用的是父类中的发短信方法System.out.println("发送图片和音频");//除了父类的方法之外还有其他的功能}
//子类中的发短信方法

重写的注解@Override

功能:放在重写后的方法上,作为重写是否正确的校验注解。加上该注解后如果重写错误,编译阶段会出现错误提示。

因此,建议重写方法都加@Override注解,代码是否错误就很明显

方法重写注意事项和要求

1.重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。

【也就是方法左括号左边那一堆和父类的方法一模一样】

2.私有方法不能被重写。

【private修饰的方法不能被重写】

4.子类不能重写父类的静态方法,如果重写会报错。

3.子类重写父类方法时,访问权限必须大于或者等于父类

【缺省(不写) < protected < public】【一般要求访问权限一致】

9.5 继承后的子类构造器的特点

子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己。

原因:

子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。

所以:子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化。

子类构造器是如何调用父类构造器的?

子类构造器的第一行语句默认都是:super(),不写也存在。

super调用父类有参数构造器的作用:

初始化继承自父类的数据。

【也就是说,因为继承了父类的一些成员变量,通过这个方法给它赋值】

如果父类中没有无参数构造器,只有有参构造器,会出现什么现象?

会报错。因为子类默认是调用父类无参构造器的。

解决方法:子类构造器中可以通过书写 super(…),手动调用父类的有参数构造器

9.6 this和super

作用:

this:代表本类对象的引用;

super:代表父类存储空间的标识。

关键字

访问成员变量

访问成员方法

访问构造方法

this

this.成员变量

访问本类成员变量

this.成员方法(…)

访问本类成员方法

this(…)

访问本类构造器

super

super.成员变量

访问父类成员变量

super.成员方法(…)

访问父类成员方法

super(…)

访问父类构造器

因为之前已经使用过各个内容,除了this访问本类构造器,因此在此处做一个案例展示


小案例题:

在注册某吃粮网站时,用户可以输入自己的id和偏好,在创建对象的过程中,如果用户只输入了id,没有输入偏好,则默认输入的是“你才是二次元,你全家都是二次元”。

解题思路:

//先设计一个用户类public class User{// 定义题目中的成员变量private String id;private String hobby;//省略一下Getter,setter
//写出各个构造器public  User() {}
//如果没有填写偏好的话,就默认“你才是二次元,你全家都是二次元”public  User(String id) {this(id,"你才是二次元,你全家都是二次元");}public User(String id, String hobby) {this.id = id;this.hobby = hobby;}}

this(...)和super(…)使用注意点:

子类通过 this (...)去调用本类的其他构造器,本类其他构造器会通过 super 去手动调用父类的构造器,最终还是会调用父类构造器的。

注意:this(…) super(…) 都只能放在构造器的第一行,所以二者不能共存在同一个构造器中。

【解释:由于super(…) 默认存在于构造器的第一行,所以,假设子类构造器调用过this(…),他就优先执行兄弟构造器的super()了,所以不能写一起】


10 包

定义:包是用来分门别类的管理各种不同类的,类似于文件夹、建包利于程序的管理和维护。

【至少在IDEA中我们都创建了无数个包了】

语法格式:package 公司域名倒写.技术名称;

建议全部英文小写,并且具备意义

案例:

package com.xuexi.javabean;

建包语句必须在第一行

导包

1.相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:import 包名.类名;

示例:

import com.xuexi.d1_package.test.Student;

比如在之前,我们想要使用Scanner扫描器,就需要导包,只不过当时IDEA已经帮我们导了。

2.假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。

示例:

com.xuexi.d1_package.test2.Student s1 = new com.xuexi.d1_package.test2.Student();

如上,当本方法中已经有一个Student类了,那么另一个Student类就会写成这样

11 权限修饰符

定义:用来控制一个成员能够被访问的范围。

使用:可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制。

分类:权限修饰符有四种,作用范围由小到大(private -> 缺省(不写) -> protected - > public )

修饰符

同一 个类中

同一个包中

其他类

不同包下的

子类

不同包下的

无关类

private

缺省

protected

public

在记忆方面:

之前我们已经了解过一点了,private是私有,我们已经多次使用getter,setter方法来访问成员变量了。

public是公共,这个我们也不需要多说。

在范围方面,我们可以将包和类作为标记。

【包(类)】

首先包包裹着类。

那么这就天然分割出了四个位置出来

【包1(类1ABCD)(类2BCD)】【包2(类3CD)(类4D)】

A 就是private的作用范围

B 就是缺省作用范围

C 就是protected的作用范围,其中类3是类1的子类

D 就是public 那里都能访问

在本节我们要达成的目标是:

1.能够识别别人定义的成员的访问范围。

2.在自己定义成员(方法,成员变量,构造器等)时,一般需要满足如下要求:

成员变量一般私有。

方法一般公开。

如果该成员只希望本类访问,使用private修饰。

如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰。

12 final

定义:final是一个关键字,含义是最终。

作用:可以修饰 类、方法、变量

修饰类:表明该类是最终类,不能被继承。

修饰方法:表明该方法是最终方法,不能被重写。

修饰变量:表示该变量第一次赋值后,不能再次被赋值(能且仅能被赋值一次)。

final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。

final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。

具体使用场景:

工具类使用final修饰,因为工具类是拿来直接使用的,所以没必要继承,这样写显得很专业

变量由final修饰的使用:

例如有一个方法,在购买的时候可以打折:

 public static void buy(final double z){其中这个z是代表折扣z = 0.1;那么假设我想再将z设定为0.1的话,就会报错}

我传了一个z 折扣值过来,并且让它不能再次被赋值,就会比较安全。

12.1 常量

定义:常量是使用了public static final修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。

案例:

 public static final String schoolName = "不知道学校";
//原来的成员变量长这样:
private String schoolName = "";

作用:通常用来记录系统的配置数据。

原因:在编译阶段会进行“宏替换”:把使用常量的地方全部替换成真实的字面量。

维护系统容易,可读性更好,实现了软编码形式。

【例如上面的学校名,在网页之类的地方会经常使用,如果要改的话,只改这一处就很方便。】


小案例题:

在小游戏中利用上下左右控制角色的移动。

解题思路:

使用常量来标志上下左右。

在配置类中定义常量 UP = 1;(以此类推)

通过switch语句,匹配上下左右,输出角色的行动,例如“角色向上走了一格”


13 枚举

定义:枚举是Java中的一种特殊类型

作用:是为了做信息的标志和信息的分类

书写格式:

修饰符 enum 枚举名称{

第一行都是罗列枚举类实例的名称(建议全部大写)。

}

示例:

enum Joy4{KATSURA,GINTOKI,TAGASUGI,SAKAMOTO;
}

枚举的特征:

枚举类都是继承了枚举类型:java.lang.Enum

枚举都是最终类,不可以被继承。

构造器都是私有的,枚举对外不能创建对象。

枚举类的第一行默认都是罗列枚举对象的名称的。

枚举类相当于是多例模式。


常量和枚举做信息标志的对比:

选择常量做信息标志和分类: 虽然可以实现可读性,但是入参值不受约束,代码相对不够严谨。

【也就是自己可以定义常量的内容】

枚举做信息标志和分类: 代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术!建议使用!

14 抽象类

14.1 abstract 关键字

定义:abstract是抽象的意思

作用:可以修饰类、成员方法。修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。

书写格式

修饰符 abstract class 类名{

修饰符 abstract 返回值类型 方法名称(形参列表);

}

public abstract class Saitama{public abstract void onepounch();
}

其中:

抽象方法只有方法签名,不能声明方法体。

一个类中如果定义了抽象方法,这个类必须声明成抽象类,否则报错。

14.2 抽象类

定义:被abstract修饰的类。

使用场景:

之前我们将类比方为图纸,用来生产某样物品。那么抽象类就可以比方为不完整的图纸。

它一般作为父类,让子类来继承。

当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成。此时这个类就可以声明成抽象类。

比如上面的示例,埼玉的拳头有多种不同的形式,所以具体用哪种拳头就交给子类去完成

在继承抽象类时的注意事项:

一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。


小案例题:

以撒进入了宝箱房,他需要在大眼和洋葱中做一个选择。

其中大眼的效果是:最终伤害=2x(基础伤害+4)并且 射速大幅度下降为(子弹延迟 x2.1+3)

洋葱的效果是:射速+0.7

请实现以撒选择两种不同的道具之后的效果。

解题思路:

创建一个抽象物品类,在其中定义伤害,射速,子弹延迟等属性和属性值变化的方法。

创建一个大眼类继承物品类,重写属性值变化的方法,计算方式按照题目中的方式来计算,输出最终结果。

创建一个洋葱类继承物品类,重写属性值变化的方法,计算方式按照题目中的方式来计算,输出最终结果。

创建一个以撒类,创建一个大眼对象和洋葱对象,分别调用方法,得到结果。


抽象类的特征和注意事项:

最重要的特征:得到了抽象方法,失去了创建对象的能力(有得有失)

1.类所有用的成员变量,方法,构造器,抽象类都具备

2.抽象类中不一定有抽象方法。有抽象方法的类一定是抽象类

3.一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

4.不能用abstract修饰变量、代码块、构造器。【根据定义,他只修饰类和方法】


final和abstract的关系

互斥关系 (不能同时出现)

原因:

abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。

抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。


14.3 模板方法模式

我们曾经学过饿汉单例模式和懒汉单例模式,这是第三个

模板方法模式的使用场景:当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。

模板方法模式实现步骤:

1、定义一个抽象类。

2、定义2个方法,一个是模板方法:把相同代码放里面去,不同代码定义成抽象方法

3、子类继承抽象类,重写抽象方法。

模板方法建议使用final修饰,这样会更专业,为什么呢?

答:模板方法是给子类直接使用的,不是让子类重写的, 一旦子类重写了模板方法,则模板方法就失效了,因此,加上final后可以防止子类重写了模板方法,这样更安全、专业。

模板方法的优势

1. 提高了代码的复用性

2.模板方法已经定义了通用结构,模板方法不能确定的部分定义成抽象方法,交给子类实现,因此,使用者只需要关心自己需要实现的功能即可。


小案例题:

作为一个热血的同人女,你有无数喜爱的cp,你和你的同好两个人准备一起安利你们最真的cp。

要求你和你的同好的安利文段的第一段和最后一段内容一样,正文部分自己发挥。

请选择最合适的面向对象方案进行设计。

解题思路:

这里使用模板方法模式最优

根据上面的模板方法模式设计步骤,我们可以这样做:

1、定义一个抽象类。

(1)定义一个名为cp类的抽象类。

2、定义2个方法,一个是模板方法:把相同代码放里面去,不同代码定义成抽象方法

(2)在其中定义一个最终(final)的wirte方法。在其中将第一段可最后一段这种标准的内容定义好。

在其中定义一个抽象的正文方法。

让write方法调用这个抽象方法。

public abstract class CP {/*** 正式:声明模板方法模式*/public final void write(){System.out.println("题目:埼杰一生推");System.out.println("他,来自地狱业火。他,去往世界最强。人间拍档,闪亮登场。暑期档震撼上映。");
//        正文部分,每个子类都要写,但是每个子类写的情况都不一样
//        因此模板方法把正文部分定义成抽象方法,交给具体子类System.out.println(writeMain());
//        最后一段System.out.println("埼杰过上了幸福快乐的生活。");}public abstract String writeMain();
}

3、子类继承抽象类,重写抽象方法。

(3)定义两个类,分别是“你”类(为了方便后期称为埼杰人),和“你同好类”(为了方便后期称为埼杰人2)

埼杰人类和埼杰人2类都继承CP类,并重写正文方法(这里只举了一个例子)

public class saigenos extends CP {
//重写一下@Overridepublic String writeMain() {return "埼杰全身都是宝,发糖发粮少不了;人生若是饿得快,磕埼杰就活到老。";}
}

最后,在测试类中创建埼杰人对象或埼杰人2对象,调用CP类的模板方法,就可以实现题目中所要求的效果了。


15 接口

如何理解接口

从现实世界来看,我们可以想象插座,插座的插头是一种接口,所有的插头都要有一定的设计规范,才能保证插上之后有电。

声明一个接口,体现的是一种规范。规范一定是公开的。

关键字:interface

书写格式:

public interface 接口名 {// 常量// 抽象方法
}

JDK8之前,接口中只能是抽象方法和常量,没有其他成分了。

记忆点:接口的写法和类的写法很类似,所以可以放一起记

注意事项:

1.接口不能实例化。

2.接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。

15.1 接口的使用

接口的用法:接口是用来被类实现(implements)的,实现接口的类称为实现类。

实现类可以理解成所谓的子类。毕竟接口的写法和类非常相似

实现类的书写格式:

修饰符 class 实现类的名称 implements 接口1, 接口2, 接口3 , ... {
}

实现的关键字:implements

接口可以被类单实现,也可以被类多实现。

接口实现的注意事项:

一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类。


小案例题:

身为一个攘夷志士,每天都要刻苦训练,为了成为桂先生身边最可靠的部下,你更是仔细的阅读了攘夷志士守则。攘夷志士每天需要:1.看最新出的家庭伦理肥皂剧。2.投喂肉球。3.吃不堕落的食物。4.开攘夷会议。

你决定恪尽职守,并在此基础之上每天探听各种消息汇报给桂先生。

请利用接口中学到的知识实现。

解题思路:

攘夷志士守则就可以设定为一个Joy接口,你额外想做的事情设定为另一个Other接口。

Joy接口中有四个抽象方法:watch();throw();eat();meet();

Other接口中有一个Snooping();方法

创建一个“”你”实现类,实现Joy接口和Other接口。

在测试类中创建“你”对象,调用方法,就可以实现了。


小结:

1.类和类的关系:单继承。

2.类和接口的关系:多实现。

3.接口和接口的关系:多继承,一个接口可以同时继承多个接口。

接口多继承的作用:规范合并,整合多个接口为同一个接口,便于子类实现。

比如在上述例题中,攘夷志士除了遵守攘夷手册和探听各种消息之外,还要与真选组战斗,与鬼兵队打嘴炮,和以快援队为首的商人交易,去人妖店打工,变成猫猫,变成老头,变成秃头等等。这些接口每个都写一遍很麻烦,所以如果让遵守攘夷手册继承与真选组战斗,与鬼兵队打嘴炮,和以快援队为首的商人交易等接口,那么具体写的时候,实现类只要实现遵守攘夷手册和探听各种消息两个接口了。

特别一提的是,接口继承的时候,因为都是抽象方法,所以不用重写。

15.2 接口方法

此处指的是JDK8开始接口新增的方法

15.2.1 默认方法

实际上,想要在接口中写“实例方法”,也就是曾经类中的方法的话,就是默认方法了。

书写格式类似于普通实例方法,区别:必须用default修饰,默认用public修饰。

默认方法的调用:需要用接口的实现类的对象来调用。

案例:

(public) default void run(){System.out.println("--开始跑--");
}

有public默认存在,所以上述案例用括号括起来,写不写都行

主要因为接口可以当做一种规范,而规范是公开的,所以其中的方法应该公开

15.2.2 静态方法

静态方法的写法与类中的静态方法也很类似

书写要求:默认会public修饰,必须static修饰。

静态方法的调用:接口的静态方法必须用本身的接口名来调用。

【对比而言,之前学的静态方法在类中的调用是不写类名的,但是在其他类中要用类名调用】

案例:

 (public) static void want(){System.out.println("想下班");}

有public默认存在,所以上述案例用括号括起来,写不写都行

主要因为接口可以当做一种规范,而规范是公开的,所以其中的方法应该公开

15.2.3 私有方法

是私有的实例方法

书写格式:必须使用private修饰,从JDK 1.9才开始有的。

私有方法的访问:只能在本类中被其他的默认方法或者私有方法访问。

【如果给私有方法加上Static关键字的话,就可以用静态方法访问了】

案例:

 private void go(){System.out.println("开始跑");
}

15.2.4 接口小结

JDK8版本开始后,Java只对接口的成员方法进行了新增,后来加入10个新的抽象方法,此时改了接口就要所有实现类实现这些方法。

为了丰富接口功能的同时 又不对子类代码进行更改,允许接口中直接定义带有方法体的方法

JDK8新增的3种方法我们自己在开发中很少使用,通常是Java源码涉及到的,我们需要理解、识别语法、明白调用关系即可。

15.2.5 接口的注意事项

1.接口不能创建对象(接口就是更加彻底的抽象)
2.一个类实现多个接口,多个接口中有同样的静态方法不冲突【因为静态方法只能由接口名来调用】
3.一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认使用父类的。【父类更近】
4.一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可【类实现接口本来就要重写方法】
5.一个接口继承多个接口是没有问题的,如果多个接口中存在规范冲突则不能继承

16 多态

定义:指对象可以有多种形态。

常见形式:父类类型 对象名称 = new 子类构造器;

以下是以上一章的案例题举个例子,作为对比

CP cp = new saigenos();Saigenos sg = new saigenos();

成员访问特点:

方法调用:编译看左边,运行看右边。

变量调用:编译看左边,运行也看左边。(多态侧重行为多态)

解释:

伊丽莎白只是一个外皮,我们将它看做父类:

public abstract class Elizabeth{
public String type = "外星生物";public abstract void do();
}

周一的伊丽莎白是江莲,那么江莲子类继承了Elizabeth:

public class jianglian extends Elizabeth{public String type = "莲蓬队长";@Overridepublic void do() {System.out.println("莲蓬队长漏出腿毛");}
}

其他的伊丽莎白都是高松信司:

public class akamatsu extends Elizabeth{public String type = "人类监督";@Overridepublic void do() {System.out.println("人类监督说话啦");}
}

在测试类中,我们调用方法时

Elizabeth e = new jianglian();
e.do()//莲蓬队长漏出腿毛
sout(e.type);//外星生物

由于

方法调用:编译看左边,运行看右边。

所以e.do的运行结果是jianglian中的do的输出语句。

变量调用:编译看左边,运行也看左边。

所以e.type的运行结果是Elizabeth的type值。

因此左边右边指的就是创建对象语句中的左边或右边的类。

多态的前提

有继承/实现关系;有父类引用指向子类对象;有方法重写(多态侧重行为多态)

多态的优势

在多态形式下,右边对象可以实现解耦合,便于扩展和维护。

也就是在上面的案例中,

Elizabeth e = new jianglian();
e.do();
sout(e.type);

把jianglian换成akamatsu就完了,剩下的内容不需要变动,其他的内容也就完全不一样了。

定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。

但是多态下会产生的一个问题: 多态下不能使用子类的独有功能。


小案例题:

训练兵团中有教官和训练兵,每个人都要训练,但只有让或者艾伦会和对方吵架。

解题思路:

创建一个抽象父类,soldier类。在其中定义姓名成员变量训练抽象方法。

创建一个soldier的子类“teacher”教官类,其中定义姓名成员变量例如Shadis,重写训练方法。

创建一个soldier的子类student类,其中其中定义姓名成员变量例如Jean,重写训练方法,并写让宝的独有方法quarrel方法。

在测试类中以多态的形式创建一个教官对象和学员对象。

定义一个日常方法,传soldier类型的数据。在其中就可以调用训练方法。

在main方法中调用日常方法,将创建的让宝对象传过去,就可以得到结果。

但是以多态形式创建的学生对象却不能访问专有的吵架方法。


16.1 多态的类型转换问题

16.1.1 自动类型转换(从子类到父类)

Elizabeth e = new jianglian();

就类似于这样,不需要额外的操作。

16.1.2 强制类型转换(从父类到子类)

书写格式: 子类 对象变量 = (子类)父类类型的变量;

作用:可以解决多态下的劣势,可以实现调用子类独有的功能。

注意事项:  有继承/实现关系的类就可以在编译阶段进行强制类型转换;但是,如果转型后的类型和对象真实对象的类型不是同一种类型,那么在运行代码时,就会出现ClassCastException

解释:

Elizabeth e = new jianglian();
Akamatsu a = (Akamatsu) e;//就会异常

解决办法:强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换

书写格式:变量名 instanceof 真实类型

判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之,返回false。

案例:

在上一道小案例题中,想要调用让宝的吵架方法就需要强转

Soldier s = new Student();//以多态的形式创建一个学员对象
Student jean = (Student) s;//为了调用吵架方法而强制类型转换。if(s instanceof Student){Student jean = (Student) s;//使用instanceof判断,如果是学员类才能转。
}

小案例题:

请利用所学知识,模拟z市出现混乱后,英雄协会派出英雄拯救世界的场景。

解题思路:

我们要结合接口与多态来模拟这样的场景。

首先,英雄不是随便能当的,我们应该设置hero接口,在其中规定英雄一定要有的一些抽象方法。例如:“使用必杀技”,“安定人心”。

有了英雄接口,我们还要设置实现类,S级,A级,B级,C级,不同的类有自己独有的方法。

例如S类中应该有姓名属性,等级属性等。除了重写抽象方法外,还有自己独特的方法,例如s级英雄对怪人有震慑效果。

之后,我们需要一个英雄协会类,有了英雄协会类才能派遣调用英雄。

设计派遣方法,传hero类型的值进去。只要有英雄,那么至少可以“使用必杀技”,“安定人心”。想要使用独特方法,需要强制转换。使用instanceof判断传来的hero是不是s级,是不是a级以此类推进行强转。强转后就可以调用自己独特的方法。

最后,用测试类来模拟。

创建一个英雄协会对象,用多态创建s级,a级英雄对象。

英雄协会调用派遣方法,传s级,a级英雄对象过去,就可以实现场景了。


17 内部类

定义:内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。

案例:

伊丽莎白的体内有腿毛大叔

public class Elizabeth{// 内部类    public class Uncle{}
}

内部类的使用场景:当一个事物的内部,还有一个部分需要一个完整的结构进行描述时。

基本作用:

内部类通常可以方便访问外部类的成员,包括私有的成员。

内部类可以访问外部类的静态成员变量
内部类不能直接访问实例成员变量,需要创建外部类对象后,调用。
public class Elizabeth{public static int eyes = 2;private String color = "黄白";    public class Uncle{System.out.println(eyes);Elizabeth e = new Elizabeth();System.out.println(e.color);}
}

内部类提供了更好的封装性,内部类本身就可以用private ,protectecd等修饰,封装性可以做更多控制。

17.1 内部类的分类

17.1.1 静态内部类

有static修饰,属于外部类本身。

特点:它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已。

案例:

public class Outer{// 静态成员内部类    public static class Inner{}
}

静态内部类创建对象的格式:

外部类名.内部类名 对象名 = new 外部类名.内部类构造器;

记忆内容:说白了就是:“外部类”里有个叫xx的“内部类”,要创建一个xx对象,new一个 用“外部类”里面的“内部类构造器”来创建。

案例:

Outer.Inner in =  new Outer.Inner();

静态内部类的访问:

1、静态内部类中是否可以直接访问外部类的静态成员

可以,外部类的静态成员只有一份可以被共享访问。

2、静态内部类中是否可以直接访问外部类的实例成员

不可以的,外部类的实例成员必须用外部类对象访问。

开发中实际上用的还是比较少。

17.1.2 成员内部类

【之前我们学习了静态成员,实例成员,那么这里有静态内部类和成员内部类,感觉上可以对应起来】

无static修饰,属于外部类的对象。

案例:

public class Outer {// 成员内部类public class Inner { }
}

成员内部类创建对象的格式:

外部类名.内部类名 对象名 = new  外部类构造器.new 内部类构造器();

案例:

Outer.Inner in =  new Outer().new  Inner();

由于内部类也不是静态类了,因此在使用构造器时,应该使用内外两个类的构造器。

注意:

JDK16之前,成员内部类中不能定义静态成员【因为成员内部类是属于对象的,对象和静态肯定不能放在一起 】JDK 16开始也可以定义静态成员了。

成员内部类的访问拓展:

1、成员内部类中是否可以直接访问外部类的静态成员?

可以,外部类的静态成员只有一份可以被共享访问。

2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?

可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员

写的时候:Outer.inner in = new Outer().new inner();外部类的构造器点内部类的构造器,所以能访问


小案例题:

请观察如下代码,写出合适的代码对应其注释要求输出的结果。

class People{private int heartbeat = 150;public class Heart{private int heartbeat = 110;public void show(){int heartbeat = 78;System.out.println(??); // 78System.out.println(??); // 110System.out.println(??); // 150}}
}

解题思路:

【学习最初的部分可以跳过】

最开始学习的时候,我的想法就是,第一个78,是局部变量,所以直接用变量名就好了。

内部类中的110应该创建对象,用get方法得到。150也同理。

只不过这样写出来的代码很多,并且似乎也不符合“填空题”的样式。

【到这里】

我们之前学习过this关键字,指的是当前对象的地址。

因此本题的答案是:

System.out.println(heartbeat); // 78
System.out.println(this.heartbeat); // 110
System.out.println(Test3.this.heartbeat); // 150

注意:在成员内部类中访问所在外部类对象 ,格式:外部类名.this。

17.1.3 局部内部类

这个只需要了解就好了

局部内部类放在方法、代码块、构造器等执行体中。

局部内部类可以由abstract修饰,也可以写成接口,都行

局部内部类的类文件名为: 外部类$N内部类.class。【看到这样的文件你知道是局部内部类就行了】

17.1.4 匿名内部类【本章重点】

定义:本质上是一个没有名字的局部内部类。

作用:方便创建子类对象,【之前构建子类对象要先定义一个父类,让子类继承,再创建子类对象。内部类可以绕过这一步】

最终目的是为了简化代码编写。

书写格式:

new 类|抽象类名|或者接口名() {

重写方法;

};//注意一下这个分号,别忘了

注意一下,我们可以把接口也当做类来理解,所以不需要implements啥的

案例:

Employee a = new Employee() {@Overridepublic void work() {}
};
a. work();

17.1.4.1 匿名内部类的特点小结

匿名内部类是一个没有名字的内部类,同时也代表一个对象。【毕竟new了】

匿名内部类产生的对象类型,相当于是当前new的那个的类型的子类类型。【所以重写了】

17.1.4.2 匿名内部类的使用具体案例

假设你快乐的买到了ns,准备进入动森的世界里一边肝一边养老。那首先你得先捏一个人。

因此,在之前的学习中,会有一个抽象类People类,里面比如有一个方法是做表情。

当你想捏人的时候,创建一个玩家类继承这个People,并重写表情方法,毕竟每个人表情不一样。之后在main方法中用多态创建对象。

但是,使用匿名内部类则不一样。

写完People之后不需要玩家类继承了。

直接写

People p = new People() {@Overridepublic void expression() {System.out.println("玩家在做表情");}};p.expression();}

并且可以简化【匿名内部类可以作为方法的实际参数进行传输】

 p.expression( @Overridepublic void expression() {System.out.println("玩家在做表情");}});

小案例题:

假设逃逸许久的开司终于被捉住了,兵藤和尊,被叫回来的利根川老师以及一条小美人这四个人准备来一场快乐的斗地主(?),模拟一下这个场景。

解题思路:

首先,大家要玩斗地主都先都得会,所以我们需要一个斗地主接口,在其中定义打牌方法。

然后使用匿名内部类创建对象,把开司,兵藤会长,一条和利根川都创建出来,并重写打牌方法,其中可以写一些每个人各自的心理活动或者哭哭之类的(不是)。

我们还需要一个斗地主的流程,因此要定义一个方法,注意,传入的数据类型是接口的类型(毕竟还是多态的思路)。

其中可以用传入的对象调用打牌方法。

public class lianxi {//2.要把人都叫来玩public static void main(String[] args) {
//        叫开司过来玩Doudizhu Kaiji = new Doudizhu() {@Overridepublic void dapai() {System.out.println("开司哭了,准备逆袭了");}};play(Kaiji);//        叫兵藤过来玩Doudizhu hyudou = new Doudizhu() {@Overridepublic void dapai() {System.out.println("zawa~zawa~");}};play(hyudou);//        叫利根川老师过来玩Doudizhu Tonegawa = new Doudizhu() {@Overridepublic void dapai() {System.out.println("飒爽奔跑的利根川!!");}};play(Tonegawa);//        叫一条(罗马字搜不到,有点迷惑)过来玩Doudizhu yitiao = new Doudizhu() {@Overridepublic void dapai() {System.out.println("我还没看过上京生活录呢");}};play(yitiao);}//3.人都到了,现在应该有方法public static void play(Doudizhu doudizhu){System.out.println("黑服发牌");doudizhu.dapai();System.out.println("一轮结束");}}
//1.首先每个人都要会斗地主才行,所以要定义一个接口
interface Doudizhu{void dapai();
}

注意:

匿名内部类可以作为一个对象,直接传输给方法。

另一个小案例题(理解就好):

匿名内部类用在什么地方?

比如在一个界面中,点击按钮会有弹出框。其实是监听器在起作用。

我们用按钮对象调用监听器方法的时候就会将匿名内部类可以作为一个对象,直接传输给方法。

btn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JOptionPane.showMessageDialog(win,"想睡觉");}});
//        2.2 把2.1简化一下btn.addActionListener( e -> JOptionPane.showMessageDialog(win,"想睡觉"));

注意:匿名内部类通常是在开发中调用别人的方法时,别人需要我们写的时候才会定义出来使用。

18 阶段性螺旋上升环节

18.1 Object类

之前我们在继承中了解到:Java中所有的类都是Object类的子类。一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类。

因此,Object类的作用:Object作为所有类的父类,提供了很多常用的方法给每个子类对象拿来使用。

18.1.1 Object类的常用方法: toString()

方法名:public String toString()

作用:默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址

重写使用:

由于:开发中直接输出对象,默认输出对象的地址其实是毫无意义的。 开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。

因此:父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息

具体使用案例:

因为所有类都默认继承Object类,因此不用额外写什么。

定义一个学生类,在其中定义一些姓名年龄什么的属性,把get,set,构造器都写了之后,重写一下toString方法。

至少在idea中有快捷键,右键Genrate,toString即可自动生成。

在测试类中创建学生对象,定义一下他的姓名年龄之后,调用toString方法即可得到对象的内容而不是地址。

//toString是父类的方法
String a = s.toString();
System.out.println(a);
//或者写
System.out.println(s.toString());
//直接输出对象变量,默认可以省略toString调用不写
System.out.println(s);

18.1.2 Object类的常用方法:equals()

我们之前学习String的API时已经使用过equals来比较字符串的内容了。

方法名:public boolean equals(Object o)

作用:默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false

重写使用:

由于:直接比较两个对象的地址是否相同完全可以用“==”替代equals。 同时,开发中很多业务情况下,更想判断2个对象的内容是否一样。

因此:它被子类重写,以便子类自己来定制比较规则(比如比较对象内容)。

具体使用案例:

因为所有类都默认继承Object类,因此不用额外写什么。

定义一个学生类,在其中定义一些姓名年龄什么的属性,把get,set,构造器都写了之后,重写一下equals方法。

至少在idea中有快捷键,右键Genrate,equals() and hashcode()即可自动生成,自己把hashcode()删掉就可以。

这里要做一些解释,要知其然也知其所以然

其中:s1.equals(s2)。s1是比较者,就是this。s2是被比较者,就是o

@Override
public boolean equals(Object o) {//传最高类,这样什么类都能传进来if (this == o) return true;//如果当前对象的地址和o一样,就是对的
//        传值为空或getClass()得到s1的类和o的类比较如果不等,都返回错if (o == null || getClass() != o.getClass()) return false;
//        当上面都不符,说明o一定是学生类,并且不为空Student student = (Student) o;//一定要强转才能调用属性return sex == student.sex &&age == student.age &&//基本类型用==比较Objects.equals(name, student.name);//字符串类型用equals比较}

这之后,在测试类中创建多个学生对象,定义一下他的姓名年龄之后,调用equals()做比较就可以了

System.out.println(s1.equals(s2));

18.2 Objects

定义:Objects是一个工具类,提供了一些方法去完成一些功能。

18.2.1 Objects的常见方法:equals()

方法名:public static boolean equals(Object a, Object b)

作用:比较两个对象的,底层会先进行非空判断,从而可以避免空指针异常。再进行equals比较

官方在进行字符串比较时,没有用字符串对象的的equals方法,而是选择了Objects的equals方法来比较。

使用Objects的equals方法在进行对象的比较时会更安全。

因为他的源码长这样

public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));
}

将两个类都传进去,判断他俩地址是否相等,或者,在a不为空的前提下用equals和b比较


小案例题:

桂先生最近交给你一项人物,他准备在攘夷志士的会议厅外安装闸机,凭身份卡进出,请模拟这个场景。

解题思路:

首先要创建一个攘夷志士类,其中有姓名等属性,通过Object的equals方法判断是否相等,相等就能开门,不等就不能开门。

public class lianxi {public static void main(String[] args) {Joy katsura = new Joy("桂小太郎");Joy katsurasave = new Joy("桂小太郎");boolean result = Objects.equals(katsura,katsurasave);door(result);}public static void door(boolean result){if (result){System.out.println("开门");}else {System.out.println("天诛!");}}}

因为equals是静态方法,所以用类名调用。


18.2.2 Objects的常见方法:isNull()

方法名:public static boolean isNull(Object obj)

作用:判断变量是否为null ,为null返回true ,反之返回false

isNull的用法和equals差不多,也是用Objects调用。

18.3 StringBuilder

定义:StringBuilder是一个可变的字符串类,它可被视为一个对象容器【所有操作都在一个容器中完成】

作用:提高字符串的操作效率。

StringBuilder构造器

名称

作用

public StringBuilder()

创建一个空白的可变的字符串对象,不包含任何内容

public StringBuilder(String str)

创建一个指定字符串内容的可变字符串对象

18.3.1 StringBuilder的常见方法append()

方法名称:public StringBuilder append(任意类型)

作用:添加数据并返回StringBuilder对象本身


小案例题:

做攘夷志士的会议记录。

解题思路:

我们想要使用StringBuilder,就应该先创建它的对象。用append将会议内容一点一点的拼接进去。

因为StringBuilder只是一种拼接字符的手段,因此我们应当把StringBuilder类型变为String类型,方便之后的传参等操作。

 public static void main(String[] args) {StringBuilder s = new StringBuilder();s.append("3月4日,周六,晴。");s.append("攘夷志士第67次会议。");s.append("会议中,桂先生明确指出应加大荞麦面和美味棒的购买量");s.append("并重点观察江户586号街道中白底黑灰花的猫咪的健康状况");s.append("为歌舞伎町所有的孕妇猫咪做好接生工作");
//        这样转为StringString s1 = s.toString();System.out.println(s1);}

18.3.2 StringBuilder的常见方法 reverse()

方法名称:public StringBuilder reverse()

作用:将对象的内容反转


小案例题:

由于最近真选组和见回组在打闹,搞得你们的攘夷工作很不好开展,因此,桂先生准备重新对情报进行加密,其中有一个环节是对内容进行反转,请你来写一个程序,完成这个任务。

解题思路:

创建一个反转方法,将StringBuilder类型的对象传过来,调用倒转方法,再转换为String类型,返回回去。

 public static void main(String[] args) {System.out.println("请输入想要反转的内容");Scanner sc = new Scanner(System.in);StringBuilder s = new StringBuilder();s.append(sc.next());System.out.println(fanzhuan(s));}public static String fanzhuan(StringBuilder s){String s1 = s.reverse().toString();return s1;}

18.3.3 StringBuilder的常见方法length()

方法名称:public int length()

作用:返回对象内容长度。


小案例题:

没啥说的自己试一下就完了


18.3.4 StringBuilder的常见方法toString()

方法名:public String toString()

作用:通过toString()就可以实现把StringBuilder转换为String

这个在之前已经使用过了,就不再赘述。


19 其他常用类

这一章中会学习一些常用的类。

19.1 Math类

作用:用于做数学运算。

以下方法全部是静态方法,直接用类名调用即可。

方法名                                          说明
public static int abs(int a)                   获取参数a的绝对值:
public static double ceil(double a)            向上取整
public static double floor(double a)           向下取整
public static double pow(double a, double b)   获取a的b次幂
public static long round(double a)             四舍五入取整
public static double random()                  获取随机数0.0 - 1.0 (包前不包后)

自己用一用就会了。


小案例题:

获取2到8之间的随机数

解题思路:

我们之前做过关于随机数的题

2到8先全都减2,得到零到六,再加二

由于Math.random()随机出来的是小数,所以给它乘七

将这个结果强制转换为int类型即可

int data =  (int)(Math.random() * 7) + 2;

19.2 System系统类

System代表当前虚拟机系统。

19.2.1 System系统类的exit()方法

方法名称:public static void exit(int status)

作用:终止JVM虚拟机,非0是异常终止。

使用方式:

public static void main(String[] args) {System.out.println("程序开始");System.exit(0); // JVM终止!System.out.println("程序还在运行");

会发现使用了exit方法之后程序就结束了。

这个别乱用。

19.2.2 System系统类的currentTimeMillis()方法

方法名称:public static long currentTimeMillis()

作用:获取当前系统此刻时间毫秒值。

计算机认为时间有起源:返回1970-1-1 00:00:00 走到此刻的总的毫秒值:时间毫秒值。

具体使用:

long time = System.currentTimeMillis();

可以看一下从时间起源开始到现在时间走了多少毫秒

也可以算一下你的电脑输出100000个数字用了多少毫秒,看看自己的电脑性能如何

//      开始的时间long startTime = System.currentTimeMillis();// 进行时间的计算:性能分析for (int i = 0; i < 100000; i++) {System.out.println("输出:" + i);}
//        结束的时间long endTime = System.currentTimeMillis();
//        毫秒换算成秒System.out.println((endTime - startTime)/1000.0 + "s");

19.2.3 System系统类的arraycopy()方法

【待理解】

方法名:public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

作用:拷贝数组。

其中:

参数一:被拷贝的数组
参数二:从哪个索引位置开始拷贝
参数三:复制的目标数组
参数四:粘贴位置
参数五:拷贝元素的个数

小案例题:

有一个原始数组a,它的内容是[1,2,3,4,5]。我想要拷贝得到[0,0,3,4,5,0]这样的结果。

解题思路:

定义一个符合要求的数组a,定义一个动态化初始数组,长度为6,使用arraycopy()方法进行拷贝。

public static void main(String[] args) {int a[] = {1,2,3,4,5};int b[] = new int[6];System.arraycopy(a,2,b,2,3);
//        输出b看一下System.out.println(Arrays.toString(b));//toString可以直接返回内容,不用遍历了}

19.3 BigDecimal大数据类

作用:由于浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。 因此用BigDecimal可以解决浮点型运算数据失真的问题。

属于的包:java.math.

创建对象的最好方式:public static BigDecimal valueOf(double val)

含义:包装浮点数成为大数据对象。

BigDecimal的方法:

public BigDecimal add(BigDecimal value)       加法运算
public BigDecimal subtract(BigDecimal value)  减法运算
public BigDecimal multiply(BigDecimal value)  乘法运算
public BigDecimal divide(BigDecimal value)    除法运算
public double doubleValue(): 把BigDecimal转换成double类型。

使用案例:

曾经我们想要计算0.1+0.2的时候会发现结果并不是0.3

double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(c);

所以使用BigDeciaml来解决类似的问题

首先使用valueOf()方法来创建对象

BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);

使用add方法做加法运算,得到结果(减乘除同理)

BigDecimal c1 = a1.add(b1);
System.out.println(c1);

并且为了以后传值的方便,应该将BigDecimal类型的数据转成double类型,使用doubleValue()方法【这个和之前的toString很类似】

double rs = c1.doubleValue();

注意:BigDecimal是一定要精度运算的

也就是说,如果用10/3,肯定除不尽,所以精确不了,就会报错

因此需要设定保留小数,和四舍五入的选择

public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
参数一:除数 参数二:保留小数位数  参数三:舍入模式

也就是说如果还是10/3,10.divide(3, 4, RoundingMode.HALF_UP)

就会得到3.3333

19.4 Date类

定义:Date类代表当前所在系统的日期时间信息

构造器:public Date()

创建一个Date对象,代表的是系统当前此刻日期时间。

构造器:public Date(long time)

把时间毫秒值转换成Date日期对象。

19.4.1 Date类的getTime()方法

名称

说明

public long getTime()

返回从1970年1月1日    00:00:00走到此刻的总的毫秒数

小案例题:

请计算出当前时间往后走1小时121秒之后的时间是多少。

public class DateDemo {public static void main(String[] args) {
//        1.创建一个Date类的对象,代表系统此刻日期事件对象Date d = new Date();System.out.println(d);
//        获取时间毫秒值System.out.println(d.getTime());
//        计算当前时间往后走1小时121秒之后的时间是多少
//        1.首先得到此时的时间Date d1 = new Date();
//        2.获取毫秒值long a= d1.getTime()+(1*60*60*1000+121*1000);
//        把时间毫秒值转换为日期对象Date d2 = new Date(a);System.out.println("当前时间:"+d1);System.out.println("加了之后的时间"+d2);
//        计算当前时间往后走1小时121秒之后的时间是多少的第二种方法Date d3 = new Date();d3.setTime(a);System.out.println(d3);}
}

public void setTime(long time)  设置日期对象的时间为当前时间毫秒值对应的时间

19.5 SimpleDateFormat类

定义:代表简单日期格式化,可以用来把日期时间格式化成为我们想要的形式

构造器

说明

public SimpleDateFormat​(String pattern)

创建简单日期格式化对象,并封装格式化的形式信息

19.5.1 SimpleDateFormat类的方法

格式化方法

说明

public final String format(Date date)

将日期格式化成日期/时间字符串

public final String format(Object time)

将时间毫秒值式化成日期/时间字符串

格式:

y    年   M    月   d    日   H    时   m    分   s    秒

例如:

2022-1-1 13:27:06  写为 yyyy-MM-dd HH:mm:ss

2022年1月1日 13:27:06 写为 yyyy年MM月dd日 HH:mm:ss

解析方法

说明

public Date parse​(String source)

解析字符串时间。从给定字符串的开始解析文本以生成日期


小案例题:

使用一下pares方法。

1.解析字符串String s1 = "2022年01月01日11点11分11秒";
//        注意,解析形式要与被解析时间的形式完全一样,否则报错SimpleDateFormat si = new SimpleDateFormat("yyyy年MM月dd日HH点mm分ss秒");Date dd1 = si.parse(s1);System.out.println(dd1);

综合小练习题:

秒杀活动,秒杀一个东西,
开始时间为2020年11月11日0:0:0,
结束时间为2020年11月11日0:10:0
当前活动结束后,系统记录到2位用户的付款时间分别如下:
小贾下单并付款的时间为:2020年11月11日 0:03:47
小皮下单并付款的时间为:2020年11月11日 0:10:11
规则:顾客的付款时间必须在秒杀时间之内,请判断出两位顾客是否秒杀成功

答案:

 public static void main(String[] args) throws ParseException {// 1、开始 和 结束时间String startTime = "2021-11-11 00:00:00";String endTime = "2021-11-11 00:10:00";// 2、小贾 小皮String xiaoJia =  "2021-11-11 00:03:47";String xiaoPi =  "2021-11-11 00:10:11";// 3、解析他们的时间SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d1 = sdf.parse(startTime);Date d2 = sdf.parse(endTime);Date d3 = sdf.parse(xiaoJia);Date d4 = sdf.parse(xiaoPi);
//和自己做的不同的是,比较用的是after和before方法if(d3.after(d1) && d3.before(d2)){System.out.println("小贾秒杀成功,可以发货了!");}else {System.out.println("小贾秒杀失败!");}if(d4.after(d1) && d4.before(d2)){System.out.println("小皮秒杀成功,可以发货了!");}else {System.out.println("小皮秒杀失败!");}}

我自己在做的时候,还判断了是否提前点击,不过这些细节不太影响我们掌握这节课学习的知识。


19.6 Calendar类

定义:Calendar代表了系统此刻日期对应的日历对象。

注意

1.Calendar是一个抽象类,不能直接创建对象

2.calendar是可变日期对象,一旦修改后其对象本身表示的时间将产生变化

方法名

说明

public static Calendar getInstance()

获取当前日历对象

public int get(int field)

取日期中的某个字段信息。

public void set(int field,int value)

修改日历的某个字段信息。

public void add(int field,int amount)

为某个字段增加/减少指定的值

public final Date getTime()

拿到此刻日期对象。

public long getTimeInMillis()

拿到此刻时间毫秒值

19.7 JDK8新增的日期类

综述:

新增的API严格区分了时刻、本地日期、本地时间,并且,对日期和时间进行运算更加方便。

其次,新API的类型几乎全部是不变类型(和String的使用类似),可以放心使用不必担心被修改。

19.7.1 LocalDate、LocalTime、LocalDateTime方法

即日期,时间,日期时间对象,他们的类的实例是不可变的对象。

三者构建对象和API都是通用的

方法名

说明

public static Xxxx now();

静态方法,根据当前时间创建对象

LocaDate localDate = LocalDate.now();

LocalTime llocalTime = LocalTime.now();

LocalDateTime localDateTime = LocalDateTime.now();

public static Xxxx of(…);

静态方法,指定日期/时间创建对象

LocalDate localDate1 = LocalDate.of(2099 , 11,11);

LocalTime localTime1 = LocalTime.of(11, 11, 11);

LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);

LocalDate、LocalTime、LocalDateTime获取信息的API.

方法名

说明

public int geYear()

获取年

public int getMonthValue()

获取月份(1-12)

Public int getDayOfMonth()

获取月中第几天

Public int getDayOfYear()

获取年中第几天

Public DayOfWeek getDayOfWeek()

获取星期

也就是说,我们先构建了时间对象之后,用上面的方法获取具体的时间信息

System.out.println(nowDate.getMonth());//AUGUST
System.out.println(nowDate.getMonth().getValue());//8

方法名

说明

public LocalDate toLocalDate()

将LocalDateTime转换成一个LocalDate对象

public LocalTime toLocalTime()

将LocalDateTime转换成一个LocalTime对象

修改相关的API

注意:

LocalDateTime 综合了 LocalDate 和 LocalTime 里面的方法,所以下面只用 LocalDate 和 LocalTime 来举例。

这些方法返回的是一个新的实例引用,因为LocalDateTime 、LocalDate 、LocalTime 都是不可变的。

方法名

说明

plusDays, plusWeeks, plusMonths, plusYears

向当前 LocalDate 对象添加几天、 几周、几个月、几年

minusDays, minusWeeks, minusMonths, minusYears

从当前 LocalDate 对象减去几天、 几周、几个月、几年

withDayOfMonth, withDayOfYear, withMonth, withYear

将月份天数、年份天数、月份、年 份 修 改 为 指 定 的 值 并 返 回 新 的 LocalDate 对象

isBefore, isAfter

比较两个 LocalDate

使用案例:


public class Demo04UpdateTime {public static void main(String[] args) {LocalTime nowTime = LocalTime.now();System.out.println(nowTime);//当前时间System.out.println(nowTime.minusHours(1));//一小时前System.out.println(nowTime.minusMinutes(1));//一分钟前System.out.println(nowTime.minusSeconds(1));//一秒前System.out.println(nowTime.minusNanos(1));//一纳秒前System.out.println("----------------");System.out.println(nowTime.plusHours(1));//一小时后System.out.println(nowTime.plusMinutes(1));//一分钟后System.out.println(nowTime.plusSeconds(1));//一秒后System.out.println(nowTime.plusNanos(1));//一纳秒后System.out.println("------------------");// 不可变对象,每次修改产生新对象!System.out.println(nowTime);System.out.println("---------------");LocalDate myDate = LocalDate.of(2018, 9, 5);LocalDate nowDate = LocalDate.now();System.out.println("今天是2018-09-06吗? " + nowDate.equals(myDate));//今天是2018-09-06吗? falseSystem.out.println(myDate + "是否在" + nowDate + "之前? " + myDate.isBefore(nowDate));//2018-09-05是否在2018-09-06之前? trueSystem.out.println(myDate + "是否在" + nowDate + "之后? " + myDate.isAfter(nowDate));//2018-09-05是否在2018-09-06之后? falseSystem.out.println("---------------------------");// 判断今天是否是你的生日LocalDate birDate = LocalDate.of(1996, 8, 5);LocalDate nowDate1 = LocalDate.now();
//      从生日对象中获取月和日MonthDay birMd = MonthDay.of(birDate.getMonthValue(), birDate.getDayOfMonth());
//        用from方法从当前年月日中直接拿月日MonthDay nowMd = MonthDay.from(nowDate1);
//进行比较System.out.println("今天是你的生日吗? " + birMd.equals(nowMd));//今天是你的生日吗? false}
}

19.7.2 Instant 时间戳

定义:

时间戳的主要目的在于通过一定的技术手段,对数据产生的时间进行认证,从而验证这段数据在产生后是否经过篡改。

【本定义来自于百度百科,由于比较清楚所以就复制过来使用了】

时间戳包含日期与时间

获取时间戳:

Instant instant = Instant.now();
System.out.println("当前时间戳是:" + instant);Date date = Date.from(instant);
System.out.println("当前时间戳是:" + date);//Instant和Date这两个类可以进行转换。
instant = date.toInstant();
System.out.println(instant);

19.7.3 DateTimeFormatter 日期与时间格式器

// 本地此刻  日期时间 对象
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);//年月日时分秒// 解析/格式化器
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEE a");
// 正向格式化
System.out.println(dtf.format(ldt));
// 逆向格式化
System.out.println(ldt.format(dtf));//指的就是ldt放前面或后面都可以格式化为某种样式// 解析字符串时间
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 解析当前字符串时间成为本地日期时间对象
LocalDateTime ldt1 = LocalDateTime.parse("2019-11-11 11:11:11" ,  dtf1);//用dtf1这个格式化解析器解析本地时间
System.out.println(ldt1);
System.out.println(ldt1.getDayOfYear());

19.7.4 Period类

作用:计算日期间隔差异

主要方法:getYears(),getMonths() 和 getDays()。只能精确到年月日

用于 LocalDate 之间的比较

// 当前本地 年月日
LocalDate today = LocalDate.now();
System.out.println(today);//// 生日的 年月日
LocalDate birthDate = LocalDate.of(1998, 10, 13);
System.out.println(birthDate);Period period = Period.between(birthDate, today);//第二个参数减第一个参数System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
System.out.printf("年龄 : %d 年 %d 月 %d 日", period.getYears(), period.getMonths());

19.7.5 Duration类

作用:计算时间间隔差异

主要方法:toDays(),toHours(),toMinutes(),toMillis() 和 toNanos()。

用于 LocalDateTime 之间的比较。也可用于 Instant 之间的比较。

LocalDateTime today = LocalDateTime.now();System.out.println(today);
LocalDateTime birthDate = LocalDateTime.of(1990,10,1,10,50,30);
System.out.println(birthDate);
Duration duration = Duration.between(birthDate, today);//第二个参数减第一个参数
System.out.println(duration.toDays());//两个时间差的天数
System.out.println(duration.toHours());//两个时间差的小时数
System.out.println(duration.toMinutes());//两个时间差的分钟数
System.out.println(duration.toMillis());//两个时间差的毫秒数
System.out.println(duration.toNanos());//两个时间差的纳秒数

19.7.6 ChronoUnit类

用于在单个时间单位内测量一段时间,这个工具类是最全的了,可以用于比较所有的时间单位

 // 本地日期时间对象:此刻的
LocalDateTime today = LocalDateTime.now();
System.out.println(today);// 生日时间
LocalDateTime birthDate = LocalDateTime.of(1990,10,1,10,50,59);
System.out.println(birthDate);System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthDate, today));
System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthDate, today));
System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthDate, today));
System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthDate, today));
System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthDate, today));
System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthDate, today));
System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthDate, today));
System.out.println("相差的微秒数:" + ChronoUnit.MICROS.between(birthDate, today));
System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthDate, today));
System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthDate, today));
System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthDate, today));
System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthDate, today));
System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthDate, today));
System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthDate, today));

19.8 包装类

定义:8种基本数据类型对应的引用类型。

基本数据类型

引用数据类型

byte

Byte

short

Short

int

Integer

long

Long

char

Character

float

Float

double

Double

boolean

Boolean

包装类存在的原因:

Java为了实现一切皆对象,为8种基本类型提供了对应的引用类型。

【引用类型存对象的地址,可视为对象】

后面的集合和泛型其实也只能支持包装类型,不支持基本数据类型。

int a = 5;
Integer a1 = 10;//定义的时候都一样
System.out.println(a);
System.out.println(a1);//输出也是都正常的输出
//        ---------------------------
Integer a2 = a;//自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。Integer b = 4;
int b1 = b;//自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量。//        ------------------------------------------
//        int c = null; //会报错
Integer c1 = null;//        ------------------------------------------
//        将基本类型的数据变为字符串形式
Integer d = 23;
String d1 = d.toString();
System.out.println(d1+1);//拼接
//        将基本类型的数据变为字符串形式,或者
String d2 = Integer.toString(d);
System.out.println(d2+2);
//        将基本类型的数据变为字符串形式,再或者
String d3 = d+"";
System.out.println(d3+3);//        ------------------------------------------
String e = "456";
//        转换为整数int e1 = Integer.parseInt(e);
//或者使用
int e2 = Integer.valueOf(e);
System.out.println(e1+1);//加减
//        转换为小数
String f = "9.9";
double f1 = Double.parseDouble(f);
//        或者使用
double f2 = Double.valueOf(f);
System.out.println(f1+1);

更推荐使用valueof

小结:

包装类的特有功能

1.包装类的变量的默认值可以是null,容错率更高。

2.可以把基本类型的数据转换成字符串类型(用处不大)

调用toString()方法得到字符串结果。

eg.调用Integer.toString(基本类型的数据)。

3.可以把字符串类型的数值转换成真实的数据类型(真的很有用)

Integer.parseInt(“字符串类型的整数”)

Double.parseDouble(“字符串类型的小数”)。

19.9 正则表达式

作用:用一些规定的字符来制定规则,并用来校验数据格式的合法性。

字符串对象提供了匹配正则表达式的方法

public boolean matches​(String regex)

判断是否匹配正则表达式,匹配返回true,不匹配返回false。

字符类(默认匹配一个字符)

[abc]           只能是a, b, 或c

[^abc]           除了a, b, c之外的任何字符

[a-zA-Z]               a到z A到Z,包括(范围)

[a-d[m-p]]           a到d,或m通过p:([a-dm-p]联合)

[a-z&&[def]]           d, e, 或f(交集)

[a-z&&[^bc]]           a到z,除了b和c:([ad-z]减法)

[a-z&&[^m-p]]     a到z,除了m到p:([a-lq-z]减法)

预定义的字符类(默认匹配一个字符)

.    任何字符

\d    一个数字: [0-9]

\D    非数字: [^0-9]

\s    一个空白字符: [ \t\n\x0B\f\r]

\S    非空白字符: [^\s]

\w    [a-zA-Z_0-9] 英文、数字、下划线

\W     [^\w] 一个非单词字符

贪婪的量词(配合匹配多个字符)

X?    X , 一次或根本不

X*    X,零次或多次

X+    X , 一次或多次

X {n}    X,正好n次

X {n, }    X,至少n次

X {n,m}    X,至少n但不超过m次


小案例题:

写出结果

System.out.println("a".matches("[abc]"));

System.out.println("z".matches("[abc]"));

System.out.println("ab".matches("[abc]"));

System.out.println("ab".matches("[abc]+"));

答案:

t f f t

小案例题2:

请编写程序模拟用户输入手机号码、验证格式正确,并给出提示,直到格式输入正确为止。

请编写程序模拟用户输入邮箱号码、验证格式正确,并给出提示,直到格式输入正确为止。

请编写程序模拟用户输入电话号码、验证格式正确,并给出提示,直到格式输入正确为止。

解题思路:

分析手机号码,邮箱和电话的特点,写出正则表达式


正则表达式在字符串方法中的使用

方法名

说明

public String replaceAll(String regex,String newStr)

按照正则表达式匹配的内容进行替换

public String[] split(String regex):

按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。

注意:例如\w,要写成\\w,也就是告诉第二个\“你和w是一起的”

正则表达式爬取信息

这部分记住就好了

eg:

String s = "要爬取的信息们";

1.定义爬取规则

String regex = "正则表达式的规则"【可以使用或来分隔】

2.编译正则表达式成为一个匹配规则对象

Pattern pattern = Pattern.compile(regex);

3.通过匹配规则对象得到一个匹配数据内容的匹配器对象

Matcher matcher = pattern.matcher(s);

4.通过匹配器去内容中爬取出信息

while(matcher.find()){

System.out.println(matcher.group());

}

【记忆的思路:

首先知道要爬取谁,据此写出正则表达式,将这个表达式编译为一条规则(这时候才能用),用规则在爬取的文字里找,最后把找到的东西拿出来】


19.10 Arrays类

定义:数组操作工具类,专门用于操作数组元素的。

常用API:

方法名

作用

public static String toString​(类型[] a)

返回数组的内容(字符串形式)

public static void sort​(类型[] a)

对数组进行默认升序排序

public static <T> void sort​(类型[] a, Comparator<? super T> c)

使用比较器对象自定义排序

public static int binarySearch​(int[] a, int key)

二分搜索数组中的数据,存在返回索引,

搜索不存在的数字返回结果是:-(本该插入的位置索引)-1

注意:使用二分搜索的前提是数组必须排序好

比较器对象

我们用一个案例来学习:

需求:降序排序(自定义比较对象只能支持引用类型)
//先定义一个整型数组
Integer ages1[] = {35,13,44,24};Arrays.sort(ages1, new Comparator<Integer>() {//参数1:被排序的数组,参数2:匿名内部类对象@Overridepublic int compare(Integer o1, Integer o2) {//数组中两两被拿来比
//                指定比较规则
//        return o1-o2;//升序return o2-o1;//降序       }
//如果认为左边数据 大于 右边数据  返回正整数
//如果认为左边数据 小于 右边数据  返回负整数
//如果认为左边数据 等于 右边数据  返回0

小案例题:

设定一个角色类,其中包含姓名,身高等属性,要求将角色类存入数组并对数组中的元素按照身高来排序。

解题思路:

首先设定角色类,把姓名,身高这些属性以及该补充的东西都补充完整。

之后创建一个数组,将角色信息加入数组中

使用sort方法,自定义比较规则,由于使用身高进行排序则可以写为

return o1.getAge()-o2.getAge();

当然,我们也会考虑到身高不为整数的情况,那么

return Double.compare(o1.getHeight(),o2.getHeight());

此为浮点型升序排序的方式,


20 常见算法

20.1 冒泡排序

思想:每次从数组中找出最大值放在数组的后面去。

案例:

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

在第一轮中,判断5与2的大小,由于5大于二,因此交换位置,继续判断5与3的大小关系。

第二轮中,从此时位于0位置的2开始。

以此类推

小结:

冒泡排序总共需要做几轮?答: 数组的长度-1

每轮比较几次? 答:数组长度-轮数

20.2 选择排序

思想:每轮选择当前位置,开始找出后面的较小值与该位置交换

案例:

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

在第一轮中,先用位于0的5和1对比,5大于1,所以5与1交换

此时变为

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

此时仍旧是第一轮,还用位于0的1与3对比,1小于3,则用1与2对比。

进入第二轮了,用位于1的5与3做对比,5大于3,交换

此时变为

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

此时仍旧是第二轮,还用位于1的3与2对比,3大于2,交换

此时变为

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

进入第三轮了,用位于2的5与3做对比,5大于3,交换

此时变为

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

小结:

选择排序总共需要做几轮?答: 数组的长度-1

20.3 二分查找

20.3.1 基本查找

在一个数组中存储着一定量的数据,我们想查询某个数组元素的位置需要从前往后找,性能差。

20.3.2 二分查找

前提:数据已经排序好

例如

[1,2,4,5,7,66,444]

想要查找7,就从(0+6)/2的三号索引开始,5小于7,因此往右边找

(3+6)/2,   4号位刚好是7.

因此二分查找的性能较好,相当于每次去掉一半的查找范围

注意:二分查找正常的检索条件应该是开始位置min <= 结束位置max


小案例题:

实现二分查找算法

/*** 二分查找算法的实现** @param arr  排序的数组* @param data 要查询的数据* @return 返回索引,若元素不存在直接返回-1*/public static int binarySearch(int arr[], int data) {
//        1.定义左边位置和右边位置int left = 0;int right = arr.length;
//        2.开始循环,折半查询while (left <= right) {
//            取中间索引int middleIndex = (left + right) / 2;
//            3.判断中间位置的元素与要查找的数据的元素的大小情况if(data>arr[middleIndex]){
//                往右边找,左边位置更新为:中间索引+1left = middleIndex+1;}else if(data<arr[middleIndex]){
//                往左边找,左边位置更新为:中间索引-1right = middleIndex-1;}else {
//                相等return middleIndex;}}return -1;//没查到}

21 Lambda表达式

定义:Lambda表达式是JDK 8开始后的一种新语法形式。

作用:简化匿名内部类的代码写法。

简化格式:

(匿名内部类被重写方法的形参列表) -> {

被重写方法的方法体代码。

}

ps:-> 是语法形式,无实际含义

其中:Lambda表达式只能简化函数式接口的匿名内部类的写法形式

函数式接口:首先必须是接口、其次接口中有且仅有一个抽象方法的形式。

通常我们见到的函数式接口上都有一个@FunctionalInterface注解,标记该接口必须是满足函数式接口。

化简之后的案例:

//自定义排序
Arrays.sort(ages, new Comparator<Integer>(){@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});
//化简之后
Arrays.sort(ages, (Integer o1, Integer o2) -> {return o2 - o1;
});

Lambda表达式的省略写法:

即进一步在Lambda表达式的基础上继续简化

参数类型可以省略不写。

如果只有一个参数,参数类型可以省略,同时()也可以省略。

如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号。

如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写

【JAVA复习系列】第一部分相关推荐

  1. JAVA复习系列(一)

    ** JAVA复习系列(一) 文章目录 JAVA复习系列(一) 1.1 Java入门(基础概念与常识) 1.1.1Java语言的特点 1.1.2 JVM,JDK,JRE的关系 1.1.2.1 JVM( ...

  2. java复习系列[6] - Java集合

    Java集合 ArrayList的扩容 在add().addAll()方法中判断是否需要扩容 使用 grow() 函数以 1.5 倍的方式进行扩容 HashMap HashMap扩容流程(1.7 与 ...

  3. java复习系列[4] - Java IO

    文章目录 Java IO IO传输 IO读写流程 IO类型 IO的访问方式 缓存IO(标准IO.传统IO) 直接IO 内存映射 总结 Java中IO与NIO的区别 Java NIO 流与缓冲 管道 为 ...

  4. java复习系列[3] - Java虚拟机

    文章目录 Java虚拟机 JRE 和 JDK 整体工作原理 类加载 class文件结构 类加载过程 双亲委派机制 运行时内存区域 整体划分 PC (Program Counter) JVM栈 局部变量 ...

  5. java复习系列[2] - Java多线程

    文章目录 JUC thread 线程状态 sleep() 与 wait() 的异同点 wait() 与 阻塞 的异同点 Some Question !!! 有了**sleep()**为什么还要有**w ...

  6. java复习系列[1] - Java 基础

    文章目录 Java 基础 final static Java的switch支持的数据类型 goto (扫盲 - 一般不用) String 不可变 不可变的优势 序列化 序列化的 *serialVers ...

  7. java复习系列[5] - Java 中的设计模式

    文章目录 Java中的设计模式 设计原则 迭代器模式 + Iterator 适配器模式 + HandlerAdapter 代理模式 + AOP 单例模式 + Spring Bean 模板方法模式 + ...

  8. java爬虫系列第二讲-爬取最新动作电影《海王》迅雷下载地址

    为什么80%的码农都做不了架构师?>>>    1. 目标 使用webmagic爬取动作电影列表信息 爬取电影**<海王>**详细信息[电影名称.电影迅雷下载地址列表] ...

  9. Java基础系列五 面向对象程序设计

    Java基础系列第一章 初识Java语言 Java基础系列第二章 Java语言基础 Java基础系列第三章 Java流程控制 Java基础系列第四章 Java数组与字符串 Java基础系列第五章 面向 ...

  10. 不迈出第一步_Java 11手册:新Java发布系列迈出的一小步,Java 8用户迈出了一大步...

    不迈出第一步 Java 11:废除Java 8是否足够重要? 为了庆祝Java 11的发布,我们邀请了9位Java专家与他们分享最新版本的最佳和最差体验. 由于本系列旨在作为Java 11的手册,因此 ...

最新文章

  1. word2vec 中的数学原理详解(二)预备知识
  2. 桑叶黑芝麻糊,从头到脚通补
  3. 双系统grub启动linux,双系统ubuntu与Centos的grub启动(解决VFS报错)
  4. 微信-支付宝-支付响应体
  5. mysql.service failed because the control process exited with error code问题
  6. 常用七大经典排序算法总结(C语言描述)
  7. int main() 与 void main()
  8. Kotlin学习笔记17 反射Part1
  9. 【Statistics】均值
  10. 嵌套循环连接(Nested Loops), 合并联接(Merge), 哈希联接(Hash)的适用情况
  11. DBN(深度置信网络)解析
  12. ZOJ - 3880 Demacia of the Ancients
  13. SwiftUI 高级用法之ForEach如何使用 enumerated() UserDefaults.standard(教程含源码)
  14. 行行出状元,大学毕业生卖煎饼月入13万
  15. 【PCB专题】什么是通孔、盲孔、埋孔?
  16. 抖音短视频买的粉丝是真的吗?多少人懂这点
  17. 树链剖分——杨子曰算法
  18. 什么是极客(Geek)?怎样成为一名极客?
  19. 网络层IP协议和数据链路层
  20. 【计算方法】实验二:python实现高斯消去、列主元高斯消去,LU分解分别求解线性方程组

热门文章

  1. 梯度、散度、旋度的关系
  2. html网页中加入音乐播放器,html 网页添加音乐播放器
  3. Java Web 2.1.4 HTML 表单标签与表单设计 (实例)
  4. 合肥工业大学暑期“三下乡”——探访悠悠古村 发扬传统文化
  5. HTML5期末大作业:商城网站设计——小米商城官网首页(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 web学生网页设计作业源码...
  6. png图片怎么转换成jpg
  7. python核密度图_python做密度图
  8. python xlwt修改excel_通过Python模块xlwt更改xls文件中的默认分页符
  9. AT24CXX、DS1302、红外HS0038 20170610 周六
  10. 定风波·三月七日(苏轼)