来都来了点个赞呗 o(*≧▽≦)ツ
这段时间要急着考试的同学,可以看我画的重点,目录上有标识,如果时间充裕也可以详细看下去,会很有帮助的。我会用视频加图画来解释。这篇文章中,包括对java的深度理解,以及内存数据的演变。对与理解计算机是有重要帮助。
(๑•̀ㅂ•́)و✧
学习很重要,复习也很重要,对于编程语言的复习更为重要。语法是编程的基础。也是逻辑编程(计算机程序编程)诞生的最根本的语言体系。学会了语法了就等于学会了计算机编程的四分之一。剩下的就需要去学习,数据结构与算法,计算机组成原理,与计算机操作系统。这里没有将数据库列入,只要是数据库的语言语法可以是数据结构与算法和编程语言的结合。后面我会在出继续更新相关内容,当然也包括数据库。
编译语言:java
编译环境:Windows
编译器:IDEA
java是一个面向对象的经典编程语言,Java语法是C++语法的一个“纯净版本”,相当于对C++做了一个减法。(对象的概念将会在下面类和对象中详细说明)
学习Java就得先学会在计算机系统上安装java,这里我们选择在Windows上安装,在Linux中安装这里不做解释,详情可以看目录十一。
首先我们去官网下载JDK,现在jdk的版本用的最多的是1.8版本,因为它足够稳定。在实际运用中稳定和安全就是程序的一切。
链接:https://www.java.com/en/download/(官网一般不好进)
链接:https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html(文件在最下方,看准参照物8u311)
需要登录甲骨文才能下载(嫌麻烦可以直接去我网盘中下载:链接:https://pan.baidu.com/s/1fFAAHYpi7UwBzSuv3bZv3g
提取码:1111)没用可以私信我。
在安装前一定要看自己的Windows 系统的类型,我的是64位,右击此电脑或者我的电脑,选择属性就可以看见。
一般而言,计算机软件我们都不推荐在C盘安装。在C盘安装会影响计算机的运行。但是JAVA特例,我们通常安在C盘,这样使得Java的优先级更高。无需去其他盘访问。(因为我已经安装过1.9了所以只做演示)
下一步就可
一定要记住自己安装位置,诺不知道安装路径可以在C盘右上角搜索Java关键字
在这里我们就安好了,但是想要进行使用,就必须配置Java相关的环境。我们先去安装的文件夹中找到java的jdk。
可以看见安装后就会出现一个jdk文件夹和jar文件夹
jre:
jre 是java runtime environment, 是java程序的运行环境。既然是运行,当然要包含jvm,也就是虚拟机,还有所有java类库的class文件,都在lib目录下打包成了jar。在windows上的虚拟机是jre/bin/client里面是一个jvm.dll。
jdk:
jdk 是java development kit,是java的开发工具包,主要是给ide 用的,里面包含了各种类库和工具。当然也包括了另外一个Jre.,而且jdk/jre/bin 里面也有一个server文件夹, server文件夹下面也有一个jvm.dll 虚拟机。(这个虚拟机是什么后,面会涉及)
环境配置
首先用鼠标右键点开我的电脑或者此电脑找到属性,然后在找到高级系统配置
系统变量和用户变量的区别
系统变量:是计算机唯一且永久的变量,诺是切换用户,并不会影响计算机关键软件的运行。
用户变量:它会随着你计算机用户的变更而变更,切换用户后诺此用户没有进行相关配置,将无法使用上个用户的软件
所以我们在这里选择计算机系统变量,配置环境。
环境一定不能出错不然无法运行java
变量名:JAVA_HOME(记住一定要大写)
变量值:C:\Program Files\Java\jdk1.8.0_192
(记住这是我的路径,不是你的路径,要配置成功一定要换成自己的路径)
变量名:classpath(这次要小写)
变量值:,;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
(你没有看错,最前面%前面有一个英文的逗号和分号)
%JAVA_HOME%代表的是jdk的路径
到这里基本上配置完毕了,要验证是否配置成功按住Windows健+r弹出运行窗口,输入cmd,弹出DOS命令窗口
输入java -version
显露出这些信息我们就算是将Java安装完毕了,在这里你可以发现我的是1.9版本,这是因为我在配置时配置的是1.9版本,虽然下载的java版本很多但是在环境配置中我配置的是java1.9版本。所以可以看出java版本是互相不干扰的,只要想用哪个,就配置哪个就完事。
自检自己安装的版本就好
我这里用的2022版本,这里请自行下载,作为程序员谁也不希望自己成功被人免费盗用(其实作为学生的话,IDEA是可以免费使用的,前提需要认证,不知道怎么做可以去B站上找教程:链接:https://www.bilibili.com/video/BV19V411k7HD?t=12.2)
安装好后
我们先创建一个项目
到这里我们的java编程的基本准备就算完成了
如何执行java文件?
可以看见在中间的方框中有我圈出了两个按钮。一个是Run(运行),一个是Debug(调试)
Run:再点击后会在你所创建的项目中生成一个class文件(一般这代表着你的代码没有任何问题,可以交付给用户)风险大
Debug:将代码在编译器中进行调试,可以将代码的错误风险在IDEA中调试中降到最低,也可以创建的项目中生成一个class。
他们两个都会生成一个out的IEDA所属的运行文件目录,class文件就会在里面生成,这个class文件叫字节码文件
这个是我没有进行任何操作的项目文件
我们先做用Debug来调试一下这个java文件。
这个就是我们的运行结果
我们去他相关的文件夹看一看,可以看见out的文件夹下的子目录下生成了一个class文件
我们在试试Run,看看是不是会生成一个class文件
可以看出Run和Debug的运行结果一样,但是在窗口出现的字符不同。
java文件不在ide中运行
JDK、JRE、JVM之间的关系
JDK:Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译器javac与自带的调试工具Jconsole、jstack等。
JRE:Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程序运行的所需环境。
JVM:Java虚拟机,运行Java代码
在实际运用会有,不同的应用就诞生了不同的数据需求,从而衍生出了一些基本的数据类型。
1byte=8bit(内存最小单位)(也叫二进制位)
数据类型 | 关键字 | 内存占用 | 范围(可以用的范围) |
---|---|---|---|
字节型 | byte | 1 字节 | -128 ~ 127 |
短整型 | short | 2 字节 | -32768 ~ 32767 |
整型 | int | 4 字节 | -2^31 ~ 2^31-1 |
长整型 | long | 8 字节 | -2^63 ~ 2^63-1 |
单精度浮点数 | float | 4 字节 | 有范围,一般不关注 |
双精度浮点数 | double | 8 字节 | 有范围,一般不关注 |
字符型 | char | 2 字节 | 0 ~ 65535 |
布尔型 | boolean | 没有明确规定 | true 和 false |
可以看见数据类型共分有8种基本类型。而八种基本类型中又分4种大类型
四类:整型、浮点型、字符型,布尔型
特点:注意
在实际应用中,有始终不变的常量,如太阳的升起的位置,而有些内容可能会经常改变,比如人的身高,它会随着人的生长而发生变化。
常量 | 例子 |
---|---|
字符串常量 | 由 " " 括起来的,比如“12345”、“hello”、“你好”。 |
整形常量 | 程序中直接写的数字,比如:1235456,1000 (注意没有小数点) |
浮点数常量 | 程序中直接写的小数,比如:3.14 |
字符常量 | 由 单引号 括起来的当个字符,比如:‘a、‘2’(ASCII码上都是) |
布尔常量 | 只有两种true和false |
空常量 | null(简单而言没有任何数据的量,甚至连0都不是) |
注意:字符串、整形、浮点型、字符型以及布尔型,在Java中都称为数据类型
故名思意,就是会变得量,如何定义一个变量?
数据类型 变量名 = 初始值;
一个变量在内存中如何存储?我们用int类型来举例:一个变量在内存中存储,会转换为二进制。
数据在内存上的存储
不同种类的数据类型进行交叉保存会怎么样?比如:int类型的变量去保存short类型,而short类型去保存int类型。
由上面视频和基本类型的存储空间大小就可以知道,int的存储大小为4个字节,short的存储大小为2个字节。所以可以得出结论,存储的数据一定不能超出类型的存储大小。
再看看这个例子。
我们打印一下看看
哎?数据变了,是不是很有意思。按道理来说,b的值是999999赋值给t了,t应该是999999才对啊。就算只有t只有两个字节,那么他的大小也该是32767,不应该是16959才对啊。
咱们再看一个视频
强制类型装换的危害
在括号里加上类型,叫做强制数据类型转换,而这种情况就有可能会向视屏中的样子一样丢失数据。从而使运算结果发生变化。
计算机诞生之初就是为了计算,复杂而庞大的数据。比如严格意义上第一个电子计算设备是图灵为了在二战中抵御德军侵略,创造出的计算德军情报密钥的机器。这台设备在二战中发挥了不可替代的作用。而如何计算,就要用到逻辑的运算符
对操作数进行操作时的符号,不同运算符操作的含义不同
我们先定义两个元素(我们这里先不考虑类型):a=5 ,b =2
计算机运算符 | 数学计算逻辑 | 机器计算逻辑 | 结论 |
---|---|---|---|
+ | a + b = 7 | a+b=7 | 取整 |
- | b - a = - 2 | b - a = - 2 | 取整 |
* | a * b =10 | a * b =10 | 取整 |
/ | a / b = 2.5 | a / b = 2 | 取整 |
% | 没有这个计算逻辑 | a % b = 5 | 取余数化整 |
演化一下% | a % b = 2…1 | a % b = 1 | 取余 |
特点:
+= | - = | *= | %= | /= |
---|
int a=1;
a+=1; //相当于a=a+1;
System.out.println(a);//结果等于2
//*****************************
a-=1;//相当于a=a-1;
//*****************************
a*=3;//a=a*3
//*****************************
a%=10;//a=a%10
//*****************************
a/=3;// a=a/3;
注意:
(++,–)
++ | - - |
---|
int b=0;
//这个叫后置++,他会先使用原来的值,然后再进行+1
b++;//此时值为:1
//这个叫前置++,他会先进行+1计算,然后在使用原来的值
++b;//此时值为:2
//************************************************
System.out.println(b++);//会输出:2
System.out.println(b);//会输出:3
int b=0;
//这个叫后置--,他会先使用原来的值,然后再进行-1
b--;//此时值为:-1
//这个叫前置++,他会先进行-1计算,然后在使用原来的值
--b;//此时值为:-2
//************************************************
System.out.println(b--);//会输出:-2
System.out.println(--b);//会输出:-4
运算符 | 计算结果 |
---|---|
== | true 或者 false |
!= | true 或者 false |
> | true 或者 false |
< | true 或者 false |
<= | true 或者 false |
>= | true 或者 false |
int a = 10;
int b = 20;
// 注意:在Java中 = 表示赋值,要与数学中的含义区分
// 在Java中 == 表示相等
System.out.println(a == b); // false
//a是不是不等于b,是,逻辑上返回true
System.out.println(a != b); // true
System.out.println(a < b); // true
System.out.println(a > b); // false
System.out.println(a <= b); // true
System.out.println(a >= b); // false
计算机中是无法识别 0
2.逻辑符号(重要)
符号 | 运算结果(boolean类型) | 理解 |
---|---|---|
&& | true 或者 false | 并且 |
! | true 或者 false | 否 |
这里csd中||有特殊含有,打不出,就用图片代替了
两真为真,一假全假
表达式1 | 表达式2 | 结果 |
---|---|---|
真(true) | 真(true) | 真(true) |
真(true) | 假(false) | 假(false) |
假(false) | 真(true) | 假(false) |
假(false) | 假(false) | 假(false) |
int a = 1;
int b = 2;
System.out.println(a == 1 && b == 2); // 左为真 且 右为真 则结果为真
System.out.println(a == 1 && b > 100); // 左为真 但 右为假 则结果为假
System.out.println(a > 100 && b == 2); // 左为假 但 右为真 则结果为假
System.out.println(a > 100 && b > 100); // 左为假 且 右为假 则结果为假
全假为假,一真为真
表达式1 | 表达式2 | 结果 |
---|---|---|
真(true) | 真(true) | 真(true) |
真(true) | 假(false) | 真(true) |
假(false) | 真(true) | 真(true) |
假 (false) | 假 (false) | 假(false) |
int a = 1;
int b = 2;
System.out.println(a == 1 || b == 2); // 左为真 且 右为真 则结果为真
System.out.println(a == 1 || b > 100); // 左为真 但 右为假 则结果也为真
System.out.println(a > 100 || b == 2); // 左为假 但 右为真 则结果也为真
System.out.println(a > 100 || b > 100); // 左为假 且 右为假 则结果为假
真变假,假变真
int a = 1;
System.out.println(!(a == 1)); // a == 1 为true,取个非就是false
System.out.println(!(a != 1)); // a != 1 为false,取个非就是true
如果两个二进制位都是 1, 则结果为 1, 否则结果为 0
int a = 10;
int b = 20;
System.out.println(a & b);
如果两个二进制位都是 0, 则结果为 0, 否则结果为 1
int a = 10;
int b = 20;
System.out.println(a | b);
如果该位为 0 则转为 1, 如果该位为 1 则转为 0
int a = 0xf;//16进制
System.out.printf("%x\n", ~a)//printf 能够格式化输出内容, %x 表示按照十六进制输出
如果两个数字的二进制位相同, 则结果为 0, 相异则结果为 1
int a = 0x1;
int b = 0x2;
System.out.printf("%x\n", a ^ b);//0
符号 | 实现逻辑 |
---|---|
<< | 最左侧位不要了, 最右侧补 0 |
>> | 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1) |
>>> | 最右侧位不要了, 最左侧补 0 |
一个二进制位的数的最左边一个位置是不用来计数的,通常叫做符号位,代表一个数的正负情况。
0:代表这个数为正
1:代表这个数为负
4.1 左移<<
这些图片的格子本该有32位,但是怕读者大人看不清,就用一个INT的位数来举例
向左移位时,丢弃的是符号位,因此正数左移可能会变成负数
int a = 0x10;
System.out.printf("%x\n", a << 1);
最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)
int a = 0x10;
System.out.printf("%x\n", a >> 1);
int a = 0x10;
System.out.printf("%x\n", a >>> 1)
表达式1 ? 表达式2 : 表达式3
当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值
当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值
// 求两个整数的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
int Min = a < b ? a : b;
小括号里面进行判断条件是否符合,正确执行语句
if(布尔表达式){
语句
}
在小括号里面进行条件判断,正确执行语句1,错误执行语句2
if (布尔表达式) {
语句1
}else{
语句2
}
表达式1正确,执行语句1,诺表达式1不正确,
则去判断表达式2是否正确,正确则执行语句2,
表达式2不正确,则去语句3。
if(布尔表达式1){
语句1
}else if(布尔表达式2){
语句2
}else{
语句3
}
外入:为了能将值能够通过键盘等工具,输入到计算机里面,java为此提供了一个方法Scanner。我们不需要懂的实现原理,只需要知道它的作用,和实现方法就行。这就是java的其中一个好处。
如何使用?
Scanner scanner=new Scanner(System.in);
//整型接收
int l= scanner.nextInt();//提供整型输入
//浮点型接收
float h= scanner.nextFloat();//提供一个浮点数输入
//字符串接收
String p=scanner.next();//提供了一个字符串输入
//没有输入char类型的方法
将两者结合一下:
实例1:
题目:输入一个1~100的数字来代表一个学生的成绩,并给他或她给予这门课评价
分数在 [90, 100] 之间的,为优秀
分数在 [80, 90) 之前的,为良好
分数在 [70, 80) 之间的,为中等
分数在 [60, 70) 之间的,为及格
分数在 [ 0, 60) 之间的,为不及格
Scanner scanner=new Scanner(System.in);
//整型接收
int score = scanner.nextInt();//提供整型输入
if(score >= 90){
System.out.println("优秀");
}else if(score >= 80 && score < 90){
System.out.println("良好");
}else if(score >= 70 && score < 80){
System.out.println("中等");
}else if(score >= 60 && score < 70){
System.out.println("及格");
}else if(score >= 0 && score < 60){
System.out.println("不及格");
}else{
System.out.println("错误数据");
}
实例2:
判断一个年份是否是闰年(什么是闰年?就是一般年份多天的年份),如何解题?
四年一闰、百年不闰、400年再闰
用年份除以4,没有余数的就是闰年,有余数的是平年,如果是世纪年(整百年)则是除以400。
Scanner scanner=new Scanner(System.in);
//整型接收
int year = scanner.nextInt();//输入年份
if (year % 100 == 0) {
//判断世纪闰年
if (year % 400 == 0) {
System.out.println("是闰年");
} else {
System.out.println("不是闰年");
}
} else {
//判断普通闰年
if (year % 4 == 0) {
System.out.println("是闰年");
} else {
System.out.println("不是闰年");
}
}
switch(表达式){
case 常量值1:{
语句1;
break;//终止语句
}
case 常量值2:{
语句2;
break;//终止语句
}
.....
default:{
内容都不满足时执行语句;
break;//终止语句
}
}
实例1
输入一个数(1~10)的数,判断它是星期几
Scanner scanner=new Scanner(System.in);
//整型接收
int day = scanner.nextInt();//输入日期
switch(day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("这个数不在日期中");
break;
}
注意:
循环条件为 true, 则执行循环语句; 当条件不满足时为false,则结束循环.
while(循环条件){
循环语句;
}
实例1:
计算 1 ~ 100 的和
int n = 1;
int result = 0;
while (n <= 100) {
result += n;
n++;
}
System.out.println(num);//5050
实例2:
计算 5 的阶乘
int n = 1;
int result = 1;
while (n <= 5) {
result *= n;
n++;
}
System.out.println(num);//120
实例3
计算 1! + 2! + 3! + 4! + 5!的和
int num = 1;
int sum = 0;
// 外层循环负责求阶乘的和
while (num <= 5) {
int factorResult = 1;
int tmp = 1;
// 里层循环负责完成求阶乘的细节.
while (tmp <= num) {
factorResult *= tmp;
tmp++;
}
sum += factorResult;
num++;
}
System.out.println("sum = " + sum);
注意:
循环内的条件一定要设置好,诺是没有设置好就会一直循环,直到程序吃完你的所有运算资源。然后崩溃。
break 的功能是让循环提前结束.
实例:找到 100 - 200 中第一个 3 的倍数
int num = 100;
while (num <= 200) {
if (num % 3 == 0) {
System.out.println("找到了 3 的倍数, 为:" + num);//102
break;
}
num++;
}
continue 的功能是跳过这次循环, 立即进入下次循环
实例:
找到 100 - 200 中所有 3 的倍数
int num = 100;
while (num <= 200) {
if (num % 3 != 0) {
num++;
continue;
}
System.out.println("找到了 3 的倍数, 为:" + num);
num++;
}
表达式1: 用于初始化循环变量初始值设置,在循环最开始时执行,且只执行一次
表达式2: 循环条件,满足条件,则继续循环,否则循环结束
表达式3: 循环变量变化方式
for(表达式1;布尔表达式2;表达式3){
表达式4;
}
如何执行?
(1,2,3,4)—>(2,3,4)—>(2,3,4)—>(2,3,4)—>(2不满足条件)终止循环
实例1:
计算 1 ~ 100 的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("sum = " + sum);5050
实例3
计算 1! + 2! + 3! + 4! + 5!的和
int sum = 0;
for (int i = 1; i <= 5; i++) {
int tmp = 1;
for (int j = 1; j <= i; j++) {
tmp *= j;
}
sum += tmp;
}
System.out.println("sum = " + sum);
注意:
和while循环一样,结束单趟循环用continue,结束整个循环用break
先执行循环语句, 再判定循环条件,循环条件成立则继续执行,否则循环结束。
do{
循环语句;
}while(循环条件);
实例
int num = 1;
do {
System.out.println(num);
num++;
} while (num <= 10);
1.常用for,if,while,等逻辑控制
2.switch,case,break,要一起用
3.break终止当前循环,continue跳出这次循环
在实际开发中,有一些代码是会被重复使用的。首先我们假设一个应用场景,假设有一个程序描述了一个计算器。一个计算器有乘,除,加,减,根号。现在我需要计算一个数字,先除,再乘,再除。那么我们就需要写入一个关于除法的代码,写一个乘法的代码,然后再写一个除法的代码。你看我们写了两次除法的代码。这样就太不方便了。
所以在这是Java就引入了一个概念,方法,将一个代码用方法装起来,等需要用的时候就将,方法名放入带到要使用的代码中,通过这个方法名调用这个代码。
修饰符 返回值类型 方法名称([参数类型 形参 …]){
方法体代码;
[return 返回值];
}
public static int add(int x, int y) {
System.out.println("调用方法中 x = " + x + " y = " + y);
return x + y;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("第一次调用方法之前");
int ret = add(a, b);
System.out.println("第一次调用方法之后");
System.out.println("ret = " + ret);
System.out.println("第二次调用方法之前");
ret = add(30, 50);
System.out.println("第二次调用方法之后");
System.out.println("ret = " + ret);
}
看见括号中的参数吗?这个是参数,而参数分为形参和实参。
形参:就相当于add函数中的自变量x,用来接收add函数在调用时传递的值的。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
实参:通过实际参数可以更改变量的值的参数。
这里就不得不说一个东西。数据在内存中如何存储?
真实的存储中,存储一个数据会将一个唯一的地址与一个数据进行映射。形参就是将数据扔给add方法。而实参就是通过地址映射,来进行修改数据。此时add中对a进行改动,那么地址与之对应的数据就会改变
public static int getSum(int n){ // n是形参
return n / 2;
}
getSum(10); // 10是实参,在方法调用时,形参n用来保存10
getSum(100); // 100是实参,在方法调用时,形参n用来保存100
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。
为什么这样呢?我要去买菜,一个猪肉20块一斤,一斤白菜3.6块。那么问题来了。我要买一斤猪肉,3斤白菜。我要计算我要花多少钱。那么我就需要定义一个addMet(),addVegetable()然后总和。可是都是加法,为什么不定义一个add()只要中间的代码不同不就行了。
public class TestMethod {
public static void main(String[] args) {
add(1, 2); // 调用add(int, int)
add(1.5, 2.5); // 调用add(double, double)
add(1.5, 2.5, 3.5); // 调用add(double, double, double)
}
public static int add(int x, int y) {
return x + y;
注意:
这种思想在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解决之后,原问题就迎刃而解了。
//计算阶乘
public static void main(String[] args) {
int n = 5;
int ret = factor(n);
System.out.println("ret = " + ret);
}
public static int factor(int n) {
if (n == 1) {
return 1;
}
return n * factor(n - 1); // factor 调用函数自身
}
数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。
数组类型 [] 数组名 = new 数组类型[数组长度];
数组类型 [] 数组名={元素,元素};
int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组
double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组
String[] array3 = new double[3]; // 创建一个可以容纳3个字符串元素的数组
//数组初始化
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hell", "Java", "!!!"};
如果数组中存储元素类型为引用类型,默认值为null
程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址
虚拟机栈(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的
堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。
方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域
int[] array = {1, 2, 3};
System.out.println(array[3]); // 数组中只有3个元素,
//下标一次为:0 1 2,array[3]下标越界
通过循环遍历数组
int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}
注意:在数组中可以通过 数组对象.length 来获取数组的长度
int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < array.length; i++){
System.out.println(array[i]);
}
for循环的强化
int[] array = {1, 2, 3};
for (int x : array) {
System.out.println(x);
}
基本变量:基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值
引用类型变量:而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址
方法参数为引用类型,这就可以通过地址改动或调用数组中的元素
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
int[][] arr = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
二维数组遍历
for (int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr[row].length; col++) {
System.out.printf("%d\t", arr[row][col]);
}
System.out.println("");
}
其实就是一个特殊的一维数组。
1.数组是引用类型(通过地址寻找)
2.下标从0~数组长度-1
3.数组中元素类型与数组类型一致
类是用来对一个实体(对象)来进行描述的,比如一个人(实体(对象)),但是一个人又有脖子(类),手(类),脚(类),眼睛(类)等,这样我们就对一个人进行了完整的刻画。当然人(对象)也是不同的。比如,我和你都是人,但是我们脖子或许有些不同。
主要描述该实体(对象)具有哪些属性(外观尺寸等)。
类中包含的内容称为类的成员。
属性主要是用来描述类的,称之为类的成员属性或者类成员变量。
方法主要说明类具有哪些功能,称为类的成员方法。
class PetDog {
public String name;//名字
public String color;//颜色
// 狗的属性
public void barks() {
System.out.println(name + ": 旺旺旺~~~");
}
// 狗的行为
public void wag() {
System.out.println(name + ": 摇尾巴~~~");
}
}
new 关键字用于创建一个对象的实例. 使用 . 来访问对象中的属性和方法. 同一个类可以创建多个实例.
简单而言就是,人不同,但描述人的方式是一样的。通过不同的实例化从而进行对不同人的描述。
class PetDog {
public String name;//名字
public String color;//颜色
// 狗的属性
public void barks() {
System.out.println(name + ": 旺旺旺~~~");
}
// 狗的行为
public void wag() {
System.out.println(name + ": 摇尾巴~~~");
}
}
public class Main{
public static void main(String[] args) {
PetDog dogh = new PetDog(); //通过new实例化对象
dogh.name = "阿黄";
dogh.color = "黑黄";
dogh.barks();
dogh.wag();
PetDog dogs = new PetDog();
dogs.name = "阿黄";
dogs.color = "黑黄";
dogs.barks();
dogs.wag();
}
}
在实际运用中,会出现一个方法会传入多种数据的情况,但是每个传进去的值,一定不能拿错。为了确定每个传进去的值,就用this关键字。
具体问题是:
具体作用:this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。
一个时间例子:
public class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d){
//多个数据传入后根本无法确定传入的值是什么。
year = y;
month = m;
day = d;
}
public void printDate(){
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
// 对d1,d2,d3的日期设置
d1.setDay(2020,9,15);
d2.setDay(2020,9,16);
d3.setDay(2020,9,17);
// 打印日期中的内容
d1.printDate();
d2.printDate();
d3.printDate();
}
}
正确写法
创建一个时间对象。
public class Date {
public int year;
public int month;
public int day;
public void setDay(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
调用
public static void main(String[] args) {
Date d = new Date();
d.setDay(2020,9,15);
d.printDate();
}
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
public class Date {
public int year;
public int month;
public int day;
// 构造方法:
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("Date(int,int,int)方法被调用了");
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显式调用构造方法
Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
d.printDate(); // 2021-6-9
}
}
构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
特点:
对象空间被申请好之后,对象中包含的成员已经设置好了初始值,
数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。
举个例子说明:
我们在使用手机时我们用户只管直接去使用,无需去理解这些具体功能是如何实现的。我只需要来用。但是对于设计者而言。他们需要去将这些功能进行实现,并将这些功能装起来,无需用户去理解功能实现,只需要他们会用就可以。
范围 | private | default | protected | public |
---|---|---|---|---|
同一包中的同一类 | ✓ | ✓ | ✓ | ✓ |
同一包中的不同类 | × | ✓ | ✓ | ✓ |
不同包中的子类 | × | × | ✓ | ✓ |
不同包中的非子类 | × | × | × | ✓ |
public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包(同一个目录)中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。
可以使用 import语句导入包
import java.util.*;
public class Computer {
private String cpu; // cpu
private String memory; // 内存
public String screen; // 屏幕
String brand; // 品牌---->default属性
public Computer(String brand, String cpu, String memory, String screen) {
this.brand = brand;
this.cpu = cpu;
this.memory = memory;
this.screen = screen;
}
public void Boot(){
System.out.println("开机~~~");
}
public void PowerOff(){
System.out.println("关机~~~");
}
public void SurfInternet(){
System.out.println("上网~~~");
}
}
public class TestComputer {
public static void main(String[] args) {
Computer p = new Computer("HW", "i7", "8G", "13*14");
System.out.println(p.brand); // default属性:只能被本包中类访问
System.out.println(p.screen); // public属性: 可以任何其他类访问
// System.out.println(p.cpu); // private属性:只能在Computer类中访问,不能被其他类访问
}
}
通过import 导入我们需要的包。可以通过 * 号将整个包导入,也可以将这个符号改成具体的文件名。我更建议后者。因为这个符号代表者文件下面的全部文件。我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况.
常见的包:
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。(俗称静态区)
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom = "Bit306";//看清楚,这里我用的是private修饰
// ...
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.classRoom);
}
}
这个代码会出现编译错误。
正确的是:
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom = "Bit306";
public static String getClassRoom(){
return classRoom;
}
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.getClassRoom());
}
}
使用 {} 定义的一段代码称为代码块。
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
实例代码块。构造代码块一般用于初始化实例成员变量。
private String name;
private String gender;
private int age;
private double score;
public Student() {
System.out.println("I am Student init()!");
}
//实例代码块
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom;
//实例代码块
{
this.name = "李思";
this.age = 12;
this.gender = "men";
System.out.println("你好!");
}
// 静态代码块
static {
classRoom = "6班";
System.out.println("你好同学!");
}
等待我后续文章,这里不多解释,建议先看我后面的数据结构在来阅读这方面的文章.
A是外部类
B是内部类
可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。(简单而言就是,在类中定义一个类,简称类中类)(调用方法在静态类中有体现)
public class A{
class B{
}
}
public class A{
// 成员位置定义:未被static修饰 --->实例内部类
public class B{
}
// 成员位置定义:被static修饰 ---> 静态内部类
static class C{
}
public void func(){
// 方法中也可以定义内部类 ---> 局部内部类:几乎不用
class D{
}
}
}
被static修饰的内部成员类称为静态内部类
public class ClassA {
private int a;
static int b;
public void methodA(){
a = 10;
System.out.println(a);
}
public static void methodB(){
System.out.println(b);
}
// 静态内部类:被static修饰的成员内部类
static class ClassB{
public void methodInner(){
// 在内部类中只能访问外部类的静态成员
// a = 100; // 编译失败,因为a不是类成员变量
b =200;
// methodA(); // 编译失败,因为methodB()不是类成员方法
methodB();
}
}
public static void main(String[] args) {
// 静态内部类对象创建 & 成员访问
ClassA.ClassB Class = new ClassA.ClassB();
Class.methodInner();
}
}
即未被static修饰的成员内部类。
public class OutClass {
private int a;
static int b;
int c;
public void methodA(){
a = 10;
System.out.println(a);
}
public static void methodB(){
System.out.println(b);
}
// 实例内部类:未被static修饰
class InnerClass{
int c;
public void methodInner(){
// 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员
a = 100;
b =200;
methodA();
methodB();
// 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的
c = 300;
System.out.println(c);
// 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
OutClass.this.c = 400;
System.out.println(OutClass.this.c);
}
}
public static void main(String[] args) {
// 外部类:对象创建 以及 成员访问
OutClass outClass = new OutClass();
System.out.println(outClass.a);
outClass.methodA();
实例内部类的访问
// 要访问实例内部类中成员,必须要创建实例内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
// 创建实例内部类对象
OutClass.InnerClass innerlass1 = new OutClass().new InnerClass();
// 上述语法比较怪异,也可以先将外部类对象先创建出来,然后再创建实例内部类对象
OutClass.InnerClass innerClass2 = outClass.new InnerClass();
innerClass2.methodInner();
}
1.类就是描述物体的一种集合,类中定义的方法以及成员是具体描述这个物体的固有属性(称其为对象)(如动物这个大类他是一个抽象的描述,并不具体,而动物有很多他们都有不同的名字,体型,身高,叫声,比如狗,猫,鸟,老虎…这些动物的描述方式各有不同)
2.用{}包裹的就是代码块,用static修饰的是静态代码块
3.内部类就是通过在一个类中再次定义一个的方式,通常分为非静态内部类,静态内部类(用static修饰的静态的内部类。)
4.内部类调用通常:(非静态内部类 ) **外部类.内部类 xxx=外部类.new 内部类();**进行实例化。(静态内部类)**外部类.内部类 xxx=new 外部类.内部类();**进行实例化。
对于java来说,最重要的就是面对对象,而如何体现这个,在其中三个概念极为重要,封装、继承、多态而无论考试还是面试通常都会考察这几个概念及其原理用法。
面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。在实际使用类和对象的过程中,会出现的几个问题,比如我们定义了一个猫和狗的类。它们有着共同的一些性质,或者说是行为。比如他们都是动物,都有名字,也都会吃饭。我们在描述它们时,就会将这些行为或者属性通过方法或者成员进行描述。这样我们就发现了他们,在某些情况下,代码是重复的。为了避免代码复写,就将一个类的共有属性进行封装。在出现这个类的子类时(什么是子类?比如“动物”他就父类,而“动物”下面会细分其他“动物”比如“狗”,那么“动物”就是“狗”的父类,“狗”是“动物”的子类),我们只需要描述,这个子类特有的特点就好。而他们的共同特点,可以通过继承他的父类的公共方法进行使用。
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
父类:又叫基类,也叫超类
子类:又叫派生类
修饰符 class 子类 extends 父类 {
// ...
}
父类
// Animal.java
public class Animal{
String name;
int age;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
}
子类
// Dog.java
//子类
public class Dog extends Animal{
void bark(){
System.out.println(name + "汪汪汪~~~");
}
}
测试类
// TestExtend.java
public class TestExtend {
public static void main(String[] args) {
Dog dog = new Dog();
// dog类中并没有定义任何成员变量,name和age属性肯定是从父类Animal中继承下来的
System.out.println(dog.name);
System.out.println(dog.age);
// dog访问的eat()和sleep()方法也是从Animal中继承下来的
dog.eat();
dog.sleep();
dog.bark();
}
}
在子类方法中 或者 通过子类对象访问成员时:
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
问题:如果子类中存在与父类中相同的成员时,那如何在子类中访问父类相同名称的成员呢?没错,通过super关键字。与this关键字相似,不过前者是声明调用的是父类中的方法。
父类
public class Base {
int a;
int b;
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
子类
public class Derived extends Base{
int a; // 与父类中成员变量同名且类型相同
char b; // 与父类中成员变量同名但类型不同
// 与父类中methodA()构成重载
public void methodA(int a) {
System.out.println("Derived中的method()方法");
}
// 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
// 对于同名的成员变量,直接访问时,访问的都是子类的
a = 100; // 等价于: this.a = 100;
b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从父类继承下来的部分
super.a = 200;
super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),父类的无法访问到
super.methodB(); // 访问父类的methodB()
}
}
构造方法
子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。
父类构造
public class Base {
public Base(){
System.out.println("Base()");
}
}
子类构造
public class Derived extends Base{
public Derived(){
super();
// 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
// 并且只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}
结果打印:
Base()
Derived()
super与this的区别
相同点:
构造方法
不同点:
执行优先分析(重要)
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
/*
Person:静态代码块执行
Student:静态代码块执行
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
*/
继承的方式种类
这个图是我从其他地方摘抄来的。以问过作者了,主要是这个图确实好用。
final关键可以用来修饰变量、成员方法以及类。
1.修饰变量
修饰变量或字段,表示常量(即不能修改)
final int a = 10;
a = 20; // 编译出错
2.修饰类
表示此类不能被继承
final public class Animal {
…
}
public class Bird extends Animal {
…
}
3.修饰方法
表示该方法不能被重写
**通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。**比如动物,它有猫这个子类,也有狗这个子类,但是他们吃的东西不同,猫吃猫粮,狗吃狗粮,在父类中出现吃这个动作。而子类将这些具象化了,呈现了不同类型不同状态的形式。(多态)
public class Animal {
String name;
int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name + "吃饭");
}
}
public class Cat extends Animal{
public Cat(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃鱼~~~");
}
}
}
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。也就是说子类能够根据需要实现父类的方法。
规则:
区别 | 重写(override) | 重载(override) |
---|---|---|
参数列表 | 一定不能修改 | 必须修改 |
返回类型 | 一定不能修改【除非可以构成父子类关系】 | 可以修改 |
访问限定符 | 一定不能做更严格的限制 | 可以修改 |
重写:方法名和参数必须一致
重载:方法名相同,参数不同
重载
向上转型:
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
父类类型 对象名 = new 子类类型()
Animal animal = new Cat("将军");
向下转型:
将父类引用再还原为子类对象,即向下转换。
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat("将军");
Dog dog = new Dog("虞姬");
// 向上转型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
注意:
向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
1.多态能够降低代码的 “圈复杂度”(形容代码的复杂程度,一般if-else不超过10), 避免使用大量的 if - else
2.多态可扩展能力更强
3.向上转型用的更多也更安全,向下转型,会横跨两个子类,可能会出现跨类调用
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类,他没有具体的实现方法,只提供了一个方法或成员
被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。
// 抽象类:被abstract修饰的类
public abstract class Shape {
// 抽象方法:被abstract修饰的方法,没有方法体
abstract public void draw();
abstract void calcArea();
// 抽象类也是类,也可以增加普通方法和属性
public double getArea(){
return area;
}
protected double area; // 面积
}
抽象类
特点:
接口可以看成是:多个类的公共规范,是一种引用数据类型。接口你可理解成父类也就是父类,接口,可以理解为一类东西,只是运用的范围不同而已。
抽象类---->接口==(约等于)父类
接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。
public interface 接口名称{
// 抽象方法
// public abstract 是固定搭配,可以不写
public abstract void method1();
public void method2();
abstract void method3();
// 注意:在接口中上述写法都是抽象方法,跟推荐方式4,代码更简洁
void method4();
}
接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。
子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。
// USB接口
public interface USB {
void openDevice();
void closeDevice();
}
// 鼠标类,实现USB接口
public class Mouse implements USB {
@Override
public void openDevice() {
System.out.println("打开鼠标");
}
}
接口
其实对于接口和类,java自带的库中有很多好用的方法。这里先不赘述,在文件末尾,我会对这些进行总结(用链接的方式)(就复习而言这些足以)
在Java中,将程序执行过程中发生的不正常行为称为异常。
1.算术异常
System.out.println(10 / 0);
java.lang.ArithmeticException
2.数组越界异常
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
java.lang.ArrayIndexOutOfBoundsException
3.空指针异常
int[] arr = null;
System.out.println(arr.length);
java.lang.NullPointerException
抛出异常
public static int getElement(int[] array, int index){
if(null == array){
//抛出异常
throw new NullPointerException("传递的数组为null");
}
if(index < 0 || index >= array.length){
//抛出异常
throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");
}
return array[index];
}
public static void main(String[] args) {
int[] array = {1,2,3};
getElement(array, 3);
}
捕获异常:
语法格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2…{
}
try-catch捕获并处理
语法格式:
try{
// 将可能出现异常的代码放在这里
}catch(要捕获的异常类型 e){
// 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的父类时,就会被捕获到
// 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
}[catch(异常类型 e){
// 对异常进行处理
}finally{
// 此处代码一定会被执行到
}]
// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行
文章链接
文章链接
文章链接
文章链接
文章链接
文章链接
文章链接
文章链接
HashMap和HashSet,TreeMap和TreeSet
文章链接
里面有堆排序的实现和逻辑
文章链接
文章链接
文章链接
这样不必担心对于复习考试而言绰绰有余。大家诺觉得有用可以收藏一波,等待后续对于数据结构,以及其他相关的文章。我会尽量讲的通俗讲清楚。代码考试需要大家去刷题,推荐一个小白刷题网站牛课网。(实测非常好用,大部分互联网公司都在用它招聘)