【JAVA基础】初学者指南--两万字知识点总结--零基础,超详细 。
Java基础知识
- JAVA入门
- JAVA三大版本
- JAVA的特性和优势
- JAVA运行机制
- JVM、JRE、JDK
- JAVA开发环境搭建
- 变量、数据类型和运算符
- 变量(variable)
- 变量的本质
- 变量的声明
- 变量的分类和作用域
- 局部变量
- 成员变量(也叫实例变量)
- 静态变量(又叫类变量)
- 常量(Constant)
- 基本数据类型
- 整型
- byte
- short
- int
- long
- 整型的不同进制表示方式
- 浮点型
- float
- double
- 字符型
- char
- 常用转义字符
- 布尔型(boolean)
- 运算符
- 算术运算符
- 赋值及其扩展赋值运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 字符串连接符
- 条件运算符
- 运算符优先级的问题
- 数据类型的转换
- 自动类型转换
- 强制类型转换
- IDEA的使用
- 下载和安装IDEA
- IDEA的配置和使用
- IDEA快捷键大全
- 控制语句
- IF
- if单分支结构
- if-else双分支结构
- if-else if-else 多分支结构
- SWITCH结构
- break和continue
- 嵌套循环
- 递归结构
- 方法
- 面向对象概念
- 初识面向对象
- 引入表格和类的比较
- 类的方法和表格中的动作
- 对象对应表格中的行数据
- 面向过程和面向对象
- 面向过程和面向对象的区别
- **面向对象和面向过程思想的总结**
- 对象和类的详解
- 类的定义
- 属性(field)
- 方法(method)
- 构造方法(构造器constructor)
- 面向对象的内存分析
- 栈(stack)
- 堆(heap)
- 方法区(method area)
- 垃圾回收机制(Garbage Collection)
- 垃圾回收原理
- 垃圾回收算法
- 引用计数法
- 引用可达法(根搜索算法)
- 分代回收垃圾机制
- 包机制(package和import)
- package
- 导入类import
- 静态导入
- 继承
- 继承的实现
- instanceof运算符
- 继承使用要点
- 父类和子类的相互转换
- 方法重写override
- final关键字
- 组合
- 封装
- 多态
- Object类详解
- Object类基本特性
- toString()方法
- “==”和equals比较
- 继承数追溯
- super关键字
- 抽象类
- 接口interface
- **接口的多继承**
- 字符串String类
- “+” 连接符
- String类和常量池
- String类常用方法:
- 内部类
- 数组
- 数组的概念
- 数组的定义
- 数组的声明方式
- 数组的初始化
- 静态初始化
- 动态初始化
- 数组的默认初始化
- 数组常见操作
- 数组的遍历
- 数组的拷贝
- java.util.Arrays类
- 多维数组
- 用二维数组存储表格数据
- 用javabean和一维数组存储表格数据
- Comparable接口
- 常用类
- 基本数据类型的包装类
- 包装类
- 自动装箱、自动拆箱机制
- new关键字和valueOf()
- 为什么需要包装类?
- 字符串相关类
- StringBuffer和StringBuilder
- 不可变和可变字符序列使用陷阱
- 时间相关类
- Date时间类(java.util.Date)
- DateFormat类和SimpleDateFormat类
- Calendar日历类
- 其他常用类
- 异常机制
- 异常(Exception)的概念
- 异常分类
- Error
- Exception
- RuntimeException
- CheckedException
- 捕获异常
- throws(声明异常)
- 自定义异常
JAVA入门
JAVA三大版本
- JavaSE(Java Standard Edition):标准版,在个人计算机上使用。
JavaSE是Java平台的核心,它提供了非常丰富的API来开发一般个人计算机上的应用程序。
- JavaEE(Java Enterprise Edition):企业版,定位在服务器端的应用。
JavaEE是JavaSE的扩展,增加了用于服务器开发的类库。
- JavaME(Java Micro Edition):微型版,定位在消费性电子产品应用上。
JavaME是JavaSE的内申,包含J2SE的一部分核心类,也有自己的扩展类,增加了适合微小装置的类库。该版本针对资源有限的电子消费产品的需求精简核心库,并提供了模块化的架构让不同产品随时能增加支持的能力。
安卓开发属于JavaME,但不要认为JavaME就是安卓开发,安卓开发只是JavaME其中的一部分。
JAVA的特性和优势
跨平台/可移植性
这是Java的核心优势。比如Java的int类型永远是32位,不像C/C++可能是16或32位,根据编译器厂商规定来变化。这样Java程序的移植就会很方便。
安全性
Java适合网络/分布式环境,为了达到这个目标,在安全性方面投入了很大的精力,使Java可以很容易构建防病毒,防篡改的系统。
面向对象
与C++相比,Java是完全面向对象的语言。
简单性
Java就是C++的简化版,也可以把Java称之为“C+±”,指的就是将C++的一些内容去掉,比如头文件、指针、结构、联合、操作符重载、虚基类等等。同时,Java的语法是基于C语言的,学习成本会很低。
高性能
Java在最初发展阶段性能较低,这在高级语言中往往是难以避免的,Java语言通过虚拟机的优化可以提升几十倍的运行效率。这样Java程序的执行效率就会大大提高。
分布式
Java是为Internet的分布式环境设计的,因为它能够处理TCP/IP协议。
多线程
多线程的使用可以带来更好的交互响应和实时行为。
健壮性
Java是一种健壮性的语言,它吸收了C/C++的优点,但去掉了影响程序健壮性的部分(如:指针,内存的申请和释放等)。Java程序不会造成计算机崩溃。及时Java程序出错时会把异常抛出,在通过异常处理机制加以处理。
JAVA运行机制
- Java首先用文本编辑器编写Java源程序,源文件的后缀名为.java;
- 再利用编译器(javac)将源程序编译成字节码文件,字节码文件的后缀名为.class;
- 最后利用虚拟机(解释器,java)解释执行。如上图所示。
计算机高级语言主要类型有编译型和解释型两种,而Java是两种类型的结合。
JVM、JRE、JDK
JVM(Java Virtual Machine):Java虚拟机,用于执行字节码的“虚拟计算机”。
不同操作系统上有不同版本的JVM,屏蔽了底层运行平台的差异,是实现跨平台的核心。
JRE(Java Runtime Environment):包含JVM,库函数等。
JDK(Java Development kit):包含JRE,编译器和调试器等。
JAVA开发环境搭建
下载JDK
https://www.oracle.com/java/technologies/downloads/
安装JDK
选择JDk安装目录,采用默认即可。(如果自定义目录,注意路径中不能包含中文)
变量、数据类型和运算符
变量(variable)
变量的本质
- 变量是一个可操作的内存空间,空间位置是确定的,但里面当放的值不确定。
- 可通过变量名来访问对应的存储空间,从而操作这个空间存储的值。
- Java是一种强类型语言,每个变量都必须声明其数据类型。变量的数据类型决定了变量所占存储空间的大小。
变量的声明
double salary;
int age;
long earth_moon_distance;
声明变量的初始化,这一点和C语言相同
int age = 18;
double e = 2.717271828;
int i,j; //同时定义两个变量,都是int类型
变量的分类和作用域
变量有三种类型:局部变量、成员变量(实例变量)和静态变量。
局部变量
方法或语句块内部定义的变量。生命周期从声明位置开始到方法或语句块执行完毕为止。局部变量在使用前必须先声明和初始化后再使用。
public void test(){int i;int j = i+1;//编译会出错,变量i未初始化
}
public void test(){int i = 1;int j = i+1;//编译正确
}
成员变量(也叫实例变量)
方法外部、类内部定义的变量。从属于对象,生命周期伴随对象始终。可以不自行初始化,系统会自动初始化为对应类型的默认值。
public class Test{int age; //int类型,默认初始化为0double score; //double类型:默认初始化为0.0char ch; //char类型:默认初始化为:'\u0000'(前缀u是指Unicode编码表示)boolean flag; //boolean类型:默认初始化为false
}
静态变量(又叫类变量)
使用static定义。从属于类,生命周期伴随类始终,从类加载到卸载。如果不自行初始化,与成员变量一样会自动初始化为对应类型的默认值。
常量(Constant)
在Java语言中,用关键字final来定义一个常量。
声明格式:
final 类型 变量名 = 初始化值; |
---|
public class TestConstant{public static void main(String[ ] args){final double PI = 3.14;PI = 3.15; //编译错误!final修饰不能再被赋值}/*我们把像PI这样的常量成为符号常量,因为定义好PI常量后,就可以把它当做一个符号来使用。事实上,这里的PI是我们自定义的一个圆周率π,完全可以用PI替换π来使用。因此,在它使用过程中是一定不能被修改的。*/
}
基本数据类型
整型
byte
1字节 表述范围:-2(7) ~ 2(7)-1 (-128~127)
short
2字节 表述范围:2(15) ~ 2(15) -1 (-32768~32767)
int
4字节 表述范围:-2(31) ~ 2(31)-1 (-2147483648~2147483647) 约21 亿
long
8字节 表述范围:-2(63) ~ 2(63)-1
Java中整型默认为int型,声明long型常量可以在后面加 ’ l ’ 或 ’ L ’ 。
long a = 10000000; //编译通过,因为在int表示范围内(21亿)。
long b = 10000000000; //编译错误(报错:The literal 10000000000 of type int is out of range),因为会把右边的数默认为int型,但超出int表示范围。必须在后面加上L
long c = 10000000000l //编译通过。
整型的不同进制表示方式
- 十进制整数,如:99,-100,0
- 八进制整数,以0开头,如:015
- 十六进制整数,以0x开头,如:0x15
- 二进制数,以0b开头,如:0b01100101
浮点型
float
4字节 表述范围:-3.403E38~3.403E38
double
8字节 表述范围:-1.798E308~1.798E308
浮点型常量默认是double,要改成float可以在后面加f或F。
通常不要比较两个浮点数的值,因为浮点数不够精确。
【示例 1】浮点型数据的比较一
float f = 0.1f;
double d = 1.0/10;
System.out.println(f==d); //结果为false
【示例 2】浮点型数据的比较二
float d1 = 123456789f;
float d2 = d1+1;
if(d1==d2)System.out.println("d1=d2");
elseSystem.out.println("d1!=d2");
//输出结果为d1=d2,说明浮点数的精度是有限的,即使d1加1也被忽略掉了。
所以,不要使用浮点数进行比较!需要比较可以使用BigDecimal类
java.math包下面有两个类:BigInteger和BigDecimal,这两个类可以处理任意长度的数值。BigInteger实现了任意精度的整数运算。BigDecimal实现了任意精度的浮点数运算。
字符型
char
2字节 在Java中使用单引号来表示字符常量。例如:‘A’,它与**“A”**是不同的。
char类型用来表示Unicode编码表中的字符。Unicode编码被设计用来处理各种语言的文字,它占2个字节,可允许有65536个字符。所以也可以用中文表示一个char类型字符。
char c1 = 'a';
char c2 = '中'; //汉字“中”和“a”的地位相同。
常用转义字符
char c1 = '\n'; //换行
char c2 = '\b'; //退格
char c3 = '\r'; //回车
char c4 = '\t'; //制表符
char c5 = '\“'; //双引号
char c6 = '\\'; //反斜杠
布尔型(boolean)
- boolean类型有两个常量值,true和false。
- 占1个或4个字节,不能使用0或非0的整数代替true和false,这点和C语言不同。
JVM把单独一个boolean当做int来处理,所以占4字节,把boolean数组当byte处理,占1字节。所以,boolean类型单独使用时占4字节,在数组中时占1字节。
运算符
算术运算符
- +,-,*,/,%属于二元运算符。%是取模运算符,就是我们常说的求余数操作。
- 算术运算符中++(自增),–(自减)属于一元运算符。
二元运算符的运算规则:
整数运算:
如果两个操作数有一个为 long, 则结果也为 long。
没有 long 时,结果为 int。即使操作数全为 short,byte,结果也是int。
浮点运算:
如果两个操作数有一个为 double,则结果为 double。
只有两个操作数都是 float,则结果才为 float。
取模运算:
- 其操作数可以为浮点数,一般使用整数,结果是“余数”,“余数”符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1。
赋值及其扩展赋值运算符
+= | a+=b | a = a+b |
---|---|---|
-= | a-=b | a = a-b |
*= | a*=b | a = a*b |
/= | a/=b | a = a/b |
%= | a%=b | a = a%b |
关系运算符
关系运算符用来进行比较运算。关系运算的结果是布尔值:true/false;
- =是赋值运算符,而真正的判断两个操作数是否相等的运算符是==。
- ==、!= 是所有(基本和引用)数据类型都可以使用。
- > 、>=、 <、 <= 仅针对数值类型
逻辑运算符
逻辑运算的操作数和运算结果都是 boolean 值。
与 | & | 只要有一个为 false,则 false |
---|---|---|
短路与 | && | 只要有一个为 false,则 false |
或 | | | 只要有一个为 true, 则 true |
短路或 | || | 只要有一个为 true, 则 true |
非 | ! | 取反 |
异或 | ^ | 相同为 false,不同为 true |
位运算符
位运算指的是进行二进制位的运算。
~ | 取反 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< | 左移运算符,左移 1 位相当于乘 2 |
>> | 右移运算符,右移 1 位相当于除 2 取商 |
&和|既是逻辑运算符,也是位运算符。如果两侧操作数都是 boolean 类型,就作为逻辑运算符。如果两侧的操作数是整数类型,就是位运算符。
字符串连接符
“+”运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一个操作数转换为字符串然后再进行连接。
int a = 10;
System.out.println("a="+12); //输出结果为:a=10
条件运算符
x?y:z |
---|
运算符优先级的问题
运算符的优先级
优先级 | 运算符 | 类 |
---|---|---|
1 | () | 括号运算符 |
2 | !、+(正号)、-(负号) | 一元运算符 |
2 | ~ | 位逻辑运算符 |
2 | ++、– | 递增与递减运算 |
3 | *、/、% | 算术运算符 |
4 | +、- | 算术运算符 |
5 | <<、>> | 位左移、右移运算符 |
6 | >、>=、<、<= | 关系运算符 |
7 | ==、!= | 关系运算符 |
8 | & | 位运算符、逻辑运算符 |
9 | ^ | 位运算符、逻辑运算符 |
10 | | | 位运算符、逻辑运算符 |
11 | && | 逻辑运算符 |
12 | || | 逻辑运算符 |
13 | ? : | 条件运算符 |
14 | =、+=、-=、*=、/=、%= | 赋值运算符、扩展运算符 |
数据类型的转换
自动类型转换
容量小的数据类型可以自动转换为容量大的数据类型
比如:int转为long、short转为int、char转为int等,所有基本数据类型都可以转为double,但转换时可能会有精度的损失。
强制类型转换
double a = 3.91;
int x = (int)a; //将a强转为int型,但损失了小数后的数据
注意:
强转时如果超出范围,就会被截断成一个错误的值!
int x = 300;
byte b = (byte)x; //byte的范围是-128~127,x的值超过强转类型的范围//输出结果 b = 44,是一个错误的值。
IDEA的使用
下载和安装IDEA
下载地址: https://www.jetbrains.com/idea/download/#section=windows
IDEA的配置和使用
在IDEA中创建Java项目
点击“Create New Project”,创建新的项目。
- 选择 JD
- 根据项目模板创建项目
- 填写项目名称和包名
- 开始编写代码
IDEA快捷键大全
Ctrl
Ctrl + F 在当前文件进行文本查找 (必备)
Ctrl + R 在当前文件进行文本替换 (必备)
Ctrl + Z 撤销 (必备)
Ctrl + Y 删除光标所在行 或 删除选中的行 (必备)
Ctrl + X 剪切光标所在行 或 剪切选择内容
Ctrl + C 复制光标所在行 或 复制选择内容
Ctrl + D 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)
Ctrl + W 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 (必备)
Ctrl + E 显示最近打开的文件记录列表
Ctrl + N 根据输入的 类名 查找类文件
Ctrl + G 在当前文件跳转到指定行处
Ctrl + J 插入自定义动态代码模板
Ctrl + P 方法参数提示显示
Ctrl + Q 光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + U 前往当前光标所在的方法的父类的方法 / 接口定义
Ctrl + B 进入光标所在的方法/变量的接口或是定义出,等效于 Ctrl + 左键单击
Ctrl + K 版本控制提交项目,需要此项目有加入到版本控制才可用
Ctrl + T 版本控制更新项目,需要此项目有加入到版本控制才可用
Ctrl + H 显示当前类的层次结构
Ctrl + O 选择可重写的方法
Ctrl + I 选择可继承的方法
Ctrl + + 展开代码
Ctrl + - 折叠代码
Ctrl + / 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 (必备)
Ctrl + [ 移动光标到当前所在代码的花括号开始位置
Ctrl + ] 移动光标到当前所在代码的花括号结束位置
Ctrl + F1 在光标所在的错误代码出显示错误信息
Ctrl + F3 调转到所选中的词的下一个引用位置
Ctrl + F4 关闭当前编辑文件
Ctrl + F8 在 Debug 模式下,设置光标当前行为断点,如果当前已经是断点则去掉断点
Ctrl + F9 执行 Make Project 操作
Ctrl + F11 选中文件 / 文件夹,使用助记符设定 / 取消书签
Ctrl + F12 弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选
Ctrl + Tab 编辑窗口切换,如果在切换的过程又加按上delete,则是关闭对应选中的窗口
Ctrl + Enter 智能分隔行
Ctrl + End 跳到文件尾
Ctrl + Home 跳到文件头
Ctrl + Space 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号 (必备)
Ctrl + Delete 删除光标后面的单词或是中文句
Ctrl + BackSpace 删除光标前面的单词或是中文句
Ctrl + 1,2,3…9 定位到对应数值的书签位置
Ctrl + 左键单击 在打开的文件标题上,弹出该文件路径
Ctrl + 光标定位 按 Ctrl 不要松开,会显示光标所在的类信息摘要
Ctrl + 左方向键 光标跳转到当前单词 / 中文句的左侧开头位置
Ctrl + 右方向键 光标跳转到当前单词 / 中文句的右侧开头位置
Ctrl + 前方向键 等效于鼠标滚轮向前效果
Ctrl + 后方向键 等效于鼠标滚轮向后效果
————————————————
Alt
Alt + ` 显示版本控制常用操作菜单弹出层
Alt + Q 弹出一个提示,显示当前类的声明 / 上下文信息
Alt + F1 显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择
Alt + F2 对于前面页面,显示各类浏览器打开目标选择弹出层
Alt + F3 选中文本,逐个往下查找相同文本,并高亮显示
Alt + F7 查找光标所在的方法 / 变量 / 类被调用的地方
Alt + F8 在 Debug 的状态下,选中对象,弹出可输入计算表达式调试框,查看该输入内容的调试结果
Alt + Home 定位 / 显示到当前文件的 Navigation Bar
Alt + Enter IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 (必备)
Alt + Insert 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等
Alt + 左方向键 按左方向切换当前已打开的文件视图
Alt + 右方向键 按右方向切换当前已打开的文件视图
Alt + 前方向键 当前光标跳转到当前文件的前一个方法名位置
Alt + 后方向键 当前光标跳转到当前文件的后一个方法名位置
Alt + 1,2,3…9 显示对应数值的选项卡,其中 1 是 Project 用得最多
————————————————
Shift
Shift + F1 如果有外部文档可以连接外部文档
Shift + F2 跳转到上一个高亮错误 或 警告位置
Shift + F3 在查找模式下,查找匹配上一个
Shift + F4 对当前打开的文件,使用新Windows窗口打开,旧窗口保留
Shift + F6 对文件 / 文件夹 重命名
Shift + F7 在 Debug 模式下,智能步入。断点所在行上有多个方法调用,会弹出进入哪个方法
Shift + F8 在 Debug 模式下,跳出,表现出来的效果跟 F9 一样
Shift + F9 等效于点击工具栏的 Debug 按钮
Shift + F10 等效于点击工具栏的 Run 按钮
Shift + F11 弹出书签显示层
Shift + Tab 取消缩进
Shift + ESC 隐藏当前 或 最后一个激活的工具窗口
Shift + End 选中光标到当前行尾位置
Shift + Home 选中光标到当前行头位置
Shift + Enter 开始新一行。光标所在行下空出一行,光标定位到新行位置
Shift + 左键单击 在打开的文件名上按此快捷键,可以关闭当前打开文件
Shift + 滚轮前后滚动 当前文件的横向滚动轴滚动
————————————————
Ctrl + Alt
Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + O 优化导入的类,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + I 光标所在行 或 选中部分进行自动代码缩进,有点类似格式化
Ctrl + Alt + T 对选中的代码弹出环绕选项弹出层
Ctrl + Alt + J 弹出模板选择窗口,讲选定的代码加入动态模板中
Ctrl + Alt + H 调用层次
Ctrl + Alt + B 在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
Ctrl + Alt + V 快速引进变量
Ctrl + Alt + Y 同步、刷新
Ctrl + Alt + S 打开 IntelliJ IDEA 系统设置
Ctrl + Alt + F7 显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来
Ctrl + Alt + F11 切换全屏模式
Ctrl + Alt + Enter 光标所在行上空出一行,光标定位到新行
Ctrl + Alt + Home 弹出跟当前文件有关联的文件弹出层
Ctrl + Alt + Space 类名自动完成
Ctrl + Alt + 左方向键 退回到上一个操作的地方 (必备)(注意与其他软件快捷键冲突)
Ctrl + Alt + 右方向键 前进到上一个操作的地方 (必备)(注意与其他软件快捷键冲突)
Ctrl + Alt + 前方向键 在查找模式下,跳到上个查找的文件
Ctrl + Alt + 后方向键 在查找模式下,跳到下个查找的文件
————————————————
Ctrl + Shift
Ctrl + Shift + F 根据输入内容查找整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + R 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + J 自动将下一行合并到当前行末尾 (必备)
Ctrl + Shift + Z 取消撤销 (必备)
Ctrl + Shift + W 递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围 (必备)
Ctrl + Shift + N 通过文件名定位 / 打开文件 / 目录,打开目录需要在输入的内容后面多加一个正斜杠 (必备)
Ctrl + Shift + U 对选中的代码进行大 / 小写轮流转换 (必备)
Ctrl + Shift + T 对当前类生成单元测试类,如果已经存在的单元测试类则可以进行选择
Ctrl + Shift + C 复制当前文件磁盘路径到剪贴板
Ctrl + Shift + V 弹出缓存的最近拷贝的内容管理器弹出层
Ctrl + Shift + E 显示最近修改的文件列表的弹出层
Ctrl + Shift + H 显示方法层次结构
Ctrl + Shift + B 跳转到类型声明处
Ctrl + Shift + I 快速查看光标所在的方法 或 类的定义
Ctrl + Shift + A 查找动作 / 设置
Ctrl + Shift + / 代码块注释 (必备)
Ctrl + Shift + [ 选中从光标所在位置到它的顶部中括号位置
Ctrl + Shift + ] 选中从光标所在位置到它的底部中括号位置
Ctrl + Shift + + 展开所有代码
Ctrl + Shift + - 折叠所有代码
Ctrl + Shift + F7 高亮显示所有该选中文本,按Esc高亮消失
Ctrl + Shift + F8 在 Debug 模式下,指定断点进入条件
Ctrl + Shift + F9 编译选中的文件 / 包 / Module
Ctrl + Shift + F12 编辑器最大化
Ctrl + Shift + Space 智能代码提示
Ctrl + Shift + Enter 自动结束代码,行末自动添加分号 (必备)
Ctrl + Shift + Backspace 退回到上次修改的地方
Ctrl + Shift + 1,2,3…9 快速添加指定数值的书签
Ctrl + Shift + 左方向键 在代码文件上,光标跳转到当前单词 / 中文句的左侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 右方向键 在代码文件上,光标跳转到当前单词 / 中文句的右侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 左方向键 在光标焦点是在工具选项卡上,缩小选项卡区域
Ctrl + Shift + 右方向键 在光标焦点是在工具选项卡上,扩大选项卡区域
Ctrl + Shift + 前方向键 光标放在方法名上,将方法移动到上一个方法前面,调整方法排序
Ctrl + Shift + 后方向键 光标放在方法名上,将方法移动到下一个方法前面,调整方法排序
————————————————
Alt + Shift
Alt + Shift + N 选择 / 添加 task
Alt + Shift + F 显示添加到收藏夹弹出层
Alt + Shift + C 查看最近操作项目的变化情况列表
Alt + Shift + F 添加到收藏夹
Alt + Shift + I 查看项目当前文件
Alt + Shift + F7 在 Debug 模式下,下一步,进入当前方法体内,如果方法体还有方法,则会进入该内嵌的方法中,依此循环进入
Alt + Shift + F9 弹出 Debug 的可选择菜单
Alt + Shift + F10 弹出 Run 的可选择菜单
Alt + Shift + 左键双击 选择被双击的单词 / 中文句,按住不放,可以同时选择其他单词 / 中文句
Alt + Shift + 前方向键 移动光标所在行向上移动
Alt + Shift + 后方向键 移动光标所在行向下移动
————————————————
Ctrl + Shift + Alt
Ctrl + Shift + Alt + V 无格式黏贴
Ctrl + Shift + Alt + N 前往指定的变量 / 方法
Ctrl + Shift + Alt + S 打开当前项目设置
Ctrl + Shift + Alt + C 复制参考信息
————————————————
其他
F2 跳转到下一个高亮错误 或 警告位置 (必备)
F3 在查找模式下,定位到下一个匹配处
F4 编辑源
F7 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中
F8 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内
F9 在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上
F11 添加书签
F12 回到前一个工具窗口
Tab 缩进
ESC 从工具窗口进入代码文件窗口
连按两次Shift 弹出 Search Everywhere 弹出层
控制语句
IF
if单分支结构
语法结构:
if(布尔表达式){
语句块
}
if-else双分支结构
语法结构:
if(布尔表达式)
{ 语句块 1 }
else
{ 语句块 2 }
if-else if-else 多分支结构
语法结构:
if(布尔表达式 1)
{ 语句块 1; }
else if(布尔表达式 2)
{ 语句块 2; }……
else if(布尔表达式 n)
{ 语句块 n; }
else
{ 语句块 n+1; }
SWITCH结构
switch多分支结构(多值情况)
语法结构:
switch(表达式){
case 值1:
语句块1;
break;
case 值2:
语句块2;
break;
... ... ...
default:
默认语句块;
}
- switch会根据表达式的值从相匹配的case处开始执行,一直执行到break处或者是switch的末尾。如果表达式的值没有与任何一个case值匹配,则执行default语句。
- switch中表达式的值,可以int(byte、short、char)、枚举、字符串(JDK7 新特性)。
public class TestSwitch{public static void main(String[] args){int month = 0;/* if(month==1||month==2||month==3)System.out.println("春季");else if(month==4||month==5||month==6)System.out.println("夏季");else if(month==7||month==8||month==9)System.out.println("秋季");else if(month==10||month==11||month==12)System.out.println("冬季");*/ //用switch实现上述if多分支语句switch(month){case 1:case 2:case 3:System.out.println("春季");break;case 4:case 5:case 6:System.out.println("夏季");break;case 7:case 8:case 9:System.out.println("秋季");break;case 10:case 11:case 12:System.out.println("冬季");break;default:System.out.println("月份信息错误!");}}
}
break和continue
- break用于强制退出整个循环
- continue用于结束本次循环,继续执行下一次循环。
/*薪水计算器,输入月薪和每年的薪资月数,
接下来按任意键可计算出年薪,并打印年薪的值;
若输入exit可以直接退出程序,输入continue可重新加载程序。*/
while(true){System.out.println("请输入您的月薪:");int month_salary = scanner.nextInt(); //从键盘上读取月薪System.out.println("请输入每年的薪资月数:");int months = scanner.nextInt(); //从键盘读取月份数System.out.println("按任意键获得年薪结果--------");System.out.println("输入exit可退出程序---------");System.out.println("输入next可以重新输入--------");//打印提示信息scanner.nextLine();String command = scanner.nextLine(); //获取用户下一步的操作指令switch(command){//用switch实现多分支语句case "exit":break;case "next":continue;default:System.out.println("您的年薪是:"+month_salary*months);}
}
嵌套循环
/*使用嵌套循环打印九九乘法表*/
public class Test{public static void main(String[] args){for(int i=1;i<=9;i++){for(int j=1;j<=i;j++){System.out.print(j+"*"+i+"="j*i+"\t");}System.out.println();}}
}
递归结构
递归的思想:自己调用自己。
递归结构包括两部分:
- 定义递归头 递归头就是递归的结束条件。没有递归头递归将会陷入死循环。
- 递归体 调用自身的方法
//利用递归求阶乘
static long factorial(int n){if(n==1){//递归头return 1;}else{//递归体return n*factorial(n-1);}
}
递归的缺陷:
算法简单是递归的优点。但是递归会调用大量的系统堆栈,导致内存消耗多,在递归层次较多时速度明显比循环慢,所以使用递归需要慎重。
方法
介绍方法前,先讲语句块。语句块就是复合语句,一个语句块需要用**{}**包起来。
语句块内定义的变量是局部变量,只能在块内使用,不能在块外使用。当然,在语句块内也可以使用语句块外的全局变量。
方法:
Java中的方法相当于C语言的函数。
- 方法用于定义该类或该类的实例的行为特征和功能实现。
- 面向过程中,函数是最基本的单位,整个程序由一个个的函数调用组成。
- 面向对象中,类是最基本的单位,方法是从属于类和对象的。
方法的声明和定义也和C语言相同,方法也可以重载,可以参照C语言的规则。
面向对象概念
初识面向对象
引入表格和类的比较
想必我们对表格再熟悉不过了,实际上,**“表格思维”**就是一种典型的面向对象思维。
在本质上,互联网上的数据都是用“表格”实现的,下面以公司雇员为例,下面介绍一下怎么由表格到类的。
ID | 姓名 | 岗位 | 基本工资 | 绩效工资 | 入职日期 |
---|---|---|---|---|---|
1001 | 张三 | 程序员 | 15000 | 6000 | 9/10 |
1002 | 李四 | 销售 | 12000 | 8000 | 8/21 |
1003 | 王五 | 财物 | 12000 | 0 | 11/20 |
1004 | 赵六 | 经理 | 20000 | 10000 | 3/19 |
上面这个雇员表,可以把公司的员工信息**“结构化”,“标准化”**,让管理者可以更方便的进行管理。
我们把表中的列叫做 “字段” ,英文叫 “filed” 。显然,一个表格的结构是有多个field构成的。
在面向对象中,类与表格的结构很相似,我们定义一个 “雇员类” ,类中的属性就是 “字段” ,一个类的实例叫 “对象” ,对应表格中的一行信息。
类的方法和表格中的动作
在现实中,公司中的每个雇员都会集体参加一些动作,这些动作有:
- 开会
- 午休
- 提交工作日志
这些动作对应在类中就是方法。
对象对应表格中的行数据
- 表结构对应:类结构
- 一行数据对应:一个对象
- 表中所有行数据对应:这个类的所有对象
面向过程和面向对象
面向过程和面向对象的区别
面向过程重点关注如何执行,面向过程时,首先思考 “ 怎么按步骤实现?” ,并将步骤对应成方法,按步骤,一步步完成这些方法。
面向对象(Oriented-Object)的思维更契合人的思维模式。首先思考 “ 怎么设计这个事物?” ,因此,面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。 但是,具体到 实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。
面向对象和面向过程思想的总结
- 都是解决问题的思维方式,都是代码组织的方式。
- 面向过程是一种“执行者思维”,解决简单问题可以使用面向过程。
- 面向对象是一种“设计者思维”,解决复杂、需要协作的问题可以使用面向对象。
- 面向对象离不开面向过程:
- 宏观上:通过面向对象进行整体设计
- 微观上:执行和处理数据,仍然是面向过程。
对象和类的详解
类的定义
//每个源文件必须有且只有一个public class,并且类名和文件名保持一致!
public class Car{...
}
//一个java文件可以同时定义多个class,但只能有一个public class
class Tyre{...
}
class Engine{...
}
class Seat{...
}
对一个类来说,有三种成员:
- 属性field
- 方法method
- 构造器constructor
属性(field)
属性用于定义该类的对象包含哪些数据或者静态特征。定义成员变量时可以不必初始化,Java将会用默认值对其初始化。
属性定义格式:
【修饰符】 类型 属性名 【= 初始值】; |
---|
方法(method)
方法用于定义该类的行为特行和功能实现。
方法定义格式:
【修饰符】 方法返回值类型 方法名(形参列表){方法体} |
---|
构造方法(构造器constructor)
构造器用于对象的初始化,而不是创建一个对象!
声明格式:
【修饰符】 类名(【形参列表】){…} |
---|
构造器的四个要点:
- 构造器通过new关键字调用
- 构造器不能定义返回值类型,不能在构造器中使用return语句
- 如果没有手动定义构造器,系统会默认调用一个无参构造器。
- 构造器的方法名就是类名!
面向对象的内存分析
Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area。
栈(stack)
虚拟机栈(简称“栈”)的特点如下:
- 栈描述的是方法执行的内存模型。每个方法被调用后都会在栈中创建一个栈帧(存储局部变量、操作数、方法出口等)。
- JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)。
- 栈属于线程私有,不能实现线程间共享。
- 栈的存储特性是 “先进后出,后进先出” 。
- 栈是由系统自动分配的,速度快,是一段连续的内存空间。
堆(heap)
堆的特点如下:
- 堆用于存储创建好的对象或数组。(数组也是对象)
- JVM只有一个堆,被所有线程共享。
- 堆是不连续的内存空间,分配灵活,速度慢。
- 堆被所有线程共享,在堆上的区域,被划分为新生代、老年代,以方便内存回收。
方法区(method area)
方法区(也是堆)特点如下:
方法区根据JAVA虚拟机的规范,有不同的实现。
JDK7以前是“永久代“
JDK7部分去除“永久代”,静态变量、字符串常量池都挪到了堆内存中
JDK8是“元数据空间”和堆结合起来
JVM只有一个方法区,被所有线程共享。
方法区实际也是堆,用于存储类、常量相关的信息。
存放程序中一些永远不变的信息或唯一的内容。
常量池主要存放常量:如文本字符串、final常量值。
【示例 】编写 Person 类并分析内存
public class Person{String name;int age;public void show(){System.out.println(name);}public static void main(String[] args){//创建p1对象Person p1 = new Person();p1.age = 23;p1.name = "张三";p1.show();//创建p2对象Person p2 = new Person();p2.age = 25;p2.name = "李四";p2.show();Person p3 = p1;Person p4 = p2;p4.age = 80;System.out.println(p1.age);}
}
运行时的内存分配图:
垃圾回收机制(Garbage Collection)
垃圾回收原理
内存管理
Java的内存管理很大程度上就是:堆中对象的管理,包括对象空间的分配和释放。
对象空间的分配:使用new关键字创建对象后,会在堆中分配一块内存空间。
对象空间的释放:将对象赋值null即可。
垃圾回收过程
- 发现无用对象
- 回收内存
当一个对象没有被任何变量引用时,该对象就成了无用对象。Java通过垃圾回收算法来发现并回收无用对象。
垃圾回收算法
引用计数法
堆中的每个对象都对应一个引用计数器,当有引用指向这个对象时,引用计数器的值加1,而当指向该对象的引用失效时,引用计数器的值减1。当引用计数器减为0时,Java的垃圾回收器就认为该对象是无用对象,对其进行回收。
优点是算法简单,缺点是当出现两个对象互相引用时,即出现“循环引用的无用对象”,该算法就无法识别其为无用对象。
引用可达法(根搜索算法)
把所有的引用关系看做一张图,从一个节点 GC ROOT 开始,寻找对应的引用 节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找 完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。
分代回收垃圾机制
分代垃圾回收机制,基于这样一个事实:不同对象的生命周期不一样。因此,不同生命周期的对象可以采用不同的回收算法。将对象分为三种状态:年轻代、年老代、永久代。同时,处于不同状态的对象放到堆中的不同的区域。
包机制(package和import)
package
包(package)相当于文件夹对文件的作用,用于管理类,解决类重名的问题。
package的使用
- 通常是类的第一句
- 包的命名规则:域名倒着写。
导入类import
如果要使用其他包的类,就要导入这个包。在本类中可以通过类名直接调用。
注意
- Java会默认导入java.lang包下的所有类,因此这些类我们可以直接使用。
- 如果导入后出现两个同名的类,则只能用包名加类名来调用。
静态导入
静态导入(static import):其作用是用于导入指定类的静态属性和静态方法,这样我们就可以直接使用这些静态属性和静态方法。
package com.myb;
import static java.lang.Math.*;
import static java.lang.Math.PI;public class Tset{public static void main(String[] args){System.out.println(PI); //直接调用静态属性System.out.print(random()); //直接调用静态方法}
}
继承
继承是面向对象的三大特征之一。
继承主要有两个作用:
- 代码复用,更加容易实现类的扩展。
- 方便建模
继承的实现
关键字extends,字面上的意思是 “扩展” 。所以和C语言不同,Java的继承只能继承一个 “父类” 。
instanceof运算符
instanceof运算符是二元运算符,左边是对象,右边是类。当左边的对象是右边的类或子类所创建的对象时,返回true,否则返回false。
继承使用要点
- Java只有单继承
- Java的类不能多继承,但接口可以
- 子类继承父类,可以得到父类所有的属性和方法,但不见得可以直接访问。
- 如果定义一个类时,没有调用extends,则他的父类的:java.lang.Object
父类和子类的相互转换
在Java中我们可以将子类的引用赋值给父类的对象,这个过程称为 ”向上转型“ ,那么这时子类中那些不是从父类继承过来的成员将不再可见,我们可以再通过强制类型转换将这个父类再转换成子类的类型,这个过程称为 ”向下转型“,那些成员又变得可见了!由此可见,将子类引用赋值给父类对象时,Java虚拟机并没有将那些非继承成员丢弃,例如:
Bus bus = new Bus();
Car car = bus;
System.out.println(car.p);
此时编译将产生错误,在car中p是不可见的。
下面将car强转成Bus类,子类的非继承域又可见了。
Bus bus2 = (Bus)car;
System.out.println(bus2.p);
此时编译不会产生错误,可见子类的非继承域并没有被抛弃。
方法重写override
子类继承父类的方法,可以用自身行为替换父类的行为。重写是实现多态的必要条件。
方法重写需要符合以下三个要点:
- “全等”:方法名和形参列表相同
- ”小于等于“:返回值类型和声明异常类型,子类小于等于父类
- “大于等于”:访问权限,子类大于父类
public class Person{int age;String name;...public Person getFriend(){return new Person();}
}public Student extends Person{int id;double scoure;...@Overridepublic Student getFriend(){return new Student();}//重写方法,返回值从Person变为Student,合法@Overridepublic Object getFriend(){return new Object();}//重写不合法,返回值变成了Object,范围变大
}
final关键字
final关键字的作用:
- 修饰变量:被final修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
final int MAX_SPEED = 120;
MAX_SPEED = 180;//任何试图改变final值都会报错
- 修饰方法:被final修饰的方法不能被子类重写。但可以被重载!
- 修饰类:被final修饰的类不能被继承。比如Math、String类。
组合
除了继承,组合也能实现代码复用。组合的核心是 “将父类的对象作为子类的属性”。
public class Test{public void main(String[] args){Student stu = new Student("张三",180,"计算机");stu.person.rest();stu.study();}class Person{String name;int height;public void rest(){System.out.println("休息!");}}class Stuent{Person person = new Person();//在Student类中定义了一个Person类对象,通过这个对象可以间接拥有它的属性和方法。String major;public Student(String name,int height,String major){this.person.name = name;this.person.height = height;this.major = majior;this.person.rest(); }public void study(){System.out.orintln("学习");}}
}
继承只能有一个父类,而组合比较灵活,可以定义多个外类的属性,这样相当于继承了多个父类。
对于“is-a"关系,建议用继承,”has-a"关系,建议用组合。
封装
程序设计追求“高内聚,低耦合”。高内聚就是类内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。
封装的实现——使用访问控制符
Java是使用“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的。
Java中4中访问控制符分别为:private、default、protected、public。
- public修饰的类可以被任何类访问
- protected修饰的类可以被同一个包内的类和子类访问
- 如果没有访问控制符修饰,默认为default修饰,此时的类只能被所在包的类访问
- private修饰的类只能在类内访问。
注意:关于protected的两个细节
- 若父类和子类在一个包内,则子类可以访问父类的protected成员,也可以访问父类对象的protected成员。
- 若父类和子类不在一个包中,则子类只能访问父类的protected成员,不能访问父类对象的protected成员。
封装的一般规则:
- 属性一般使用private访问权限
- 属性私有后,可以提供相应的get/set方法来访问和修改相关的私有属性,这些方法通常是public修饰的,以提供对属性的读写操作。(boolean属性的get方法命名要以is开头)
- 方法:一些只用于本类的方法可以有private修饰,希望被其他类调用的方法可以用public修饰。
多态
多态是指方法的多态,不是属性的多态。
多态的实现:继承,方法重写,父类引用指向子类的对象。
父类引用子类的对象时,该父类引用会调用子类重写的方法,这样多态就实现了。
package com.myb.test;abstract class Animal{abstract String shout();
}class Dog extends Animal{@OverrideString shout() {return "汪汪汪";}
}class Cat extends Animal{@OverrideString shout() {return "喵喵喵";}
}class Sheep extends Animal{@OverrideString shout() {return "咩咩咩";}
}public class Test2 {public static void main(String[] args) {Dog dog = new Dog();System.out.println(dog.shout());Cat cat = new Cat();System.out.println(cat.shout());Sheep sheep = new Sheep();System.out.println(sheep.shout());}
}
Object类详解
Object类基本特性
Object类是所以类的父类,所有Java对象都拥有Object类的属性和方法。
toString()方法
Object类中定义有public String tiString()方法,其返回值是String类型。其源码为:
public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
根据源码得知,默认返回的是“类名+@+16进制的hashcode”。在打印输出对象时或用字符串连接对象时,会自动调用该对象的toString()方法。
在类中重写toString()方法
class Person{int age;String name;public String toString(){return name+"年龄: "+age;}
}
“==”和equals比较
“==” 代表比较双方是否相同。如果是基本数据类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
euqals()用于比较两个对象,默认比较的是两个对象的hashcode。但可以根据自己的要求重写equals方法。
继承数追溯
super关键字
调用父类中的某一个构造函数,引用格式如下:
super(实参);
通过super来访问父类中被子类覆盖的方法或属性。
super.方法名/属性名
在子类构造函数中,如果我们不显式地调用super()完成父类的构造,系统会自动调用父类的构造函数,但有时会存在一些问题。
如果我们自定义了父类的构造函数,那么系统提供我们了不带参数的默认构造函数将会被收回,这时在子类定义构造函数时,我们必须显式指定super(),否则系统自动调用的super()会去找那个已经被回收的构造函数,编译器就会报错!
class Person{int age;String name;Person(int age,String name){this.age = age;this.name = name;}/**系统默认构造函数,当用户自定义构造函数后就会被系统收回。Person(){}*/
}class Student extends Person{int id;Student(int id){super(int age,String name)//如果不显式调用super(),编译器会报错!this.id = id;}Student(int age,String name,int id){super(age,name);//如果不显式调用super(),编译器会报错!this.id = id;}Student(int age,String name,int id){this.age = age;this.name = name;this.id = id;}//想让编译器不报错可以在父类添加默认构造函数Person(){}
}
抽象类
抽象方法
使用abstract修饰的方法,没有方法体,只有声明。
这种定义方法就是一种 “规范”,告诉子类必须要给抽象方法提供具体的实现。
抽象类
包含抽象方法的类就是抽象类
通过抽象类,我们就可以严格限制子类的设计,使子类之间更加通用。
abstract class Animal{abstract public void shout();
}
class Dog extends Animal{public void shout(){System.out.println("汪汪汪");}
}
class Cat extends Animal{public void shout(){System.out.println("汪汪汪");}
}
class Dog extends Animal{public void shout(){System.out.println("汪汪汪");}
}
注意:
- 有抽象方法的类必须定义为抽象类
- 抽象类不能实例化,不能用new来创建对象
- 抽象类可以包含属性、方法和构造方法,可以被子类调用。
- 抽象类只能被继承
- 抽象方法必须被子类实现
接口interface
为什么需要接口?接口和抽象类的区别?
接口就是比 ”抽象类“ 还抽象的 ”抽象类“ ,可以更加规范的对子类进行约束。全面实现了:规范和具体实现的分离
把一个接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。
一个接口和实现的类不是父子关系,而是实现规则的关系,一个类如果声明一个接口,那么这个类必须严格按照该接口的规则来实现。
声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2...]{
常量定义;
方法定义;
}
定义接口的说明:
- 访问修饰符:只能是public或默认。
- 接口名:和类名采用相同的命名机制。
- extends:接口可以多继承。
- 常量:接口中的属性只能是常量,总是public static final修饰,可以不写。
- 方法:接口中的方法只能是public abstract,也可以不写。
- 子类:子类通过implements来实现接口中的规范
要点:
- 接口不能创建实例,这点和抽象类相同
- 一个类实现了接口,就必须实现接口中所有的方法,并且这些方法只能是public的。
- 接口中可以包含普通的静态方法、默认方法。(JDK1.8后)
接口的多继承
接口支持多继承,一个接口可以继承多个父接口。
interface A{void testa();
}interface B{void testb();
}interface C extends A,B{void testc();
}public class Test3 {public void testc(){}public void testb(){}public void testa(){}
}
字符串String类
String类又称不可变字符序列
String位于java.lang包中,Java程序默认导入java.lang包下的所有类
Java字符串就是Unicode字符序列,例如“Java”就是4个Unicode字符 ‘J’、’a‘、’v’、‘a’组成的
Java没有内置字符串类型,而是在标准Java库中提供了一个预定义的类String,每个用双引号括起来的字符串都是String类的一个实例
String e = ""; //空字符串
String greeting = "hello!";
//e和greeting都是String类的两个实例对像
“+” 连接符
用于连接两个String类型的对象或者一个String类型和其他类型的对象或常量。
String类和常量池
每各class都有一个运行时的常量池
String g1 = "123";
String g2 = "123";
String g3 = new String("123");
//比较g1、g2、g3是否相等
System.out.println(g1==g2);//true
System.out.println(g1==g3);//false
System.out.println(g1.equals(g3));//true
上述示例说明字符串“123”首次被创建后会存到常量池中,第二次可以直接引用。
String类常用方法:
- char charAt(int index);返回指定索引处的char值
- int compareTo(Object o);把一个字符串和另一个字符串比较
- String concat(String str);将指定字符串连接到此字符串的结尾
- boolean endsWith(String suffix);测试此字符串是否以指定字符后缀结束
- boolean equalsIgnoreCase(String str);将此字符串与另一字符串比较,不考虑大小写
- byte[] getBytes();使用平台默认字符集将此字符串编码成byte,存储到一个新的byte数组中
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);将此字符串的部分字符复制到指定数组中,从指定数组的desBegin索引处开始存储。
- int indexOf(int ch);返回此字符在字符串中第一次出现的位置
- int indexOf(String str);返回此子字符串在字符串中第一次出现的位置
- int length();返回此字符串的长度
- String replace(char oldChar,char newChar);返回一个新的字符串,
内部类
把一个类放在另一个类的内部定义,成为内部类。
- 内部类只能让外部类访问,不允许同一个包中的其他类访问。
- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员 。但外部类不能访问内部类的内部属性。
非静态内部类
内部类的访问:
- 外部类中定义内部类:new Inner()
- 外部类以外的地方使用非静态类内部类:Outer.Inner varname = new Outer().new Inner()
静态内部类
定义方式:
static class Inner{
``
}
- 静态内部类只能访问外部类的静态成员。
- 静态内部类看做外部类的一个静态成员。
匿名内部类
适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中最常见。
构造方法:
new 父类构造器(实参列表)/实现接口(){
``
}
- 匿名内部类没有访问修饰符
- 匿名内部类没有构造方法。它连名字都没有何谈构造方法。
数组
数组的概念
数组的定义
数组是相同类型数据的有序集合。
数组的四个特点:长度确定、类型相同、任意类型、引用类型
数组的声明方式
类型[] arr_name;
或
类型 arr_name[];
声明的时候没有实例化对象,声明数组的时候并没有数组真正被创建。
构造一个数组必须指定其长度。
数组的初始化
静态初始化
除了用new关键字来产生数组外,还可以直接在定义数组的时候就为数组元素分配空间并赋值
int[] a = {1,2,3};
Man[] man = {new Man(1,1),new Man(2,2)};
动态初始化
数组定义与为数组分配空间并赋值分开进行
int[] a1 = new int[2];
a1[0] = 1;
a1[1] = 2;
数组的默认初始化
数组是对象,它的元素相当于对象的属性;每个元素也可以按照对象属性的初始化来进行默认初始化。
int[] a2 = new int[2];//默认值为:0,0
Boolean[] b = new Boolean[2];//默认值为:false,false
String[] s = new String[2];//默认值为:null,null
数组常见操作
数组的遍历
通过数组元素下标来遍历数组中的元素
f-each循环(增强for循环)
for-each专门用于读取数组或容器中所有的元素
定义格式:
for(类型 实例对象 :数组对象){}
String[] ss = {"aa","bb","cc"};
for(String s:ss){...
}
缺点:只能遍历不能修改元素的值。
数组的拷贝
System.arraycopy(arr1,x1,arr2,x2,length);
x1:源数组开始拷贝的位置 x2:目的数组开始存储的位置
java.util.Arrays类
Array类包含了:排序、查找、填充、打印等常见数组操作。
- 用**toString()**方法打印数组元素的值,该方法在Arrays类里是静态方法。
import java.util.Arrays;
public class Test{public static void main(Stringp[] args){int a[] = {1,2};System.out.println(a);//打印数组引用的值System.out.println(Arrays.toString(a));//打印数组元素的值}
}
执行结果为:
[I@15db9742]
[1,2]
用**Arrays.sort()**对数组元素进行排序
用**Arrays.binarySearch()**对有序数组进行二分查找
用**Arrays.fill()**对数组进行填充
多维数组
多维数组可以看出元素是数组的数组。
二维数组的声明:
int[][] a = new int[x][];
其中用new申请数组空间时,需要指明二维数组的行数,但不必指明二维数组的列数!
二维数组的静态初始化:
int[][] a = {{1,2,3},{4,5},{1,3,6}};
二维数组的动态初始化:
int[][] a = new int[3][];
a[0] = {1,2,3};//错误!没有声明类型
a[0] = new int[]{1,2};
a[1] = new int[]{2,3};
a[2] = new int[]{1,4,5,6}
用二维数组存储表格数据
观察表格,每行可以用一个一维数组存储,然后把每个一维数组当做对象存储到另一个数组中,构成二维数组。
Object[ ] a1 = {1001,"高淇",18,"讲师","2-14"};
Object[ ] a2 = {1002,"高小七",19,"助教","10-10"};
Object[ ] a3 = {1003,"高小琴",20,"班主任","5-5"};
Object[ ][ ] emps = new Object[3][ ];
emps[0] = a1;
emps[1] = a2;
emps[2] = a3;
用javabean和一维数组存储表格数据
利用java封装特性实现表格类,把表格类的对象存到一维数组中。
public static void main(String[] args) {Emp[] emps = new Emp[3];emps[0] = new Emp(1001,"高淇",21,"讲师","2-14");emps[1] = new Emp(1002,"高小七",19,"助教","10-10");emps[2] = new Emp(1003,"高小八",17,"班主任","5-5");
}class Emp{private int id;private String name;private int age;private String job;private String hireDate;public Emp(int id, String name, int age, String job, String hireDate) {this.id = id;this.name = name;this.age = age;this.job = job;this.hireDate = hireDate;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getJob() {return job;}public void setJob(String job) {this.job = job;}public String getHireDate() {return hireDate;}public void setHireDate(String hireDate) {this.hireDate = hireDate;}
}
Comparable接口
Comparable接口只有一个方法:
public int compareTo(Object obj)
obj是要比较的对象
Comparable接口就是用来定义排序规则的。
当对象与obj这个对象比较,如果大于返回1,小于返回-1,等于返回0(此处的1可以是正整数,-1可以是负整数)。
compareTo方法的代码比较固定:
public int compareTo(Object o){Emp e = (Emp)o;if(this.age<o.age){return -1;}if(this.age>o.age){return 1;}return 0;
}//此方法实现了两个表格类对象比较大小的规则,自定义的比较规则是按照年龄的大小。
常用类
基本数据类型的包装类
为了将基本数据类型和对象之间实现相互转化,Java为每个基本数据提供了相应的包装类。
Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这八个基本数据类型对应的类统称为“包装类”。
包装类
包装类位于java.lang包中,八种包装类和基本数据类型的对应关系:
基本数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
包装类创建对象的方式跟其他类一样
Integer num1 = new Integer(0);//手动创建对象,现实情况不需要
Integer num2 = Integer.valueOf(1);//手动装箱,现实情况不需要
包装类的转换机制:
Integer num1 = new Integer(1);//基本数字类型向包装类转换
int num2 = num1.intValue();//包装类向基本数据类型转换
数字型包装类继承了Number类,Number是抽象类,它的抽象方法所有包装类都提供了实现。Number类中的抽象方法有:intValue()、longValue()、floatValue()、doubleValue(),意味着数字型包装类都可以互相转型。
自动装箱、自动拆箱机制
Java为了方便我们使用,以及出于其他目的如性能调优,给我们提供了自动装箱、拆箱机制。这种机制简化了基本类型和包装类型的转换。
Integer num1 = 1;//自动装箱
int num2 = num1;//自动拆箱
可见,java编译器帮我们完成了转换操作。
另外,使用new关键字和valueOf()方法创建对象是有区别的。
new关键字和valueOf()
Integer num3 = 10;
Integer num4 = 10;
Integer num5 = new Integer(20);
Integer num6 = new Integer(20);
Integer num7 = 128;
Integer num8 = 128;
System.out.println(num3==num4)+" "+num3.equals(num4);
System.out.println(num5==num6)+" "+num5.equals(num6);
System.out.println(num7==num8)+" "+num7.equals(num8);
运行结果为:
true true
false true
false true
我们看下它的反编译代码:
Integer integer = Integer.valueOf(10);
Integer integer1 = Integer.valueOf(10);
Integer integer2 = new Integer(20);
Integer integer3 = new Integer(20);
Integer integer4 = Integer.valueOf(128);
Integer integer5 = Integer.valueOf(128);
System.out.println((new StringBuilder()).append(integer == integer1).append("\t").append(integer.equals(integer1)).toString());
System.out.println((new StringBuilder()).append(integer2 == integer3).append("\t").append(integer2.equals(integer3)).toString());
System.out.println((new StringBuilder()).append(integer4 == integer5).append("\t").append(integer4.equals(integer5)).toString());
首先,我们查看Integer的valueOf()方法的源码
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
再查看Integer的内部类IntegerCache的cache数组成员:low、high成员
static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}
可以发现,只要Integer类第一次被使用到,Integer的静态内部类就会被加载,加载的时候会创建-128到127的Integer对象,同时创建一个cache数组来缓存这些对象。当使用valueOf()方法创建对象时,就直接返回已缓存的对象,也就是说不会再创建新的对象(前提是创建的值合法);当使用new关键字创建对象或者用valueOf()方法创建小于-127大于127的对象时,就会创建一个新的对象。
这时候就能理解只有num3==num4的值是true,其他两个的值都是false
接着,我们再看看源码中Integer类的equals()方法的实现
public boolean equals(Object obj) {if (obj instanceof Integer) {return value == ((Integer)obj).intValue();}return false;}
可见,equals()方法比较的是Integer对象的值,并不关心是否属于同一对象。
所以上述三次调用equals()返回值都是true
在8种包装类中,有缓存区的有Character、Byte、Short、Integer、Long,都是-128到127的缓存范围。
为什么需要包装类?
为什么需要包装类?有了包装类为什么还要保留基本数据类型?
首先,java语言是一个面向对象的语言,但java中的基本数据类型不是面向对象的,将每个基本数据类型设计一个对应的类进行代表,这种方式增强了java面向对象的性质。
其次,如果仅仅有基本数据类型,那么在使用的时候存在很多不便,很多地方需要使用对象而不是基本数据类型。比如,在集合类中我们需要的元素类Object类型,无法将int、double等类型放进去。而集合类的存在使得向集合中传入数值成为可能。包装类弥补了基本数据类型的不足。
此外,包装类还为基本数据类添加了属性和方法,丰富了基本数据类型的操作。如当我们想知道int的取值范围的时候,我们需要进行运算,但是有了包装类,我们可以直接使用Integer.MAX_VALUE即可。
//求int的最大值
int max = 0;
int flag = 1;
for (int i=0; i<31; i++) {max += flag;flag = flag << 1;
}
System.out.println(max +" "+ Integer.MAX_VALUE); //2147483647 2147483647
为什么要保留基本数据类型?
我们知道在Java语言中,用new关键字创建的对象是存储在堆区中,我们通过栈中的引用来使用这些对象,所以对象本身是很消耗资源的。如果我们常用的基本数据类型也封装成对象,在大量使用的时候很容易浪费大量资源,这就是java保留基本数据类型的原因。
字符串相关类
StringBuffer和StringBuilder
StringBuffer和StringBuilder都是可变字符序列。
- StringBuffer 线程安全,做线程同步检查,效率较低。
- StringBuilder 线程不安全,不做线程同步检查,因此效率高,建议采用该类。
常用方法列表:
重载的public StringBuilder append(…)方法
为该字符串添加字符序列,仍然返回自身对象。
public StringBuilder delete(int start,int end)
删除从start开始到end-1结束的字符序列,仍然返回自身对象。
public StringBuilder deleteCharAt(int index)
移除此序列指定位置的字符,仍然返回自身对象。
重载的public StringBuilder insert()
在指定位置插入指定字符(串)序列,仍然返回自身对象。
public String toString()
返回此序列中数据的字符串表示形式
和String类相似的方法
public int indexOf(String str)
public int indexOf(String str,int fromIndex)
public String substring(int start)
public String substring(int start,int end)
public int length()
char charAt(int index)
不可变和可变字符序列使用陷阱
String的使用陷阱
String已经初始化后,就不会再改变其内容了。对String字符串的操作实际上是对其副本的操作,原来的字符串没有改变。比如:
String s = “a”;
s = s + “b” ;
此时会产生一个新的s,实际上就是"a+b",原来的 s = “a” 被忽略但仍然留存在内存中。如果多次执行这些改变字符串的操作,会导致大量副本字符串对象被留存在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的时间和空间性能。
相反,StringBuffer和StringBuilder类是对原字符串本身操作,不会产生副本,因此可以提高效率。
时间相关类
时间是一维的,我们可以用一把刻度尺来表示和度量时间,在计算机中,我们把1970年1月1日00:00:00定为基准时间,每个度量单位是毫秒。
我们用long类型的变量来表示时间,long类型能表示的时间范围是从基准时间前后几亿年,所以完全足够用。
Date时间类(java.util.Date)
在标准java类库中包含了一个Date类。它的对象表示一个特定的瞬间,精确到毫秒。
Date()分配一个Date对象,并初始化此对象为当前的日期和时间,可以精确到毫秒。
Date(long date)分配Date对象并初始化,表示从基准时间到当前时间以来的毫秒数。
boolean equals(Object o)比较两个日期的想等性。
long getTime()返回当前时间的毫秒数
String tostring()把此Date对象转换为以下形式的String:
dow mon dd hh:mm:ss zzz yyyy 其中:dow 是一周中的某一天。
Date类的使用:
Date d = new Date();
System.out.println(d.getTime());
Date d2 = new Date(1000L*3600*24*365*100);//距离1970年100年的时间
System.out.println(d2);
DateFormat类和SimpleDateFormat类
DateFormat类:把时间对象转化为指定格式的字符串。反之,把指定格式的字符串转化为时间对象。
DateFormat是抽象类,一般使用它的子类SimpleDateFormat类来实现。
//new出SimpleDateFormat对象
SimpleDateFormat s1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") ;
SimpleDateFormat s2 = new SimpleDateFormat("yyyy-MM-dd") ;
//将时间对象转换为字符串格式的时间
String daytime = s1.format(d);
System.out.println(daytime);
System.out.println(s2.format(new Date()));
//将指定格式的字符串转化为时间对象,字符串格式需要和指定格式一致
String time = "2049-10-1";
Date date = s2.parse(time);
System.out.println("date1: "+date);
time = "2049-10-1 20:15:30";
date = s1.parse(time);
System.out.println("date2: "+date);
格式化字符的具体含义:
字母 | 日期或时间元素 | 表示 | 示例 |
---|---|---|---|
G | Era标志符 | Text | AD |
y | 年 | Year | 1996,96 |
M | 月份 | Month | July;Jul;07 |
w | 年中的周数 | Number | 27 |
W | 月中的周数 | Number | 2 |
D | 年中的天数 | Number | 189 |
d | 月中的天数 | Number | 10 |
F | 月份中的星期 | Number | 2 |
E | 星期中的天数 | Text | Tuesday;Tue |
a | Am/pm | Text | PM |
H | 一天中的小时数(0-23) | Number | 0 |
k | 一天中的小时数(1-24) | Number | 24 |
K | am/pm 中的小时数(0-11) | Number | 0 |
h | am/pm 中的小时数(1-12) | Number | 12 |
m | 小时中的分钟数 | Number | 30 |
s | 分钟中的秒数 | Number | 55 |
S | 毫秒数 | Number | 978 |
z | 时区 | General time zone | PST; GMT-08:00 |
Z | 时区 | RFC 822 time zone | 0800 |
时间格式化类为我们提供了很方便的获得不同时间的方法。比如:获取今天是今年的第几天:
SimpleDateFormat s1 = new SimpleDateFormat("D");
String daytime = s1.format(new Date());
System.out.println(daytime);
Calendar日历类
Calendar类是一个抽象类,为我们提供了关于日期计算的功能,比如:年、月、日、时、分、秒的展示和计算。
GregorianCalendar是Calendar的子类,表示公历。
注意月份的表示,一月是 0,二月是 1,以此类推,12 月是 11。
// 得到相关日期元素
GregorianCalendar calendar = new GregorianCalendar(2049, 9, 1, 22, 10, 50);
int year = calendar.get(Calendar.YEAR); // 打印:2049
int month = calendar.get(Calendar.MONTH); // 打印:9
int day = calendar.get(Calendar.DAY_OF_MONTH); // 打印:1
int day2 = calendar.get(Calendar.DATE); // 打印:1
// 日:Calendar.DATE 和 Calendar.DAY_OF_MONTH 同义
int date = calendar.get(Calendar.DAY_OF_WEEK); // 打印:1
// 星期几 这里是:1-7.周日是 1,周一是 2,。。。周六是 7
System.out.println(year);
System.out.println(month);
System.out.println(day);
System.out.println(day2);
System.out.println(date);
// 设置日期
GregorianCalendar calendar2 = new GregorianCalendar();
calendar2.set(Calendar.YEAR, 2049);
calendar2.set(Calendar.MONTH, Calendar.OCTOBER); // 月份数:0-11
calendar2.set(Calendar.DATE, 1);
calendar2.set(Calendar.HOUR_OF_DAY, 10);
calendar2.set(Calendar.MINUTE, 20);
calendar2.set(Calendar.SECOND, 23);
printCalendar(calendar2);
// 日期计算
GregorianCalendar calendar3 = new GregorianCalendar(2049, 9, 1, 22, 10, 50);
calendar3.add(Calendar.MONTH, -7); // 月份减 7
calendar3.add(Calendar.DATE, 7); // 增加 7 天
printCalendar(calendar3);
// 日历对象和时间对象转化
Date d = calendar3.getTime();
GregorianCalendar calendar4 = new GregorianCalendar();
calendar4.setTime(new Date());
}
static void printCalendar(Calendar calendar) {int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int date = calendar.get(Calendar.DAY_OF_WEEK) - 1; // 星期几
String week = "" + ((date == 0) ? "日" : date);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
System.out.printf("%d 年%d 月%d 日,星期%s %d:%d:%d\n", year, month, day, week, hour, minute, second);
其他常用类
异常机制
软件程序在运行过程中,可能会遇到一些异常,例如打开文件是文件不存在或者格式不对、程序运行时内存满了等等,我们把这些异常成为:exception,所以又叫例外。
异常机制是为了让程序遇到异常时做出合理的处理,并安全的退出,而不至于程序崩溃。
试想,如果没有异常机制,我们设计程序时必须事先考虑到所有可能出现的意外情况,这时候会用到大量判断语句,造成代码冗长,可读性差。
异常(Exception)的概念
异常是指程序运行过程中出现的非正常现象,例如除数为0、需要处理的文件不存在、数组下标越界等。
在Java中的异常处理机制中,引进了很多用来描述和处理异常的类,成为异常类。异常类中定义了异常信息和对异常的处理方法。
Java采用面向对象的方式来处理异常。处理过程:
- **抛出异常:**在执行一个方法时,如果发生了异常,则这个方法生成代表该异常的一个对象,停止当前执行路经,并把异常提交给JRE。
- **捕获异常:**JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
异常分类
Java中定义了很多异常类,这些类对应了各种各样可能出现的异常事件,所有异常对象都是派生于Throwable类的一个实例。如果内置的异常类不能满足需要,就需要自己创建自定义异常类来解决实际问题。
java对异常类进行了分类,不同类型的异常分别用不同的java类表示,所有异常的根类为:java.lang.Throwable,Throwable下面有派生了两个子类:Error和Exception。Java异常类的层次结构如图所示:
Error
Error是程序无法处理的错误,表示运行应用程序出现较严重的问题。大多数错误与代码编 写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java 虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源 时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机一般会选择线程终止。
Error声明系统JVM已经处于不可恢复的崩溃状态中。
Error的直接子类:
Error与Exception的区别
- 车子在路上开着,前面堵车了,需要停车。这叫一个异常。
- 车子在路上开着,突然抛锚了,车子被迫停下了。这叫错误。
Exception
Exception是程序本身能够处理的异常。
Exception类是所有异常类的父类。通常的Java异常可分为:
- RuntimeException 运行时异常
- CheckedException 已检查异常
RuntimeException
派生于RuntimeException的异常,如被0除、数组下标越界、空指针异常等。为避免这些异常,通常需要增加逻辑处理来避免这些异常。
【示例】NullPointerException 异常
public class Test4 {public static void main(String[ ] args) {String str=null;System.out.println(str.charAt(0));}
}
执行结果如图所示:
解决空指针异常,通常是增加非空判断:
public class Test4 {public static void main(String[ ] args) {String str=null;if(str!=null){System.out.println(str.charAt(0));}}
}
【示例】ClassCastException 异常
Animal a = new Dog();
Cat c = (Cat)a;
执行结果如图所示:
错误原因:不能将狗类强转成猫类。
解决ClassCastException的典型方式:
Animal a = new Dog();
if(a instanceof Cat){Cat c = (Cat)a;
}
【示例】NumberFormatException 异常
数字格式化异常的解决,可以引入正则表达式判断是否为数字:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test7 {public static void main(String[ ] args) {String str = "1234abcf";Pattern p = Pattern.compile("^\\d+$");Matcher m = p.matcher(str);if (m.matches()) { // 如果 str 匹配代表数字的正则表达式,才会转换System.out.println(Integer.parseInt(str));}}
}
CheckedException
已检查异常是指在编译时就必须处理,否则无法通过编译。
CheckedException的处理方式:
- 使用 “try/catch” 捕获异常
- 使用 “throws” 声明异常
捕获异常
try/catch语句用于处理异常,这些异常通常是程序员造成的编码错误或错别字,也可能是语言中缺少的功能,以及一些语法错误。
如果没有try/catch的话,就有可能出现程序崩溃,而try/catch则可以保证程序的正常运行。
例如:当除数出现0时,编译器不会报错,如果没有try/catch的话,程序直接崩溃。用try/catch可以跳过该异常,让程序继续执行下去,并且输出异常信息。
try语句包括的代码是异常捕获并处理的范围,在执行过程中,只要try语句中的代码出现异常,就会跳过后面的代码。异常代码会产生并抛出一种或几种类型的异常对象,它后面的catch语句会对这些异常做出相应的处理。
一个try语句后面必须带有至少一个catch语句或一个finally语句块。
finally语句:
- 不管是否发生异常,都要执行。
- 通常在finally中挂壁已打开的资源。
try-catch-finally 语句块的执行过程详细分析:
程序首先执行可能发生异常的 try 语句块。如果 try 语句没有出现异常则执行完后跳至 finally 语句块执行;如果 try 语句出现异常,则中断执行并根据发生的异常类型跳至相应的 catch 语句块执行处理。catch 语句块可以有多个,分别捕获不同类型的异常。catch 语句 块执行完后程序会继续执行 finally 语句块。finally 语句是可选的,如果有的话,则不管是 否发生异常,finally 语句都会被执行。
在IDEA 中,使用:ctrl+alt+t 快捷键自动增加try-catch代码块。
throws(声明异常)
- CheckedException产生时,不一定要立刻处理它,可以把异常throws,由调用者处理。
- 一个方法抛出多个已检查异常,就必须在方法首部列出所有异常。
【示例】异常处理的典型代码(声明异常抛出 throws)
package com.bjsxt;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;
public class Test9 {public static void main(String[ ] args) {try {readFile("joke.txt");} catch (FileNotFoundException e) {System.out.println("所需文件不存在!");} catch (IOException e) {System.out.println("文件读写错误!");}}public static void readFile(String fileName) throwsFileNotFoundException, IOException {FileReader in = new FileReader(fileName);int tem = 0;try {tem = in.read();while (tem != -1) {System.out.print((char) tem);tem = in.read();}} finally {if(in!=null) {in.close();}}}
}
注意:
方法重写中声明异常原则:子类重写父类方法时,如果父类方法有声明异常,那么子类 声明的异常范围不能超过父类声明的范围。
try-with-resource 自动关闭 AutoClosable 接口的资源
JAVA 中,JVM 的垃圾回收机制可以对内部资源实现自动回收,给开发者带 来了极大的便利。但是 JVM 对外部资源(调用了底层操作系统的资源)的引用却 无法自动回收,例如数据库连接,网络连接以及输入输出 IO 流等。这些连接就 需要我们手动去关闭,不然会导致外部资源泄露,连接池溢出以及文件被异常占 用等。 JDK7 之后,新增了“try-with-resource”。它可以自动关闭实现了 AutoClosable 接口的类,实现类需要实现 close()方法。”try-with-resources 声明”,将 try-catch-finally 简化为 try-catch,这其实是一种语法糖,在编 译时仍然会进行转化为 try-catch-finally 语句。
自定义异常
在现实中我们难免会遇到各种异常,有些异常是标准异常类无法解决的,这时候就需要我们自定义异常类。
自定义异常类只需从Exception类或者它的子类派生一个子类即可。
自定义异常如果继承Exception类,则为CheckedException异常,必须对其进行处理;如果不想处理,则必须让自定义异常类继承运行时异常RunTimeException类。
习惯上,自定义异常类应该包含两个构造器,一个是默认构造器,另一个是带有详细信息的构造器。
【示例】自定义异常类
/**IllegalAgeException:非法年龄异常,继承 Exception 类*/
public class IllegalAgeException extends Exception {//默认构造器public IllegalAgeException() {}//带有详细信息的构造器,信息存储在 message 中public IllegalAgeException(String message) {super(message);}
}
【示例】自定义异常类的使用
class Person {private String name;private int age;public void setName(String name) {this.name = name;}public void setAge(int age) throws IllegalAgeException {if (age < 0) {throw new IllegalAgeException("人的年龄不应该为负数");}this.age = age;}public String toString() {return "name is " + name + " and age is " + age;}
}
public class TestMyException {public static void main(String[ ] args) {Person p = new Person();try {p.setName("Lincoln");p.setAge(-1);} catch (IllegalAgeException e) {e.printStackTrace();}System.out.println(p);}
}
执行结果:
【JAVA基础】初学者指南--两万字知识点总结--零基础,超详细 。相关推荐
- 两万字深度讲解系统设计!超详细解析!面试复习必备!
Table of Contents generated with DocToc 三高 高并发 高性能 高可用 网站统计IP PV UV实现原理 如何进行系统拆分? 场景题:设计判断论文抄袭的系统 设计 ...
- 《C语言编程——零基础初学者指南(第3版)》一第1章 什么是C程序设计1.1 什么是程序...
本节书摘来自异步社区<C语言编程--零基础初学者指南(第3版)>一书中的第1章,第1.1节,作者 [美]Greg Perry , Dean Miller,更多章节内容可以访问云栖社区&qu ...
- 呕心沥血 JavaScript知识点梳理大全,超详细 建议收藏!!!
呕心沥血 JavaScript知识点梳理大全,超详细 建议收藏!!! ✴️大家好,我是王同学,爆肝三天三夜王同学把JavaScript 知识点梳理了一遍,文章没有一点套路,只有满满的干货 ✴️如果对你 ...
- 下标索引必须为正整数类型或逻辑类型_python量化基础 | 变量和简单的数据类型,零基础都可以看懂...
编辑 | Cowboy 校对 | 李明 来源 | 牛角财经 目的 | python量化基础 | 变量和简单的数据类型,零基础都可以看懂!!! python教程 从入门到高级(免费) 特点:案例基于金融 ...
- 保姆级教程 CSS 知识点梳理大全,超详细!!!
保姆级教程 CSS 知识点梳理大全,超详细!!! ✴️大家好,我是王同学,好久不见,趁着假期王同学把CSS 知识点梳理了一遍 ✴️如果对你有帮助就给我点个赞吧,这样我们就互不相欠了 ✴️星光不负赶路人 ...
- 学ps要计算机基础吗,零基础怎样学会PS?电脑0零基础绘画
原标题:零基础怎样学会PS?电脑0零基础绘画 轻微课来源:轻微课APP(一个专门学画画的人气平台) 零基础怎样学会PS?电脑0零基础绘画!在学习PS电脑绘画的过程中,您需要逐步学习什么? 今天,对于P ...
- 0基础能学漫画么?漫画零基础入门教程!
漫画零基础入门教程!很多人都喜欢看动漫,同时也会幻想成为动漫里的主角,与此同时也会诞生学漫画的想法.不论是你真的想学习漫画,又或出于个人爱好,或职业需要,或为了具备一项自己喜欢的看家本领.我们都要先清 ...
- 大数据基础学习三:Ubuntu下安装VMware Tools超详细步骤及需要注意的问题(以ubuntu-18.04.3、Mware Workstation 15.1.0 Pro为例)
大数据基础学习三:Ubuntu下安装VMware Tools超详细步骤及需要注意的问题 (以ubuntu-18.04.3.Mware Workstation 15.1.0 Pro for Window ...
- java算法竞赛必备之快读快写(超详细解读)
java算法竞赛必备之快读快写(超详细解读) java写算法的缺点:速度慢.读写复杂.莫名WA(错误答案).TL(超时).CL(超内存)- (那我们还学个啥啊,都转c++写算法不香嘛.)别急别急,有缺 ...
最新文章
- fatal error LNK1169: 找到一个或多个多重定义的符号
- 脑科学与脑电基础知识汇总
- 算法设计与分析——回溯法——旅行售货员问题
- 【多线程】:Synchronized和ReentrantLock的对比
- 模板方法模式(Template Method Pattern)
- 标点符号/特殊符号的英文名称
- Django 国际化和本地化
- 网页前端培训笔记(JavaScript事件)
- linux文件目录加密,适用于Linux的10款最佳文件和磁盘加密工具
- Android模仿微信浮窗功能的效果实现
- 华为外包员工是什么样的群体?
- DNA测序也有批次效应?
- 密码学入门(3):分组密码的模式
- 汤姆斯的天堂梦(par)
- 和菜头:放开那些员工
- 语法体系:揭秘同位语从句day9
- 线上频繁GC怎么处理
- 用 Wireshark 让你看见 TCP 到底是什么样!
- 宽屏透明html5产品展示模板
- 特殊矩阵的压缩存储(对称矩阵,三角矩阵,对角矩阵,稀疏矩阵的顺序,链序存储,十字链表的建立)