目录
1 初始Java
JDK,JRE,JVM
Java 代码书写
注释
标识符
关键字
标识符:在程序中由用户给类名、方法名或 者变量所取的名字
标识符中可以包含:字母、数字以及 下划线和 $ 符号等等
注意:标识符不能以数字开头,也不能是关键字,且严格区分大小写
类名:每个单词的首字母大写(大驼峰)
方法名:首字母小写,后面每个单词的首字母大写(小驼峰)
变量名:与方法名规则相同
关键字:由 Java 语言提前定义好的,有特殊含义的标识符,或者保留字
2 数据类型与变量
字面常量
变量
数据类型
类型转换
类型提升
字符串类型
int 和 String 之间相互转换
数据类型:基本数据类型 和 引用数据类型
基本数据类型有四类(八种):
整形:byte、short、int、long
浮点型:float、double
字符型:char
布尔型:boolean
int 的包装类型为 Integer
long 的包装类型为 Long
short 的包装类型为 Short
byte 的包装类型为 Byte
double 的包装类型为 Double
float 的包装类型为 Float
char 的包装类型为 Character
boolean 的包装类型为 Boolean
字符串、数组、类、接口都属于引用类型
类型转换:自动类型转换(隐式)和强制类型转换(显式)
自动类型转换(隐式)
int a = 10;
long b = 100L;
b = a; // int-->long,数据范围由小到大,隐式转换
强制类型转换(显式)
注意:强制类型转换必须是同种数据类型或有关联
类型提升
1. 不同类型的数据混合运算, 范围小的会提升成范围大的
2,由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short 这种低于 4 个字节的类型, 会先提升成 int, 再参与计算
字符串类型:在 Java 中使用 String 类定义字符串类型
字符串类型不属于基本数据类型,包装类型只是针应的对基本数据类型,字符串类型不是包装数据类型
int 和 String 之间相互转换:2种方法(ValueOf 、 parselnt)
①
②
ValueOf 底层也是 parselnt
int 转为 String的其它方法:拼接
3 运算符
基本四则运算符:加减乘除模(+ - * / %)
增量运算符 (+= -= *= %=)
自增/自减运算符 (++ --)
关系运算符主要有六个(== != < > <= >=)
逻辑运算符主要有三个 (&& || !)
位运算符主要有四个(& | ~ ^)
移位运算有三个(<< >>> >>)
条件运算符 (表达式1? 表达式2: 表达式3)
运算符的优先级
① 基本四则运算符:加减乘除模(+ - * / %)
两侧操作数类型不一致时,向类型大的提升:System.out.println(1+0.2)
② 增量运算符 (+= -= *= %=)
对于 += -= *= %= 运算符,会自动进行转换,包括强转
③ 自增/自减运算符 (++ --)
【前置++】先+1,然后使用变量+1之后的值
【后置++】先使用变量原来的值,表达式结束时给变量+1
如果单独使用,【前置++】和【后置++】没有任何区别
④ 关系运算符主要有六个(== != < > <= >=)
其计算结果是 true 或者 false
注意:当需要多次判断时,不能连着写,比如:3 < a < 5,Java程序与数学中是有区别的
⑤ 逻辑运算符主要有三个 (&& || !)
&& 和 || 遵守短路求值的规则
&& 表达式1为假,表达式2不执行,因此表达式2 /(除)右端为0,不出现报错
&& 表达式1为真,表达式2执行,但表达式2 /(除)右端为0,出现报错
& 和 | 不是逻辑与也不是逻辑或,如果表达式结果为 boolean 时, 也表示逻辑运算,但与 && || 相比, 它们不支持短路求值,所以不建议这么写
⑥ 位运算符主要有四个(& | ~ ^)
当 & 和 | 的操作数为整数(int, short, long, byte) 的时候, 表示按位运算, 当操作数为 boolean 的时候, 表示逻辑运算
⑦ 移位运算有三个(<< >>> >>)
注意:
1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算 代替.
4.移动负数位或者移位位数过大都没有意义.
⑧ 条件运算符 (表达式1? 表达式2: 表达式3)
当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值;
当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值.
⑨ 运算符的优先级
运算符之间是有优先级的(如 + 的优先级要高于 >>),具体的规则我们不必记忆,在可能存在歧义的代码中加上括号即可
4 程序逻辑控制
顺序结构
分支结构:if 语句、switch 语句
循环结构:while 循环、break、continue、for 循环、do while 循环
输入输出:输出到控制台、从键盘输入分支结构:if 语句、switch 语句
分支结构:if 语句、switch 语句
① if 语句
if / else 语句中可以不加大括号,也可以写语句(只能写一条语句),但是实际开发中我们不建议这么写,最好加上大括号
② switch 语句
遇到break停止,没有break则继续走,直到遇到break,default 建议加上
case 后面可以跟多个语句
多个 case 后的常量值不可以重复
switch 的括号内只能是以下类型的表达式:
基本类型:byte、char、short、int,
不可以是long、float、double、boolean类型 (主要来说是语法上不支持)
也可以是引用类型:String常量串、枚举类型
没有明确规定什么时候用 if 什么时候用 switch,但 switch 的使用局限性是比较大 switch 和 if 最大区别是:switch 不能表达复杂的条件
循环结构:while 循环、break、continue、for 循环、do while 循环
① while 循环
② break
break 的功能是让循环提前结束
③ continue
continue 的功能是跳过这次循环, 立即进入下次循环
遇到 continue 直接进入下一次循环,执行不到步进 i++,i 的值永远不会改变
④ for 循环
⑤ do while 循环
do while 循环最后的分号不要忘记 先执行再判断,循环条件成立则继续执行,否则循环结束
一般 do while 很少用到, 更推荐使用 for 和 while,do while 循环一定比正常循环多执行一次
输入输出:输出到控制台、从键盘输入
① 输出到控制台
printf 格式化输出,可自定义输出格式,如是否换行:
② 从键盘输入
先输入年龄的话出现 bug
输入10以后回车,就把姓名当做回车输进去了
处理这种情况只能多写一个 scanner.nextLine ( ); 读取回车,把回车收走
或者直接使用next把回车处理了也可以,不然就先输入年龄
一般不建议用Scanner,直接定义一下就好了,但是做题得用 一般简单的测试才使用scanner,平时不怎么需要输入,一般传参
5 方法的使用
方法格式
实参形参
方法重载
方法签名
实参形参
方法重载条件
方法签名:经过编译器编译修改过之后方法最终的名字
具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字
方法中不能定义两个名字一样的变量,但类中可以定义方法名相同的方法
6 数组的定义与使用
定义数组
数组的初始化
数组的使用:数组访问、遍历数组
数组是引用类型:JVM 内存划分、引用变量、再谈引用变量、认识 null
数组的应用场景:数组作为参数、数组作为返回值
操作数组的工具类:Arrays.toString、Arrays.sort、Arrays.equals、Arrays.fill
数组练习:冒泡排序、数组逆序、求数组中元素的平均值、顺序查找、二分查找
数组拷贝
二维数组:二维数组的定义、二维数组的使用、访问二维数组 、打印二维数组
定义数组
数组的初始化
局部变量在使用时一定要进行初始化
数组的初始化主要分为动态初始化以及静态初始化
动态初始化:在创建数组时直接指定数组中元素的个数,默认数组初始化为0
静态初始化:在创建数组时不直接指定数据元素个数
( 静态初始化可以简写,省去后面的 new int[] )
数组的使用
① 数组访问:通过下标访问快速访问数组中任意位置的元素,下标从0开始,不能越界,否则会报出下标越界异常
② 遍历数组:2种方法
数组是引用类型
① JVM 内存划分
局部变量 存放于虚拟机栈中
new 对象放入堆中
② 引用变量
arr 引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址 通过该地址,引用变量便可以去操作对象
a,b是基本数据类型
③ 再谈引用变量
一个引用不能同时指向多个对象
对象不能指向对象,只有引用才能指向对象
传引用不一定能改变实参的值,重要的是看拿引用做了什么
是让引用指向了新的对象(只是修改了形参的指向,打印出来的实参并未改变)
还是让引用里面的值改变(修改的是同一块内存,实参改变)
④ 认识 null:"空引用" , 也就是一个不指向对象的引用
数组的应用场景
数组作为参数
参数传基本数据类型
在 func 方法中修改形参 x 的值, 不影响实参的 num 值
参数传数组类型(引用数据类型)
func 方法内部修改数组的内容, 方法外部的数组内容也发生改变.
因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的
操作数组的工具类
① Arrays.toString:把数组以字符串形式进行输出
Arrays.toString() 是 Java中的一个方法,属于java.util.Arrays 类。这个方法的主要作用是将数组转换成字符串的形式输出,而不是输出数组的内存地址
② Arrays.sort:利用 Arrays.sort 进行排序,可以区间排序,开发效率非常高
③ Arrays.equals:比较两个数组内容一不一样
④ Arrays.fill:填充、可以区间填充
数组拷贝
最简单的拷贝方法
可以直接调用工具类 Arrays.copyOf 进行拷贝,有两个参数,一个数组,一个长度
这个拷贝返回值是一个数组,所以定义一个数组变量进行接收然后打印
也可以把这个拷贝当成一个扩容
Arrays.copyOfRange 对一定区间内容进行拷贝
拷贝数组返回的都是一个新的数组
也可以直接用 arraycopy 进行拷贝
两个引用指向同一个引用不属于拷贝
二维数组
① 二维数组的定义
② 二维数组的使用
访问二维数组
打印二维数组
应该用 Arrays.deepToString 打印二维数组
另一种打印二维数组方法
特殊的二维数组打印
只定义了两行,没有定义列有多长,列此时是值 null 不能.lenght,所以出现空指针异常
定义列后 :
这个二维数组不是方方列列,也就是所说的不规则的二维数组
二维数组是一个特殊的一维数组
7 Java 类和对象
面向对象与面向对象过程
类的具体语法
定义一个类
类的实例化
this 引用
初始化对象:默认初始化、就地初始化、调用构造方法初始化
封装
包:导入包中的类、自定义包、包的访问权限控制
Static 成员
代码块:普通代码块、构造代码块、静态代码块
对象的打印
内部类:实例内部类、静态内部类、局部内部类、匿名内部类
this 引用
初始化对象:默认初始化、就地初始化、调用构造方法初始化
调用构造方法初始化
封装
从语法上来说就是被 private 修饰的成员变量或者方法只能在当前类当中使用
包
① 导入包中的类
② 自定义包
包名一般小写,采用公司域名的跌倒形式,比如说公司域名 www.baidu.com 跌倒写为com.baidu.www
③ 包的访问权限控制
表格前提:继承的父类一定是 public 修饰的
static成员
代码块
① 普通代码块
② 构造代码块
③ 静态代码块
对象的打印
内部类:实例内部类、静态内部类、局部内部类、匿名内部类
① 实例内部类:即未被 static 修饰的成员内部类
实例内部类是需要外部类引用对象调用的
在实例内部类的成员变量不能是静态的
原因:实例内部类是需要外部类引用对象调用的,而静态成员是不需要实例化对象的
实例内部类对象必须在先有外部类对象前提下才能创建
因为其本身是实例内部成员,因此要有外部类的引用
在实例内部类方法中访问同名的成员时,优先访问自己的
如果要访问外部类同名的成员,必须:外部类名称.this.同名成员来访问
外部类中,不能直接访问实例内部类中的成员
如果要访问必须先要创建内部类的对象(调用成员方法的同时也先需要实例化外部类对象)
外部类中的任何成员都可以在实例内部类方法中直接访问
实例内部类所处的位置与外部类成员位置相同,受 public、private 等访问限定符的约束
② 静态内部类:被 static 修饰的内部成员类称为静态内部类
创建静态内部类对象时,不需要先创建外部类对象
在静态内部类中只能访问外部类中的静态成员
如果一定在内部类访问外部类中非静态成员就要创建外部类对象然后利用对象引用访问
③ 局部内部类:定义在外部类的方法体或者 {} 中
不能被 public、static 等修饰符修饰
④ 匿名内部类
8 继承和多态
继承概念
父类成员访问
super 关键字
子类构造方法
super和this
再谈初始化
protected关键字
final关键字
组合
多态概念
向上转型
动态绑定
重写
继承概念:发现定义的两个类有共同的地方,于是就出现了继承,也就是对类的共性进行抽取出来放到一个特定的类中
private 修饰的也是能被继承的,访问修饰符只能决定访问权限,不能够决定能不能被继承,不能直接访问但可以通过间接访问,给它提供一个 get 方法就可以访问了
父类成员访问:同名情况下优先看子类是否有当前成员,成员遵循就近原则,自己有优先自己的,如果没有则向父类找
super 关键字:子类和父类成员重名如果非得访问父类的,通过 super 关键字
子类构造方法
父类提供默认不带参数的构造方法,子类同样提供了一个不带参数的构造方法,且里面有super 对父类进行默认初始化,如果父类提供带参数构造方法,在子类当中调用父类构造方法对其初始化后将不报错
子类在构造方法完成之前一定要先帮助父类进行初始化
super 和 this:
super() 和 this() 一样都只能在第一行
再谈初始化
子类当中也有静态和实例化代码块,按顺序执行
protected 关键字
不能通过对象的引用访问,应该通过 super 访问
但改成 super 也报错,因为在 main 方法里面是 static 不依赖于对象,不能用 super
(语法规定 super 不能出现在 static 修饰的方法里)
final 关键字:final 代表的就是一个不可变
接口可以解决多继承问题
组合
多态概念:面对不同对象是产生不同的状态
向上转型
通过父类引用只能调用父类特有的成员方法或者成员变量
将子类给到父类,进行向上转型,但父类依旧不能调用子类方法
动态绑定
重写
重写的方法,可以使用 @Override 注解来显式指定,有了这个注解能帮我们进行一些合法性校验,例如不小心将方法名字拼写错了(比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法,就会编译报错, 提示无法构成重写
避免在构造方法中调用重写的方法
构造 D 对象的同时,会调用 B 的构造方法,B 的构造方法中调用了 func 方法,此时会触发动态绑定,会调用到 D 中的 func 此时 D 对象自身还没有构造,此时 num 处在未初始化的状态,值为 0 如果具备多态性,num的值应该是1 所以在构造函数内,尽量避免使用实例方法,除了 final 和 private 方法
“用尽量简单的方式使对象进入可工作状态”,尽量不要在构造器中调用方法(如果这个方法被子类重写,就会触发动态绑定, 但是此时子类对象还没构造完成),可能会出现一些隐藏的但是又极难发现的问题
9 抽象类和接口
抽象类
接口特性
实现多个接口
接口间的继承
接口使用实例:Comparable 、Comparator
Clonable接口
浅拷贝
深拷贝
抽象类和接口区别
Object类
抽象类
抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,除非子类也是抽象类,必须要使用 abstract 修饰,当又再次被继承时需要重写其抽象方法
抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
抽象类本身不能被实例化,要想使用只能创建该抽象类的子类,让子类重写抽象类中的抽象方法
接口特性
接口:多个类的公共规范,是一种引用数据类型
① 接口是使用 interface 方法来修饰的
接口的定义格式与定义类的格式基本相同
将 class 关键字换成 interface 关键字,就定义了一个接口
② 接口当中的成员变量默认都是 public static final 修饰的
③ 接口当中的成员方法默认都是 public abstract 修饰的
④ 类和接口之间的关系,可以使用 implements 来进行关联
⑤ 接口不能进行实例化
接口也可以实现向上转型:接口不能实例化自己,但接口可实例化引用一个具体的对象,这个过程相当于发生了向上转型
⑥ 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
有两种修改方式,要么被 static 修饰,要么被 default 修饰,然后接口中可以实现方法
被 static 修饰的方法不能被重写了,用途在直接用接口访问
而被 default 修饰的方法无法直接用接口访问,由实现接口的类来实现
如果不想使用默认的 default 修饰的方法,也可以重写接口中 default 修饰的方法然后调用
⑦ 重写接口中方法时,不能使用默认的访问权限
⑧ 接口中不能有静态和实例代码块以及构造方法
⑨ 接口也是有对应字节码文件的
⑩ 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类,但下一个类再继承时全需要重写(普通类继承抽象类)
实现多个接口
在 Java 中,类和类之间是单继承的,一个类只能有一个父类,即 Java 中不支持多继承,但是一个类可以实现多个接口
注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类
接口间的继承
接口可以继承一个接口,达到复用的效果,使用 extends 关键字
接口使用实例:Comparable 、Comparator
Comparable
Comparator
Comparable 作用就是默认的,已经提供好的,和比较器可以共存是不冲突的
Clonable接口
Object 类中存在一个 clone 方法,调用这个方法可以创建一个对象的 "拷贝",但是要想合法调用 clone 方法,必须要先实现 Clonable 接口,否则就会抛出 CloneNotSupportedException 异常
Cloneable 接口是空接口,也称为标记接口,表明当前类是可以克隆的
浅拷贝
Object 的默认是浅拷贝这种说法是错的,深浅拷贝跟每个类的克隆方法没有关系,在于代码的实现,而不在于某个方法
深拷贝:指在拷贝这个对象的同时,把对象里面包含的引用所指的对象也拷贝一份
抽象类和接口区别
抽象类是一个类可以被继承,里面可以包含普通方法普通字段,而接口里面只能包含抽象方法,静态方法也可以,成员方法默认是 public static final 修饰
抽象类当中的普通方法和字段可以被子类直接使用(不必重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法
10 Java 中 String 类
常用方法:
字符串构造
字符串包含的成员
String 对象的比较
字符串查找
转化(数值和字符串转换、大小写转化、字符串转数组、格式化)
字符串替换
字符串拆分
字符串截取
其它操作方法
字符串的不可变性
字符串修改
StringBuilder 和 StringBuffer
字符串构造
字符串包含的成员
String 对象的比较
② equals比较(比较内容)
字符串查找
转化(数值和字符串转换、大小写转化、字符串转数组、格式化)
数值和字符串转换
大小写转化
① toUpperCase (小写变大写,原来大写的不动)
② toLowerCase (大写变小写,原来小写的不动)
转变大小写需要进行接收,是一个新对象,未接收则是原来的对象
字符串转数组
格式化
字符串替换
与 replace有关的两个
字符串拆分
字符串截取
其它操作方法
字符串的不可变性:String 类不能修改的主要原因是:String 类功能是私有的
字符串修改
StringBuilder 和 StringBuffer
StringBuilder 和 StringBuffer 这两个类包含了一些 String 没有的方法,它的功能进一步扩大
11 Java 异常
认识异常:异常的体系结构
异常的处理:防御式编程、异常的抛出、异常的捕获(异常声明throws、try-catch捕获并处理、finally)、异常的处理流程
自定义异常类
认识异常:异常的体系结构
异常的处理:防御式编程、异常的抛出、异常的捕获(异常声明 throws、try-catch捕获并处理、finally)、异常的处理流程
防御式编程
异常的抛出
异常的捕获(异常声明 throws、try-catch捕获并处理、finally)
异常声明 throws
try-catch 捕获并处理
throws 对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要 try-catch
finally
问题:既然 finally 和 try-catch-finally 后的代码都会执行,那为什么还要有 finally 呢?
(意思是没有finally,后面代码也能执行,为什么还需要finally)
需求:实现 getData 方法,内部输入一个整形数字,然后将该数字返回,并再 main 方法中打印
上述程序,如果正常输入,成功接收输入后程序就返回了,try-catch-finally 之后的代码根本就没有执行,即输入流就没有被释放,造成资源泄漏
异常的处理流程
自定义异常
Java 中虽然已经内置了丰富的异常类,但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我们实际情况的异常结构