模块一: 环境变量、HelloWorld
第一章 Java概述
JavaSE知识图解
第二章.Java语言前言
1.字节
1.字节:计算机中存储数据的最小存储单元(计量单位),用byte或者B表示
二进制位:用bit(比特)表示
8个二进制位代表一个字节
2.存储单元之间的转换:
8bit = 1B
1024B = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
PB EB ZB ...
2.常用的dos命令
1.打开dos命令窗口: win+r -> 输入cmd -> 回车
| 作用 | 命令 |
|---|---|
| 切换盘符 | 盘符名: -> 回车 盘符名不区分大小写,但是计算机上必须有指定的盘符 |
| 查看当前路径下的文件或者文件夹 | dir |
| 进入到指定文件夹下 | cd 文件夹名字 |
| 进入到多级文件夹下 | cd 文件夹名字\文件夹名字 |
| 退到上一级目录 | cd..或者 cd .. |
| 直接退到磁盘位置(退到根目录) | cd\或者cd \ |
| 清屏 | cls |
| 退出黑窗口 | exit |
| 创建文件夹 | mkdir 文件夹名 |
| 创建多级文件夹 | mkdir 文件夹名\文件夹名 |
| 删除文件夹 | rd 文件夹名 注意:删除的文件夹必须是空的 不走回收站 |
| 删除文件 | del 文件名.后缀名 不走回收站 |
| 批量删除文件 | del *.后缀名 |
1.如何区分正斜杠和反斜杠:
/:正斜杠
:反斜杠
2.快速打开该目录对应的dos命令窗口:
a.选中路径
b.输入cmd -> 回车
3.按上下箭头,切换之前输入过的命令
4.在dos命令窗口中,可以输入文件夹名或者文件名的一部分,按 -> tab键 -> 自动补全文件夹名或者文件名
第三章.Java所需要的环境
1.jvm和跨平台
1.jvm(java虚拟机):java运行程序的假想计算机,主要用来运行java程序的
2.跨平台:java代码可以在不同的操作系统上运行(一次编写,到处运行) 跨:跨越 平台:操作系统 -> windows linux mac os
3.关系:java程序想要在不同的操作系统上运行,实现跨平台,就需要安装不同版本的jvm
2.JDK和JRE
1.jdk:(Java Development Kit):java开发工具包,包含了jre
javac 编译工具
java 运行工具
jdb 调试工具
jhat 内存分析工具
...
2.jre:(Java Runtime Environment):java运行环境,包含了jvm以及后面开发用到的核心类库
3.jdk和jre以及jvm的关系:
jdk包含了jre,jre包含了jvm,所以我们只需要安装jdk即可
但是从jdk9开始jdk目录中就没有单独的jre目录了,因为jre作为一个运行时,里面不需要包含太多的东西浪费空间,降低运行效率,在jdk9的时候引用模块化的技术,让开发者能按照自己的应用创建一个最小的运行时(比如一个微服务的部署应用仅仅需要一个非常小的runtime,而不是像以前一样不管应用复杂还是简单,都需要一个近百兆的jre运行)这样提高了运行效率
2.1.jdk安装
1.下载:www.oracle.com
1.安装:双击 -> 选择安装路径(安装路径上不要有中文,不要有空格)
2.一定要记住:以后所有开发相关的安装路径上都不要有中文和空格
测试:进入到jdk的bin路径下,打开对应dos命令窗口
输入javac(编译命令)和java(运行命令)
2.2.环境变量的配置
方式1:直接将jdk的bin路径粘贴到path中 -> 不推荐
方式2:极力推荐
配置JAVA_HOME
jdk安装之后,自带环境变量配置->javapath(可以删除)->推荐使用JAVA_HOME
可能出现的问题:电脑重启之后,环境变量失效了
1.解决问题1:点到环境变量中,啥都不要做,直接点一下确定
2.解决问题2:直接将bin路径粘进去
当然,后面学了idea之后,不会出现这种问题了
第四章.Java第一个程序的开发
1.开发三步骤
1.编写:
a.创建一个文本文档,将后缀名改成.java,变成一个java文件
b.注意:我们需要将文件的后缀名显示出来
2.编译:
a.命令:javac java文件名.java
b.注意:javac会将java文件编译,生成一个.class文件(字节码文件),jvm运行只认class文件
3.运行:
a.命令:java class文件名(不需要带后缀名了)
2.编写HelloWorld
public class Demo01HelloWorld{
public static void main(String[] args){
System.out.println("HelloWorld");
}
}
编译:
javac java文件名.java
运行:
java class文件名(不要带后缀名了)
3.注释
1.概述:对代码的解释说明
2.分类:
a.单行注释:
//注释内容
b.多行注释:
/*
注释内容
*/
c.文档注释:
/**
注释内容
*/
4.第一个Java程序中每一句话的解释以及注意事项
/*
1.public class Demo03HelloWorld:定义一个类
2.class:代表的就是类,类是java程序最基本的组成单元,所有代码都需要在类中写
3.class后面跟的名字叫做类名,类名要和java文件名保持一致
*/
public class Demo03HelloWorld{
/*
public static void main(String[] args)
叫做main方法,是程序的入口
jvm执行代码,会从main方法开始执行
*/
public static void main(String[] args){
//打印语句(输出语句),会将我们想要输出的内容打印到控制台上
System.out.println("helloworld");
}
}
注意事项:
1.类名要和java文件名保持一致
2.程序中的标点符号必须是英文的
3.不要将main写成mian
4.System和String的首字母s要大写
5.每个单词写完来个空格增强代码的可读性
6.括号要一对一对的写
7.代码写完语句用;代表结束了,一句话来个分号,证明这是一个单独的语句
5.关键字
1.关键字:java提前定义好的,具有特殊含义的小写单词
6.编写HelloWorld时要注意的问题
6.1字符编码问题
1.编码:保存数据的过程就是编码的过程
2.解码:读数据的过程就是解码的过程
3.注意:
a.编码和解码遵守的编码规范必须是一样的
b.常见的两个编码规范:
GBK:专门为我们中文所设计的编码
ANSI代表的是GBK
一个中文汉字在GBK中占2个字节
UTF-8:一个中文汉字在UTF-8中占3个字节
c.dos命令窗口默认编码:GBK
6.2源文件名(java文件名)与类名一致问题?
1.类名必须要和java文件名一致嘛?
不是必须的
如果类名和java文件名不一致,需要将class前面的public干掉
2.如果class前面带public,此时类名必须要和java文件名一致
3.一个java文件中可以写多个class类,但是只能有一个类带public
但是建议不要随意在一个java文件中写多个class -> 一个java文件中就写一个class,而且带public的
4.main方法必须写在带public的类中
小结:
1.一个java文件只写一个class,而且带public
2.类名和java文件名保持一致
3.main方法写在带public的类中
7.println和print区别
相同点:都是输出语句
不同点:
a.println:输出之后自带换行效果
b.print:输出之后不带换行效果
模块二:变量、数据类型转换
第一章.常量
1.概述:在代码的运行过程中,值不会发生改变的数据
2.分类:
整数常量:所有整数
小数常量:所有带小数点的
2.5 1.5 2.0
字符常量:带单引号的 '' 单引号中必须有且只能有一个内容
'1'(算) '11'(不算) ''(不算) 'a1'(不算)
' '(算) ' '(两个空格不算)
'写一个tab键'(算)
字符串常量:带双引号的 "" 双引号中内容随意
"" "helloworld"
布尔常量:true(真) false(假) -> 这两个单词不要加双引号
"true"(这样写属于字符串,不属于布尔常量)
空常量:null 代表的是数据不存在
第二章.变量
| 数据类型 | 关键字 | 内存占用 | 取值范围 |
|---|---|---|---|
| 字节型 | byte | 1个字节 | -128 至 127 定义byte变量时超出范围,废了 |
| 短整型 | short | 2个字节 | -32768 至 32767 |
| 整型 | int(默认) | 4个字节 | -2^31^ 至 2^31^-1 正负21个亿 -2147483648——2147483647 |
| 长整型 | long | 8个字节 | -2^63^ 至 2^63^-1 19位数字 -9223372036854775808到9223372036854775807 |
| 单精度浮点数 | float | 4个字节 | 1.4013E-45 至 3.4028E+38 |
| 双精度浮点数 | double(默认) | 8个字节 | 4.9E-324 至 1.7977E+308 |
| 字符型 | char | 2个字节 | 0 至 2^16^-1 |
| 布尔类型 | boolean | 1个字节 | true,false(可以做判断条件使用) |
1.变量的介绍以及使用
1.变量的数据类型:
基本数据类型:4类8种
整型:byte short int long
浮点型:float double
字符型:char
布尔型:boolean
引用数据类型: 类 数组 接口 枚举 注解
2.概述:在代码的运行过程中,值会随着不同的情况而随时发生改变的数据
3.作用:一次接收一个数据
将来定义一个变量,接收一个值,后续可能会根据不同的情况对此值进行修改,此时可以用变量
4.定义:
a.数据类型 变量名 = 值;
b.数据类型 变量名;
变量名 = 值;
c.连续定义三个相同类型的变量
数据类型 变量名1,变量名2,变量名3;
变量名1 = 值;
变量名2 = 值;
变量名3 = 值;
比如:int i,j,k;
i = 10;
j = 20;
k = 30;
数据类型 变量名1 = 值,变量名2 = 值,变量名3 = 值;
比如: int i = 10,j = 20,k = 30;
正确读法:先看等号右边的,再看等号左边的 -> 将等号右边的数据赋值给等号左边的变量
哪怕等号右边有运算,我们都得先将等号右边的运算算出一个值来,最后赋值给等号左边的变量
5.注意:
a.字符串不属于基本数据类型,属于引用数据类型,用String表示
String是一个类,只不过字符串在定义的时候可以和基本数据类型格式一样
6.float和double的区别:
a.float的小数位只有23位二进制,能表示的最大十进制为2的23次方(8388608),是7位数,所以float型代表的小数,小数位能表示7位
b.double的小数位只有52位二进制,能表示的最大十进制为(4 503 599 627 370 496),是16位数,所以double型代表的小数,小数位能表示出16位
7.切记:将来开发不要用float或者double直接参与运算,因为直接参与运算会有精度损失问题
2.变量使用时的注意事项
1.变量不初始化(第一次赋值)不能直接使用
2.在同一个作用域(一对大括号就是一个作用域)中不能定义重名的变量
3.不同作用域中的数据尽量不要随意互相访问
在小作用域中能直接访问大作用域中的变量
在大作用域中不能直接访问小作用域中的变量
第三章.标识符
1.概述:咱们给类,方法,变量取的名字
2.注意:
a.硬性规定(必须遵守)
标识符可以包含"英文字母","数字","$和_"
标识符不能以数字开头 int i1 = 100(正确) int 1i = 100(错误)
标识符不能是关键字 int static = 100(错误) int public = 100(错误)
b.软性建议(可遵守可不遵守,但是建议遵守)
给类取名字:遵循大驼峰式 -> 每个单词首字母大写
给方法和变量取名字:遵循小驼峰式 -> 从第二个单词开始往后首字母大写
见名知意
第四章.数据类型转换
1.什么时候发生类型转换:
a.等号左右两边类型不一致
b.不同类型的数据做运算
2.分类:
a.自动类型转换
将取值范围小的数据类型赋值给取值范围大的数据类型 -> 小自动转大
取值范围小的数据类型和取值范围大的数据类型数据做运算 -> 小自动转大
b.强制类型转换
当将取值范围大的数据类型赋值给取值范围小的数据类型 -> 需要强转
3.基本类型中按照取值范围从小到大排序:
byte,short,char -> int -> long -> float -> double
1.自动类型转换
1.将取值范围小的数据类型赋值给取值范围大的数据类型 -> 小自动转大
2.取值范围小的数据类型和取值范围大的数据类型做运算 -> 小自动转大
public class Demo09DataType{
public static void main(String[] args){
/*
等号右边是整数,整数默认类型为int
等号左边是long型的变量
将取值范围小的数据类型赋值给取值范围大的数据类型,发生了自动类型转换
*/
long num1 = 100;
System.out.println(num1);
int i = 10;
double b = 2.5;
/*
double = int+double
double = double+double
int自动提升为了double,发生了自动类型转换
*/
double sum = i+b;
System.out.println(sum);
}
}
2.强制类型转换
1.将取值范围大的数据类型赋值给取值范围小的数据类型
取值范围小的数据类型 变量名 = 取值范围大的数据类型 -> 需要强转
2.怎么强转:
取值范围小的数据类型 变量名 = (取值范围小的数据类型)取值范围大的数据类型
public class Demo10DataType{
public static void main(String[] args){
/*
等号右边的数据是小数,小数默认类型为double
等号左边的变量是float型
将取值范围大的赋值给取值范围小 -> 报错,需要强转
*/
//float num1 = 2.5;
//float num1 = (float)2.5;
float num1 = 2.5F;
System.out.println(num1);
}
}
3.强转的注意事项
1.不要随意写成强转的格式,因为会有精度损失问题以及数据溢出现象,除非没有办法
2.byte,short定义的时候如果等号右边是整数常量,如果不超出byte和short的范围,不需要我们自己强转,jvm自动转型
byte,short如果等号右边有变量参与,byte和short自动提升为int,然后结果再次赋值给byte或者short的变量,需要我们自己手动强转
3.char类型数据如果参与运算,会自动提升为int型,如果char类型的字符提升为int型会去ASCII码表(美国标准交换代码)范围内去查询字符对应的int值,如果在ASCII码表范围内没有对应的int值,回去unicode码表(万国码)中找
模块三:idea、运算符
第一章.IDEA的使用
1.idea的介绍
1.概述:开发工具
2.特点:
a.idea是java写的,所以本地上必须有正确的jdk环境(JAVA_HOME)
b.idea自动保存
c.不用我们打开dos命令窗口执行javac和java命令
d.idea有强大的快捷键,生成代码,纠错等
e.idea会自动管理我们写的代码
3.相关开发工具:eclipse myeclipse
4.作用:加速我们的开发
2.idea的目录结构
先创建project,在project下创建module,在module下创建package -> 必须记住
3.创建类以及基本语句生成快捷键
1.生成main方法:输入main -> 回车
2.生成输出语句:sout -> 回车
3.将变量名放到输出语句中:
a.变量名.sout
b.变量名.soutv -> 带字符串平拼接格式的输出方式-> 输出格式好看
4.快捷键
| 快捷键 | 功能 |
|---|---|
Alt+Enter | 导入包,自动修正代码(重中之重) |
Ctrl+Y | 删除光标所在行 |
Ctrl+D | 复制光标所在行的内容,插入光标位置下面 |
Ctrl+Alt+L | 格式化代码 |
Ctrl+/ | 单行注释 |
Ctrl+Shift+/ | 选中代码注释,多行注释,再按取消注释 |
Alt+Shift+上下箭头 | 移动当前代码行 |
第二章.运算符
1.算数运算符
| 符号 | 说明 |
|---|---|
| + | 加法 |
| - | 减法 |
| * | 乘法 |
| / | 除法 如果符号前后都是整数,结果取整数部分 如果符号前后有一个为小数,结果就是正常小数 |
| % | 模,取余数部分 |
+:
1.运算
2.字符串拼接:任何类型的数据遇到字符串都会变成字符串,此时+就不再是运算了,而是字符串拼接,将内容直接往后拼接
2.自增自减运算符(也算算数运算符的一种)
1.格式:
变量++ -> 后自加
++变量 -> 前自加
变量-- -> 后自减
--变量 -> 前自减
自增和自减只变化1
2.使用:
a.单独使用: ++ -- 单独为一句,没有和其他的语句掺和使用
i++;
符号前在在后都是先运算
b.混合使用: ++ -- 和其他的语句掺和使用了(比如:输出语句,赋值语句)
符号在前:先运算,在使用运算后的值
符号在后:先使用原值,使用完毕之后,自身再运算
3.赋值运算符
1.基本赋值运算符:
= -> 先看等号右边的,再将右边的数据赋值给等号左边的变量
2.复合赋值运算符:
+=:
int i = 10;
i+=2 -> i = i+2
-=
*=
/= : 取整数部分
%= : 取余数部分
3.注意:byte short 遇到复合赋值运算符,jvm会自动转型
4.关系运算符(比较运算符)
1.结果:boolean型 -> 要么是true,要么是false
2.作用:做条件判断使用
| 符号 | 说明 |
|---|---|
| == | 如果符号前后相等为true;否则为false |
| > | 如果符号前的数据大于符号后的数据为true,否则为false |
| < | 如果符号前的数据小于符号后的数据为true,否则为false |
| >= | 如果符号前的数据大于或者等于符号后的数据为true,否则为false |
| <= | 如果符号前的数据小于或者等于符号后的数据为true,否则为false |
| != | 如果符号前后不相等为true;否则为false |
5.逻辑运算符
1.作用:连接多个boolean结果的
2.结果:boolean型结果
| 符号 | 说明 |
|---|---|
| &&(与,并且) | 有假则假,符号前后有一个结果为false,整体就是false |
| ||(或者) | 有真则真,符号前后有一个结果为true,整体就是true |
| !(非,取反) | 不是true,就是false;不是false,就是true |
| ^(异或) | 符号前后结果一样为false;不一样为true true^true -> false true^false -> true false^true -> true false^false -> false |
| 符号 | 说明 |
|---|---|
| & | 1.单与,如果前后都是布尔型,有假则假,但是如果符号前为false,符号后的判断会继续执行 2.如果该符号前后都是数字,看做是位运算符 |
| && | 1.双与,有假则假,但是有短路效果,如果符号前为false,符号后的判断就不会执行了 |
| | | 1.单或,如果前后都是布尔型,有真则真,但是如果符号前为true,符号后的判断会继续执行 2.如果该符号前后都是数字,看做是位运算符 |
| || | 1.双或,有真则真,但是有短路效果,如果符号前为true,符号后的判断就不会执行了 |
6.三元运算符
1.格式:
boolean表达式?表达式1:表达式2
2.执行流程:
先判断,如果是true,就走?后面的表达式1,否则就走:后面的表达式2
模块四:流程控制
第一章.键盘录入_Scanner
1.概述:是java定义好的一个类
2.作用:将数据通过键盘录入的形式放到代码中参与运行
3.位置:java.util
4.使用:
a.导包:通过导包找到要使用的类 -> 导包位置:类上
import java.util.Scanner -> 导入的是哪个包下的哪个类
b.创建对象
Scanner 变量名 = new Scanner(System.in);
c.调用方法,实现键盘录入
变量名.nextInt() 输入整数int型的
变量名.next() 输入字符串 String型的
变量名.next():录入字符串 -> 遇到空格和回车就结束录入了
变量名.nextLine():录入字符串 -> 遇到回车就结束录入了
第二章.Random随机数
1.概述:java自带的一个类
2.作用:可以在指定的范围内随机一个整数
3.位置:java.util
4.使用:
a.导包:import java.util.Random
b.创建对象:
Random 变量名 = new Random()
c.调用方法,生成随机数:
变量名.nextInt() -> 在int的取值范围内随机一个整数
第三章.switch(选择语句)
1.switch基本使用
1.格式:
switch(变量){
case 常量值1:
执行语句1;
break;
case 常量值2:
执行语句2;
break;
case 常量值3:
执行语句3;
break;
case 常量值4:
执行语句4;
break;
...
default:
执行语句n;
break;
}
2.执行流程:
用变量接收的值和下面case后面的常量值匹配,匹配上哪个case就执行哪个case对应的执行语句
如果以上所有case都没有匹配上,就走default对应的执行语句n
3.break关键字:代表的是结束switch语句
4.注意:switch能匹配什么类型的数据:
byte short int char 枚举类型 String类型
2.case的穿透性
1.如果没有break,就会出现case的穿透性,程序就一直往下穿透执行,直到遇到了break或者switch代码执行完毕了,就停止了
第四章.分支语句
1.if的第一种格式
1.格式:
if(boolean表达式){
执行语句;
}
2.执行流程:
先走if后面的boolean表达式,如果是true,就走if后面大括号中的执行语句,否则就不走
3.注意:
if后面跟的是boolean表达式,只要是结果为boolean型的,都可以放在小括号中,哪怕直接写一个true或者false
2.if的第二种格式
1.格式:
if(boolean表达式){
执行语句1;
}else{
执行语句2;
}
2.执行流程:
a.先走if后面的boolean表达式,如果是true,就走if后面的执行语句1
b.否则就走else后面的执行语句2
3.if的第三种格式
1.格式:
if(boolean表达式){
执行语句1
}else if(boolean表达式){
执行语句2
}else if(boolean表达式){
执行语句3
}...else{
执行语句n
}
2.执行流程:
从if开始往下挨个判断,哪个if判断结果为true,就走哪个if对应的执行语句,如果以上所有的判断都是false,就走else对应的执行语句n
3.使用场景:2种情况以上的判断
switch和if的区别:
1.switch:会直接跳到相匹配的case
2.if:从上到下挨个判断 -> 实际开发主要用if做判断,灵活
第五章.循环语句
1.for循环
1.格式:
for(初始化变量;比较;步进表达式){
循环语句 -> 哪段代码循环执行,就将哪段代码放到此处
}
2.执行流程:
a.先走初始化变量
b.比较,如果是true,走循环语句,走步进表达式(初始化的变量的值进行变化)
c.再比较,如果还是true,继续走循环语句,走步进表达式
d.再比较,直到比较为false,循环结束了
2.while循环
1.格式:
初始化变量;
while(比较){
循环语句;
步进表达式
}
2.执行流程:
a.初始化变量
b.比较,如果是true,就走循环语句,走步进表达式
c.再比较,如果还是true,继续走循环语句,继续走步进表达式
d.再比较,直到比较为false,循环结束
3.do...while循环(了解)
1.格式:
初始化变量;
do{
循环语句;
步进表达式
}while(比较);
2.执行流程:
a.初始化变量
b.走循环语句
c.走步进表达式
d.判断,如果是true,继续循环,直到比较为false,循环结束
3.特点:
至少循环一次
4.循环控制关键字
1.break:
a.在switch中代表结束switch语句
b.在循环中代表结束循环
2.continue:
结束当前本次循环,直接进入下一次循环,直到条件为false为止
模块五:数组
第一章.数组的定义
1.问题:想将一个数据保存起来,我们可以使用变量,但是变量一次只能存储一个数据,所以我们想能不能一次存多个数据
2.数组概述:是一个容器,数组本身属于引用数据类型
3.作用:一次存储多个数据
4.特点:
a.既可以存储基本类型的数据,还能存储引用类型的数据
b.定长(定义数组时长度为多长,最多就能存多少个数据)
5.定义:
a.动态初始化:
数据类型[] 数组名 = new 数据类型[长度]
数据类型 数组名[] = new 数据类型[长度]
b.静态初始化
数据类型[] 数组名 = new 数据类型[]{元素1,元素2...} -> 不推荐使用
数据类型 数组名[] = new 数据类型[]{元素1,元素2...} -> 不推荐使用
c.简化的静态初始化:
数据类型[] 数组名 = {元素1,元素2...}-> 推荐使用
6.区别:
a.动态初始化:定义的时候只指定了长度,没有存具体的数据
当只知道长度,但不知道具体存啥数据时可以使用动态初始化
b.静态初始化:定义的时候就直接知道存啥了
第二章.数组操作
1.获取数组的长度
1.格式:
数组名.length
2.注意:
length后面不要带小括号,因为length不是一个方法,而是数组中的一个属性
2.索引
1.概述:元素在数组中存储的位置
2.特点:
a.索引唯一
b.索引都是从0开始的,最大索引是数组长度-1
3.注意:
我们将来操作元素,必须通过索引来操作
存数据,要指定索引
取数据,要指定索引
查数据,要指定索引
3.存储元素
1.格式:
数组名[索引值] = 值
4.获取元素
1.地址值:
数组在内存中的身份证号,唯一标识,我们可以通过这个唯一标识到内存中准确找到这个数,从而操作这个数组中的数据
2.注意:
a.直接输出数组名,会直接输出数组在内存中的地址值
b.如果数组中没有存元素,那么直接获取索引上对应的元素也是有值的,只不过不是我们存储的数据,而是数组中的元素默认值
整数: 0
小数: 0.0
字符: '\u0000' -> 空白字符 -> 对应的int值是0
布尔: false
引用: null
5.遍历数组
1.遍历:for循环 将元素从数组中一个一个的获取出来
2.快速遍历快捷键: 数组名.fori
第三章.操作数组时两个常见的问题
1.数组索引越界异常_ArrayIndexOutOfBoundsException
1.原因:
操作的索引超出了数组索引范围了
2.空指针异常_NullPointerException
1.原因:
当一个对象为null时,再调用此对象中的其他成员
public class Demo10Array {
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr.length);//3
arr = null;
System.out.println(arr.length);//NullPointerException
}
}
第四章.内存图
1.内存:可以理解"内存条",任何程序,软件运行起来都会在内存中运行,占用内存,在java的世界中,将内存分为了5大块
2.分为哪5大块
栈(重点)(Stack)
主要运行方法,方法的运行都会去栈内存中运行,运行完毕之后,需要"弹栈",腾空间
堆(重点):(Heap)
每new一次,都会在堆内存中开辟空间,并为此空间自动分配一个地址值
堆中的数据都是有默认值的
整数:0
小数:0.0
字符: '\u0000'
布尔:false
引用:null
方法区(重点)(Method Area)
代码的"预备区",记录了类的信息以及方法的信息
本地方法栈(了解):专门运行native方法(本地方法)
本地方法可以理解为对java功能的扩充
有很多功能java语言实现不了,所以就需要依靠本地方法完成
寄存器(了解) -> 跟CPU有关
总结:内存:
a.栈:方法的运行在栈
b.堆:数组,对象都在堆,而且每new一次都会在堆中开辟一个空间,堆内存会为此空间分配一个地址值
c.方法区:代码运行之前的预备区,存储class文件
d.本地方法栈
e.寄存器
1. 两个数组内存图
我们创建了两个数组,在堆内存中开辟了两个不同的空间,此时修改一个数组中的元素不会影响到另外一个数组中的数据
2. 两个数组指向同一片内存空间
arr2不是new出来的,是arr1直接赋值的,arr1在内存中保存的是地址值,给了arr2,那么arr2的地址值和arr1就是一样的
所以此时arr1和arr2指向了堆内存中的同一片空间(同一个地址值,同一个数组),此时改变一个数组中的元素会影响到另外一个数组
第六章.二维数组
1.二维数组的定义格式
1.概述:数组中的套多个数组
2.定义格式
a.动态初始化
数据类型[][] 数组名 = new 数据类型[m][n]
数据类型 数组名[][] = new 数据类型[m][n]
数据类型[] 数组名[] = new 数据类型[m][n]
m:代表的是二维数组的长度
n:代表的是二维数组中每一个一维数组的长度
数据类型[][] 数组名 = new 数据类型[m][] -> 二维数组中的一维数组没有被创建
b.静态初始化
数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型 数组名[][] = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型[] 数组名[] = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
c.简化静态初始化:
数据类型[][] 数组名 = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型 数组名[][] = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
数据类型[] 数组名[] = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}}
2.获取二维数组长度
1.格式:
数组名.length
2.获取每一个一维数组长度,需要先遍历二维数组,将每一个一维数组从二维数组中拿出来
3.获取二维数组中的元素
1.格式:
数组名[i][j]
i:代表的是一维数组在二维数组中的索引位置
j:代表的是元素在一维数组中的索引位置
4.二维数组中存储元素
1.格式:
数组名[i][j] = 值
i:代表的是一维数组在二维数组中的索引位置
j:代表的是元素在一维数组中的索引位置
5.二维数组的遍历
1.先遍历二维数组,将每一个一维数组遍历出来
2.再遍历每一个一维数组,将元素获取出来
模块六:方法
第一章.方法的使用
1.无参无返回值的方法定义和执行流程
1.无参无返回值方法定义:
public static void 方法名(){
方法体 -> 实现此方法的具体代码
}
2.调用:直接调用
在其他方法中: 方法名()
3.注意事项:
a.void关键字代表无返回值,写了void,就不要在方法中写return 结果
b.方法不调用不执行, main方法是jvm调用的
c.方法之间不能互相嵌套,方法之间是平级关系
d.方法的执行顺序只和调用顺序有关
2.有参数无返回值的方法定义和执行流程
1.格式:
public static void 方法名(数据类型 变量名){
方法体
}
2.调用:
直接调用:方法名(具体的值) -> 调用的时候要给参数赋值
3.无参数有返回值定义以及执行流程
1.格式:
public static 返回值类型 方法名(){
方法体
return 结果
}
2.调用: 返回值返回给了谁? 哪里调用返回给哪里
a.打印调用:sout(方法名()) -> 不推荐使用
b.赋值调用:调用完之后用一个变量接收返回值结果 -> 极力推荐
数据类型 变量名 = 方法名()
4.有参数有返回值定义以及执行流程
1.格式:
public static 返回值类型 方法名(参数){
方法体
return 结果
}
2.调用:
a.打印调用:
sout(方法名(具体的值))
b.赋值调用(极力推荐)
数据类型 变量名 = 方法名(具体的值)
5.形式参数和实际参数区别
1.形式参数(形参):在定义方法的时候形式上定义的参数,此参数还没有值
2.实际参数(实参):在调用方法的时候给形参赋予的具体的值
第二章.方法注意事项终极版
1.方法不调用不执行
2.方法的执行顺序只和调用顺序有关
3.方法之间不能互相嵌套
4.void不能和[return 结果]共存,但是void能和[return]共存
a.void:代表没有返回值
b.return 结果:就代表有返回值了
先将结果返回,然后结束方法
c.return:仅仅代表结束方法,不代表有返回值
5.一个方法中不能连续写多个return(也就是说一个方法不能都多个返回值)
6.调用方法的时候要看看下面有没有这个方法,没有的方法直接调用会报错
第三章.方法的重载(Overload)
1.概述:方法名相同,参数列表不同的方法
2.什么叫参数列表不同:
a.参数个数不同
b.参数类型不同
c.参数类型顺序不同
3.判断两个方法是否为重载方法,和什么无关:
a.和参数名无关
b.和返回值无关
模块七:面向对象
第一章.类和对象
1.面向对象的介绍
1.面向过程:自己的事情自己干,代表语言C语言
洗衣服:每一步自己要亲力亲为 -> 找个盆,放点水,找个搓衣板,搓搓搓
2.面向对象:自己的事情别人帮忙去干,代表语言Java语言
洗衣服:自己的事情别人干 -> 全自动洗衣机
3.为啥要使用面向对象思想编程:懒
很多功能别人都给我们实现好了,我们只需要直接拿过来使用即可,简化了我们自己的编写过程,减少了我们的代码量
4.什么时候使用面向对象思想编程:
调用别人的功能时
在一个类中想使用别的类中的成员时,就使用面向对象思想编程
至于我们使用的功能人家怎么实现的,我们不需要关心,我们只需要知道怎么使用即可
5.怎么使用面向对象思想编程:
a.new呀,new完点呀-> 点代表的是调用
b.特殊:如果调用的成员带static关键字,我们不需要new,我们直接类名点即可
2.类和对象
2.1类(实体类)_class
1.测试类:带main方法的类,主要是运行代码的
2.实体类:是一类事物的抽象表示形式
世间万物的分类:比如: 人类 狗类 猫类 鼠标类
组成部分:
1.属性(成员变量):这一类事物有啥
a.定义位置:类中方法外
b.作用范围:作用于当前类
c.定义格式: 数据类型 变量名
d.默认值:
整数:0
小数:0.0
字符:'\u0000'
布尔:false
引用:null
2.行为(成员方法):这一类事物都能干啥
只需要将模块六所学的方法中的static干掉,其他的都一样
2.2对象
1.概述:一类事物的具体体现
2.使用:
a.导包: import 包名.类名
如果两个类在同一个包下,想要使用对方的成员不需要导包
如果两个类不在同一个包下,想要使用对方的成员需要导包
特殊包:java.lang -> 使用lang包下的类不需要导包 -> String
友情提示:在学四种权限修饰符之前,尽量让两个类在同一个包下
b.创建对象:想要使用哪个类中的成员,就new哪个类的对象
类名 对象名 = new 类名() -> 比如: Person person = new Person()
c.调用成员(成员变量,成员方法) -> 想要使用哪个类中的成员,就用哪个类的对象去点哪个成员
对象名.成员变量名 = 值
对象名.方法名() -> 调用的是无参无返回值方法
对象名.方法名(实参) -> 调用的是有参无返回值方法
数据类型 变量名 = 对象名.方法名() -> 调用的是无参有返回值方法
数据类型 变量名 = 对象名.方法名(实参) -> 调用的是有参有返回值方法
3.匿名对象的使用
1.所谓的匿名对象:其实就是没有等号左边的部分,只有等号右边的部分(对象)
2.使用:
new 对象().成员
3.注意:
a.如果我们只想单纯的调用一个方法,让方法执行,我们可以考虑使用匿名对象
b.但是如果涉及到赋值,千万不要用匿名对象
4.一个对象的内存图
5.两个对象的内存图
phone1和phone2都是new出来的,所以在堆内存中产生了两个不同的空间,所以改变一个空间的数据不会 影响另外一个空间中的数据
6.两个对象指向同一片空间内存图
phone2是phone1给的,phone1在内存中保存的是地址值,此时phone1和phone2地址值是一样的了,操作的是同一片空间的数据,所以改变一个对象的数据会影响到另外一个对象
第二章.成员变量和局部变量的区别
1.定义位置不同(重点)
a.成员变量:类中方法外
b.局部变量:定义在方法之中或者参数位置
2.初始化值不同(重点)
a.成员变量:有默认值的,所以不用先手动赋值,就可以直接使用
b.局部变量:是没有默认值的,所以需要先手动赋值,再使用
3.作用范围不同(重点)
a.成员变量:作用于整个类
b.局部变量:只作用于自己所在的方法,其他方法使用不了
4.内存位置不同(了解)
a.成员变量:在堆中,跟着对象走
b.局部变量:在栈中,跟着方法走
5.生命周期不同(了解)
a.成员变量:随着对象的创建而产生,随着对象的消失而消失
b.局部变量:随着方法的调用而产生,随着方法的调用完毕而消失
【备注】 给引用数据类型赋值,需要new对象(String比较特殊,可以直接=赋值)
模块八:封装
第一章.封装
1.封装的介绍以及使用
1.面向对象三大特征: [封装] 继承 多态
2.什么是封装思想:
a.我们找来了一个对象(洗衣机),只需要按一下按钮就可以了(使用洗衣机功能的过程就是在使用面向对象思想编程的过程),每一个按钮下面都包含了很多内部结构的细节(细节被封装到按钮里面了->封装),在使用的时候有必要了解洗衣机的内部构造吗?我们没有必要去了解内部结构,我们只知道调用就可以了
所以,洗衣机来说,将细节隐藏起来了,细节我们不要关注,会对外提供了一个公共的接口(按钮),供我们人类使用
b.隐藏对象内部的复杂性,只对外提供公开,公共的接口,便于外界调用,从而提高了系统的可扩展性,可维护性,安全性,通俗来说,把该隐藏的隐藏起来(细节),把该暴露的暴露出来(对外提供的供别人使用的接口),这就是封装思想
我们只需要调用这个接口(功能)即可,此接口背后封装起来的细节就开始执行了,但是我们不需要关注细节,只关注公共的接口怎么调用
c.将细节隐藏起来,不让外界随便使用,但是我们可以提供一个公共的接口让外界间接使用隐藏起来的细节->封装思想
1.问题:
定义成员变量,只要是new出来对象,就可以随便调用,随便赋值,哪怕是不合理的值我们也挡不住,怎么办?
将属性封装起来(隐藏细节)
a.关键字:private(私有化的) -> 被private修饰的成员只能在本类中使用,在别的类中使用不了
b.注意:
将代码放到一个方法中,也是封装的体现
一个成员被private修饰也是封装的体现,只不过private最具代表性
c.private的使用:
修饰成员变量:private 数据类型 变量名
修饰方法:将public改成private,其他的都一样
2.问题:属性被私有化了,外界直接调用不了了,那么此时属性就不能直接赋值取值了,所以需要提供公共的接口
get/set方法
set方法:为属性赋值
get方法:获取属性值
2.this的介绍
1.如果成员变量和局部变量重名时,我们遵循"就近原则",先访问局部变量
2.this概述:代表的是当前对象
3.作用:this可以区分重名的成员变量和局部变量
this点出来的一定是成员的变量
4.this代表当前对象,那么具体代表哪个对象呢?
哪个对象调用的this所在的方法,this就代表哪个对象
3.构造方法
1.概述:方法名和类名一致并且能初始化对象的方法
2.分类:
a.无参构造:没有参数
b.有参构造:有参数,参数是为指定的属性赋值
c.满参构造:给所有属性赋值
以上构造咱们不用记那么详细,我们就记有参和无参构造就可以了
3.特点:
a.方法名和类名一致
b.没有返回值,连void都没有
3.1空参构造
1.格式:
public 类名(){
}
2.作用:
new对象使用
3.特点:
每个类中默认都有一个无参构造,不写也有,jvm会自动提供
4.使用:一new对象就是在调用构造方法
3.2有参构造
1.格式:
public 类名(形参){
为属性赋值
}
2.作用:
a.new对象
b.为属性赋值
3.特点:
jvm不会自动提供有参构造,但是将有参构造手写出来,jvm将不再提供无参构造,所以建议有参,无参的构造都手写上去
4.标准JavaBean
JavaBean是 Java语言编写类的一种标准规范。符合JavaBean` 的类,要求:
(1)类必须是具体的(非抽象 abstract)和公共的,public class 类名
(2)并且具有无参数的构造方法,有参构造
(3)成员变量私有化,并提供用来操作成员变量的set 和get 方法。
小结:
1.知道private的作用嘛?私有的,别的类不能直接调用
2.知道空参构造作用嘛?new对象
3.知道有参构造作用嘛? new对象 为属性赋值
4.知道set方法作用嘛? 为属性赋值
5.知道get方法作用嘛? 获取属性值
6.知道this的作用嘛? 区分重名的成员变量和局部变量
7.知道快捷键生成标准javabean嘛? alt+insert
5.JavaBean怎么来的
1.将来的javabean都是和数据库的表相关联
a.类名 -> 表名
b.属性名 -> 列名
c.对象 -> 表中每一行数据
d.属性值 -> 表中单元格中的数据
模块九:面向对象1
第一章.static关键字
1.static的介绍以及基本使用
1.概述:static是一个静态关键字
2.使用:
a.修饰一个成员变量:
static 数据类型 变量名
b.修饰一个方法:
修饰符 static 返回值类型 方法名(形参){
方法体
return 结果
}
3.调用静态成员:
类名直接调用(不用new对象)
4.静态成员特点:
a.静态成员属于类成员,不属于对象成员(非静态的成员属于对象成员)
b.静态成员会随着类的加载而加载
c.静态成员优先于非静态成员存在在内存中
d.凡是根据静态成员所在的类创建出来的对象,都可以共享这个静态成员
2.static修饰成员的访问特点
1.在静态方法中能直接访问非静态成员嘛? 不能
想要调用的话:new对象调用
2.在非静态方法中能直接访问静态成员嘛? 能
a.同类:
直接调用
类名调用
b.不同类:
类名调用
3.在静态方法中能直接访问静态成员嘛?能
a.同类:
直接调用
类名调用
b.不同类:
类名调用
4.在非静态方法中能直接访问非静态成员嘛?能
a.同类:
直接调用
new对象调用
b.不同类:
new对象调用
总结:
1.不管在不在同一个类中,非静态成员都可以new对象调用
2.不管在不在同一个类中,静态成员都可以类名调用
第二章.可变参数
1.介绍和基本使用
1.定义格式:
数据类型...变量名
2.注意:
a.可变参数的本质是一个数组
b.参数位置不能连续写多个可变参数,而且当可变参数和其他普通参数一起使用时,可变参数需要放到参数列表最后
第三章.递归
1.概述:方法内部自己调用自己
2.分类:
a.直接递归
public static void method(){
method()
}
b.间接递归:
A(){
B()
}
B(){
C()
}
C(){
A()
}
3.注意:
a.递归必须要有出口,否则会出现"栈内存溢出"
b.递归即使有出口,递归次数不不要太多
第四章.数组常见算法
1.数组翻转
public class Demo01Reverse {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7};
for (int min = 0,max = arr.length-1;min<max;min++,max--){
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
2.冒泡排序
数组的排序,是将数组中的元素按照大小进行排序,默认都是以升序的形式进行排序,数组排序的方法很多,我们讲解的是数组的冒泡排序。
排序,都要进行数组 元素大小的比较,再进行位置的交换。冒泡排序法是采用数组中相邻元素进行比较换位。 arri arr[i+1](后一个元素
public class Demo02Bubble {
public static void main(String[] args) {
//定义一个数组,长度为5,最大索引为4
int[] arr = {5,4,3,2,1};
/*
外层循环代表比较了几圈
n-1圈
*/
for (int j = 0; j < arr.length-1; j++) {
/*
内层循环代表每一圈比较的次数
每圈都少比较一次
*/
for (int i = 0; i < arr.length-1-j; i++) {
if (arr[i]>arr[i+1]){
int temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
3.二分查找
1.前提:数组中的数据必须是有序的
2.查询思想:
a.老式查询:遍历数组,一个一个比较 -> 查询效率慢
b.二分查找:每次找中间索引对应的元素进行比较查询(每一次查询少一半数据)
public class Demo03Binary { public static void main(String[] args) { int[] arr = {1,2,3,4,5,6,7,8,9}; int index = binary(arr, 60); System.out.println(index); }
public static int binary(int[] arr,int data){
//定义三个变量,分别代表最大索引,最小索引,中间索引
int min = 0;
int max = arr.length-1;
int mid = 0;
//查找
while(min<=max){
mid = (min+max)/2;
if (data>arr[mid]){
min = mid+1;
}else if(data<arr[mid]){
max = mid-1;
}else{
return mid;
}
}
return -1;
}
}
第五章.对象数组
第六章.方法参数
1.基本数据类型做方法参数传递
基本类型做方法参数传递,传递的是值,不是变量本身
方法运行:压栈
方法运行完毕:弹栈 -> 释放栈内存
2.引用数据类型做方法参数传递
引用数据类型做方法参数传递时,传递的是地址值
第七章.其他操作
1.快速生成方法
1.初学者要求先定义,再调用;不是初学者,就可以先调用,再定义方法
a.快捷键:alt+回车
2.快速将一段代码抽取到一个方法中:
a.选中要抽取的方法
b.按ctrl+alt+m
2.debug调试
1.概述:调试代码的一种手段
2.作用:
a.能清楚的看到每个变量在代码执行过程中的变化
b.找错
3.使用:
a.在想要开始debug的那一行左边点击一下,出现红色小圆点(断点)
b.右键-> 点击debug
模块十:面向对象2
第一章.继承
1.什么是继承
1.父类怎么形成的:我们的定义了多个类,发现这些类中有很多重复性的代码,我们就定义了一个父类,将相同的代码抽取出来放到父类中,其他的类直接继承这个父类,就可以直接使用父类中的内容了
2.怎么去继承: extends
子类 extends 父类
3.注意:
a.子类可以继承父类中私有和非私有成员,但是不能使用父类中私有成员
b.构造方法不能继承
2.继承如何使用
1.定义一个父类,在其中定义重复性的代码
2.定义一个子类继承父类 -> extends
子类 extends 父类
3.创建子类对象,直接使用父类中非私有成员
3.继承中,成员变量和成员方法的访问特点
3.1 成员变量
3.1.1 子类和父类中的成员变量不重名:
public class Fu {
int numFu = 100;
}
public class Zi extends Fu{
int numZi = 10;
}
public class Test01 {
public static void main(String[] args) {
//创建父类对象
Fu fu = new Fu();
System.out.println(fu.numFu);//父类中的numFu
//System.out.println(fu.numZi);//不能直接调用子类特有的成员
System.out.println("=================");
//创建子类对象
Zi zi = new Zi();
System.out.println(zi.numZi);
System.out.println(zi.numFu);//继承了父类,可以使用父类中非私有成员
}
}
总结:看等号左边是谁,先调用谁中的成员
如果等号左边是父类类型,只能调用父类中的成员变量,如果等号左边是子类类型,既能调用子类的,还能调用父类中继承过来的非私有成员
3.1.2.子类和父类中的成员变量重名
public class Fu {
int numFu = 100;
int num = 10000;
}
public class Zi extends Fu{
int numZi = 10;
int num = 1000;
}
public class Test01 {
public static void main(String[] args) {
//创建父类对象
Fu fu = new Fu();
System.out.println(fu.numFu);//父类中的numFu
//System.out.println(fu.numZi);//不能直接调用子类特有的成员
System.out.println(fu.num);//父类的
System.out.println("=================");
//创建子类对象
Zi zi = new Zi();
System.out.println(zi.numZi);
System.out.println(zi.numFu);//继承了父类,可以使用父类中非私有成员
System.out.println(zi.num);//子类的
}
}
总结:继承前提下,成员变量访问特点口诀:
看等号左边是谁,先调用谁中的成员,子类没有,找父类
3.2 成员方法
成员方法:看new的是谁,先调用谁中的方法,子类没有,找父类
继承中,成员变量访问特点:看等号左边是谁,先调用谁中的成员变量
成员方法访问特点:看new的是谁,先调用谁中的方法
4.方法的重写
1.概述:子类中有一个和父类方法名以及参数列表相同的方法
2.前提:继承
3.访问:看new的是谁,先调用谁中的,如果new的是子类,调用调用子类重写的方法,子类没有,找父类
4.检测是否为重写方法:在该方法上写
@Override
4.1.注意事项
1.子类重写父类方法之后,权限必须要保证大于等于父类权限(权限指的是访问权限)
public -> protected -> 默认 -> private
2.子类方法重写父类方法,方法名和参数列表要一样
3.私有方法不能被重写,构造方法不能被重写,静态方法不能被重写
4.子类重写父类方法之后,返回值类型应该是父类方法返回值类型的子类类型
4.2.使用场景
1.使用场景:功能升级改造,子类需要对父类中已经实现好的功能进行重新改造
第二章.super和this
1.继承中构造方法的特点
1.注意:new子类对象时,会先初始化父类(先走父类无参构造方法)
2.原因:
每个构造方法的第一行,默认都会有一个super(),不写jvm自动提供一个
super()代表的是父类无参构造
2.super和this的具体使用
2.1 super的具体使用
1.概述:代表的是父类引用
2.作用:可以调用父类中的成员
3.使用:
a.调用父类构造方法-> 在子类中的构造中写
super() -> 调用父类无参构造
super(实参) -> 调用父类有参构造
b.调用父类成员变量:
super.成员变量名
c.调用父类成员方法:
super.成员方法名(实参)
2.2 this的具体使用
1.this概述:代表的是当前对象(哪个对象调用的this所在的方法,this就代表哪个对象)
2.作用:
a.区分重名的成员变量和局部变量
b.调用当前对象中的成员
3.使用:
a.调用当前对象的构造:在构造中写
this():调用当前对象的无参构造
this(实参):调用当前对象的有参构造
b.调用当前对象的成员变量:
this.成员变量名
c.调用当前对象的成员方法:
this.成员方法名(实参)
4.注意:
不管是super还是this,只要在构造中使用,都必须在第一行,所以二者不能同时手写出来
3.继承的特点
1.继承只支持单继承,不能多继承
public class A extends B,C{} -> 错误
2.继承支持多层继承
public class A extends B{}
public class B extends C{}
3.一个父类可以有多个子类
public class A extends C{}
public class B extends C{}
4.构造方法不能继承,也不能重写
私有方法可以继承,但是不能被重写
静态方法可以继承,但是不能被重写
4.问题:如何为父类中private的成员变量赋值
4.1.利用set赋值
public class Employee {
private String name;
private int age;
public Employee() {
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
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 void work(){
System.out.println("工作");
}
}
public class Teacher extends Employee{
}
Teacher teacher = new Teacher();
teacher.setName("y");
teacher.setAge(18);
System.out.println(teacher.getName()+"..."+teacher.getAge());
4.2.利用构造方法赋值
public class Employee {
private String name;
private int age;
public Employee() {
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
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 void work(){
System.out.println("工作");
}
}
public class Manager extends Employee{
public Manager() {
}
public Manager(String name, int age) {
super(name, age);
}
}
Manager manager = new Manager("yy", 24);
System.out.println(manager.getName()+"..."+manager.getAge());
第三章.抽象
1.抽象的介绍
1.抽象类怎么来的?
抽取共性方法,放到父类中,发现方法没法实现,因为每个子类对此方法的实现方式细节不一样
此时方法体说不清道不明,可以定义成抽象方法
抽象方法所在的类一定是抽象类
2.关键字: abstract
3.抽象方法:
修饰符 abstract 返回值类型 方法名(参数);
4.抽象类:
public abstract class 类名{}
5.注意:
a.抽象方法所在的类一定是抽象类
b.抽象类中不一定非得有抽象方法
c.子类继承父类之后,需要重写父类
中所有的抽象方法,不然编译报错
d.抽象类不能new对象,只能通过new子类对象调动重写方法
6.可以将抽象类看成是一类事物的标准,要求只要是属于这一类的,都必须要拥有抽象类中的方法,必须要给我实现,怎么证明拥有了,怎么证明实现了呢?-> 重写
至于这个方法怎么实现,就看子类重写之后怎么写方法体了
public abstract class Animal {
public abstract void eat();
public abstract void drink();
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃骨头");
}
@Override
public void drink() {
System.out.println("狗喝水");
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void drink() {
System.out.println("猫喝水");
}
}
public class Test01 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.drink();
System.out.println("===================");
Cat cat = new Cat();
cat.eat();
cat.drink();
}
}
2.抽象的注意事项
1.抽象类不能直接new对象,只能创建非抽象子类的对象
2.抽象类中不一定非得有抽象方法,但是抽象方法所在的类一定抽象类
3.抽象类的子类,必须重写父类中的所有抽象方法,否则,编译报错,除非该子类也是抽象类
4.抽象类中可以有成员变量,构造,成员方法
5.抽象类中可以有构造方法,是供子类创建对象时,初始化父类属性使用的
模块11:面向对象3
第一章.接口
1.## 接口的定义以及使用
1.接口:是一个引用数据类型,是一种标准,规则
2.关键字:
a.interface 接口
public interface 接口名{}
b.implements 实现
实现类 implements 接口名{}
3.接口中可以定义的成员:
a.jdk7以及之前:
抽象方法: public abstract -> 即使不写public abstract,默认也有
成员变量:public static final 数据类型 变量名 = 值-> 即使不写public static final,默认也有
final是最终的,被final修饰的变量不能二次赋值,所以我们一般将final修饰的变量视为常量
b.jdk8:
默认方法:public default 返回值类型 方法名(形参){}
静态方法:public static 返回值类型 方法名(形参){}
c.jdk9开始:
私有方法:
private的方法
1.定义接口:
public interface 接口名{}
2.实现:
public class 实现类类名 implements 接口名{}
3.使用:
a.实现类实现接口
b.重写接口中的抽象方法
c.创建实现类对象(接口不能直接new对象)
d.调用重写的方法
2.接口中的成员
2.1抽象方法
1.定义格式:
public abstract 返回值类型 方法名(形参);
2.注意:
不写public abstract 默认也有
3.使用:
a.定义实现类,实现接口
b.重写抽象方法
c.创建实现类对象,调用重写的方法
2.2默认方法
1.格式:
public default 返回值类型 方法名(形参){
方法体
return 结果
}
2.使用:
a.定义实现类,实现接口
b.默认方法可重写,可不重写
c.创建实现类对象,调用默认方法
2.3静态方法
1.定义格式:
public static 返回值类型 方法名(形参){
方法体
return 结果
}
2.使用:
接口名直接调用
2.4成员变量
1.格式:
public static final 数据类型 变量名 = 值
2.相关知识点:final
final代表最终的,被它修饰的变量,不能二次赋值,可以视为常量
3.特点:
不写public static final 默认也有
4.使用:
接口名直接调用
5.注意:
a.被static final修饰的成员变量需要手动赋值
b.习惯上我们会将static final修饰的成员变量名大写
3.接口的特点
1.接口可以多继承 -> 一个接口可以继承多个接口
public interface InterfaceA extends InterfaceB,InterfaceC{}
2.接口可以多实现 -> 一个实现类可以实现一个或者多个接口
public class InterfaceImpl implements InterfaceA,InterfaceB{}
3.一个子类可以继承一个父类的同时实现一个或者多个接口
public class Zi extends Fu implements InterfaceA,InterfaceB{}
4.注意:
继承也好,实现接口也罢,只要是父类中或者接口的抽象方法,子类或者实现类都要重写
4.接口和抽象类的区别
相同点:
a.都位于继承体系的顶端,用于被其他类实现或者继承
b.都不能new
c.都包含抽象方法,其子类或者实现类都必须重写这些抽象方法
不同点:
a.抽象类:一般作为父类使用,可以有成员变量,构造,成员方法,抽象方法等
b.接口:成员单一,一般抽取接口,抽取的都是方法,视为功能的大集合
c.类不能多继承,但是接口可以
第二章.多态
1.多态的介绍
1.前提:
a.必须有子父类继承或者接口实现关系
b.必须有方法的重写(没有重写,多态没有意义),多态主要玩儿的是重写方法
c.new对象:父类引用指向子类对象
Fu fu = new Zi() -> 理解为大类型接收了一个小类型的数据 ->比如 double b = 10
2.注意:
多态不能直接调用子类特有功能
2.多态的基本使用
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃骨头");
}
//特有方法
public void lookDoor(){
System.out.println("狗会看门");
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//特有方法
public void catchMouse(){
System.out.println("猫会捉老鼠");
}
}
public class Test01 {
public static void main(String[] args) {
//原始方式
Dog dog = new Dog();
dog.eat();//重写的
dog.lookDoor();//特有的
Cat cat = new Cat();
cat.eat();//重写的
cat.catchMouse();//特有的
System.out.println("==================");
//多态形式new对象
Animal animal = new Dog();//相当于double b = 10
animal.eat();//重写的 animal接收的是dog对象,所以调用的是dog中的eat
// animal.lookDoor(); 多态前提下,不能直接调用子类特有成员
Animal animal1 = new Cat();
animal1.eat();//cat重写的
}
}
3.多态的条件下成员的访问特点
3.1成员变量
public class Fu {
int num = 1000;
}
public class Zi extends Fu{
int num = 100;
}
public class Test01 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.num);
}
}
看等号左边是谁,先调用谁中的成员变量
3.2成员方法
public class Fu {
int num = 1000;
public void method(){
System.out.println("我是父类中的method方法");
}
}
public class Zi extends Fu{
int num = 100;
public void method(){
System.out.println("我是子类中的method方法");
}
}
public class Test01 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.num);//父类中的num
fu.method();//子类中重写的method方法
}
}
看new的是谁,先调用谁中的成员方法,子类没有,找父类
4.多态的好处(为什么学多态)
1.问题描述:
如果使用原始方式new对象(等号左右两边一样),既能调用重写的,还能调用继承的,还能调用自己特有的成员
但是多态方式new对象,只能调用重写的,不能直接调用子类特有的成员,那为啥还要用多态呢?
2.多态方式和原始方式new对象的优缺点:
原始方式:
a.优点:既能调用重写的,还能调用父类非私有的,还能调用自己特有的
b.缺点:扩展性差
多态方式:
a.优点:扩展性强
b.缺点:不能直接调用子类特有功能
Fu fu = new Zi()
double b = 10;
b = 100L;
【注意】形参传递父类类型,调用此方法父类类型可以接收任意它的子类对象。 传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法
5.多态中的转型
5.1向上转型
1.父类引用指向子类对象
好比是: double b = 1;
5.2向下转型
1.向下转型:好比强转,将大类型强制转成小类型
2.表现方式:
父类类型 对象名1 = new 子类对象() -> 向上转型 -> double b = 1
子类类型 对象名2 = (子类类型)对象名1 -> 向下转型 -> int i = (int)b
3.想要调用子类特有功能,我们就需要向下转型
6.转型可能会出现的问题
1.如果等号左右两边类型不一致,会出现类型转换异常(ClassCastException)
2.解决:
在向下转型之前,先判断类型
3.怎么判断类型: instanceof
判断结果是boolean型
4.使用:
对象名 instanceof 类型 -> 判断的是关键字前面的对象是否符合关键字后面的类型
模块12:面向对象4
第一章.权限修饰符
1 概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
-
public:公共的,最高权限,被public修饰的成员,在哪里都能访问
-
protected:受保护的
-
default::默认的 注意 不写权限修饰符就是默认权限,不能直接把default写出来
-
private:私有的,只能在自己的类中直接访问
我们只需要知道一个成员被这四个权限修饰符修饰在4种情况下能不能访问就行了
2 不同权限的访问能力
public | protected | default(空的) | private |
| ------- | ------ | --------- | ----------- | ------- |
| 同类 | yes | yes | yes | yes |
| 同包不同类 | yes | yes | yes | no |
| 不同包子父类 | yes | yes | no | no |
| 不同包非子父类 | yes | no | no | no |
public具有最大权限,private有最小权限
编写代码时,如果没有特殊的考虑,建议这样使用权限:
1.属性:用private -> 封装思想
2.成员方法public -> 便于调用
3.构造public -> 便于new对象
第二章.final关键字
1.概述:最终的
2.使用:
a.修饰一个类
b.修饰一个方法
c.修饰一个局部变量
d.修饰一个成员变量
e.修饰一个对象
3.怎么学final:只需要知道被final修饰之后特点是啥即可
1.final修饰类
1.格式:
public final class 类名{}
2.特点:
被final修饰的类不能被继承
2.final修饰方法
1.格式:
修饰符 final 返回值类型 方法名(形参){
方法体
return 结果
}
2.特点:
被final修饰的方法,不能被重写
3.注意:
final和abstract不能同时修饰一个方法
3.final修饰局部变量
1.格式:
final 数据类型 变量名 = 值
2.特点:
被final修饰的变量不能二次赋值
4.final修饰对象
1.格式:
final 数据类型 对象名 = new 对象();
2.特点:
被final修饰的对象,地址值不能改变,但是对象中的属性值可以改变
5.final修饰成员变量
1.格式:
final 数据类型 变量名 = 值
2.特点:
a.需要手动赋值
b.不能二次赋值
第三章.代码块
1.构造代码块
1.格式:
{
代码
}
2.执行特点:优先于构造方法执行,每new一次,就会执行一次
public class Person {
public Person(){
System.out.println("我是无参构造方法");
}
//构造代码块
{
System.out.println("我是构造代码块");
}
}
2.静态代码块
1.格式:
static{
代码
}
2.执行特点:
静态代码块优先于构造代码块和构造方法执行的,而且只执行一次
public class Person {
public Person(){
System.out.println("我是无参构造方法");
}
//构造代码块
{
System.out.println("我是构造代码块");
}
//静态代码块
static{
System.out.println("我是静态代码块");
}
}
3.静态代码块使用场景
如果想让一些数据最先初始化,而且只需要初始化一次,就可以将这些数据放到静态代码块中
第四章.内部类
1.什么时候使用内部类:
当一个事物的内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又只为外部事物提供服务,那么整个内部的完成结构最好使用内部类
比如:人类都有心脏,人类本身需要用属性,行为去描述,那么人类内部的心脏也需要心脏特殊的属性和行为去描述,此时心脏就可以定义成内部类,人类中的一个心脏类
2.在java中允许一个类的定义位于另外一个类内部,前者就称之为内部类,后者称之为外部类
class A{
class B{
}
}
类A就是类B的外部类
类B就是类A的内部类
3.分类:
成员内部类(静态,非静态)
局部内部类
匿名内部类(重点)
1 静态成员内部类
1.格式:直接在定义内部类的时候加上static关键字
public class A{
static class B{
}
}
2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以被final或者abstract修饰
被final修饰之后,不能被继承
被abstract修饰之后,不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰
3.调用静态内部类成员:
外部类.内部类 对象名 = new 外部类.内部类()
public class Person {
public void eat(){
System.out.println("人要干饭");
}
static class Heart{
public void jump(){
System.out.println("心脏哐哐哐跳");
}
}
}
public class Test01 {
public static void main(String[] args) {
// 外部类.内部类 对象名 = new 外部类.内部类()
Person.Heart heart = new Person.Heart();
heart.jump();
}
}
2 非静态成员内部类
1.格式:直接在定义内部类的时候加上static关键字
public class A{
class B{
}
}
2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以被final或者abstract修饰
被final修饰之后,不能被继承
被abstract修饰之后,不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰
3.调用非静态内部类成员:
外部类.内部类 对象名 = new 外部类().new 内部类()
public class Person {
public void eat(){
System.out.println("人要干饭");
}
class Heart{
public void jump(){
System.out.println("心脏哐哐哐跳");
}
}
}
public class Test01 {
public static void main(String[] args) {
// 外部类.内部类 对象名 = new 外部类().new 内部类()
Person.Heart heart = new Person(). new Heart();
heart.jump();
}
}
外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时,怎么区分?
public class Student {
String name = "yy";
class Heart{
String name = "yyyy";
public void display(String name){
System.out.println(name);//内部类的局部变量
System.out.println(this.name);//内部类的成员变量
System.out.println(Student.this.name);//外部类的成员变量
}
}
}
public class Test02 {
public static void main(String[] args) {
Student.Heart heart = new Student().new Heart();
heart.display("yy");
}
}
3.局部内部类
3.1.局部内部类基本操作
1.可以定义在方法中,代码块中,构造中
public class Person {
public void eat(){
class Heart{
public void jump(){
System.out.println("心脏哐哐哐的跳");
}
}
new Heart().jump();
}
}
public class Test01 {
public static void main(String[] args) {
Person person = new Person();
person.eat();
}
}
3.2.局部内部类实际操作
3.2.1.接口类型作为方法参数传递和返回
1.接口作为方法参数,传递实参时,传递的是实现类对象
2.接口作为返回值类型返回,实际返回的是实现类对象
public interface USB {
public abstract void open();
}
public class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标打开");
}
}
public class Test01 {
public static void main(String[] args) {
Mouse mouse = new Mouse();
method(mouse);
System.out.println("================");
USB usb = method01();//USB usb = new Mouse();
usb.open();
}
/*
接口作为方法参数,传递实参时,传递的是实现类对象
*/
public static void method(USB usb){//USB usb = mouse -> 多态
usb.open();
}
/*
接口作为返回值类型返回,实际返回的是实现类对象
*/
public static USB method01(){
//Mouse mouse = new Mouse();
//return mouse;
return new Mouse();
}
}
3.2.2.抽象类作为方法参数和返回值
1.抽象类作为方法参数传递,传递实参时,传递的是其子类对象
2.抽象类作为方法返回值类型返回时,实际返回的是其子类对象
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃骨头");
}
}
public class Test02 {
public static void main(String[] args) {
Dog dog = new Dog();
method01(dog);
System.out.println("=================");
Animal animal = method02();//Animal animal = new Dog()
animal.eat();
}
public static void method01(Animal animal){//Animal animal = dog
animal.eat();
}
public static Animal method02(){
return new Dog();
}
}
3.2.3.普通类做方法参数和返回值
普通类作为方法参数传递,传递的是对象
普通类作为方法返回值返回,返回的是对象
public class Person {
public void eat(){
System.out.println("人要干饭");
}
}
public class Test03 {
public static void main(String[] args) {
Person person = new Person();
method01(person);
System.out.println("==================");
Person person1 = method02();//Person person1 = new Person()
person1.eat();
}
public static void method01(Person person){
person.eat();
}
public static Person method02(){
return new Person();
}
}
3.2.4.局部内部类实际操作
public interface USB {
void open();
}
public class Test01 {
public static void main(String[] args) {
USB usb = method();//USB usb = new Mouse()
usb.open();
}
public static USB method(){
//局部内部类
class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标打开");
}
}
return new Mouse();
}
}
4.匿名内部类(重点)
1.问题描述:我们如果想实现接口,简单使用一次抽象方法,我们就需要创建一个实现类,实现这个接口,重写抽象方法,还要new实现类对象,所以我们在想如果就单纯的想使用一次接口中的方法,我们能不能不这么麻烦呢?可以
a.创建实现类,实现接口
b.重写方法
c.创建实现类对象
d.调用方法
2.如果就想单纯的使用一下接口中的方法,我们就没必要经过以上四步了,我们可以四合一
3.匿名内部类怎么学:就按照一种格式来学,这一种格式就代表了实现类对象或者子类对象
4.格式:
new 接口/抽象类(){
重写方法
}.重写的方法();
=================================
类名 对象名 = new 接口/抽象类(){
重写方法
}
对象名.重写的方法();
1.什么时候使用匿名内部类:
当简单调用一次接口中的方法,我们就可以使用匿名内部类
2.将一种格式代表实现类对象或者子类对象来看待,来学习
3.匿名内部类会编译生成的,咱们不要管,我们只需要利用咱们讲的格式去new对象,调用重写的方法即可
4.1 匿名内部类复杂用法_当参数传递
public interface USB {
void open();
}
public class Test01 {
public static void main(String[] args) {
method01(new USB() {
@Override
public void open() {
System.out.println("usb打开了");
}
});
}
public static void method01(USB usb){
usb.open();
}
}
4.2 匿名内部类复杂用法_当返回值返回
public interface USB {
void open();
}
public class Test02 {
public static void main(String[] args) {
USB usb = method01();
usb.open();
}
public static USB method01(){
return new USB() {
@Override
public void open() {
System.out.println("USB打开了");
}
};
}
}
模块13:异常、Object
第一章.异常
1.异常介绍
1.概述:代码出现了不正常的现象;在java中,异常都是一个一个的类
2.异常出现的过程
3.创建异常对象(了解)
1.关键字:throw
2.格式: throw new 异常
4.异常处理方式(重点)
4.1 异常处理方式一_throws
1.格式:在方法参数和方法体之间位置上写
throws 异常
2.意义:处理异常
将异常往上抛
4.2 异常处理方式一_throws多个异常
1.格式:throws 异常1,异常2
2.注意:
如果throws的多个异常之间有子父类继承关系,我们可以直接throws父类异常
如果不知道多个异常之间是否有子父类继承关系,我们可以直接throws Exception
4.3 异常处理方式二_try...catch
1.格式:
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}
4.4.异常处理方式二_多个catch
1.格式:
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}...
2.注意:
如果catch的多个异常之间有子父类继承关系,我们可以直接catch父类异常
如果不知道多个异常之间是否有子父类继承关系,我们也可以直接catch Exception
5.finally关键字
1.概述:代表的是不管是否触发了异常,都会执行的代码块
特殊情况:如果之前执行了System.exit(0)终止当前正在执行的java虚拟机
2.使用:都是配合try...catch使用
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}finally{
不管是否有异常,都会执行的代码
}
finally的使用场景:
1.关闭资源
2.原因:对象如果没有用了,GC(垃圾回收器)回收,用来回收堆内存中的垃圾,释放内存,但是有一些对象GC回收不了,比如:连接对象(Connection),IO流对象,Socket对象,这些对象GC回收不了,就需要我们自己手动回收,手动关闭
将来不能回收的对象new完之后,后续操作不管是否操作成功,是否有异常,我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中
6.抛异常时注意的事项
1.如果父类中的方法抛了异常,那么子类重写之后要不要抛?
可抛可不抛
2.如果父类中的方法没有抛异常,那么子类重写之后要不要抛?
不要抛
7.try_catch和throws的使用时机
1.如果处理异常之后,还想让后续的代码正常执行,我们使用try...catch
2.如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个统一的异常处理
1.编译时期异常是必须要处理的,不处理爆红,没法往下写
a.throws
b.try...catch
2.运行时期异常我们一般不处理,一旦出现运行时期异常,肯定是代码写的有问题,我们直接修改代码细节就行啦
8.自定义异常
1.定义一个类
2.如果继承Exception 就是编译时期异常
3.如果继承RuntimeException,就是运行时期异常
9.打印异常信息的三个方法
Throwable类中的方法:
String toString() :输出异常类型和设置的异常信息
String getMessage(): 输出设置的异常信息
void printStackTrace():打印异常信息是最全的:包括异常类型,信息,以及出现的行数等
第二章.Object类
1.概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类
1.Object中的toString
1.Object中的toString方法:返回该对象的字符串表示形式
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
2.注意:
a.如果没有重写Object中的toString方法,直接输出对象名会默认调用Object中的toString方法,直接输出地址值
b.如果重写了Object中的toString方法,再输出地址值,重写没有意义,所以重写完toString之后,应该返回对象的内容
3.总结:
如果直接输出对象名不想输出地址值,就重写Object中的toString方法
快速生成toString
alt+insert -> 选择toString -> 直接下一步
2.Object中的equals
1.概述:比较两个对象的地址值是否相等
public boolean equals(Object obj) {
return (this == obj);
}
== 针对于基本数据类型来说,比较的是值
== 针对于引用数据类型来说,比较的是地址值
2.注意:
a.如果没有重写Object中的equals方法,那么就会调用Object中的equals方法,比较对象的地址值
b.如果重写了Object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容
小结:
1.如果直接输出对象名不想输出地址值,重写toString方法
2.如果想比较两个对象的内容,就重写一下equals方法
3.怎么重写:alt+insert -> 选toString 或者equals and hashcode -> 啥也不要管 -> 一路下一步即可
3.Object中的clone方法
1.作用:复制一个属性值一样的新对象
2.使用:
需要被克隆的对象实现Cloneable
重写clone方法
第三章.经典接口
1.java.lang.Comparable
我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,之间使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?
Java给所有引用数据类型的大小比较,指定了一个标准接口,就是java.lang.Comparable接口:
package java.lang;
public interface Comparable{
int compareTo(Object obj);
}
那么我们想要使得我们某个类的对象可以比较大小,怎么做呢?步骤:
第一步:哪个类的对象要比较大小,哪个类就实现java.lang.Comparable接口,并重写方法
- 方法体就是你要如何比较当前对象和指定的另一个对象的大小
第二步:对象比较大小时,通过对象调用compareTo方法,根据方法的返回值决定谁大谁小。
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)大于0,返回正整数
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)小于0 返回负整数
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)等于0 返回零
代码示例:
public class Student implements Comparable{
private String name;
private int score;
public Student() {
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", score=" + score +
'}';
}
/*
this:代表students[i]
o:代表students[i+1]
如果students[i].getScore()-students[i+1].getScore()>0
证明数组中的前面一个对象比后面一个对象的分数高
*/
@Override
public int compareTo(Object o) {
Student s = (Student) o;
return this.getScore()- s.getScore();
}
}
2.java.util.Comparator
思考:
(1)如果一个类,没有实现Comparable接口,而这个类你又不方便修改(例如:一些第三方的类,你只有.class文件,没有源文件),那么这样类的对象也要比较大小怎么办?
(2)如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?
JDK在设计类库之初,也考虑到这种情况了,所以又增加了一个java.util.Comparator接口。
package java.util;
public interface Comparator{
int compare(Object o1,Object o2);
}
那么我们想要比较某个类的两个对象的大小,怎么做呢?步骤:
第一步:编写一个类,我们称之为比较器类型,实现java.util.Comparator接口,并重写方法
- 方法体就是你要如何指定的两个对象的大小
第二步:比较大小时,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入,根据方法的返回值决定谁大谁小。
- o1对象减o2大于0返回正整数
- o1对象减o2小于0返回负整数
- o1对象减o2等于0返回零
public class Student implements Comparator {
private String name;
private int score;
public Student() {
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", score=" + score +
'}';
}
/*
o1代表students[i]
o2代表students[i+1]
如果o1的分数大于o2的分数-> compare方法返回正整数
如果o1的分数小于o2的分数-> compare方法返回负整数
如果o1的分数等于o2的分数-> compare方法返回0
*/
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return s1.getScore()-s2.getScore();
}
}
模块14:基础API
第一章.String
1.String介绍
1.概述:String 类代表字符串
2.特点:
a.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例(对象)实现
凡是带双引号的,都是String的对象
String s = "abc"
"abc"就是对象;String就是对象的数据类型;s就是对象名
b.字符串是常量,它们的值在创建之后不能更改
String s = "hello"
s+="world" -> 会产生新对象
c.String 对象是不可变的,所以可以共享
String s1 = "abc"
String s2 = "abc"
2.String的实现原理
1.jdk8的时候:String底层是一个被final修饰的char数组-> private final char[] value;
2.jdk9开始到之后:底层是一个被final修饰的byte数组-> private final byte[] value;
一个char类型占2个字节
一个byte类型占1个字节 -> 省内存空间
字符串定义完之后,数组就创建好了,被final一修饰,数组的地址值直接定死
3.String的创建
1.String() -> 利用String的无参构造创建String对象
2.String(String original) -> 根据字符串创建String对象
3.String(char[] value) -> 根据char数组创建String对象
4.String(byte[] bytes) -> 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
a.平台:操作系统
b.操作系统默认字符集:GBK
GBK:一个中文占2个字节
UTF-8:一个中文占3个字节
而且,中文对应的字节一般都是负数
代码在idea中写的,idea启动的时候,会自动加一个启动参数,此启动参数为UTF-8
-Dfile.encoding=UTF-8
5.简化形式:
String 变量名 = ""
1.String(char[] value, int offset, int count)->将char数组的一部分转成String对象
value:要转String的char数组
offset:从数组的哪个索引开始转
count:转多少个
2.String(byte[] bytes, int offset, int length)->将byte数组的一部分转成String对象
bytes:要转String的byte数组
offset:从数组的哪个索引开始转
length:转多少个
4.String 面试题
问1:String s = new String("abc")共有几个对象? 2个
一个new本身 一个是"abc"
问2:String s = new String("abc")共创建了几个对象? 1个或者2个
就看abc有没有提前创建出来了
5.字符串常见问题
1.字符串拼接,如果等号右边是字符串字面值拼接,不会产生新对象
2.字符串拼接,如果等号右边有变量参数拼接,会产生新字符串对象
第二章.String的方法
1.判断方法
boolean equals(String s) -> 比较字符串内容
boolean equalsIgnoreCase(String s) -> 比较字符串内容,忽略大小写
2.获取功能
int length() -> 获取字符串长度
String concat(String s)-> 字符串拼接,返回新串儿
char charAt(int index) -> 根据索引获取对应的字符
int indexOf(String s) -> 获取指定字符串在大字符串中第一次出现的索引位置
String subString(int beginIndex) -> 截取字符串,从指定索引开始截取到最后,返回新串儿
String subString(int beginIndex,int endIndex) -> 截取字符串,从beginIndex开始到endIndex结束
含头不含尾,返回新串儿
3.转换功能
1.char[] toCharArray() -> 将字符串转成char数组
2.byte[] getBytes() -> 将字符串转成byte数组
3.String replace(CharSequence c1,CharSequence c2)-> 替换字符
CharSequence->String的接口
4.byte[] getBytes(String charsetName) -> 按照指定的编码将字符串转成byte数组
4.分割功能
1.String[] split(String regex)->按照指定的规则分割字符串
注意:regex写的是正则表达式 -> . 在正则表达式中代表任意一个字符
第三章.其他方法
1.boolean contains(String s) -> 判断老串儿中是否包含指定的串儿
2.boolean endsWith(String s) -> 判断老串儿是否以指定的串儿结尾
3.boolean startsWith(String s) -> 判断老串儿是否以指定的串儿开头
4.String toLowerCase()-> 将字母转成小写
5.String toUpperCase() -> 将字母转成大写
6.String trim() -> 去掉字符串两端空格
第四章.StringBuilder类
1.StringBuilder的介绍
1.概述:一个可变的字符序列,此类提供了一个与StringBuffer兼容的一套API,但是不保证同步(线程不安全,效率高)
2.作用:主要是字符串拼接
3.问题:
a.刚讲完String,String也能做字符串拼接,直接用+即可,但是为啥还要用StringBuilder去拼接呢?
b.原因:
String每拼接一次,就会产生新的字符串对象,就会在堆内存中开辟新的空间,如果拼接次数多了,会占用内存,效率比较底
StringBuilder,底层自带一个缓冲区(没有被final修饰的byte数组)拼接字符串之后都会在此缓冲区中保存,在拼接的过程中,不会随意产生新对象,节省内存
4.StringBuilder的特点:
a.底层自带缓冲区,此缓冲区是没有被final修饰的byte数组,默认长度为16
b.如果超出了数组长度,数组会自动扩容
创建一个新长度的新数组,将老数组的元素复制到新数组中,然后将新数组的地址值重新赋值给老数组
c.默认每次扩容老数组的2倍+2
如果一次性添加的数据超出了默认的扩容数组长度(2倍+2),比如存了36个字符,超出了第一次扩容的34,就按照实际数据个数为准,就是以36扩容
2.StringBuilder的使用
1.构造:
StringBuilder()
StringBuilder(String str)
常用方法:
StringBuilder append(任意类型数据) -> 字符串拼接,返回的是StringBuilder自己
StringBuilder reverse()-> 字符串翻转,返回的是StringBuilder自己
String toString() -> 将StringBuilder转成String-> 用StringBuilder拼接字符串是为了效率,为了不占内存,那么拼完之后我们后续可能会对拼接好的字符串进行处理,就需要调用String中的方法,所以需要将StringBuilder转成String
public class Demo02StringBuilder {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
StringBuilder sb1 = sb.append("张无忌");
System.out.println(sb1);
System.out.println(sb);
System.out.println(sb==sb1);
System.out.println("==============");
//链式调用
sb.append("赵敏").append("周芷若").append("小昭");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
String s = sb.toString();
System.out.println(s);
}
}
模块15:常用API
第一章.Math类
1.Math类介绍
1.概述:数学工具类
2.作用:主要用于数学运算
3.特点:
a.构造方法私有了
b.方法都是静态的
4.使用:
类名直接调用
2.Math类方法
static int abs(int a) -> 求参数的绝对值
static double ceil(double a) -> 向上取整
static double floor(double a) ->向下取整
static long round(double a) -> 四舍五入
static int max(int a, int b) ->求两个数之间的较大值
static int min(int a, int b) ->求两个数之间的较小值
第二章.BigInteger
1.BigInteger介绍
1.问题描述:我们操作数据,将来的数据有可能非常大,大到比long还要大,这种数据我们一般称之为"对象"
2.作用:
处理超大整数
3.构造:
BigInteger(String val) -> 参数的格式必须是数字形式
4.方法:
BigInteger add(BigInteger val) 返回其值为 (this + val) 的 BigInteger
BigInteger subtract(BigInteger val) 返回其值为 (this - val) 的 BigInteger
BigInteger multiply(BigInteger val) 返回其值为 (this * val) 的 BigInteger
BigInteger divide(BigInteger val) 返回其值为 (this / val) 的 BigInteger
2.BigInteger使用
int intValue() 将BigInteger转成int
long longValue() 将BigInteger 转成 long
BigInteger上限:42亿的21亿次方,内存根本扛不住,所以我们可以认为BigInteger无上限
第三章.BigDecimal类
1.BigDecimal介绍
1.问题描述:我们知道直接用float或者double做运算会出现精度损失的问题,所以将来设计到钱,我们就不能用float或者double直接做运算
2.作用:主要是解决float和double直接做运算出现的精度损失问题
3.构造方法:
BigDecimal(String val) -> val必须要是数字形式
4.常用方法:
static BigDecimal valueOf(double val) -> 此方法初始化小数时可以传入double型数据
BigDecimal add(BigDecimal val) 返回其值为 (this + val) 的 BigDecimal
BigDecimal subtract(BigDecimal val) 返回其值为 (this - val) 的 BigDecimal
BigDecimal multiply(BigDecimal val) 返回其值为 (this * val) 的 BigDecimal
BigDecimal divide(BigDecimal val) 返回其值为 (this / val) 的 BigDecimal
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
divisor:除号后面的那个数
scale:指定保留几位小数
roundingMode:取舍方式
static int ROUND_UP -> 向上加1
static int ROUND_DOWN -> 直接舍去
static int ROUND_HALF_UP -> 四舍五入
5.注意:
如果除不尽,会报错,出现运算异常
2.BigDecimal使用
double doubleValue() 将此BigDecimal转成double
3.BigDecimal除法过时方法解决
1.注意:如果调用的成员上面有一个横线,证明此成员过时了,底层会有一个注解@Deprecated修饰,但是过时的成员还能使用,只不过被新的成员代替了,不推荐使用了
2.方法:
divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
divisor:代表除号后面的数据
scale:保留几位小数
roundingMode:取舍方式-> RoundingMode是一个枚举,里面的成员可以类名直接调用
UP:向上加1
DOWN:直接舍去
HALF_UP:四舍五入
第四章.Date日期类
1.Date类的介绍
1.概述:表示特定的瞬间,精确到毫秒
2.常识:
a.1000毫秒 = 1秒
b.时间原点:1970年1月1日 0时0分0秒(UNIX系统起始时间),叫做格林威治时间,在0时区上
c.时区:北京位于东八区,一个时区经度差15度,时间相差一个小时,所以北京时间比时间原点所在时区时间差8个小时
d.北京经纬度:东经116 北纬39.56 -> 温带大陆性季风气候
e.赤道 本初子午线(0度经线)
2.Date类的使用
1.构造:
Date() -> 获取当前系统时间
Date(long time) -> 获取指定时间,传递毫秒值 -> 从时间原点开始算
3.Date类的常用方法
1.void setTime(long time) -> 设置时间,传递毫秒值-> 从时间原点开始算
2.long getTime()->获取时间,返回毫秒值
第五章.Calendar日历类
1.概述:日历类,抽象类
2.获取:Calendar中的方法:
static Calendar getInstance()
3.月份对比:
国外: 0 1 2 3 4 5 6 7 8 9 10 11
国内: 1 2 3 4 5 6 7 8 9 10 11 12
常用方法:
int get(int field) ->返回给定日历字段的值
void set(int field, int value) :将给定的日历字段设置为指定的值
void add(int field, int amount) :根据日历的规则,为给定的日历字段添加或者减去指定的时间量
Date getTime():将Calendar转成Date对象
field:代表的是日历字段-> 年 月 日 星期等,都是静态的
第六章.SimpleDateFormat日期格式化类
1.SimpleDateFormat介绍
1.概述:日期格式化类
2.构造:
SimpleDateFormat(String pattern)
3.pattern代表啥:代表的是我们自己指定的日期格式
字母不能改变,但是中间的连接符我们可以改变
yyyy-MM-dd HH:mm:ss
2.SimpleDateFormat常用方法
1.String format(Date date) -> 将Date对象按照指定的格式转成String
2.Date parse(String source)-> 将符合日期格式的字符串转成Date对象
第七章.JDK8新日期类
1. LocalDate 本地日期
1.1.获取LocalDate对象
1.概述:LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日
2.获取:
static LocalDate now() -> 创建LocalDate对象
static LocalDate of(int year, int month, int dayOfMonth) -> 创建LocalDate对象,设置年月日
1.2.LocalDateTime对象
1.LocalDateTime概述:LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒。
2.获取:
static LocalDateTime now() 创建LocalDateTime对象
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) 创建LocalDateTime对象,设置年月日时分秒
1.3.获取日期字段的方法 : 名字是get开头
int getYear()->获取年份
int getMonthValue()->获取月份
int getDayOfMonth()->获取月中的第几天
1.4.设置日期字段的方法 : 名字是with开头
LocalDate withYear(int year):设置年份
LocalDate withMonth(int month):设置月份
LocalDate withDayOfMonth(int day):设置月中的天数
1.5.日期字段偏移
设置日期字段的偏移量,方法名plus开头,向后偏移
设置日期字段的偏移量,方法名minus开头,向前偏移
2.Period和Duration类
2.1 Period 计算日期之间的偏差
方法:
static Period between(LocalDate d1,LocalDate d2):计算两个日期之间的差值
getYears()->获取相差的年
getMonths()->获取相差的月
getDays()->获取相差的天
2.2 Duration计算时间之间的偏差
1.static Duration between(Temporal startInclusive, Temporal endExclusive) -> 计算时间差
2.Temporal : 是一个接口
实现类:LocalDate LocalDateTime
3.参数需要传递 Temporal 的实现类对象, 注意要传递LocalDateTime
因为Duration计算精确时间偏差,所以需要传递能操作精确时间的 LocalDateTime
4.利用Dutation获取相差的时分秒 -> to开头
toDays() :获取相差天数
toHours(): 获取相差小时
toMinutes():获取相差分钟
toMillis():获取相差秒(毫秒)
如果计算年月日 ,就用Period
如果计算时分秒,就用Duration
3.DateTimeFormatter日期格式化类
1.获取:
static DateTimeFormatter ofPattern(String pattern) -> 获取对象,指定格式
2.方法:
String format(TemporalAccessor temporal)-> 将日期对象按照指定的规则转成String
TemporalAccessor:接口,子接口有Temporal
Temporal的实现类:LocalDate LocalDateTime
TemporalAccessor parse(CharSequence text)-> 将符合规则的字符串转成日期对象
如果想将TemporalAccessor转成我们常见的LocalDateTime日期对象,就需要用到LocalDateTime中的静态方法:
static LocalDateTime from(TemporalAccessor temporal)
第八章.System类
1.概述:系统相关类,是一个工具类
2.特点:
a.构造私有,不能利用构造方法new对象
b.方法都是静态的
3.使用:
类名直接调用
| 方法 | 说明 |
|---|---|
| static long currentTimeMillis() | 返回以毫秒为单位的当前时间,可以测效率 |
| static void exit(int status) | 终止当前正在运行的 Java 虚拟机 |
| static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length | 数组复制 src:源数组 srcPos:从源数组的哪个索引开始复制 dest:目标数组 ldestPos:从目标数组哪个索引开始粘贴 length:复制多少个元素 |
第九章.Arrays数组工具类
1.概述:数组工具类
2.特点:
a.构造私有
b.方法静态
3.使用:类名直接调用
| 方法 | 说明 |
|---|---|
| static String toString(int[] a) | 按照格式打印数组元素 [元素1, 元素2, ...] |
| static void sort(int[] a) | 升序排序 |
| static int binarySearch(int[] a, int key) | 二分查找(前提是升序) |
| static int[] copyOf(int[] original, int newLength) | 数组扩容 |
第十章.包装类
1.基本数据类型对应的引用数据类型(包装类)
1.概述:就是基本类型对应的类(包装类),我们需要将基本类型转成包装类,从而让基本类型拥有类的特性(说白了,将基本类型转成包装类之后,就可以使用包装类中的方法操作数据)
2.为啥要学包装类:
a.将来有一些特定场景,特定操作,比如调用方法传递包装类
比如:ArrayList集合,里面有一个方法add(Integer i),此时我们不能调用add方法之后直接传递基本类型,因为引用类型不能直接接收基本类型的值,就需要先将基本类型转成包装类,传递到add方法中
b.将来我们还可以将包装类转成基本类型:
包装类不能直接使用+ - * /,所以需要将包装类转成基本类型,才能使用+ - * /
| 基本类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Charactor |
| boolean | Boolean |
2.Integer的介绍以及使用
2.1.Integer基本使用
1.概述:Integer是int的包装类
2.构造: 不推荐使用了,但是还能用
Integer(int value)
Integer(String s) s必须是数字形式
1.装箱:将基本类型转成对应的包装类
2.方法:
static Integer valueOf(int i)
static Integer valueOf(String s)
1.拆箱:将包装类转成基本类型
2.方法:
int intValue();
2.2.自动拆箱装箱
1.拆箱和装箱很多时候都是自动完成的
public class Demo04Integer {
public static void main(String[] args) {
Integer i = 10;//发生了自动装箱了
Integer sum = i+10;//发生了自动拆箱装箱
System.out.println("sum = " + sum);
}
}
3.基本类型和String之间的转换
3.1 基本类型往String转
1.方式1:
+ 拼接
2.方式2:String中的静态方法
static String valueOf(int i)
3.2 String转成基本数据类型
每个包装类中都有一个类似的方法: parseXXX
| 位置 | 方法 | 说明 |
|---|---|---|
| Byte | static byte parseByte(String s) | 将String转byte类型 |
| Short | static short parseShort(String s) | 将String转成short类型 |
| Integer | static int parseInt(String s) | 将String转成int类型 |
| Long | static long parseLong(String s) | 将String转成long类型 |
| Float | static float parseFloat(String s) | 将String转成float类型 |
| Double | static double parseDouble(String s) | 将String转成double类型 |
| Boolean | static boolean parseBoolean(String s) | 将String转成boolean类型 |
1.在实际开发过程中如何定义一个标准javabean
定义javabean的时候一般会将基本类型的属性定义成包装类型的属性
public class User {
//private int uid;//用户id
private Integer uid;//用户id
private String username;//用户名
private String password;//密码
public User() {
}
public User(Integer uid, String username, String password) {
this.uid = uid;
this.username = username;
this.password = password;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
1.举例:如果uid为Integer型,默认值是null
2.将来javabean中的数据都是和数据库表联系起来的,我们可以将javabean中的数据添加到表中
如果表中的uid为主键自增的,此时添加语句时uid中的数据不用我们单独维护赋值了,添加语句的sql语句就可以这样写:
insert into user(uid,username,password) values (NULL,'yy','36666');
3.到时候,我们需要将javabean中封装的数据获取出来放到sql语句中,如果uid为主键自增,而且javabean中的uid为包装类型,默认值为NULL,这样就不用单独维护uid的值了,也不用先给javabean中的uid赋值,然后在保存到数据库中了,咱们就可以直接使用uid的默认值,将默认值放到sql语句的uid列中
4.而且将javabean中的属性变成包装类,还可以使用包装类中的方法去操作此属性值