零.JDK
1.jdk的卸载:
计算机–>卸载或更改程序–>
javaSE Development Kit9 update -->右键卸载
2.jdk的安装
双击jdk-9.0.4_windows-x64_bin.exe -->下一步–>更改C:\Java\jdk-9.0.4–>下一步
3.检测是否安装成功
win+r -->输入cmd–>回车–>进入黑窗口(Dos命令行窗口)
输入cd C:\Java\jdk-9.0.4\bin 回车 —>输入java -version回车 -->版本为9.0.4
一.java语言发展
java语言之父:詹姆斯.高斯林
jdk1.0发布时间:1995年
最早的公司:Sun公司 -->最后被Oracle甲骨文公司收购,发布jdk7.0
二.Dos命令行窗口
1.进入dos命令行窗口:win+R–>输入cmd–>回车
进入计算机窗口:win+E
快速显示桌面:win+D
2.常用的命令
1)切换盘符–> 盘符名称: (注意冒号是英文状态下的)
统一设置:搜狗输入法–>工具箱–>属性设置–>常用–>中文时使用英文标点(把√勾上)–>应用–>确定
2)进入单级文件夹–> cd 文件夹名称
3)进入多级文件夹–> cd 文件夹名称1\文件夹名称2
4)回退到上一级文件夹–> cd …
5)回退到磁盘根目录–> cd
6)显示当前文件夹下的所有内容–> dir
7)清除屏幕–> cls
8)退出命令行–> exit
9)tab键–> 自动补全
10)ctrl+s–> 手动保存
三.java程序的跨平台
java程序只用写一遍,针对不同的操作系统有对应的jvm虚拟机,保证java程序的跨平台是借助于jvm虚拟机的
Java的跨平台性和原理
平台:操作系统,常见的操作系统,Windows、mac、Linux等
跨平台:Java程序可以在不同的操作系统下运行
原理:不同的操作系统有对应的JVM,JVM在中间相当于一个翻译
注:JVM保证了Java的跨平台性,但是JVM并不具备跨平台性,也就是说不同
的操作系统下有不同的JVM对应
四.JDK,JRE,JVM
JDK:java开发工具包,如果想要开发java程序,必须安装JDK
JRE:java的运行环境,如果只是运行java程序,只需要安装JRE
JVM:java的虚拟机, 保证java程序的跨平台
JDK包含JRE,JRE包含JVM
总结:由JDK来开发java程序,交给JRE运行,由JRE中的JVM保证java程序的跨平台
JDK、JRE和JVM的概念和区别
JDK:Java开发工具包
JRE:Java运行环境
JVM:Java虚拟机
JRE = JVM + 核心的类库
JDK = JRE + 开发工具包
JDK > JRE > JVM
如果要运行Java程序,必须安装JRE
如果要进行Java程序开发,必须按照JDK
五.配置环境变量
1.为什么要配置环境变量:
如果没有配置环境变量,那么所有的java程序必须在jdk安装的bin目录下编写,
配置环境变量就可以在任意目录下编写java程序,通过javac和java命令来运行
2.怎么配置环境变量:
计算机右键–>属性–>高级系统设置–>环境变量–>在系统变量下
1)新建 变量名:JAVA_HOME
变量值:C:\Java\jdk-9.0.4
新建完成之后确定
2)编辑Path:在变量值上将光标移动到最前面添加 %JAVA_HOME%\bin;
3)点击三个确定–>重启dos命令窗口输入java -version查看jdk版本
六.进制转换
Java中常见的进制
二进制:由0和1组成的,0b开头
八进制:由0~7组成的,0开头,一个八进制为等于3个二进制位
十进制:由0~9组成的
十六进制:由09,af组成的,0x开头,一个十六进制等于4个二进制位
8421码
16 8 4 2 1
请画图演示十进制数78这个数字,转为二进制的过程,然后再将这个二进制转为十进制
计算机中存储数据的最小单元:字节(Byte)
七.Java程序开发的三步骤
1.编写
1、创建一个文本文档,修改名称和后缀名,目前文件就叫HelloWorld,后缀名是java
2、打开HelloWorld.java文件,编写HelloWorld代码
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello,World!");
}
}
3、保存文件(ctrl+s)
2.编译
javac命令
compile 编译
(1)进入到源代码所在的目录,找到源代码
(2)通过javac命令
javac 文件名.java
编译之后会生成一个.class文件,该文件称为字节码文件
3.运行
java命令
java 类名
八.注释
作用:对代码进行解释说明
分类:
(1)单行注释
// 注释的内容
(2)多行注释
/*
注释的内容
*/
(3)文档注释
/**
注释的内容
*/
九.关键字
在Java中有特定含义的单词,只能在特定的情况下使用,不能随便使用
比如class就是一个关键字,只能在定义类的时候使用
特点:
(1)形式上都是英文的小写
(2)在高级编辑工具中会有颜色变化
十.标识符
什么是标识符
用于取名字的符号,比如给类、方法、变量等取名字的
标识符的组成规则【硬性要求】
(1)英文大小写字母,另外中文、日文和韩文等字符也可以使用
(2)数字
(3)美元符($)
(4)下划线(_)
注意事项:
(1)不能以数字开头
(2)不能是关键字
标识符的命名规范【软性要求】
类:如果是一个单词组成,首字母大写即可,如果是多个单词组成,每个单词的首字母大写,其余小写,比如HelloWorld,Hello
方法和变量:如果是一个单词组成,全部小写,如果是多个单词组成,从第二个单词开始首字母大写,其余小写,比如main,getMax
以下属于合法的标识符的有()
hello123 √
$class √
Hello World ×,包含了空格
Hello_World √
public2 √
void ×,是一个关键字
十一.常量
什么是常量
在程序运行的过程中,其值固定不变的量
常量的分类
自定义常量
字面值常量
(1)字符串常量,是使用""引起来的内容,比如:"Hello,World!","123"
(2)整数常量,比如:10,20,-5
(3)浮点数(小数)常量,比如:2.5,-8.0
(4)字符常量,是使用''引起来的内容,其中的内容有且只能有一个字符,不能有多个,也不能一个都没有
比如:'a','1',' '
(5)布尔常量,只有两个值:true和false
(6)空常量(null)
十二.数据类型
基本数据类型(4类8种)
整数类型 字节 取值范围
byte 1 -128~127 -2^7 ~ 2^7-1
short 2 -2^15 ~ 2^15-1
int 4 -2^31 ~ 2^31-1
long 8 -2^63 ~ 2^63-1
浮点类型
float 4
double 8
布尔类型
boolean 1 true和false
字符类型
char 2 0 ~ 65535
引用数据类型
类
String
接口
枚举
数组
十三.变量
什么是变量
在程序的运行过程中,其值可以发生改变的量
变量的定义和使用格式:
(1)先定义再使用
数据类型 变量名; // 定义变量
变量名 = 值; // 使用变量,赋值
(2)定义的同时赋值
数据类型 变量名 = 值;
十四.数据类型的转换
这里的转换,指的是基本数据类型的转换
分类
自动类型转换(隐式转换):不需要进行特殊处理,能够直接转换,类型的取值范围从小到大
转换的小公式:
byte、short、char->int ->long ->float ->double
注意:
(1)boolean类型的不能和其他7种之间进行转换
(2)byte、short不能直接转换成char,反之亦然
强制类型转换(显式转换):需要进行特殊处理,不能直接转换,类型的取值范围从大到小
格式:
小的数据类型 变量名 = (小的数据类型)大类型的数据;
比如:
int i = (int)120L;
十五.运算符
1.算术运算符
+ - * / % ++ --
/ :
(1)得到相除的商,整数相除只能得到整数,如果要得到小数,必须有小数参与运算
(2)负数参与运算,如果除数或者被除数其中有一个为负,得到的结果也为负,否则都是正
%:
(1)得到的相除的余数
(2)负数参与运算,得到的结果是正还是负,只和被除数是正还是负有关,和除数无关的
++:自增1
--:自减1
面试题:
++在前和在后,使用的时候的区别?
(1)单独使用,没有区别
++num;
num++;
(2)混合使用
++在前,变量自增1,然后将自增的结果再使用
++在后,先使用变量原来的值,然后再自增1
2.赋值运算符
基本的赋值运算符:=
将运算符右边的值,赋给左边,让左边的变量来存储右边的值
复合的赋值运算符:+= -= *= /= %=
将运算符左边和右边进行运算,得到的结果赋值给左边
注:
复合的赋值运算符隐含了强制类型转换
short s = 5;
s += 1;// s = (short)(s + 1);
System.out.println(s);// 6
3.比较运算符
== != < <= > >=
得到的结果都是boolean类型的,不是true就是false
4.逻辑运算符
&&:遇false则false,只有两边都为true时结果才为true
||:遇true则true,只有两边都为false时结果才为false
!:非true则false,非false则true
&:遇false则false,只有两边都为true时结果才为true
|:遇true则true,只有两边都为false时结果才为false
^(异或):只有两边不同时结果才为true,否则都为false
面试题:
&和&&的区别?
&&有短路效果,当运算符左边已经能够确定最终的结果,右边不参与运算
5.三元运算符
格式:
数据类型 变量名 = 布尔表达式?表达式1:表达式2;
执行流程:
先执行布尔表达式,看结果是true还是false
如果结果是true,执行表达1
如果结果是false,执行表达2
注:布尔表达式的结果一定是true或者false,不能是其他结果
十六.流程控制语句
1.顺序结构
按照从上往下的顺序依次执行
2.选择结构
(1)if语句
格式一:单if
if(布尔表达式){
// 语句体;
}
执行流程:
首先判断布尔表达式的结果,如果是true,就执行if里面的语句体
如果是false,就不执行。
格式二:if...else...
if(布尔表达式){
// 语句体1;
}else {
// 语句体2;
}
执行流程:
首先判断布尔表达式的结果,如果是true,就执行if里面的语句体
如果是false,就执行else里面的语句体
二选一的情况,有且仅会有一个语句体会执行
格式三:if...else if...else
if(布尔表达式1){
// 语句体1;
}else if(布尔表达式2){
// 语句体2;
}else if(布尔表达式3){
// 语句体3;
}
...
else {
// 语句体n+1;
}
执行流程:
首先执行if小括号中的布尔表达式1,如果为true,就执行语句体1,然后整个if语句结束;
如果为false,继续判断else if小括号中的布尔表达式2,如果为true,就执行语句体2,然后整个 if语句结束;
如果为false,依次类推,继续判断else if小括号中的表达式
最后如果所有的布尔表达式的结果都为false,这时才执行else里面的语句体n+1
多选一的情况,有且仅会有一个语句体会执行
(2)switch语句
格式:
switch(表达式){
case 值1:
// 语句体1;
break;
case 值2:
// 语句体2;
break;
case 值3:
// 语句体3;
break;
...
default:
// 语句体n+1;
break;
}
执行流程:
首先执行表达式,拿到表达式的结果从上往下依次匹配case后面的值,
如果相等,就执行对应case里面的语句体,执行完之后结束整个switch语句
如果不相等,继续匹配下面的case后面的值
依次类推,如果相等就执行对应的case后面的语句体,执行完之后结束整个switch语句
如果不相等,继续匹配下面的case后面的值
当所有的case都不匹配的时候,最终会执行default里面的语句体,结束整个switch语句
注意事项:
(1)default语句的位置可以任意,可以在所有的case之上,也可以在所示的case之下,还可以在多个case之间
default语句的位置在哪里,不影响程序的正常执行流程
甚至default语句都可以省略,一般不建议省略default语句
(2)switch后面的小括号中的表达式的结果的类型只能是
byte short char int
JDK1.5之后可以是枚举
JDK1.7之后可以是String
(3)case穿透问题
switch语句结束的条件由两个:第一个是遇到break,第二个遇到switch的右大括号(})
当break省略之后就容易出现case穿透问题
(3)循环结构
for循环
格式:
for(初始化语句;布尔表达式;步进语句){
循环体;
}
while循环
标准格式:
while(布尔表达式){
循环体;
}
扩展格式:
初始化语句;
while(布尔表达式){
循环体;
步进语句;
}
do...while循环
标准格式:
do{
循环体;
}while(布尔表达式);
扩展格式:
初始化语句;
do{
循环体;
步进语句;
}while(布尔表达式);
特点:
不论布尔表达式结果是否为true,循环体一定至少会执行一次
1.三种循环的区别
1、do...while跟for和while的区别
do...while不论布尔表达式结果是否为true,一定会至少执行一次循环体
for和while如果布尔表达式结果为false,不会执行循环体
2、for跟do...while和while的区别
for中定义的初始化语句,只在for循环中有效,出了for循环消失了不可以用
do...while和while循环里的初始化语句,即使出了循环也可以继续使用
2.循环的选择
(1)循环的次数确定,选择的顺序: for > while > do...while
(2)循环的次数不确定,选择的顺序: while > for > do...while
while(true){
// 当满足条件,可以通过跳转语句,结束循环
}
3.跳转语句
break
使用场景:
1、在switch语句中,用于退出switch语句
2、在循环中,用于结束整个循环
注:
出了使用场景使用break会出错。
continue
使用场景:
只能在循环中使用
用于结束当次循环,继续下一次循环
面试题:
请说说break和continue的区别?
(1)使用场景的区别
(2)在循环中的作用的区别
4.死循环
1、
while(true){
}
2、
for(;;){
}
十七.方法
什么是方法
是一段特定功能的代码,抽取出来放到一对大括号中,然后取上名字
*.注意事项:
(1)方法必须位于类中,不能直接写在.java文件中,也不能写到另一方法中(方法不能嵌套)
(2)方法要运行必须调用
方法名();
1.格式:
修饰符 返回值类型 方法名(参数列表){
// 方法体;
retrun 返回值;
}
修饰符:public static
返回值类型:
规定了方法的返回值对应的数据类型
如果方法有返回值,类型必须对应
如果方法没有返回值,返回值类型也不能省略,必须使用void
方法名:
给方法取一个见名知意名字
方法名方便调用
参数列表:
参数列表可以有,也可以没有
参数列表可以有多个,多个之间用逗号(,)隔开
由两部分组成:
参数类型
变量名称
方法体:
方法执行的核心代码
return 返回值:
return有两个作用,一:结束方法 二:返回方法执行后的结果
如果方法有返回值,就可以通过return返回
如果方法没有返回值,这时return;,这样的语句可以省略
参数列表相当于原材料(输入)、返回值相当于成品(输出)
2.方法的调用
有返回值的方法
(1)单独调用,得不到结果
(2)输出调用,将得到的结果打印出来
(3)赋值调用,将得到的结果用一个变量接收起来,方便使用
无返回值的方法
(1)单独调用
3.方法重载(Overload)
在同一个类,有多个方法名相同,但是参数列表不同的方法
重载的条件
(1)同一个类中,方法名相同
(2)参数列表不同
a:参数个数不同
b:类型不同
c:顺序不同
只和以上两个条件有关,和其他(返回值类型、修饰符、变量名)无关
面试题:
以下和public static int method(int a,double b)方法构成重载的有()
public int method(int i,double j) ×
public static int method(double a,int b) √
public static void method(int a,double b) ×
public static void method(int a,int b) √
public static void method(int a,int b,double c) √
4.方法重写(Override)
十八.数组
数组的概念:
数组是一种容器,可以存储多个元素
特点:
(1)数组是一种容器,可以存储"同一种数据类型"的多个元素
(2)数组有整数索引(编号),索引的范围在0~数组的长度-1
(3)数组存储的元素即可以是基本数据类型,也可以是引用数据类型
(4)数组一经初始化长度就固定了
1.数组的定义
数据类型[] 数组名; // 推荐使用的方式
举例:int[] array;
数据类型 数组名[];
举例:int array2[];
2.数组的初始化
动态初始化:在初始化的时候给定数组的长度,由系统来赋予默认初始化值
数据类型[] 数组名 = new 数据类型[数组的长度];
格式举例:
int[] arr = new int[3];
格式解释:
数据类型[] 数组名 = new 数据类型[数组的长度];
左边
数据类型:规定了数组中能够存储的元素的数据类型
[]:说明定义的是一个数组类型
数组名:给数组取一个名字,方便使用
右边
new:是一个关键字,用于在内存中开辟一片内存空间,固定写法
数据类型:规定了数组中能够存储的元素的数据类型,和定义的时候的数据类型必须一模一样
[]:说明定义的是一个数组
数组的长度:规定了数组能够存储的元素的个数
数组中元素的默认初始值:
整数类型(byte、short、int、long) :0
浮点类型(float、double) :0.0
布尔类型(boolean) :false
字符类型(char) :'\u0000'
引用数据类型 :null
静态初始化:在初始化的时候,给定数组的元素,由系统计算数组的长度
标准格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,....};
举例:
int[] array = new int[]{10,20,30};
简化格式
数据类型[] 数组名 = {元素1,元素2,....};
举例:
int[] array = {10, 20, 30};
3,数组的元素访问
取值
数据类型 变量名 = 数组名[索引];
赋值
数组名[索引] = 新值;
4.Java中的内存划分
栈:方法要执行在栈区中要开辟空间,局部变量是方法中的变量,随着方法都在栈区
栈内存中的变量,一使用完立马消失
堆:一切new出来的东西,比如数组、对象
有地址值
堆内存中的东西用完不是立马消失,消失有时机(垃圾回收机制)
方法区
.class文件
本地方法栈:和操作系统相关
寄存器:和CPU相关
5.数组中的两个常见错误(异常)
数组索引越界异常
ArrayIndexOutOfBoundsException
产生的原因:
操作的索引超出了数组的索引范围:0~数组的长度-1
解决方式:
让操作的索引在数组的索引范围
空指针异常
NullPointerException
产生的原因:
直接给数组类型的引用赋值为null,而没有new
还去使用它
解决方式:
给它补上new
6.获取数组的长度
length属性
int len = 数组名.length;
7.数组的常见操作
1、数组的遍历:将数组中的元素按顺序依次取出来
// 定义一个数组
int[] arr = {3,1,5,8,9};
// 遍历数组
for(int i=0;i<arr.length;i++){// i在0~arr.length-1之间变化
// i代表的就是索引值,每循环一次会依次增加1
System.out.println(arr[i]);
}
2、数组元素求和:将数组的元素的值加总起来
// 定义一个数组
int[] array = {9,10,-2,5,3};
// 求和变量
int sum = 0;
// 遍历求和
for (int i = 0; i < array.length; i++) {
// array[i]代表的就是每一个元素
sum += array[i];
}
// 打印求和的结果
System.out.println(sum);
3、数组元素求最值(最大值和最小值):求出数组中的元素的最大值或者最小值
// 定义一个数组
int[] array = {9,10,-2,5,3};
// 定义一个变量用于记录最大值
int max = array[0];
// 遍历比较,求出最大值
for(int i=1; i<array.length; i++){
if(array[i] > max){
max = array[i];
}
}
System.out.println("最大值为:"+max);
4、数组的反转:将数组中存储的元素倒过来 1 2 3 -> 3 2 1
5、数组元素查找:给定一个元素查找出该元素在数组中的索引位置
6、数组的元素排序:按照一定的顺序(从小到大或者从大到小)对元素进行排列 {3,1,5,8,9} ->{1,3,5,8,9}
冒泡排序
选择排序
十九.面向对象
面向对象的概念
面向过程:强调的是过程(步骤),关注的是“我该如何做”,所有完成功能的步骤和过程都是自己亲力亲为
面向对象:强调的是对象,关注的是“谁来帮我做”,其中的“谁”指的就是对象
面向对象是基于面向过程的
面向对象的优点:
(1)更符合人们的思维习惯,懒人思想
(2)将复杂的事情简单化
(3)从任务的执行者变成了指挥者
1.类与对象
学习编程语言为了解决现实世界的实际问题,使现实世界实现信息化
在Java语言中我们使用类来描述现实世界的事物
类 事物
成员变量 属性:特点
成员方法 行为:能够做什么
类:是对象的抽象描述,是一系列属性和行为的集合,它是模板
对象:是类的具体体现,它是根据模板创建的一个个具体事物
类只有一个,但是根据类可以创建出无数个对象
要创建对象,必须先有类
类根据作用不同可以分为很多种:
标准类(JavaBean):描述现实事物类
测试类:每个类都有主方法,都可以独立运行
2.使用一个类的步骤
(1)创建对象(导包)
类名 对象名 = new 类名();
举例:
Student stu = new Student();
(2)使用
成员变量
赋值
对象名.成员变量名 = 新值; // 这里“.”可以为“的”
举例:
stu.age = 18;
取值
数据类型 变量名 = 对象名.成员变量名;
举例:
int age = stu.age;
成员方法
调用格式:
对象名.成员方法名(参数);
举例:
stu.study();
3.类作为方法的形式参数
形式参数
数据类型
基本数据类型
引用数据类型
数组
类
JDK提供的:String
自定义的:Phone
接口
枚举
变量名
如果一个类作为方法的形式参数的类型,需要传递的是该类的对象,本质上其实传递的是该对象的内存地址值
4.类作为方法的返回值类型
类作为返回值类型,应该使用return返回的是该类的对象,本质上其实返回值的该对象的内存地址值
局部变量和成员变量的区别(面试题)
(1)定义的位置
局部变量:在方法的小括号或者大括号
成员变量:在类中方法外
(2)作用域(范围)
局部变量:只能在所在的方法中
成员变量:在整个类中
(3)默认值
局部变量:没有默认值,使用之前必须先赋值,否则就报错
成员变量:有默认值
(4)内存中的位置
局部变量:跟着方法进入栈内存
成员变量:跟着对象进入堆内存
(5)生命周期
局部变量:随着方法的进栈而存在,随着方法的出栈而消失,立刻回收
成员变量:随着对象的创建而存储,随着对象被垃圾回收机制回收而消失,在合适的时候回收
5.面向对象的三大特征
封装
继承
多态
封装
简单说,拿一个箱子装起来,密封起来,让其中的东西对外界不可见
隐藏实现的细节问题,对外不可见,但是要提供公共(public)的访问方式。
封装的体现:
(1)方法
(2)private修饰成员变量
private
是一个关键字,被private修饰的成员变量只能在本类中使用,其他类中不能用
以后我们都必须用private修饰成员变量,同时提供一对getter和setter方法
this关键字
this:代表的是当前对象的引用,谁来调用方法,当前对象就是谁,每一个非静态(不是static修饰)方法内部都有一个this
作用:
(1)通过this.成员变量的方法调用本类的成员变量
当局部变量和成员变量同名的时候,通过this.成员变量的方式区分这是一个成员变量
构造方法
用于创建对象,并给成员变量赋值
格式:
public 类名(参数列表){
// 方法体
return;
}
格式的特点:
(1)没有返回值,当然也没有返回值类型,连void都没有
(2)构造方法名和类名一致,大小写也相同
(3)return;可以省略
给成员变量赋值的方式
方式一:
对象名.成员变量名 = 新值;
不推荐使用,原因是学习了封装之后,所有的成员变量都会用private修饰
修饰之后,这种方式用不了了
方式二:
通过setter方法
Student stu = new Student();
stu.setName("张三");
方式三:
有参构造
Student stu = new Student("张三", 30);
继承(extends)
现实世界中的继承是儿子拥有父辈的财产
在Java中的继承是子类拥有父类的“内容”
描述的是一种所属关系,"is a"的关系
子类拥有父类的“内容”
内容:
非private修饰的成员变量
非private修饰的成员方法
注意:
(1)构造方法不能被继承
(2)私有的成员变量和成员方法不能被继承
继承的由来
多个类的共性内容不断向上抽取,得到的类就是父类,这多个类就可以称为子类
继承的格式:
public class 子类 extends 父类 {}
继承的好处:
(1)提供了代码的复用性
(2)继承是多态的前提之一
继承中成员变量访问的特点
(1)继承之后,只可能子类拥有父类的内容,但是不可能父类去拥有子类的内容
(2)就近原则,子类中如果有则使用子类的,如果子类中没有则使用父类的
(3)如果是通过成员方法间接访问,对象是谁我就找谁,如果没有再往上找
局部变量、本类的成员变量和父类的成员变量重名情况下的访问
(1)就近原则,谁离我近我就使用谁
如果有局部变量,就使用局部变量,
如果没有局部变量,就找本类的成员变量,
如果本类的成员变量没有,就找父类的成员变量
如果父类的成员变量也没有,报错
(2)如果局部变量、本类的成员变量和父类的成员变量都有
如果想访问局部变量,直接访问
如果想访问本类的成员变量,通过this.的方式访问
如果想访问父类的成员变量,通过super.的方式访问
继承中成员方法访问的特点:
就近原则,谁离我近我就使用谁
子类有该方法,创建子类对象使用的是子类的方法,
如果子类没有该方法,则向上找父类的方法
如果父类也没有该方法,则报错
方法重写(覆盖)
什么是方法重写
在继承关系中(子父类),子类和父类中的方法声明(一般)一致,但是方法体进行重新定义的过程
为什么要方法重写(使用场景)
继承之后,父类的方法无法满足子类对于功能的需求
方法重写的条件(注意事项)
方法重写一般都是子类的方法声明和父类完全一致,但是如果偏要声明不一致,则需要满足以下条件:
一大两同两小
一大:子类重写的方法的权限修饰符必须大于等于父类方法的权限修饰符
权限修饰符:public > protected > 默认 > private
以下属于的权限修饰符的是
a.private
b.static
c.default
d.void
两同:
子类重写的方法必须和父类的方法名完全相同
子类重写的方法的参数列表必须和父类的方法参数列表完全相同
两小:
子类重写的方法的返回值类型必须小于等于父类方法的返回值类型(针对的只是引用数据类型,对基本数据无效)
如果返回值类型是基本数据类型或者是void,那么子类必须一样
如果返回值类型是引用数据类型,满足小于等于就可以,引用数据类型大小:父类 > 子类
子类重写方法抛出的异常必须小于等于父类的异常,或者少于等于父类的异常,
如果父类没有抛出异常,子类方法必须不能有异常
面试题:方法重写和方法重载的区别
方法重载(Overload)
(1)在同一个类中
(2)方法名相同,参数列表不同
(3)和其他(权限修饰符、返回值类型、抛出的异常)的无关
方法重写(Override)
(1)在多个类(有继承关系的子父类)中
(2)方法名相同,参数列表相同
(3)和其他(权限修饰符、返回值类型、抛出的异常)的有关
如果不同需满足以上的条件
继承中,父子类构造方法访问的特点:
父类构造方法一定会先于子类构造方法执行。
(1)每一个构造方法的第一行语句默认都有一个super(),调用的是父类的无参构造方法
(2)如果显式在构造方法中使用super(参数)和this(参数),这样的语句调用父类的构造方法或者本类的其他构造方法,
那么默认的super()就没有了。
super(参数)和this(参数)必须位于构造方法的第一行来调用,而且它们在同一个构造方法中不能同时出现
super(参数)和this(参数)只能在构造方法中使用,不能在其他地方使用
this和super的区别
this:代表当前对象的引用,谁来调用方法谁就代表当前对象
(1)可以调用本类的成员变量,通过this.成员变量
(2)可以调用本类的成员方法,通过this.成员方法
(3)可以在本类的构造方法中的调用本类的其他构造方法,通过this(参数)的方式
super:代表父类的那片空间,通过它可以访问父类的内容
(1)可以在本类成员方法中调用父类的成员变量,通过super.成员变量
(2)可以在本类成员方法中调用父类的成员方法,通过super.成员方法
(3)可以在本类的构造方法中调用父类的构造方法,通过super(参数)的方式
继承中的三个特点:
(1)Java语言中的类是单继承的,不支持多继承
也就是一个类只能有一个直接父类,不能有多个直接父类
(2)Java语言中的类可以多层继承
多层继承,一个类不光可以继承父类中的内容,还可以继承爷爷类中内容
(3)Java语言中一个类可以是多个类的父类
抽象(abstract)类
抽象:反义词是具体,不清楚不确定
抽象的由来
多个类不断向上抽取,在多个类中的功能是具体是明确的,但是抽取到父类中之后该功能就不明确了
例如:一个三角形计算面积可以具体实现,一个圆形计算面积也可以具体实现,它们两个都有计算面积的方法
这时共性内容不断向上抽取,形成一个父类,父类中的计算面积的方法就无法明确如何实现,这是这个方法就应该
定义为抽象的方法。
抽象类:使用abstract关键字修饰的类
如果一个类中有抽象方法,那么这个类必须是抽象类
格式:
// 抽象类
public abstract class 类名 {
// 抽象方法
public abstract 返回值类型 方法名(参数列表);
}
抽象类的特点:
(1)抽象类和抽象方法都必须使用abstract关键字修饰
(2)不能创建对象
(3)一个类去继承抽象类,要么实现所有的抽象方法
要么该类必须也是一个抽象类
(4)抽象类有构造方法
构造方法两个作用:
a:创建对象
b:给成员变量初始化
(5)类与抽象类之间的关系是继承
(6)抽象类中可以有抽象方法也可以没有抽象方法
抽象类中可以非抽象的方法
多态
什么是多态
现实中指的是,事物的多种形态
在Java中的多态,指的是对象的多种形态
多态的前提:
(1)有继承或者实现关系
(2)方法重写
(3)父类的引用指向子类的对象,父接口的引用指向实现类的对象
多态格式:
父类类名【父接口名】 对象名 = new 子类类名【实现类名】();
例如:Animal a = new Dog();
多态下成员方法调用的特点:
编译看左边(父类),运行看右边(子类)
编译的时候看父类中是否有这个方法,如果没有编译就报错,如果有,运行的时候执行的子类中的方法
引用数据类型的转换
向上转型:小的类型(子类或者实现类)转为大的类型(父类或者接口),其实多态就是一种向上转型
向下转型:大的类型(父类或者接口)转为小的类型(子类或者实现类)
格式:
小的类型 变量名 = (小的类型)大的类型的数据;
基本数据类型的转换
隐式转换(自动类型转换):取值范围小的类型转为取值范围大的类型
byte/short/char ->int ->long ->float ->double
byte b = 20;
int i = b;
short s = 30;
int i2 = b + s;
显式转换(强制类型转换):取值范围大的类型转为取值范围小的类型
小的类型 变量名 = (小的类型)大的类型的数据;
int i3 = 100;
byte b2 = (byte)i3;
多态的优缺点
缺点:
多态之后(向上转型),不能再调用子类特有的方法
优点:
提高了代码的复用性
类型转换异常:ClassCastException
instanceof运算符
格式:
对象或者对象名 instanceof 类型名
作用:
判断对象是否是指定的类型
使用
编译报不报错
instanceof作用的对象的类型和右边的类型名必须有子父类或者父子类关系,否则编译报错
运行结果是否为true
如果编译不报错,结果到底是true还是false,要看运行是否属于指定的类型
二十.接口(interface)
接口是有一种公共的规范标准。
定义格式:
public interface 接口名 {}
接口名的命名规范和类名一致
接口中的内容
如果是Java 7,那么接口中可以包含的内容有:
1. 常量
1. 抽象方法
如果是Java 8,还可以额外包含有:
1. 默认方法
1. 静态方法
如果是Java 9,还可以额外包含有:
1. 私有方法
注意:接口中不能有变量和构造方法
接口中的抽象方法
定义格式:
public abstract 返回值类型 方法名(参数);
接口中的抽象方法有默认修饰符:public abstract,即使不写默认也有
抽象类中的抽象方法没有默认修饰符,如果是抽象方法就必须加上abstract
接口的使用步骤:
(1)不能直接创建对象,编写一个实现类去实现该接口
实现的格式:
public class 实现类名 implements 接口 {}
(2)实现类要实现接口的所有的抽象方法
一个类去实现接口必须实现其中的所有抽象方法,否则该实现类必须声明为抽象类。
(3)在测试类中创建实现类的对象,使用
接口中的默认方法
格式:
public default 返回值类型 方法名(参数) {}
默认方法中的public可以省略,但是default不能省略
默认方法可以被实现类型创建对象直接调用,也可以被实现类重写
接口中的静态方法
格式:
public static 返回值类型 方法名(参数) {}
使用格式:
接口名.静态方法名();
注意:不能通过实现类的对象来调用接口中的静态方法
接口中的私有方法
普通私有方法,多个默认方法重复代码的问题
private 返回值类型 方法名(参数列表){}
静态私有方法
private static 返回值类型 方法名(参数列表){}
接口中的常量
常量分类
字面值常量
整数常量 10,-5
浮点数常量 2.5
字符常量 'a'
布尔常量 true false
字符串常量 "abc"
空常量 null
自定义常量
通过final关键字定义
格式:
public static final 数据类型 常量名 = 值;
(1)接口中的常量有默认修饰符:public static final ,即使不写默认也有
(2)常量的命名规范:都是大写字母组成,如果有多个单词组成,每个单词之间用下划线(_)隔开
(3)常量必须赋值
(4)由于接口中的常量是static修饰的,所以使用的时候可以直接“接口名.常量”的方式使用
一个类在继承一个类的同时,还可以实现多个接口
类与类之间是继承关系,单继承,不支持多继承,支持多层继承
类与接口是实现关系,多实现
接口与接口之间是继承关系,多继承
class A extends B implements C,D {
}
二十一.Scanner类 Random类 String类
Scanner类
作用:通过键盘录入数据
使用步骤:
(1)创建对象
Scanner sc = new Scanner(System.in);
(2)使用
int i= sc.nextInt();
String str =sc.next();
Random类
作用:用于生成随机数(任意变化的数)
使用步骤:
(1)创建对象
Random r = new Random();
(2)使用
int num = r.nextInt();
int num = r.nextInt(10);// [0,10)
常用方法:
int nextInt():生成一个在int范围内(-2^31 ~ 2^31-1)的随机整数 [使用较少]
int nextInt(int i):生成一个在0~i-1范围的随机整数 [使用较多]
String类
String类的概述
表示的是字符串,它位于java.lang包下,使用的时候不需要导包
字符串是一个常量,一旦创建了内容不会发生改变
是一个引用数据类型(类类型),不是基本数据类型
"abc"这样的字符串也是String类的一个对象,即使没有new
创建对象的4中方式
构造方法:
String(): //使用很少
String str = new String(); // String s = "";
String(char[] chs):传递char类型数组构造一个String类型对象
String(byte[] bys):传递byte类型数组构造一个String类型对象
String(String original):传递一个String类型的数据构造一个String类型的对象
String str = new String("abc");// String str = "abc";
直接创建:
String str = "abc"; // 使用最多
判断方法
boolean equals(Object o):判断两个字符串的内容是否相等,区分大小写
boolean equalsIgnoreCase(Object o):判断两个字符串的内容是否相等,不区分大小写
面试题:请说出==和equals的区别
==可以比较基本数据类型的数据,比较的时候是比较值是否相等,
也可以比较引用数类型,比较的时候是比较地址值
equals方法只能比较引用数据类型,比较的时候是比较里面的内容,
String也是一种引用数据类型,所以使用equals比较的也是内容
获取方法
int length():获取字符串的长度(字符串中字符的个数)
char charAt(int index):获取指定索引处的字符
String concat(String str):拼接字符串,作用和“+”
int indexOf(String str):获取指定的字符串在大字符串中第一次出现的索引位置,如果没有找到返回-1
面试题:请说说数组、集合和字符串分别如何获取长度?
数组的长度:数组名.length
集合的长度:集合名.size()
字符串的长度:字符串.length()
截取方法
String substring(int index):从指定索引(包括)处截取一直到末尾
String substring(int start,int end):从指定的start索引(包括)处开始截取一直到end索引(不 包括)处结尾
转换方法
char[] toCharArray():将字符串转为字符数组
byte[] getBytes():将字符串转为字节数组
String replace(String oldString,String newString):将字符串中的oldString转为newString
切割方法
String[] split(String regex):,和空格这些可以直接根据它们来切割,但是如果是.必须转义写成\\.
二十二.static关键字 final关键字 权限修饰符
static是一个关键字,也可以叫做静态修饰符,可以修饰成员变量、成员方法和静态代码块
static修饰的成员变量属于类,而不属于某个对象,而是被该类的所有对象所共享
什么情况下使用static修饰成员变量?
当一个类的多个对象中有某个成员变量的值都相同,该成员变量就可以使用static修饰,否则不用
static的特点:
(1)static修饰的成员(成员变量和成员方法)都是属于类的,调用的时候更方便,直接通过类名.的方式调用
原来的调用方式也是可以的,但是我们推荐使用类名.的方式来调用
MyClass obj = new MyClass(); // 首先创建对象
// 对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名称来调用。
obj.methodStatic(); // 正确,不推荐,这种写法在编译之后也会被javac翻译成为“类名称.静态方法名”
MyClass.methodStatic(); // 正确,推荐
System.out.println(obj.numStatic);// 正确,不推荐
System.out.println(MyClass.numStatic);// 正确,推荐
(2)静态只能访问静态,不能访问非静态
静态的方法
访问非静态的成员变量 不可以
访问静态的成员变量 可以
访问非静态的成员方法 不可以
访问静态的成员方法 可以
非静态可以访问静态,也可以访问非静态
非静态的方法
访问非静态的成员变量 可以
访问静态的成员变量 可以
访问非静态的成员方法 可以
访问静态的成员方法 可以
因为静态在内存中先出现的,非静态的东西是后出现的,先出现的不能使用后出现的
静态代码块
格式:
static {
// 代码
}
位置:类中方法外
特点:
(1)静态代码块在程序的运行过程中只会执行一次
静态代码块随着类的加载而执行,由于类的加载只会加载一次,所以静态代码块也只会执行一次
(2)随着类的加载而执行,所以执行的时间比较早,比构造方法执行早
(3)比main方法还早执行
运用场景:
对数据进行提前准备的工作,比如:JDBC加载数据库驱动
final关键字
最终,不可以改变的意思,它可以修饰类、方法、成员变量和局部变量
final修饰类
final修饰的类不能被继承
注:没有子类,但是可以有父类,可以继承和重写父类的方法
final修饰的类其中的方法都不能被重写
面试题:
请说出JDK提供的API中常见的final类。
Math类、String类、Scanner类和System类
final修饰方法
final修饰的方法不能被重写
注:但是可以被继承
final修饰成员变量
final修饰的成员变量不能被重新赋值,变成了常量
final修饰的成员变量必须赋值,赋值两个时机:
(1)直接手动赋值
private final String name = "张三";
(2)通过构造方法赋值
// 没有手动赋值,就必须使用构造方法赋值
private final String name;
public Person() {
name = "关晓彤";
}
final修饰局部变量
final修饰的局部变量不能被重新赋值,变成了常量
基本数据类型的局部变量,不能改变的是值
// final修饰的基本数据类型的局部变量
final int num = 10;
// 错误,值不能改变
// num = 20;
引用数据类型的局部变量,不能改变的是地址值,但是其中存储的内容是可以改变的
// final修饰的引用数据类型的局部变量
final Student s = new Student("张三",20);
// 错误,地址值不能改变
// s = new Student("张三",21);
System.out.println(s.getName() +","+s.getAge());// 张三,20
// 正确,内容改变,但是地址值没有改变
s.setAge(21);
System.out.println(s.getName() +","+s.getAge());// 张三,21
总结:
(1)final修饰的类不能被继承
(2)final修饰的方法不能被重写
(3)final修饰的变量(成员或者局部变量)不能重新赋值
权限修饰符
可以修饰类、成员变量、成员方法、构造方法等,限制它们的访问范围(本类、本包、本模块)
4个:public > protected > default > private
本类 本包 不同包子类 不同包其他类
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×
总结:
private修饰的只能在本类中访问,出了类不能访问
default修饰的只能在本包中访问,出了包不能访问
protected在本包和不同包的子类中可以访问
public修饰的在整个模块中访问,出了模块不能访问
修饰符
权限修饰符:public protected 默认 private
其他修饰
静态修饰符:static
最终修饰符:final
抽象修饰符:abstract
修饰类
public 默认
final abstract
修饰成员变量
public protected 默认 private
static final
修饰局部变量
final
修饰成员方法
public protected 默认 private
static final abstract
修饰构造方法
public protected 默认 private
二十三.内部类
一个类中的组成部分:
成员变量(常量)
成员方法
构造方法
代码块(静态代码块、构造代码块)
成员内部类(内部接口、内部枚举)
注:一个类只能直接编写以上的内容,否则编译报错
在一个类的内部再定义一个类,内部定义的那个类就是内部类
分类:
(1)成员内部类
(2)局部内部类
(3)匿名内部类(特殊的局部内部类)
成员内部类
位置:类中方法外
格式:
修饰符 class 外部类类名{ // 外部类
修饰符 class 内部类类名{ // 成员内部类
}
}
特点:
内部类可以直接访问外部类的成员,即使是private修饰的
外部类想访问内部类的成员,不能直接访问,必须借助内部类的对象
不管是外部类还是内部类,都会生成.class文件,如果是成员内部类生成的文件名的格式:
外部类名$内部类名.class
Outer$Inner.class
使用:
(1)间接使用
在外部类的方法中创建内部类的对象,再通过对象调用内部类的方法
在测试类中创建外部类的对象,再通过对象调用外部类的方法
(2)直接使用
在测试类中创建内部类的对象,再通过对象调用方法
内部类的对象创建的格式:
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
Outer.Inner oi = new Outer().new Inner();
Body.Heart bh = new Body().new Heart();
内部类的成员变量和外部类的成员变量同名,在内部类中访问外部类的同名成员变量:
外部类名.this.成员变量
成员内部类的修饰符:
我们目前学习到的7种修饰符都可以使用
public protected 默认 private
static final abstract
局部内部类
位置:
方法中
特点:
只能在其所定义的方法内部使用,而且必须先定义再使用
出了所定义的方法内部是不能使用的,即使在本类的其他方法中都不能使用
使用:
在其所定义的方法内部创建局部内部类的对象,然后再通过对象调用方法
编译之后的.class文件格式:
外部类名$编号内部类名.class
Outer$1Inner.class
局部内部类访问所在方法的局部变量时,局部变量必须使用final修饰
从JDK1.8开始,如果保证局部变量事实不改变(没有对其进行重新赋值),final关键字可以省略
匿名内部类(掌握)
本质:
是一个局部内部类,只不过它没有名字
应用场景:
当一个接口的实现类(父类的子类)只使用一次的情况下,为了简化操作
匿名对象:解决对象只使用一次的情况,是为了代码简化,不需要再使用变量接收
匿名内部类:解决类只使用一次的情况,是为了简化操作,不需要再创建类
格式:
接口名或者父类名 对象名 = new 接口名或者父类名(){
// 方法重写
};
new 接口名或者父类名(){
// 方法重写
}.重写的方法;
(1)由于匿名内部类没有名字,所以使用的时候只能直接创建其对象
(2)new 接口名或者父类名(),不是在创建接口的对象,也不是在创建父类的对象,
而是创建接口的实现类对象,或者父类的子类对象
(3)要使用匿名内部类必须有一个接口,或者有一个父类(普通类或者抽象类)
如果一个类作为方法的形式参数,调用方法传递的实参是该类的对象或者该类的子类对象
如果一个抽象类作为方法的形式参数,调用方法传递的实参只能是该类的子类对象
如果一个接口作为方法的形式参数,调用方法传递的实参只能是该接口的实现类对象