Java的基础学习总结(上)
来源:001_Java语言发展史_哔哩哔哩_bilibili
Java概述
一、JAVA跨平台原理
平台->操作系统(Windows,Mac,Linux)
跨平台:Java可以在任意操作系统运行(需要安装对应版本Java虚拟机,JVM:Java Virtual Machine)
JRE和JDK
JRE:Java Runtime Environment,是Java程序的运行环境,包括JVM+核心类库;
JDK:Java Development Kit,是Java程序开发工具包,包括JRE+开发工具(编译工具javac.exe、运行工具java.exe)
因此在官网安装JDK就行。
二、JDK的安装目录
bin(重点目录):存放JDK的各种工具命令(例如javac.exe和java.exe);
conf:存放了JDK的相关配置文件;
include:存放了一些特定的头文件;
jmods:存放了JDK的各种模块;
legal:存放了JDK各模块的授权文档;
lib:存放了JDK工具的一些补充jar包;
其余文件为说明性文档。
第一个程序
一、常用DOS命令:
【win+r】打开命令窗口;
【盘符名称:】切换盘符;
【dir】查看目录;
【cd 目录】访问单级目录;
【cd 目录1/目录2】访问多级目录;
【cd..】回退上一级;
【cd /】回退到根目录;
【cls】清屏;
【exit】退出命令窗口
二、path环境变量配置
为了方便使用javac和java命令,在高级系统设置中配置环境变量:
1、新建JAVA_HOME变量,变量值是JDK的安装目录
2、编辑Path变量,新建变量值%JAVA_HOME%\bin
三、HelloWorld案例
JAVA程序开发步骤编写程序、编译程序、运行程序
用txt(或者NotePad)写好源程序后,后缀名改为.java,打开命令提示符窗口,进入到HelloWorld.java所在目录,编译javac 文件名"javac HelloWorld.java",运行java 类名"java HelloWorld"
基础语法:
一、注释
【单行注释】// 注释信息
【多行注释】/ * 注释信息 * /
【文档注释】/** 注释信息 */
java中程序的基本组成单位【类】,public class 类名{},main方法是程序的入口方法,代码的执行是从main方法开始的。
二、关键字
Java语言赋予了特殊含义的单词,英文小写,代码编辑器一般有特殊的颜色标记,例如private、class、true
三、常量
值不可以改变,包括字符串常量、整数常量、小数常量、字符常量、布尔常量、空常量null(只有它不可以直接输出)
四、数据类型
计算机存储设备的最小信息单元是位bit,而计算机最小的存储单元叫字节byte。1B=8bit、 1KB=1024B 、1MB=1024KB 、1GB=1024MB 、ITB=1024GB,不同的数据类型分配了不同的内存空间,Java是强类型语言。
五、变量
值可以改变的量。数据类型 变量名=变量值;
例如int a=10;取值就使用变量名a,修改值就用变量名=修改值,a=20;
变量的注意事项:
1、变量名不能重复;
2、变量必须赋值使用;
3、long类型变量定义的时候,后面要加l(整数默认是int);
4、float类型变量定义的时候,后面要加f(浮点数默认是double);
六、标识符
1、由数字、字母、下划线_、美元符$组成;
2、不能数字开头;
3、不能是关键字;
4、区分大小写,常见的命名约定有小驼峰命名法(firstName,常用于方法、变量)和大驼峰命名法(GoodStudent,常用于类)
七、类型转换
自动类型转换
表示数据范围小的数值赋值给另一个表示数据范围大的变量,例如double a=10;
强制类型转换
表示数据范围大的数值赋值给另一个表示数据范围小的变量,会存在数据丢失的问题,例如int k =(int)88.88;
运算符
运算符:对常量/变量进行操作的符号
表达式:用运算符把常量/变量连接起来,符合java语法的式子
一、算术运算符
(+、-、* 、/、%)
+(字符参与的话,涉及到计算机底层对应的数值进行计算,如'A'-65,'a'-97,'0'-48;字符串参与,则是进行拼接,注意+操作从左到右执行) 、-、*、/(整数相除只能得到整数,要想得到小数必须有浮点数参与)、%
算术表达式包含多个基本数据类型的时候,整个算术表达式的类型会自动提升,提升规则:1、byte/short/char自动提升到int;2、整个表达式的类型自动提升到表达式中的最高等级操作数的类型(等级顺序:byte-short,char-int-long-float-double)
二、赋值运算符
(=、+=、-=、* =、/=、%=)
=以及扩展赋值运算符+=、-=、*=、/=、%=,扩展运算符底层隐含了强制类型转换)、自增自减运算符(++自增、--自减,单独使用时效果一样。参与操作的时候,如果在后边,就先拿变量操作再++/--;如果在前边,就先++/--再让变量参与操作
三、关系运算符
(==、!=、>、>=、<、<=)
四、逻辑运算符
(&、|、&&、||)
连接关系表达式/布尔类型的常变量的运算符(&、|、^不同为true、!),另外有短路逻辑运算符&&、||,存在短路不执行右边的情况
五、三元运算符
(关系表达式?表达式1:表达式2;),先计算关系表达式的值,为true运算结果就是表达式1的值,否则就是表达式2的值
流程控制
1、顺序结构:按照代码的先后顺序,依次执行
2、分支结构
3、循环结构
分支语句
一、if语句
//格式一
if(关系表达式)
{语句体;}
首先计算关系表达式的值,如果为true执行语句体,为false就不执行。最终都要继续执行后面的语句。
//格式二
if(关系表达式)
{语句体1;}
else
{语句体2;}
首先计算关系表达式的值,如果为true执行语句体1,为false就执行语句体2。最终都要继续执行后面的语句。
//格式三
if(关系表达式1)
{语句体1;}
else if(关系表达式2)
{语句体2;}
..
else
{语句体n+1;}
首先计算关系表达式1的值,如果为true执行语句体1,为false就计算关系表达式2的值,值为true则执行语句体2,为false则计算关系表达式3的值...如果没有任何关系表达式true,就执行语句体n+1。最终都要继续执行后面的语句。
二、switch语句
1、表达式:取值为byte、 short、 int、 char,JDK5以后可以是枚举,JDK7以后可以是String;
2、case:后面跟的是要和表达式进行比较的值;
3、break:表示中断,结束的意思,用来结束switch语句;
4、default:表示所有情况都不匹配的时候,就执行该处的内容,和if语句的else相似
//格式
switch(表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
循环语句
循环结构
1、初始化语句:用于表示循环开启时的起始状态。简单说就是循环开始的时候什么样;
2、条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去;
3、循环体语句:用于表示循坏反复执行的内容,简单说就是循环反复执行的事情;
4、条件控制语句:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去
循环结构对应的语法
1、初始化语句:这里可以是一条或者多条语句,这些语句可以完成一些初始化操作;
2、条件判断语句:这里使用一个结果值为boolean类型的表达式,这个表达式能决定是否执行循环体。例如: a<3;
3、循环体语句:这里可以是任意语句,这些语句将反复执行;
4、条件控制语句:这里通常是使用一条语句来改变变量的值,从而达到控制循环是否继续向下执行的效果。常见i++,i--这样的操作
一、for循环语句
【执行流程】
1、执行初始化语句;
2、执行条件判断语句,看其结果是true还是false;
如果是false,循环结束
如果是true,继续执行
3、执行循环体语句;
4、执行条件控制语句;
5、回到第2点继续
//格式
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
二、while循环语句
【执行流程】
1、执行初始化语句;
2、执行条件判断语句,看其结果是true还是false;
如果是false,循环结束
如果是true,继续执行
3、执行循环体语句;
4、执行条件控制语句;
5、回到第2点继续
//格式
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句;
}
三、do..while循环语句
【执行流程】
1、执行初始化语句
2、执行循环体语句
3、执行条件控制语句
4、执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行回到第2点继续
//格式
初始化语句;
do{
循环体语句;
条件控制语句;
}while(条件判断语句);
四、三种循环的区别
1、for循环、while循环先判断后执行;do..while循环先执行后判断
2、条件控制语句的自增变量,for循环结束后就不能再访问了,while循环结束后还可以继续使用
五、死循环格式
for(;;){}
while(true){}
do{}while(true);
六、跳转控制语句
1、continue 用在循环中,基于条件控制,跳过某次循环体内容的执行,继续下一次的执行
2、break 用在循环中,基于条件控制,终止循环体内容的执行,也就是说结束当前的整个循环
七、循环嵌套
分支语句中包含分支语句成为分支嵌套;
循环语句中包含循环语句成为循环嵌套;
八、Random:用于产生一个随机数
使用步骤
1、导包
import java.util.Random
2、创建对象
Random r=new Random();
3、获取随机数
int number = r.nextInt(10);//获取数据的范围[0,10)
IDEA学习
一、概述
全称IntelliJ IDEA,是用于Java语言开发的集成环境(把代码编写、编译、执行、调试等多功能综合一起的开发工具),是业界公认的目前用于Java程序开发最好的工具。
二、IDEA写HelloWorld
1、创建一个空项目
2、创建一个新模块
3、在新模块的src下创建一个包
4、在包下新建一个类
5、在类中编写代码并执行程序
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
三、项目结构
四、内容辅助键和快捷键
psvm:快速生成main方法
sout:快速生成输出语句
Tab:内容提升、代码补全等
Ctrl+/:单行注释
Ctrl+Shift+/:多行注释
Ctrl+Alt+L:格式化
五、模块操作
新建模块、删除模块、导入模块
数组
一、数组定义格式
数组array:用于存储多个相同类型数据的存储模型
【格式一】“定义了一个int类型的数组,数组名是arr”
//数据类型[] 变量名
int[] arr
【格式二】“定义了一个int类型的变量,变量名是arr数组”
//数据类型 变量名[]
int arr[]
二、数组动态初始化
数组必须先初始化再使用!
初始化:为数组元素分配内存空间,并为每个数组元素赋值。
动态初始化:只指定数组长度,由系统为数组分配初始值。
【格式】数据类型[] 变量名 = new 数据类型[数组长度]
int[] arr=new int[5];// (new是申请内存空间,5就是元素个数)
三、数组元素访问
数组变量访问【格式】数组名
数组内部保存的数据访问【格式】数组名[索引]
索引:是数组中数据的编号,从0开始,连续的,逐1增加的,用于访问数组中的数据,数组名[索引]等同于变量名,是特殊的变量名
int[] arr = new int[3]; //默认赋值0,输出arr是地址。
四、内存分配
Java程序运行时需要在内存中分配空间,为了提高效率,对空间进行了不同区域的划分,每片区域都有特定的数据处理方式、内存管理方式。
int[] arr = new int[3];
单个数组:
多个数组:
多个数组指向相同:
栈内存:存储局部变量,定义在方法中的变量例如arr,使用完毕,立即消失;
堆内存:存储new出来的内容(实体、对象),每一个new出来的东西都有一个地址值,使用完毕,会在垃圾回收器空闲时回收。
数组初始化时,会为存储空间添加默认值:整数:0/浮点数:0/布尔值:false/字符:空字符/引用数据类型:null。
五、数组静态初始化
静态初始化:初始化时指定每个元素的初始值,由系统决定数组长度。
【格式】数据类型[] 变量名 = new 数据类型[]{a1,a3,a3...};
int[] arr = new int[]{1,2,3};
【简化格式】数据类型[] 变量名 = {a1,a2,a3};
int[] arr = {1,2,3};
六、数组操作常见小问题
1、索引越界 ArrayIndexOutOfBoundsException:访问了数组中不存在的索引对应的元素
2、空指针异常 NullPointerException
arr = null:访问的数组已经不再指向堆内存的数据,造成空指针异常。null,空值,引用数据类型的默认值,表示不指向任何有效对象。
七、数组常见操作
1、遍历(利用循环)
获取数组元素数量(arr.length),得到遍历通用格式:
int[] arr = {11,22,33};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
2、获取最值
思路:定义一个变量保存最大/小值,取数组的第一个数据作为变量的初始值,与数组其余数据逐个比对。
int[] arr = {121,22,421,43};
int max;
max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max=arr[i];
}
}
System.out.println("arr的最大值:"+max);
}
方法
一、方法概述
方法method:是将具有独立功能的代码块组织成一个整体,使其具有特殊功能的代码集
方法必须创建才可以使用,这个过程称为方法定义
方法创建后不是直接运行的,需要手动使用后才执行,该过程成为方法调用
方法必须先定义后调用!
二、无参方法的定义和调用
//方法定义的格式
public static void 方法名() {
//方法体
}
//方法调用的格式
方法名();
三、带参方法的定义和调用
public static void 方法名(参数) {
//方法体
}
//单个参数
public static void 方法名(数据类型 变量名) {
//方法体
}
//多个参数
public static void 方法名(数据类型 变量名1,数据类型 变量名2) {
//方法体
}
//方法调用的格式
方法名(参数);
1、方法定义时,数据类型和变量名缺一不可;
2、方法定义时,多个参数直接用","隔开
形参与实参
形参:方法定义中的参数,等同于变量定义格式,例如int number
实参:方法调用中的参数,等同于使用变量/常量,例如 10 / number
四、带返回值方法的定义和调用
定义
public static 数据类型 方法名(参数) {
return 数据;
}
方法定义时,return后面的返回值与方法定义上的数据类型要匹配!
调用
//格式一
方法名(参数);
//格式二
数据类型 变量名 = 方法名(参数);
方法的返回值通常使用变量接收,否则该返回值将无意义!
五、方法的注意事项
- 方法不能嵌套定义
- void表示无返回值,可以省略return,也可以单独书写return,后面不加数据
public static void method(){
//代码片段
}
public static void method(){
//代码片段
return;
}
方法的通用格式
public static 返回值类型 方法名(参数){
//方法体
return 数据;
}
- public static 修饰符
- 返回值类型 方法操作完毕后返回数据的数据类型,如果没有数据返回则写void,一般不写return
- 方法名 调用方法时使用的标识
- 参数 由数据类型和变量名组成,多个参数用,隔开
- 方法体 完成功能的代码块
- return 如果方法操作完毕有数据返回则用于把数据返回给调用者
定义方法时,两个明确
1、明确返回值类型(方法操作完毕后是否有数据返回,没有是写void,有是写对应的数据类型)
2、明确参数(明确参数的类型和数量)
调用方法时
void类型的方法直接调用、非void的方法推荐用变量接收调用
六、方法重载
方法重载:指同一个类中定义的多个方法间的关系,满足下列条件的多个方法相互构成重载:
1、多个方法在同一个类中
2、多个方法具有相同的方法名
3、多个方法参数不相同,类型不同或数量不同
方法重载的特点
1、重载仅对应方法的定义,与调用无关
2、重载仅针对同一个类中方法的名称和参数进行识别,与返回值无关
七、方法的参数传递
对于基本类型的参数,形参的改变,不影响实参的值!
对于引用类型的参数,形参的改变影响实参的值!
Debug
Debug:
供程序猿使用的程序调试工具,可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序。Debug调试:
又称为“断点调试”,断点其实是一个标记,告诉我们从哪里开始查看
要学习如何加断点、如何运行加了断点的程序、看哪里、点哪里、如何删除断点。如果数据来自键盘输入,一定要先输入数据,否则不能继续往下查看。
加断点
选择要设置断点的代码行,在行号的区域后面单击鼠标左键
如何运行加了断点的程序
在代码区域,右键Debug执行
看哪里
看Debugger窗口+console窗口
点哪里
点Step Into(F7)这个箭头或者直接按F7
点Stop结束
删除断点
选择要删除的断点,再次点击断点即可,多个断点也可以一次性全部删除
面向对象基础
一、类和对象
对象:万物皆对象,客观存在的事物皆为对象
类:现实生活中一类具有共同属性和行为的事物的抽象
属性:对象的各种特征,每个对象的每个属性都拥有特定的值
行为:对象能够执行的操作
类的特点
1、类是对象的数据类型
2、类是具有相同属性和行为的一组对象的集合
类的定义
- 类的重要性:是java程序的基本组成单位
- 类是现实生活中一类具有共同属性和行为的事物的抽象,确定对象将会拥有的属性和行为。
- 类的组成:属性+行为
属性:在类中通过成员变量来体现(类中方法外的变量)
行为:在类中通过成员方法来体现(和前面的方法相比,去掉static关键字)
类的定义步骤
1、定义类
2、编写类的成员变量
3、编写类的成员方法
public class 类名 {
//成员变量
变量1的数据类型 变量1;
变量2的数据类型 变量2;
...
//成员方法
方法1;
方法2;
...
}
对象的使用
创建对象:
【格式】类名 对象名 = new 类名();
例如Phone p =new Phone();
使用对象:
1、使用成员变量 【格式】对象名.变量名 例如p.brand
2、使用成员方法 【格式】对象名.方法名() 例如p.call()
二、对象内存图
单个对象
多个对象
多个对象指向相同
指向相同时,一个对象的修改,影响另一个对象!
三、成员变量和局部变量
成员变量 :类中方法外的变量
局部变量:方法中的变量
四、封装
private关键字
- 是一个权限修饰符
- 可以修饰成员(成员变量和成员方法)
- 作用:保护成员不被别的类使用,仅限本类访问
如果其他类要使用:
需提供get变量名() 方法,用于获取成员变量的值,方法用public修饰
需提供set变量名(参数) 方法,用于设置成员变量的值,方法用public修饰
标准类的编写
- 把成员变量用private修饰
- 提供对应的getXXX()/setXXX()方法
this关键字
this修饰的变量用于指代成员变量!
- 方法形参若和成员变量同名,不带this的变量指形参
- 方法形参和成员变量不同名,不带this的变量指成员变量
什么时候用this:解决局部变量隐藏成员变量
this:代表所在类的对象引用,方法被哪个对象调用,this就代表哪个对象
this的内存原理
封装
封装,面向对象三大特征之一(封装、继承、多态),是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
封装原则:将某些信息隐藏在类内部,不允许外部程序直接访问,通过该类提供的方法来实现对隐藏信息的操作和访问,成员变量private,提供对应的getXXX()/setXXX()方法
封装好处:通过方法控制成员变量的操作,提高了代码的安全性,把代码方法进行封装,提高了代码的复用性。
五、构造方法
构造方法是一种特殊的方法,作用是创建对象,功能主要是完成对象数据的初始化。
//格式
public class 类名{
修饰符 类名(参数){
//一般是public修饰,也可无参构造
}
}
构造方法的注意事项
- 创建:如果没有定义构造方法,默认有一个无参构造方法;如果定义了构造方法,系统将不再提供默认的无参构造方法。
- 重载:如果自定义了带参构造方法,还要使用无参构造方法,就必须再写一个无参构造方法
- 推荐:无论是否使用,都写好无参构造方法!
字符串
一、API
API:Application Programming Interface,应用程序编程接口
JAVA API:指的是JDK中提供的各种功能的Java类
如何使用帮助文档
1、找到帮助文档的索引,输入关键字进行查找
2、在输入框输入Random
3、看类在哪个包下(java.lang不用导包)
4、看类的描述
5、看构造方法
6、看成员方法
调用方法的时候,方法有明确的返回值的话,我们要用变量接收,可以手动,也可以使用快捷键Alt+Enter
二、String
概述
String在java.lang包下,使用的时候不需要导包
String类代表字符串,java程序的所有字符串文字(例如"abc")都被实现为此类的实例,也就是所有双引号字符串,都是String类的对象。
字符串的特点
- 字符串不可变,他们的值在创建后不能被更改
- 虽然值不可变,但是它们可以被共享
- 字符串效果上相当于字符数组char[],但是底层原理是字节数组byte[] (JDK8以前是字符数组,JDK9以后是字节数组)
String构造方法
String对象的特点
1、通过new创建的字符串对象,每一次new都会申请一个内存空间,虽然内容相同,但是地址值不同。
char[] chs = {'a','b','c'};
String s1 = new String(chs);
String s2 = new String(chs);
JVM会首先创建一个字符数组,每一次new都会有一个新地址,只不过s1和s2参考的字符串内容是相同的。
2、以""方式给出的字符串,只要字符序列相同(顺序、大小写),JVM只会建立一个String对象,并在字符串池中维护。
String s3 = "anan";
String s4 = "anan";
针对第一行代码,JVM会建立一个String对象放在字符串池,给s3参考。第二行则让s4直接参考字符串池中的String对象,也就是本质上说他们其实是同一个对象。
字符串的比较
"=="的比较:
- 基本类型:比较的是数据值
- 引用类型:比较的是地址值(String对象就是比较的地址值)
字符串想要比较内容,是通过一个方法实现的:equals()
public boolean equals(Object anObject):将此字符串与指定对象进行比较,比较字符串对象的话,参数直接传递一个字符串。
通过帮助文档,查看String中的方法
三、StringBuilder
概述
对字符串进行+=直接进行拼接,耗时、浪费空间 String内容不可变
解决方案:StringBuilder
StringBuilder是一个可变的字符串类,可以看成一个容器,这里的可变是StingBuilder对象中的内容是可变的。
StringBuilder构造方法
StringBuilder的添加和反转方法
StringBuilder和String相互转换
1、StringBuilder->String:
用StringBuilder的toString()方法public String toString()
2、String->StringBuilder:
用StringBuilder的构造方法public StringBuilder(String s)
通过帮助文档查看StringBuilder的方法
集合基础
概述
使用长度固定的数组存储格式,不一定满足需求。
集合的特点:提供一种存储空间可变的存储模型,存储的数据容量可变。集合有很多种,先学ArrayList<E>:
- 可调整大小的数组实现
- <E>是一种特殊的数据类型,泛型。在所有出现E的地方,使用引用数据类型替换即可。ArrayList<String>或者 ArrayList<Student>
ArrayList构造方法和添加方法
ArrayList集合常用方法
继承
继承概述
继承是面向对象三大特征之一,可以使子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法。
子类可以有父类的内容,还可以有自己特有的内容。
【格式】public class 子类名 extends 父类名{ }
父类,也叫超类,基类;子类,也叫派生类。
继承的好处和弊端
- 提高了代码的复用性
- 提高了代码的维护性
- 但是增加了类的耦合性,削弱了子类的独立性
什么时候用继承
假设有两个类AB,如果满足A是B的一种或者B是A的一种,就说明存在继承关系。
继承中子类访问变量的特点
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
- 如果没有就报错(不考虑父亲的父亲)
super
- this:代表本类对象的引用
- super:代表父类存储空间的标识(可理解为父类对象引用)
继承中构造方法的访问特点
子类中所有的构造方法都会默认访问父类的无参构造方法(完成父类数据的初始化,每个子类构造方法的第一句默认是super();)
如果父类没有无参构造方法,可以显式调用super(参数),父类的带参构造方法。或者在父类中手动提供无参构造方法。
继承中成员方法的访问特点
通过子类对象访问一个方法:
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲)
继承中的方法重写
子类中出现了和父类一模一样的方法声明
应用:当子类需要父类的功能,而功能主体子类有自己的特有内容时,可以重写父类的方法,这样既沿袭了父类的功能,又定义了子类特有的内容。@Override是一个注解,检查重写方法的方法声明的正确性。
注意事项
- 私有方法不能被重写(父类的私有成员,子类是不能被继承的)
- 子类方法的权限只能>=父类的(public > 默认 > 私有)
- Java中,类只支持单继承,但支持多层继承
修饰符
一、包
其实就是文件夹,作用是对类进行分类管理
定义格式:package 包名;(多级包用.分开),例如package com.itheima;
带包的java类编译和执行:
- 手动建包:编译java文件
javac HelloWorld.java,在相应磁盘下建立对应的文件夹,把class文件放到文件夹下,带包执行:java com.itheima.HelloWorld - 自动建包
javac -d . HelloWorld.java、java com.itheima.HelloWorld
二、导包
使用不同包下的类,使用的时候除了写类的全路径,还可以直接导包。格式:import 包名; 例如import cn.itcast.Teacher
三、修饰符
权限修饰符
状态修饰符
1、final(最终态):可以修饰成员变量(常量),成员方法(不可重写),类(不能被继承),局部变量(基本类型变量-数据值不可变;引用类型变量-地址值不可变,内容可变)
2、static(静态):可以修饰成员变量,成员方法。
- 被类的所有对象共享(这也是是否使用静态关键字的条件)
- 可以通过类名调用,当然也可用对象名调用。
静态成员方法只能访问静态成员!非静态的没有限制
多态
同一个对象,在不同时刻表现出的不同形态
例如,猫 cat = new 猫(); 动物 animal = new 猫();这里的猫就在不同时刻表现出了不同的形态,这就是多态。
多态的前提和体现
- 有继承/实现关系
- 有方法重写
- 有父类引用指向子类对象
多态中成员访问特点
成员变量:编译看左边,执行看左边
成员方法:编译看左边,执行看右边
为什么访问不一样呢。因为成员方法有重写,成员变量没有
多态的好处和弊端
1、好处:提高了程序的扩展性。定义方法的时候,使用父类型作为参数,将来实现的时候,使用具体的子类型参与操作。
2、弊端:不能使用子类的特有功能。
多态的转型
1、向上转型:从子到父,父类引用指向子类对象Animal a = new Cat();
2、向下转型:从父到子,父类引用转换为子类对象Cat c = (Cat)a
多态转型内存图图解
抽象类
在java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
public abstract class Animal {
public abstract void eat();
}
抽象类的特点
- 抽象类和抽象方法都必须使用abstract关键字修饰:
public abstract class 类名{};public abstract void eat(); - 抽象类里不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类不能实例化,但是可以参照多态的方式,通过子类对象实例化,这叫抽象类多态
- 抽象类的子类,要么重写抽象类所有的抽象方法,要么是抽象类
抽象类的成员特点
- 成员变量:可以是变量,也可以是常量;
- 构造方法:有,但是不能实例化,它的作用是用于子类访问父类数据的初始化
- 成员方法:可以有抽象方法限定子类必须完成的动作,也可以有非抽象方法:提高代码的复用性。
接口
接口就是一种公用的规范标准,只要符合规范标准,大家都可以通用。java中的接口更多体现在对行为的抽象。
接口的特点
- 接口用关键字interface修饰
public interface 接口名{} - 类实现接口用implements表示
public class 类名 implements 接口名{} - 接口不能实例化,但是可以参照多态的方式,通过实现类对象实例化,这叫接口多态。
多态的形式:具体类多态、抽象类多态、接口多态。
多态的前提:有继承/实现关系,有方法重写,有父类/接口引用指向子/实现类对象 - 接口的实现类:要么重写接口中所有的抽象方法,要么是抽象类
接口的成员特点
- 成员变量,只能是常量
public static final - 没有构造方法。因为接口主要是对行为进行抽象,没有具体存在。一个类如果没有父类,默认继承自Object类。
- 成员方法,只能是抽象方法
public abstract
类和接口的关系
【类和类的关系】继承关系,只能单继承,但是可以多层继承
【类和接口的关系】实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
【接口和接口的关系】继承关系,可以单继承、多继承
抽象类和接口的区别
【成员】
抽象类:变量;常量;有构造方法;有抽象和非抽象方法;
接口:常量;抽象方法;
【关系区别】
类与类:继承,单继承
类与接口:实现,单实现,多实现
接口与接口:继承、单继承、多继承
【设计理念区别】
抽象类:对事物的抽象,包括属性、行为
接口:对行为抽象,主要是行为
形参和返回值
类名作为形参和返回值
作为形参时:需要的是该类的对象
作为返回值时,返回的是该类的对象
抽象类名作为形参和返回值
作为形参时:需要的是该抽象类的子类对象
作为返回值时,返回的是该抽象类的子类对象
接口名作为形参和返回值
作为形参时:需要的是该接口的实现类对象
作为返回值时,返回的是该接口的实现类对象
内部类
内部类:就是在一个类中定义一个类,也就是内部类
public class 类名 {
修饰符 class 类名{
}
}
public class Outer {
public class Inner{
}
}
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建包裹它的外层类的对象
按照内部类在类中定义位置不同,可以分为如下两种形式:
在类的成员位置:成员内部类
在类的局部位置:局部内部类
一、成员内部类
如何创建对象使用:
【格式】外部类名.内部类名 对象名 = 外部类对象.内部类对象Outer.Inner oi = new Outer.new Inner();(内部类如果是私有的,这个格式不可行),常用:在Outer类里定义有关方法。
public class Outer {
private int num =10;
private class Inner{
public void show(){
System.out.println(num);
}
}
public void method(){
Inner i = new Inner();
i.show();
}
}
二、局部内部类
public class Outer {
private int num =10;
public void method(){
class Inner{
public void show(){
System.out.println(num);
}
}
Inner i = new Inner();
i.show();
}
}
局部内部类是在方法中定义的类,外界无法直接使用,需要在方法内部创建对象并使用。该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
三、匿名内部类(局部内部类的特殊形式)
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类;
本质:是一个继承了该类或者实现了该接口的子类匿名对象
【格式】
new 类名/接口名(){
重写方法;
}
常用API
一、Math
Math包含执行基本数字运算的方法,没有构造方法,但类的成员都是静态的,可以通过类名直接调用。
二、System
System包含几个有用的类字段和方法,不能被实例化
三、Object
Object是类层次结构的根,每个类都可以将Object作为超类,所有类都是直接或者间接的继承该类
构造方法:public Object()
子类的构造方法默认访问的是父类的无参构造方法,因为他们的顶级父类中只有无参构造方法。
四、Arrays
冒泡排序:n个元素,两两比较,一共n-1轮,每轮参与的元素-1个
int[] arr = {12,34,3,21,5};
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
Arrays的概述和常用方法
Arrays类包含用于操作数组的各种方法
Arrays属于工具类,工具类的设计思想:
- 构造方法用private修饰
- 成员用public static修饰
int[] arr = {12,324,53,2,51};
System.out.println("转为字符串:"+ Arrays.toString(arr));
Arrays.sort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
五、基本类型包装类
概述
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。
常用的操作之一:用于基本数据类型和字符串之间的转换
Integer类的概述和使用
Integer:包装一个对象中的原始数据类型int的值
Integer i1 = new Integer(100);
System.out.println(i1);
Integer i2 = new Integer("100");
System.out.println(i2);
// Integer i3 = new Integer("abc");//NumberFormatException 只接受数字型的字符串
// System.out.println(i3);
// 推荐使用静态方法
Integer ii1 = Integer.valueOf(100);
System.out.println(ii1);
Integer ii2 = Integer.valueOf("100");
System.out.println(ii2);
int和String的相互转换
基本类型包装类的最常见操作就是:用于基本类型和字符串之间的相互转换
1、int->String
public static String valueOf(int i) 返回int参数的字符串表现形式,该方法是String类中的方法
int num = 100;
// 方式一
String s1 = ""+num;
System.out.println(s1);
// 方式二
String s2=String.valueOf(num);
System.out.println(s2);
2、String->int
public static int parseInt(String s)将字符串解析为int类型,该方法是Integer类中的方法
String s = "100";
// 方式一
Integer i = Integer.valueOf(s);
int intValue = i.intValue();
System.out.println(intValue);
// 方式二
int intValue2 = Integer.parseInt(s);
System.out.println(intValue2);
自动装箱和拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
Integer i = Integer.valueOf(100);//装箱
Integer ii = 100;//自动装箱
// ii = ii.intValue() + 200;
ii+=200;//自动拆箱、自动装箱
Integer iii = null;
if(iii !=null){//所以需要先判断
iii+=300;//NullPointerException
}
// 使用包装类型前最好先判断是否为null
// 事实上,只要是对象,使用前就必须进行不为null的判断
六、日期类
Date类的概述和使用
Date代表了一个特定的时间,精确到毫秒
Date类的常用方法
Date d = new Date();
long time = d.getTime();
System.out.println(time*1.0/1000/60/60/24/365+"年");
long t = 1000*60*60;
d.setTime(t);//由于东八区 Thu Jan 01 09:00:00 CST 1970
System.out.println(d);
long tt=System.currentTimeMillis();
d.setTime(tt);
System.out.println(d);//Thu Jan 26 11:04:39 CST 2023
SimpleDateFormat类概述和使用
SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。
日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从'A'到'Z'以及从'a'到'z'引号的字母被解释为表示日期和时间字符串的组件的模式字母
常见的模式字母及对应关系:y年M月d日H时m分s秒
构造方法:
1、格式化(Date->String)
public final String format(Date date),将日期格式化成日期/时间字符串
2、解析(String->Date)
public Date parse(String source),从给定字符串的开始解析文本以生成日期
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(date);
System.out.println(s);//2023-01-26 11:49:31
String ss="2022-12-4 23:00:21";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = sdf2.parse(ss);
System.out.println(parse);//Sun Dec 04 23:00:21 CST 2022
Calendar(日历)类概述和使用
Calendar为某一时刻和一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法。
Calendar提供了一个类方法getInstance用于获取Calendar对象,其日历字段已使用当前日期和时间初始化:Calendar rightNow = Calendar.getInstance();
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1;
int d = c.get(Calendar.DATE);
System.out.println(y+"年"+m+"月"+d+"日");//2023年1月27日
Calendar的常用方法
Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR, -4);
c.add(Calendar.MONTH, 2);
int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1;
int d = c.get(Calendar.DATE);
System.out.println(y + "年" + m + "月" + d + "日");//2019年3月27日
c.set(2028,9,21);
y = c.get(Calendar.YEAR);
m = c.get(Calendar.MONTH);
d = c.get(Calendar.DATE);
System.out.println(y + "年" + m + "月" + d + "日");//2028年9月21日
异常
概述
Throwable: java所有错误和异常的超类
异常:就是程序出现了不正常的情况
异常体系:
1、Error:严重问题,不需要处理
2、Exception:异常类,表示程序本身可处理的问题
- RuntimeException:编译期间不检查,出现问题后需要回来修改代码,例如ArrayIndexOutOfBoundsException
- 非RuntimeException:编译期间必须处理,否则程序不能通过编译,就不能正常运行
JVM的默认处理方案
如果程序出了问题,我们没有做任何处理,最终jvm会做默认处理:把异常的名称,异常原因,异常出现的位置等信息输出在控制台
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at com.review.Demo.method(Demo.java:16)
at com.review.Demo.main(Demo.java:11)
异常处理
如果程序出现了问题,我们需要自己处理,有两种方案:
- try..catch
- throws
try{
可能出现异常的代码
}catch (异常类名 变量名){
异常的处理代码
}
System.out.println("开始");
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
System.out.println("结束");
Throwable的成员方法
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
// System.out.println(e.getMessage());;//出现异常的原因 Index 3 out of bounds for length 3
// System.out.println(e.toString());//出现异常的类名及原因 java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
e.printStackTrace();//报错最全,常用java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at com.review.Demo.main(Demo.java:14)
}
编译时异常和运行时异常的区别
异常分为编译时异常和运行时异常,也被称为受检异常和非受检异常。 所有的RuntimeException类及其子类被称为运行时异常,其他的异常就是编译时异常。
编译时异常:必须显示处理,否则程序会发生错误,无法通过编译
运行时异常:无需显示处理,也可以和编译时异常一样处理
异常处理之throws
throws只是抛出异常,没有处理,真正的处理还是需要try catch,程序才能继续往下执行。
编译时异常必须要进行处理,两种处理方案,try catch或者throws,如果用throws,将来谁调用谁处理。
运行时异常可以不处理,出现问题后需要回来修改代码。
自定义异常
【格式】
public class 异常类名 extends Exception {
无参构造;
带参构造;
}
自定义异常:
public class ScoreException extends Exception {
public ScoreException() {
}
public ScoreException(String message) {
super(message);
}
}
使用自定义异常:
public class Teacher {
public void checkScore(int score) throws ScoreException{
if(score<0||score>100){
throw new ScoreException("分数异常");
}else {
System.out.println("分数正常");
}
}
}
测试自定义异常:
public class ScoreTest {
public static void main(String[] args) {
System.out.println("输入分数:");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
Teacher teacher = new Teacher();
try {
teacher.checkScore(i);
} catch (ScoreException e) {
e.printStackTrace();//com.review.ScoreException: 分数异常
// at com.review.Teacher.checkScore(Teacher.java:6)
// at com.review.ScoreTest.main(ScoreTest.java:12)
}
}
}
throws和throw的区别:
集合进阶
一、Collection
集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。
集合类的体系结构
集合和概述
Collection是单例集合的顶层接口,表示一组对象,这些对象也成为Collection的元素,JDK不提供此接口的任何直接实现,它提供更具体的子接口(如List和Set)实现
创建Collection集合的对象:
- 多态
- 具体的实现类
Collection集合常用方法
Collection集合的遍历
Iterator:迭代器,集合的专用遍历方式。
Iterator< E > iterator(): 返回此集合中元素的迭代器,通过集合的iterator()方法得到。迭代器是通过集合的iterator方法得到的,所以我们说它是依赖于集合存在的。
Iterator中的常用方法:
E next():返回迭代中的下一个元素
boolean hasNext():如果迭代具有更多元素,则返回true
Collection<String> c = new ArrayList<>();
c.add("hello");
c.add("world");
c.add("anan");
Iterator<String> iterator = c.iterator();
while (iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
集合的使用步骤
二、List
List集合概述和特点
- 有序集合(序列),用户可以精确控制列表中每个元素的插入位置,可以通过整数索引访问元素,并搜索列表中的元素
- 与Set集合不同,允许重复的元素
有序:存储和取出的顺序一致;
可重复:存储的元素可以重复
List集合特有方法
并发修改异常
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
Iterator<String> it = list.iterator();
// while (it.hasNext()){
// String s = it.next();
// if(s.equals("world")){
// list.add("anan");
// }
// }
// System.out.println(list);//ConcurrentModificationException
for (int i = 0; i < list.size(); i++) {
if(list.get(i).equals("world")){
list.add("anan");
}
}
System.out.println(list);//[hello, world, java, anan]
并发修改异常:ConcurrentModificationException
产生原因:迭代器遍历的过程中,通过集合对象修改了集合元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一样
解决方案:用for循环遍历,然后用集合对象做对应的操作即可
ListIterator列表迭代器
通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器。允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置。
常用方法:
E next() 返回迭代中的下一个元素
boolean hasNext() 如果迭代具有更多元素,则返回true
E previous() 返回列表中的上一个元素
boolean hasPrevious() 如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
增强for循环
简化数组和Collection集合的遍历
- 实现Iterable接口的类允许其对象成为增强型for循环的目标
- 它是JDK5以后出现的,其内部原理是一个Iterator迭代器
【格式】
for(元素数据类型 变量名:数组或者Collection集合){
//在此使用变量即可,该变量就是元素
}
int[] arr ={1,23,45};
for(int i:arr){
System.out.println(i);
}
String[] arr2 ={"ai","sa"};
for (String s:arr2){
System.out.println(s);
}
List<String> list = new ArrayList<>();
list.add("hello");
list.add("hello2");
list.add("hello3");
for(String s:list){
System.out.println(s);
}
数据结构
数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素的集合。精心选的数据结构可以带来更高的运行或者存储效率。
1、栈:
2、队列:
常见数据结构之数组
常见数据结构之链表
List集合子类特点
List集合常用子类:ArrayList,LinkedList
ArrayList:底层数据结构是数组,查询快,增删慢
LinkedList:底层数据结构是链表,查询慢,增删快
LinkedList集合的特有功能:
三、Set
特点
- 不包含重复元素的集合
- 没有带索引的方法,所以不能使用普通for循环遍历
哈希值
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。Object类中有一个方法可以获取对象的哈希值。public int hashCode()。默认情况,不同对象的哈希值不相同,可以通过方法重写实现不同对象的哈希值相同。String就重写了。
HashSet集合的概述和特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不做保证,不保证存储和取出的顺序一致
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以是不包含重复元素的集合
常见数据结构之哈希表
JDK8前,底层采用数组+链表实现,可以说是一个元素为链表的数组,JDK8之后,在长度比较长的时候,底层实现了优化。
先比较哈希值取余16后的数字,对应不同的位置。如果位置相同,看有没有元素,有的话比较哈希值是否相同,如果相同再比较equals内容,如果不同就可以存。
LinkedHashSet集合的概述和特点
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 由哈希表保证元素唯一,也就是没重复的元素
TreeSet集合的概述和特点
- 元素有序,这里不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法。
TreeSet():根据元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序 - 没有带索引的方法,所以不能使用普通for循环遍历
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素排序,自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法,重写方法时,一定要注意排序规则必须按照主要条件和次要条件来写;带参构造方法使用的是比较器排序,比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compareTo(T o1,T o2)方法,重写方法时,一定要注意排序规则必须按照主要条件和次要条件来写。
四、泛型
泛型,是JDK5以后引入的特性。它提供了编译时类型安全检测机制。该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用、调用时传入具体的类型。这种参数类型可以用在类、方法、接口中,分别成为泛型类、泛型方法、泛型接口。
参数定义格式
<类型>:指定一种类型的格式,这里的类型可以看作形参
<类型1,类型2..>:指定多种类型的格式
将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型。
泛型的好处
把运行时期的问题提前到编译期间;避免了强制类型转换
泛型类
【定义格式】
修饰符 class 类名<类型>{}
例如:public class Generic< T >{}
的T可以为任意标识,常见T.K.V.E等
泛型方法
【定义格式】
修饰符<类型>返回值类型 方法名(类型 变量名){}
例如:public< T > void show (T t){}
泛型接口
【定义格式】
修饰符 interface 接口名<类型>{}
例如:public interface Generic< T >{}
类型通配符
为了表示各种泛型List的父类,可以使用类型通配符 < ? >
List< ? >:表示元素类型未知的List,它的元素可以匹配任何的类型。这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中。如果只希望它代表某一类泛型List的父类,可以使用类型通配符的上限。< ? extends 类型>,例如List< ? extends Number>表示它的类型是Number或者其子类型。也可以指定类型通配符的下限。< ? super 类型 >,例如List< ? super Number>表示它的类型是Number或者其父类型。
可变参数
可变参数,也称参数个数可变,用作方法的形参出现。
【格式】修饰符 返回值类型 方法名(数据类型...变量名){}
例如:public static int sum(int...a)
这里的a是一个数组。如果有多个参数,包含可变参数,可变参数要放在最后。
可变参数的使用
Arrays工具类中有一个静态方法:public static < T > List< T > asList(T...a) 返回由指定数组支持的固定大小的列表。不能使用添加、删除,可以修改。
List接口中有一个静态方法:public static < E > List< E > of(E...elements) 返回包含任意数量元素的不可变列表。可重复元素,不能添加、删除,也不能修改。
Set接口中有一个静态方法:public static < E > Set< E > of(E...elements) 返回一个包含任意数量元素的不可变集合。不可重复元素,不能添加、删除,没有修改的方法(因为没有索引)。
五、Map
Map集合概述和使用
Interface Map<K,V> K:键的类型 V:值的类型
将键映射到值的对象,不包含重复的键,每个键可以映射到最多一个值。创建Map集合的对象:多态的方式,具体的实现类HashMap。Hash主要是保证键唯一不重复。
Map集合的基本功能
Map集合的获取功能
Map集合的遍历
方式一:获取所有键的集合,用keySet()方法实现;遍历键的集合,获取到每一个键,用增强for实现;根据键去找值,用get(Object key)方法实现。
方式二:获取所有键值对对象的集合,Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合;遍历键值对对象的集合,增强for实现,得到每一个Map.Entry;根据键值对对象获取键和值:getKey()、getValue()
TreeMap可以对键进行排序。
六、Collections
Collections类是针对集合操作的工具类。
常用方法:
public static< T extends Comparable< ?super T> > void sort(List< T > list) 将指定的列表按升序排序
public static void reserve(List< ? > list) 反转指定列表中元素的顺序
public static void shuffle(List< ? > list) 使用默认的随机源随机排列指定的列表
更多内容接“Java基础学习总结(下)”