Java学习旅程-(一)基础篇

261 阅读1小时+

一、计算机基础

Windows常用DOS命令 :
shutdown -s -t 300     5分钟后关闭计算机 image.png 打开计算机 :
     按下 win+R 键,输入 calc 后回车;
     第一次用可能回车后弹出获取程序,点开获取windows计算器就好

二、Java背景

image.png Java的三大平台 : Java SE、Java EE 、Java ME image.png image.png image.png
Java的跨平台性 :
image.png
java实现跨平台是需要对应平台的Java虚拟机的
JDK : 开发环境 : 包含JRE、类库和开发工具包(编译器+调试工具)
JRE : 运行环境 : 包含JVM和解释器,即完整的Java运行环境。
JVM : Java虚拟机 : 使软件在不同的操作系统中,模拟相同的环境。编译后的Java程序指令并不直接在硬件操作系统的CPU上执行,而是由JVM执行
image.png

三、环境搭建

1、JDK的下载和安装

image.png JDK (Java Development Kit)      Java开发工具包
JRE (Java Runtime Environment)      Java运行环境
下载地址:www.oracle.com/technetwork…
Oracle账号密码:见手机图片
安装 : www.runoob.com/java/java-e…
1.双击打开JDK安装文件,所有选项全部下一步,默认安装位置在C:/Progarm Files/Java/ image.png image.png 2.配置环境变量
a. 右键我的电脑属性-->高级系统设置
b. 弹出界面中选择->高级->环境变量
c. 在系统变量窗口找到Path变量,将JDK安装目录下的C:\Program Files\Java\jdk1.8.0_131\bin添加到系统Path变量中(win7的系统是在一行的,注意不要把原来的给删掉) image.png path : image.png image.png
有些教程没有配置CLASSPATH,不确定是否是必须。建议配置上
3.测试:徽标 + r 呼出运行窗口,输入cmd,打开dos命令窗口
a.输入javac -version
b.输入java -version
以上两个命令都出现版本号表示安装并且配置成功

2、Mysql数据库安装

访问与下载 :
官方网站:www.mysql.com/
下载地址:dev.mysql.com/downloads/m…
安装 :
【     同意协议,点击下一步
【     选择安装类型,点击下一步
【     注意:安装需要依赖环境,如需安装的功能缺少对应环境,需先安装环境
【     下一步的时候会提示缺少环境,此处的提示是说你期望安装的产品中缺少依赖,不一定提示的是数据库服务器安装的依赖,可能是其他功能组件的依赖缺少
【     此处发现没有 mysql server, 说明它对应的依赖缺少,可以先执行安装这些可以安装的,之后安装完依赖后再重新安装其他模块,我们此处的操作是先安装依赖,然后后退再次安装
【     下载安装前面提示的 mysql server 需要的 vc2013后,vc2013 如果在64位系统上面建议32和64的程序都安装,然后在上图的地方后退,重新 next 就可以看到可以安装 mysql server 了
【     检查是否存在失败项
【     进行第一步配置,除了需要设置密码外,后面的步骤基本上都是下一步
【     类型与网络配置
【     设置 root 密码
【     创建SQL服务与窗口
【     插件
【     应用配置
【     finish 后回到当前页面继续配置
【     连接服务器(先 check检查, 后下一步)
【     执行完此步骤 下一步 finish 配置完成
配置环境变量 :

  • Windows
    • 创建MYSQL_HOME:C:\Program Files\MySQL\MySQL Server 5.7
    • 追加PATH:%MYSQL_HOME%\bin;
  • MacOS / Linux
    • 终端中输入cd ~ 进入目录,并检查.bash_profile是否存在,有则追加,无则创建
    • 创建文件 touch .bash_profile
    • 打开文件 open .bash_profile
    • 输入export PATH=${PATH}:/usr/local/mysql/bin 保存并退出终端

【    1.安装完成以后找到C:\Program Files\MySQL\MySQL Server 5.7\bin 这个路径,复制到环境变量Path变量中即可。
    2.徽标+r打开dos命令窗口输入 mysql 命令连接数据库
         mysql -u root -p直接加密码 这种 方式不安全 因为密码是以明文的方式显示的
         mysql -u root -p 回车 然后输入密码 这种方式比较安全
    3.数据库服务
         徽标+r 输入 services.msc打开服务界面,找到MySql57服务,右键可以开关服务,也可以右键设置为自动启动,表示每次开机将自动开启服务
     我们也可以通过dos命令窗口
     net start mysql57 开启数据库服务
     net stop mysql57 关闭数据库服务】

3、Maven安装

www.runoob.com/maven/maven…
下载Maven :
archive.apache.org/dist/maven/…
Maven安装
     1.解压
          注意: 解压文件尽量不要放在含有中文或者特殊字符的目录下。解压后,有如下目录:
          bin:含有mvn运行的脚本
          boot:含有plexus-classworlds类加载器框          架,Maven 使用该框架加载自己的类库。
          conf:含有settings.xml配置文件
          lib:含有Maven运行时所需要的java类库
     2、 环境变量
          MAVEN_HOME = maven的安装目录
          PATH = maven的安装目录下的bin目录
     3、测试
          mvn -v      查看maven版本信息
配置 :

本地仓库

maven的conf目录中有 settings.xml ,是maven的配置文件,做如下配置:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 			  	http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository
  <localRepository>/path/to/local/repo</localRepository>
  -->
  <!-- 选择一个磁盘目录,作为本地仓库 -->
  <localRepository>D:\Program Files\maven\myrepository</localRepository>

公共仓库【重点

<!--setting.xml中添加如下配置-->
<mirrors>
	<mirror>
        <id>aliyun</id>  
        <!-- 中心仓库的 mirror(镜像) -->
        <mirrorOf>central</mirrorOf>    
        <name>Nexus aliyun</name>
        <!-- aliyun仓库地址 以后所有要指向中心仓库的请求,都会指向aliyun仓库-->
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>  
    </mirror>
</mirrors>

注:maven版本3.8.2有问题,最好使用其他版本,推荐3.6.x版本

4、IDEA下载和安装

下载 : 搜官网直接下载就行
2021.2.1版本 :
链接:pan.baidu.com/s/1jHJ5v_-U…
提取码:t4ne
无限试用30的插件 :
链接:pan.baidu.com/s/1lRpxDBAi…
提取码:w22r

四、HelloWorld

image.png
编译 : javac 源文件名称.java
运行 : java 类名

代码编写规范 :

类 :

  • 同一个源文件中可以定义多个类。
  • 编译后,每个类都会生成独立的 .class文件。
  • 一个类中,只能有一个主函数,每个类都可以有自己的主函数。
  • public修饰的类称为公开类,要求类名必须与文件名称完全相同,包括大小写。
  • 一个源文件中,只能有一个公开类。

Package(包) :

  • 作用:类似于文件夹,用于管理字节码(.class)文件。
  • 语法:package 包名;
  • 位置:必须写在源文件的第一行。
  • 带包编译:javac -d . 源文件名称.java (自动生成目录结构)
  • 带包运行:java 包名.类名 (包名+类名又称全限定名)
  • 采用域名倒置的规则:www.baidu.com.cn -> cn.com.baidu.xxx
  • 例如:cn.com.company.department.group.project. module.XxxClass

编码规范(1)书写格式 :

  • 层级之间必须缩进(Tab:一个制表位)。
  • 一行只写一句代码。

编码规范(2)代码注释 :

  • 单行注释:
  • 多行注释:
  • 文档注释:(生成外部文档:javadoc -d . HelloWorld.java)
  • 注:注释不参与编译。

编码规范(3)标识符命名 :

  • 类名语法规定:
    • 可以由:字母、数字、_、$ 组成,但不能以数字开头。
    • 不能与关键字、保留字重名。
  • 约定俗成:
    • 望文生义、见名知义。
    • 类名由一个或多个单词组成,每个单词首字母大写(pascal)。
    • 函数名、变量名由一个或多个单词组成,首单词首字母小写,拼接词首字母大写(camel)。
    • 包名全小写,只可以使用特殊字符“.”,并且不以“.”开头或结尾。
    • 常量全大写,多个单词用 _ 连接。

初学笔记:

控制台输出语句 :

system.out.print();			//输出信息后不会自动换行
system.out.println();		//输出信息后会自动换行

一些转义符 :
\n           换行符,将光标移动到下一行的第一格
\t           将光标移动到下一个水平制表位的地方
标识符 : 标识符是用来给变量、类、方法以及包进行命名的

  • 标识符必须以字母、下划线_、美元符号$开头
  • 标识符其他部分可以是字母、下划线_、美元符号$和数字的任意组合
  • java标识符大小写敏感,且长度无限制、
  • 标识符不可以是Java里面的关键字
  • 表示类名的标识符 : 每个单词的首字母大写
  • 表示方法和变量的标识符 : 第一个单词小写,从第二个单词开始首字母大写(驼峰命名)
//一个简单的Java程序
public class Welcome{
  public static void main(String[] args){
    System.out.println("hello World");
  }
}

//控制台输出语句
System.out.print("hello World");          //输出信息后不会自动换行		
System.out.println("hello World");        //输出信息后会自动换行

//转义字符
\n         //换行符,将光标移动到下一行的第一个
\t         //      ,将光标移动到下一个水平制表位的地方
//eg:
public class Test6{
	public static void main(String [] args){
		// \n 表示换行
		System.out.print("hello world1\n");
		System.out.print("hello\n world2\n");
		
		// \t 制表位  可以将上下打印语句的文字 尽量对齐
		System.out.println("窗前明月光\t疑是地上霜");
		System.out.println("举头望明月\t低头思故乡");
	
		// \\ 打印一个反斜线 需要书写两个 第一个为转义字符 表示第二个反斜线只是普通文本
		System.out.println("\\");
		
		char ch1 = '\\';
		System.out.println(ch1);
		
		// \' 单引号  第一个斜线为转义 表示第二个单引号只是普通文本
		char ch2 = '\'';
		System.out.println(ch2);
		
		char ch3 = '\"';
		System.out.println(ch3);
	}
}

命名规范 :

  • 项目名全部小写
  • 包名全部小写,域名倒置,可以包含点,但不能以点开头或者结尾
  • 类名首字母大写,一般都是使用驼峰命名
  • 变量名、方法名首字母小写,驼峰命名
  • 常量名全部大写

变量命名 :

  • 字(字母AZ az)、下(下划线_)、美($)、人(¥)、数(0~9)、骆驼(驼峰命名)
  • 可以以 字母、下划线、美元符号、人民币符号开头、可以包含数字,但不能以数字开头,采用驼峰命名

五、IDEA基础操作

image.pngimage.png image.pngimage.png image.pngimage.png image.png 主题调整 : image.png 字体调节 : image.png 新建模块 : image.png 项目关联JDK : image.png

六、注释、关键字和字面量

注释 : 对代码进行解释说明

// 单行注释
/*
    多行注释
*/
/**
 * 文档注释
 */

注释的字体、颜色设置 : image.png 关键字 : 关键字不能被我们用来命名 字面量 : 数据在程序中的书写格式 整数、小数、字符串、字符、布尔值、空值 image.png

七、变量、标识符、数据类型

变量

变量就是内存中的存储空间,空间中存储着经常发生改变的数据 变量的声明: 数据类型 变量名; 变量的赋值: 变量名 = 值

局部变量:方法或语句块内部 成员变量(实例变量):类的内部,方法的外部 静态变量:类的内部,被static修饰

三种定义方式

1、先声明,再赋值: 数据类型 变量名; 变量名 = 值; 2、声明并赋值: 数据类型 变量名 = 值; 3、同时声明多个同类型的变量 赋值 个别变量: 数据类型 变量1,变量2,变量3 = 值3,变量4;

单位换算

1TB = 1024GB 1GB = 1024MB 1MB = 1024KB 1KB = 1024Byte 1Byte = 8bit(位)

Debug工具 Debug : 是供程序员使用的程序调试工具 它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序。

常量

常量 : 一个固定的值,用final修饰

标识符

标识符 : 就是给类,方法,变量等起名字的符号。

  • 标识符必须以字母、下划线_、美元符号$开头
  • 标识符其他部分可以是字母、下划线_、美元符号$和数字的任意组合
  • java标识符大小写敏感,且长度无限制、
  • 标识符不可以是Java里面的关键字,不能以数字开头
  • 表示类名的标识符 : 每个单词的首字母大写
  • 表示方法和变量的标识符 : 第一个单词小写,从第二个单词开始首字母大写(驼峰命名)

命名规范 :

  • 项目名全部小写
  • 包名全部小写,域名倒置,可以包含点,但不能以点开头或者结尾
  • 类名首字母大写,一般都是使用驼峰命名
  • 变量名、方法名首字母小写,驼峰命名
  • 常量名全部大写

变量命名 :

  • 字(字母AZ az)、下(下划线_)、美($)、人(¥)、数(0~9)、骆驼(驼峰命名)
  • 可以以 字母、下划线、美元符号、人民币符号开头、可以包含数字,但不能以数字开头,采用驼峰命名、

数据类型

基本数据类型(四类八种): 整数型:byte、short、int、long ,所占空间大小排序: long > int > short > byte byte : 一个字节,1 byte = 8 bits,byte 的默认值是 0 ,取值:-128127 (-27 ~ 27-1) short : 两个字节,1 short = 16 bits,它的默认值也是 0,取值:-3276832767 (-215 ~ 215-1) int : 四个字节,1 int = 32 bits,默认值是 0,取值:约21亿 ( -231 ~ 231-1) long : 八个字节,1 long = 64 bits,默认值是 0L,取值:-263 ~ 263-1 浮点型:float 和 double float : 单精度浮点型,占用 4 位,1 float = 32 bits,默认值是 0.0f,尾数可以精确到7位有效数字 double : 双精度浮点型,占用 8 位,1 double = 64 bits,默认值是 0.0d,数值精度是float的两倍 字符型:char char 类型是一个单一的 16 位 Unicode 字符,最小值是 \u0000 (也就是 0 ), 最大值是 \uffff (即为 65535),char 数据类型可以存储任何字符,例如 char a = 'A'。 内存占用 2个字节 1 char = 16bits 布尔型:boolean boolean 只有两种值,true 或者是 false,只表示 1 位,默认值是 false 内存占用 1个字节 1 boolean = 8 bits 引用数据类型:字符串:String、数组:、对象 值传递 : 基本数据类型参数的传值 : 值的拷贝 不影响原数据 引用数据类型参数的传值 : 地址的引用 会更改原数据

键盘录入

scanner

Scanner sc = new Scanner(System.in);
int age = sc.nextInt();
double v = sc.nextDouble();
boolean b = sc.nextBoolean();
String next = sc.next();
System.out.println(age);
/*
    int age = sc.nextInt();
    double v = sc.nextDouble();
    boolean b = sc.nextBoolean();
    String next = sc.next();
* */

八、运算符

算术运算符 : + 、-、 * 、/ 、 % 、++ 、-- 赋值运算符 : =、+=、-=、*=、/=、%= 关系运算符 : >、<、>=、<=、==、!= 逻辑运算符 : &(与)、|(或)、!(非)、^(异或)、&&(逻辑与)、||(逻辑或) 三元运算符 : 布尔表达式 ? 结果1 : 结果2;当表达式结果为真,获得结果1,当表达式结果为假,获得结果2

算术运算符 : :::info ps : 当 + 操作中遇到了字符串,这时 + 就是 字符串连接符,而不是算术运算 / : 整数相除,结果只能得到整数,想要得到带有小数的结果,需要有小数参与运算 % : 取模,作用是用来取余数 % 目前能够想到的使用场景是它可以进行奇偶数的判断 任何一个数 % 2 的结果,不是0,就是1 自增自减运算符 : ++ : 让变量自身的值 + 1 -- : 让变量自身的值 - 1 1、单独使用 : 一句代码中,只做 ++ 或者 -- 操作, ++和-- 在变量的前面还是后面没有任何区别 2、参与运算 : ++ 在前,先自增,再操作;++ 在后,先操作再自增 :::

类型转换 :

隐式转换 : 把一个 取值范围小的数值或者变量,赋值给另一个取值范围大的变量

  - 取值范围小的数据,和取值范围大的数据进行运算,小的会先提升为大的那个的类型,再进行运算
  - byte  short char 三种数据在运算的时候,都会提升为 int ,然后再进行运算

强制转换 : 把一个取值范围大的数值或者变量,赋值给另一个取值范围小的变量,不允许直接赋值,需要加入强制转换。

  - 强制转换【有可能】会出现精度损失
  - 尽快改变

进制 :

二进制、十进制、八进制、十六进制 image.png image.png 原码反码补码 : image.png 计算机在运算的时候,都是以二进制补码的形式在运算 赋值运算符 : :::info = : 直接赋值 += : 将符号左右两边的数据,做加法运算,再将结果赋值给左边 -= : 将符号左右两边的数据,做减法运算,再将结果赋值给左边 *= : 将符号左右两边的数据,做乘法运算,再将结果赋值给左边 /= : 将符号左右两边的数据,做除法运算,再将结果赋值给左边 %= : 将符号左右两边的数据,做取余运算,再将结果赋值给左边

细节补充 : 扩展赋值运算符,内部自带强转效果 ::: 关系运算符 : :::info

: a>b,判断a是否大于b,成立则结果为true,不成立则结果为false < : a<b,判断a是否小于b,成立则结果为true,不成立则结果为false = : a >= b,判断a是否大于等于b,成立则结果为true,不成立则结果为false <= : a <= b,判断a是否小于等于b,成立则结果为true,不成立则结果为false == : a == b,判断a和b的值是否相等,成立则结果为true,不成立则结果为false != : a ! = b,判断a和b的值是否不相等,成立则结果为true,不成立则结果为false ::: 逻辑运算符 : :::info 1、用于连接boolean类型的表达式,或者是值 2、整合多个条件,为一段整体的逻辑 & : 与,并且的意思,遇false,则为false,多用于范围性的判断查找的场景 | : 或,或者的意思,遇true,则为true,多用于多个条件任选其一的场景 ! : 非,取反的意思 ^ : 异或,相同为false,不同为true && : 逻辑与 || :逻辑或 优先级 : 小括号的优先级最高 ::: 三元运算符 : :::info 格式 : 布尔表达式 ? 结果1 : 结果2 解释 : 当表达式结果为真,获得结果1,当表达式结果为假,获得结果2 :::

九、方法

概念 : 实现特定功能的一段代码块,可反复使用,不调用就不执行 方法是类和对象行为特征的抽象

定义语法 :

[修饰符1 修饰符2 ...] 返回值类型 方法名(形参列表) { //方法主体 } 例如 : public static void 方法名称( ){ //方法主体 } 调用 : 对象名.方法名(实参列表); 描述(规则) : 修饰符和关键字可有可无,表示不同的权限和要求; 形参可以有,可以没有,也可以有多个; 返回值类型为数据类型,则必须有返回值,若为void,则不需要有返回值; 静态方法可以直接调用,普通方法只能使用对象名调用; 调用方法时,会优先执行方法内部代码,结束后,返回到方法调用处,继续向下执行; image.png 可变长参数 : 可接收多个同类型实参,个数不限,使用方式与数组相同 语法:数据类型... 形参名 --- 必须定义在形参列表的最后,且只能有一个 好处 : 1、可以将原本挤在一起的臃肿代码,按照功能做分类管理 2、提高了代码的复用性 方法调用内存 :

  • 方法没有被调用的时候,在方法区中的字节码文件中存放
  • 方法被调用的时候,需要进入到栈内存中运行

image.png return关键字 : 应用在具有返回值类型的函数中 : return value; //表示结束当前函数,并伴有返回值,返回到函数调用处 应用在没有返回值类型(void)的函数中 : return; //表示结束当前函数,直接返回到函数调用处

方法重载 : Overload

定义 : 在同一个类中,定义了多个同名的方法,但每个方法具有不同的参数类型或参数个数,这些同名的方法,就构成了重载关系。 注 : 重载的方法,实际上是完全不同的方法,只是名称相同而已。

  • 方法名称相同
  • 参数列表不同
  • 与访问修饰符、返回值类型无关

方法重写 : Override

在子父类中,出现了方法声明一模一样的方法(方法名,参数,返回值) 方法重写的使用场景 : 当子类需要父类的方法,但是觉得父类的方法逻辑不好 (需要 修改|增强) 就可以对父类的方法进行重写。 方法重写 : 子类重写父类的方法,需要保证方法声明完全一致(方法名,参数,返回值类型需要保持一致) 注意事项 :

  - 父类中的私有方法不能被重写
  - 子类重写父类的方法时,访问权限必须大于等于父类

特点 : 方法名、形参列表相同;返回值类型和声明异常类型,子类小于等于父类;访问权限,子类大于等于父类。 方法重写会覆盖父类的方法 方法重写快捷键 : 方法名写入后,按 ALT + / + 回车 **递归 : ** 自己调自己 必须声明自己何时结束 递归调用即花费时间又消耗内存 定义递归头 递归体

十、控制语句

分支语句

基本if选择结构 : 语法 : if(布尔表达式){ //代码块} if else选择结构 : 语法 : if(布尔表达式){ //代码块1 }else{ //代码块2 } 多重if选择结构 : 语法 : if(布尔表达式1){ //代码块1 }else if(布尔表达式2){ //代码块2 }else if(布尔表达式3){ //代码块3 }else{ //代码块4 } 嵌套if选择结构 : 语法 : if(外层表达式){ if(内层表达式){ //内层代码块1 }else{ //内层代码块2 } }else{ //外层代码块 } image.png switch分支结构 : 语法 : switch(变量|表达式){ case 值1: 逻辑代码1; case 值2: 逻辑代码2; case 值n: 逻辑代码n; default: 未满足时的逻辑代码; } 执行流程 : :::info 1、拿着()中将要匹配的值,跟case给出的选项,逐个进行匹配 匹配成功,执行对应的语句体,再由break结束掉整个的switch语句 2、如果给出的所有case,都匹配失败了,将会执行最后的default,由break结束掉整个的switch语句 ::: 注意事项 : :::info 1、case后面的值不允许重复 2、case后面的值,只能是字面量,不能是变量 3、switch() 中可以接收的类型 : a、基本数据类型 : byte、short、char、int b、引用数据类型 : jdk5版本开始可以是枚举,jdk7版本开始可以是String字符串 4、case穿透现象 : case里面缺失break字段,导致另一个case里面的代码也执行了 ::: image.png if语句 : 适用于范围性的判断 switch语句 : 适用于固定值的匹配

循环语句

循环 : 将一段代码逻辑,重复的执行很多次 for循环语句 : 格式 : for (初始化语句; 条件判断语句; 条件控制语句) { 循环体语句; } 执行流程 : 1、执行初始化语句,在整个循环过程中,只执行一次 2、执行判断条件,看其返回结果是 true还是 false false : 循环结束 true : 执行第3步 3、执行循环体语句 4、执行条件控制语句 5、回到 2 继续 while循环语句 : 格式 : 初始化语句; while (循环条件) { 循环体语句; 条件控制语句; } 执行流程 : 1、执行初始化语句 2、执行判断条件,看其返回结果是 true还是 false false : 循环结束 true : 执行第3步 3、执行循环体语句 4、执行条件控制语句 5、回到 2 继续 do...while循环语句 : 格式 : 初始化语句; do { 循环体语句; 条件控制语句; } while (条件判断语句); 执行流程 : 1、执行初始化语句 2、执行循环体语句 3、执行条件控制语句 4、执行判断条件,看其返回结果是 true还是 false true : 回到 2 继续循环 false : 循环结束 三种循环的区别 : for循环 :
先判断后执行; 用于控制循环的那个变量,在循环结束后,就会从内存中消失,循环结束后,不能继续使用; while循环 : 先判断后执行; 用于控制循环的那个变量,在循环结束后,不会从内存中消失,循环结束后,可以继续使用; do...while循环 : 先执行后判断; 用于控制循环的那个变量,在循环结束后,不会从内存中消失,循环结束后,可以继续使用; :::info 循环次数固定,for比while更简洁 break : 结束循环,结束switch语句 注意事项 : 只能在 循环 或者 switch语句 中进行使用

::: 循环嵌套 : 在循环语句中,继续循环语句; Random 随机数 :

Random random = new Random();
//  0 ~ 19 的随机数
int num = random.nextInt(20);
System.out.println(num);

十一、数组

数组基础

数组指的是一种容器,可以用来存储同种数据类型的多个值 数组 : 一组连续的存储空间,存储多个相同数据类型的值。 数组是相同数据类型的有序集合。 数组的特点 : 长度固定、类型相同、空间连续、数组类型可以是任何数据类型、数组变量属于引用数据类型、数组也是对象 PS : 数组本身存在于堆中 数组的声明方式 : 方式一 :(推荐) 数据类型[] 数组名; 方式二 : 数据类型 数组名[]; 注意 : 声明的时候并没有实例化任何对象,只有在实例化数组对象的时候,JVM才会去分配空间 数组创建语法 :

  • 先声明、再分配空间 :

数据类型[] 数组名; 数组名 = new 数据类型[长度];

  • 声明并分配空间 :

数据类型[] 数组名 = new 数据类型[长度];

  • 声明并赋值(繁) :

数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};

  • 声明并赋值(简) :

数据类型[] 数组名 = {value1,value2,value3,...}; 数组的元素访问格式 : 数组名[下标] //例如 存:a[0]=10; 取:a[0]; 有效下标范围 : 0 ~ 数组长度-1 访问无效下标,会导致数组下标越界 : image.png **初始化 : **就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。 数组静态初始化 : eg : int[] a = {11,22,33}; 数组动态初始化 : 初始化时只指定数组长度,由系统为数组分配初始值。 eg : int[] a = new int[2]; a[0] = 1; a[1] = 2; 两种初始化的区别 : 动态初始化 : 手动指定数组长度,由系统给出默认初始化值。 静态初始化 : 手动指定数组元素,系统会根据元素的个数,计算出数组的长度 数组的初始化默认值 : 整型 : 0 浮点型(小数) : 0.0 布尔类型 : false 字符型 : '\U0000' ---> Unicode字符 ---> 常见的体现是空白字符,也就是这里的默认值 注意 : 这里的空白字符不是null 引用数据类型(例如:字符串) : null 数组的拷贝(复制):

  1. 用循环逐一赋值给新数组
  2. System.arraycopy(新数组, 原数组起始, 新数组, 新数组起始, 长度);

eg : System.arraycopy(a, 2, b, 0, 3);

  1. java.util.Arrays.copyof(原数组, 新长度)

eg : Arrays.copyof(e, 10); java.util.Arrays --- 操作数组的工具类,提供了常见的方法 数组的扩容 : 1、创建爱你大于原数组长度的新数组 2、将原数组一次复制到新数组中

Java内存分配

Java内存分配介绍 :

  • 栈 : 方法运行时所进入的内存
  • 堆 : new 出来的东西会在这块内存中开辟空间并产生地址
  • 方法区 : 字节码文件加载时进入的内存
  • 本地方法栈
  • 寄存器

image.png image.png

一些常见异常

索引越界异常 : ArrayIndexOutOfBoundsException --- 当访问了数组中不存在的索引,就会引发索引越界异常 image.png 空指针异常 : NullPointerException --- 当引用数据类型的变量被赋值为null之后,地址的指向被切断,还继续访问堆内存数据,就会引发空指针异常 image.png

二维数组 :

二维数组是一种容器,该容器用于存储一维数组 多维数组 : 多维数组可以看做以数组为元素的数组 二维数组的静态初始化 : 格式 : 数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2},{元素1,元素2}}; 简化格式 : 数据类型[][] 数组名 = {{元素1,元素2},{元素1,元素2}}; 二维数组的元素访问格式 : 数组名[m索引][n索引] m索引 : 指定访问哪一个一维数组 n索引 : 访问一维数组中的哪一个元素 二维数组的遍历 : 循环嵌套 二维数组的动态初始化 : 格式 : 数据类型[][] 数组名 = new 数据类型[m][n]; m表示这个二维数组可以存放多少个一维数组 n表示每一个一维数组可以存放多少个元素 image.png

数组的排序:

冒泡排序 (相邻对比) 选择排序 (拿一个比全部) jdk排序 image.png

十二、面向对象

面向过程 : 将步骤对应成方法,一步一步实现,最终得到结果 --- 执行者思维 面向对象 : 将行为包装为方法,需要什么行为(走,跳) 就调用相应的方法 --- 设计者思维 面向对象离不开面向过程 面向对象有三大特性 : 封装、继承、多态 创建对象 : 类名 对象名 = new 类型(); 引用类的属性 : 对象名.属性 引用类的方法 : 对象名.方法名() 对象名存的是对象的地址;new对象时开辟内存空间;

类的介绍 类 : class 对象 : Object 类是对象的抽象 对象是类的具体

  • Java 中想要创建对象,必须先要有类的存在
  • 类指的是一组相关属性和行为的集合,我们将其理解为是一张对象的设计图

类的组成 类一般有三种常见的成员 : 属性(field)、方法(method)、构造器(constructor) 一个类可以作为另一个类的属性类型或数组,即类型的属性,类类型的数组。 对象也可以作为参数,对象也可以作为返回值。

package 域名倒置... 导包 : import ...... java 会默认导入 java.lang 下的所有的类 当使用同名但是不同包的类时,只能用 包名 + 类名 的方式来调用相关类 image.png

内存图

方法区(method area) : (静态区)、不连续 栈(stack) : 先进后出,后进先出,连续的空间 堆(heap) : 不连续的空间,分配灵活,速度慢 image.png JAVA虚拟机内存模型 : image.png 垃圾回收 : 对象空间的分配 : 使用 new 关键字创建对象即可 对象空间的释放 : 将对象赋值 null 即可,垃圾回收器将负责回收所有的 "不可达"对象的内存空间 垃圾回收器回收 : 1、发现无用的对象 2、回收无用对象占用的内存空间

成员变量和局部变量的区别

image.png 局部变量 : 方法或语句块内部 从属于方法/语句块 方法执行完,消失 成员变量 : 类内部, 方法外部 从属于对象 对象创建,创建;对象回收,消失 静态变量 : 类内部,static修饰 从属于类 类加载 , 有效;类缺载 , 消失

this关键字

成员变量和局部变量 重名 的情况下,Java使用的是就近原则,哪个近用哪个 this关键字的作用 : this 表示当前对象 本质 : 创建好的对象的地址 this关键字的使用 : this 访问属性 : this.属性名 this 访问普通方法 : this.方法名() this 访问构造方法 : this(形参列表) this 调用构造方法只能位于第一句 this 不能用于 static 方法中

构造方法

用于对象的初始化,也叫构造器 构造器 : 初始化一个新建的对象;构建、创造对象的时候,所调用的方法。 格式 : 1、方法名与类名相同,大小写也要一致 2、没有返回值类型,连 void 都没有 3、没有具体的返回值(不能由 return 带回结果数据) 特点 : 构造器通过new关键字调用 构造器虽然有返回值,但是不能定义返回值类型,不能在构造器里 return 返回某个值 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数,如果已定义,则编译器不会自动添加 构造器的方法名必须和类名一致 代码示例 : 访问修饰符 + 类名(形参列表){} 分类 : 无参构造 有参构造 构造方法重载

封装

使用类设计对象时,将需要处理的数据,以及处理这些数据的方法,设计到对象中。 封装可以 更好的维护数据 、使用者无需关心内部实现,只需要知道如何使用即可。 特点 : 高内聚、低耦合 优点 : 1、提高代码的安全性 2、提高代码的复用性 3、"高内聚" : 封装细节,便于修改内部代码,提高可维护性 4、"低耦合" : 简化外部调用,便于调用者使用,便于扩展和协作 步骤 : 属性使用 private 修饰,方法公开,每个属性提供一对 getter、setter 方法,getter方法用于获取值,settter方法用于设置值

访问权限修饰符

  • private 私有
  • (defalut) 默认 在代码中就是默认不写
  • protected 受保护的
  • public 公共

类的修饰符 :

  • public
  • (defalut)

类的成员的修饰符 :

  • public 同一个类中可以调用 同一个包中可以调用 子类中可以调用 所有类
  • protected 同一个类中可以调用 同一个包中可以调用 子类中可以调用
  • (defalut) 同一个类中可以调用 同一个包中可以调用
  • private 同一个类中可以调用

标准 JavaBean : 1、成员变量私有化 2、需要 空参 、带参的构造方法 3、对于私有的成员变量,提供对应的 setXxx 和 getXxx 方法 setXxx 和 getXxx 方法 以及构造方法的快捷键 : alt + insert 或者 添加 ptg 插件 使用插件的功能自动生成

继承

让类与类之间产生关系(子父类关系) , 子类可以直接使用父类中非私有的成员 继承的格式 :

  - 格式 : public  class  子类名  extends  父类名  { }
  - 范例 : public  class  Zi  extends  Fu  { }
  - Fu : 是父类,也被称为基类、超类
  - Zi : 是子类,也被称为派生类

当类与类之间,存在相同(共性)的内容,并且产生类 is a 的关系,就可以考虑使用继承,来优化代码 extends - "扩展" 继承的两个主要作用 : 代码复用,更加容易实现类的扩展 方便对事物建模

public class InheritEmployee {
    /**
     *  姓名
     */
    String name;
    /**
     *  年龄
     */
    int age;
    /**
     *  工资
     */
    double salary;
    /**
     *  super 测试
     */
    int num = 10;
}

public class InheritCoder extends InheritEmployee {
    int num = 20;

    /**
     *  super
     */
    public void superMethod() {
        int num = 30;
        //30
        System.out.println(num);
        // 20
        System.out.println(this.num);
        //10
        System.out.println(super.num);
    }
}

public class InheritManager extends InheritEmployee {
}

方法重写(Override) :

在子父类中,出现了方法声明一模一样的方法(方法名,参数,返回值) 方法重写的使用场景 : 当子类需要父类的方法,但是觉得父类的方法逻辑不好 (需要 修改|增强) 就可以对父类的方法进行重写。 方法重写 : 子类重写父类的方法,需要保证方法声明完全一致(方法名,参数,返回值类型需要保持一致) 注意事项 :

  - 父类中的私有方法不能被重写
  - 子类重写父类的方法时,访问权限必须大于等于父类

特点 : Java 中只支持单继承,不支持多继承,但是支持多层继承 方法名、形参列表相同;返回值类型和声明异常类型,子类小于等于父类;访问权限,子类大于等于父类。 方法重写会覆盖父类的方法 方法重写快捷键 : 方法名写入后,按 ALT + / + 回车

public class InheritEmployee {
    public void show() {
        System.out.println("Fu...... show");
    }
}

public class InheritCoder extends InheritEmployee {
    /**
     *  方法重写
     */
    @Override
    public void show() {
        super.show();
        System.out.println("Zi...... show");
    }
}

内存分析

image.png

多态

多态 是指 同一个方法调用,由于对象不同可能会有不同的行为。 也就是 同一个行为具有多个不同表现形式或者形态的能力。 多态前提 : 有继承/实现 关系 有方法重写 有父类引用指向子类对象 要点(之前总结的) : 多态是方法的多态,不是属性的多态(多态与属性无关) 多态的存在要有3个必要条件 : 继承,方法重写,父类引用指向子类对象 父类引用指向子类对象后,用该父类引用调用子类重写的方法,就出现了多态 多态的成员访问特点 : 1、成员变量 : 编译看左边(父类),运行看左边(父类) 2、成员方法 : 编译看左边(父类),运行看右边(子类) image.png image.png

Animal a1 = new Cat();
// 父类引用指向子类对象
//编译器认为 a1 是 Animal 类型的对象,但其实 a1 使用的是子类 Cat 类的方法
// 多态就是 : 同一段代码,同一个方法,由于传入实参的不同,产生不同的运行结果

多态的好处和弊端 : 多态的好处 : 提高了程序的扩展性 对象多态 : 将方法的形参定义为父类类型,这个方法可以接收该父类的任意子类对象 行为多态 : 同一个行为,具有多个不同表现形式或形态的能力 多态的弊端 : 不能使用子类的特有成员

多态中的转型

向上转型 : (自动转型) a、父类作为形参,子类作为实参 b、父类作为返回值,具体返回子类 向上转型得方式实现了多态;但是这个时候的对象不能去访问子类独有的方法,因此,如果需要访问子类独有的方法就必须将这个对象进行强制向下转型。 向下转型 : (强制转型)

// eg :
Animal a1 = new Cat();	// 向上转型
Cat c = (Cat) a;		// 向下转型
Dog d = (Dog) a;		// 向下转型
// Dog d = (Dog) a; 这个代码编译的时候不会报错,但是运行的时候一定会报 ClassCastException 错误,
//因为 a 是 Cat 类型,强制转换为 Dog 类型就会报错
//为了防止报错可以使用一下方式判断一下
if (a instanceof Cat) {
    //code
}

image.png image.png image.png image.png

代码块

使用 {} 括起来的代码被称为代码块 分类 :

  - 局部代码块
  - 构造代码块
  - 静态代码块
  - 同步代码块

局部代码块 : 位置 : 方法中定义 作用 : 限定变量的生命周期,提早的释放内存,提高内存利用率 构造代码块 : 位置 : 类中方法外定义 特点 : 在创建对象,执行构造方法的时候,就会执行构造代码块(优先于构造方法执行) 作用 : 将多个构造方法中,重复的代码,抽取到构造代码块中,从而提升代码的复用性 静态代码块 : 位置 : 类中方法外定义 特点 : 需要通过 static 关键字修饰,随着类的加载而执行,因为类只加载一次,所以也就只执行一次 作用 : 在类加载的时候做一些数据初始化的操作

十三、API帮助文档的使用

API(Application Programming Interface) : 应用程序编程接口 就是别人写好的一些类,可以直接拿去调用的类的文档描述 具体API帮助文档可以自己搜一下 image.png java.lang 包下的类不需要写导包代码 image.png image.png 百度云盘链接:pan.baidu.com/s/1XbrR1iuG… 提取码:jdfs

十四、关键字

this 和 super 关键字

this关键字 成员变量和局部变量 重名 的情况下,Java使用的是就近原则,哪个近用哪个 this关键字的作用 : this 表示当前对象 本质 : 创建好的对象的地址 this关键字的使用 : this 访问属性 : this.属性名 this 访问普通方法 : this.方法名() this 访问构造方法 : this(形参列表) this 调用构造方法只能位于第一句 this 不能用于 static 方法中 super 关键字 super : 调用父类成员;直接父类的引用 this : 调用本类成员; super可以访问 : 父类的属性;父类的方法;父类的构造方法。 image.png

static关键字

在类中,用 static 声明的成员变量为静态成员变量,优先于对象存在,也称类变量;类变量的生命周期和类相同,在整个应用程序执行期间都有效。 介绍 : static 是静态的意思,可以修饰成员变量,也可以修饰成员方法。 生命周期 : 局部变量 : 方法或语句块内部 从属于 方法/语句块 运行到该局部变量定义语句,创建;方法执行完,消失 成员变量 : 类内部、方法外部 从属于对象 对象创建(new),创建;对象回收,消失; 静态变量 : 类内部、static修饰 从属于类 类加载(进入方法区),有效;类缺载,消失 static 修饰的成员变量和方法 : 从属于类 普通属性和方法 : 从属于对象 修饰 : static 修饰成员变量 : static 修饰普通方法 : 在 static 方法中不能访问 非 static 的成员 static 修饰代码块 : 注意事项 : static 方法中,只能访问静态成员(直接访问) static 中不允许使用 this 关键字

public class StaticDemo {
    /**
     *  static 关键字 : 修饰符,可以修饰成员变量和成员方法
     *      特点 :
     *          1、被类的所有对象所共享
     *          2、多了一种调用方式,可以通过类名进行调用
     *          3、随着类的加载而加载,优先于对象存在
     *      修饰成员方法 :
     *          1、成员方法什么时候加入 static
     *              - 常用于制作工具类的时候
     *          2、工具类 : 不是描述事物,而是帮我们完成一些事情(打工)
     *          3、如果发现一个类中,所有的方法,全都是 static 所修饰
     *              - 私有该类的构造方法
     *              - 目的 : 为了不让其他类,再创建对象
     *  static 方法中,只能访问静态成员(直接访问)
     *  static 中不允许使用 this 关键字
     */
    public static void main(String[] args) {
        // static 修饰成员方法
        staticMethod();

    }

    /**
     *  static 修饰成员方法
     */
    private static void staticMethod() {
        int[] arr = {12,23,43,123,43,345,12,43,345,1,23};
        //StaticTool tool = new StaticTool();
        System.out.println(StaticTool.getMax(arr));
        System.out.println(StaticTool.getMin(arr));
        StaticTool.printArray(arr);
    }
}

public class StaticTool {
    /**
     *  当一个类中全是静态方法的时候,常常创建一个 私有 的无参构造方法
     *  好处是 禁止使用 new 的方式调用这些方法,通过类名进行调用
     */
    private StaticTool() {
    }

    /**
     *  获取数组最大值
     */
    public static int getMax(int[] arr) {
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        return max;
    }

    /**
     *  获取数组最小值
     */
    public static int getMin(int[] arr) {
        int max = arr[0];
        for (int j : arr) {
            if (j < max) {
                max = j;
            }
        }
        return max;
    }

    /**
     *  打印数组
     */
    public static void printArray(int[] arr) {
        System.out.println("[");
        for (int i = 0; i < arr.length - 1; i++) {
            System.out.println(arr[i] + ",");
        }
        System.out.println(arr[arr.length - 1] + "]");
    }
}

final关键字

final 关键字是最终的意思,可以修饰 (方法、类、变量) final 修饰的特点 :

  - 修饰方法 : 表明该方法是最终方法,不能被重写;
  - 修饰类 : 表明该类是最终类,不能被继承;
  - 修饰变量 : 表明该变量是常量,不能再次被赋值。
  • final 修饰变量 : 被 final 修饰的变量 不可改变,一旦 被赋了初始值,就不能被重新赋值,即常量;
  • final 修饰方法 : 被 final 修饰的方法不能被子类重写,但可以被重载;
  • final 修饰类 : 被 final 修饰的类不能被继承。

使用 final 修饰的属性,称之为常量 : a、通常在定义的时候赋值,值不可改变; b、常量的名字全部大写,多个单词之间使用下划线分隔; static final 修饰的属性 称为静态常量,通常在定义的时候或者静态代码块中赋值

十五、Java常用类

String类

String类的特点 : 1、Java 程序中所有双引号字符串,都是String这个类的对象 2、字符串不变; 它们的值在创建后不能被更改 3、String对象是不可变的,但是它们可以被共享 字符串常量池 : 当我们使用双引号创建字符串对象时,会检查常量池中是否存在该数据 不存在 : 创建 存在 : 复制 image.png 字符串常量池 : image.png String常见的构造方法 : image.png

String面试题

1、String 类直接使用 "=" 进行赋值会先去常量池中查找是否已经存在当前相同内容的字符串,如果存在,直接使用之前字符串的地址;如果不存在,将当前字符串存放在常量池中;这样做的目的是节省内存开销。

String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);

System.out.println("----------------------------");

String str3 = "abc";
//这里 new 的形式赋值 其实是在堆内存中开辟一个空间,拷贝了一份常量池中 "abc" 的字节类型的数组的地址
// 而 str4 保存的是开辟的那个 堆空间中的地址
String str4 = new String("abc");
System.out.println(str3 == str4);
// 字符串类型底层其实是一个字节类型的数组

System.out.println("----------------------------");

String str5 = "abc";
String str6 = "a"+"b"+"c";
System.out.println(str5 == str6);   //  true
// 因为 String 存在常量优化机制 , 这里 是 常量和常量拼接,而不是 地址与常量拼接

image.png image.png

String常见比较

public class StringMethodDemo {
    /**
     *  String类中用于比较的方法 :
     *      public boolean equals(Object anObject)      将此字符串与指定对象进行比较。
     *
     *      public boolean equalsIgnoreCase(String anotherString)   将此 String与其他 String比较,忽略大小写。
     */
    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = new String("abc");
        System.out.println(str1 == str2);       //false
        System.out.println(str1.equals(str2));  //true

        System.out.println("- - - - - - - - - - - - - - - - - - ");

        String s1 = "abc";
        String s2 = "ABC";
        System.out.println(s1.equals(s2));              //false
        System.out.println(s1.equalsIgnoreCase(s2));    //true
    }
}

image.png

String字符串的遍历

public class StringMethodDemoTwo {
    /**
     *  String类中用于遍历的方法 :
     *      public char[] toCharArray()      将此字符串转换为新的字符数组。
     *
     *      public char charAt(int index)   返回 char指定索引处的值。
     *
     *      public int length()             返回此字符串的长度.
     */
    public static void main(String[] args) {
        methodOne();
        methodTwo();
    }

    /**
     *  String 的 第一种遍历方式    相对第二种效率更高
     *      public char[] toCharArray()      将此字符串转换为新的字符数组。
     */
    private static void methodOne() {
        String str1 = "jkasbfgviJKASDBfdaDFBSNAIvguij";
        char[] chars = str1.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }
    }

    /**
     *  String 的 第二种遍历方式
     *      public char charAt(int index)      返回 char指定索引处的值。
     */
    private static void methodTwo() {
        String str1 = "asdSDAdfswaf";
        //char c = str1.charAt(9);
        //System.out.println(c);
        for (int i = 0; i < str1.length(); i++) {
            char c = str1.charAt(i);
            System.out.println(c);
        }
    }
}

String 的截取、替换和切割

public class StringMethodDemoThree {
    /**
     *  String 的截取 :
     *      public String substring(int beginIndex) : 返回一个字符串,该字符串是此字符串的子字符串。
     *          根据传入的索引开始做截取,截取到字符串的末尾。
     *      public String substring(int beginIndex, int endIndex) : 返回一个字符串,该字符串是此字符串的子字符串。
     *          根据传入的开始和结束索引,对字符串做截取
     *              -包含头,不包含尾
     *      这两种截取方法都需要一个变量来接收截取拿到的字符串
     *  String 的替换 :
     *      public String replace(CharSequence target, CharSequence replacement) :
     *          将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。
     *          参数1 : 旧值            参数2 : 新值
     *  String 的切割 :
     *      public String[] split(String regex) : 将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。
     *          根据传入的字符作为规则,切割当前字符串
     *          需要注意有些规则字符是有特殊含义或者。。的,如果想让它以你想要的方式切割要在符号前面加上 \\
     *          比如:   .split(".")       要写为 :   .split("\\.")
     *                  .split("+")       要写为 :   .split("\\+")
     */
    public static void main(String[] args) {
        //String 的截取1
        intercept1();
        //String 的截取2
        intercept2();

        //String 的替换
        replace();

        // String 的切割
        split();
    }

    private static void split() {
        String str1 = "Always remember, there must be echoes";
        String[] split = str1.split(", ");
        for (int i = 0; i < split.length; i++) {
            System.out.println(split[i]);
        }
    }

    /**
     *  String 的替换 :
     *      public String replace(CharSequence target, CharSequence replacement) :
     *          将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。
     *          参数1 : 旧值            参数2 : 新值
     */
    private static void replace() {
        String str1 = "Always remember, there must be echoes";
        String str2 = str1.replace("must", "maybe");
        System.out.println(str2);
    }

    /**
     *  String 的截取 2 :
     *      public String substring(int beginIndex, int endIndex) : 返回一个字符串,该字符串是此字符串的子字符串。
     *          根据传入的开始和结束索引,对字符串做截取
     *              -包含头,不包含尾
     */
    private static void intercept2() {
        String str1 = "Always remember, there must be echoes";
        String str2 = str1.substring(0,15);
        System.out.println(str2);
    }

    /**
     *  String 的截取 1 :
     *      public String substring(int beginIndex) : 返回一个字符串,该字符串是此字符串的子字符串。
     *          根据传入的索引开始做截取,截取到字符串的末尾。
     */
    private static void intercept1() {
        String str1 = "Always remember, there must be echoes";
        String str2 = str1.substring(17);
        System.out.println(str2);
    }
}

StringBuilder

public class StringBuilderDemo {
    /**
     *  StringBuilder :
     *      介绍 :
     *          1、一个可变的字符序列
     *          2、StringBuilder是字符串缓冲区,将其理解是容器,这个容器可以存储任意数据类型,但是只要进入到这个容器,全部变成字符串
     *      StringBuilder 的作用 : 提高字符串的操作效率
     *          1、StringBuilder的特点
     *          2、StringBuilder的构造方法
     *          3、StringBuilder常用成员方法
     *          4、StringBuilder如何提升效率
     *      StringBuilder的构造方法 :
     *          public StringBuilder() : 创建一个空白的字符串缓冲区(容器),其初始容量为16个字符
     *          public StringBuilder(String str) : 创建一个字符串缓冲区(容器),容器在创建好之后,就会带有参数的内容
     *          另外两个构造方法不常用,不做介绍
     *      StringBuilder的成员方法 :
     *          1、public StringBuilder append(Object obj) : 追加 Object参数的字符串 Object形式。
     *              添加数据,并返回自己
     *          2、public StringBuilder reverse() : 导致该字符序列被序列的相反代替。
     *              将缓冲区中的内容,进行翻转
     *          3、public int length() : 返回长度(字符数)。
     *          4、public String toString() : 返回表示此顺序中的数据的字符串。
     *              将缓冲区的内容,以String字符串类型返回
     */
    public static void main(String[] args) {
        //  StringBuilder 导引
        introduce();
        // 第一个简单的StringBuilder示例
        one();
        //  StringBuilder的成员方法
        memberMethod();
    }
    
    /**
     *  StringBuilder的成员方法
     */
    private static void memberMethod() {
        StringBuilder strb = new StringBuilder();
        // 链式编程 : 调用的方法,返回的结果是对象,就可以继续向下调用方法
        strb.append("红色").append("黄色").append("绿色");
        System.out.println(strb);
        strb.reverse();
        System.out.println(strb);
        System.out.println(strb.length());
        // 当数据在 StringBuilder 当中,要调用的方法 StringBuilder里面没有,但是String里有
        // 将 StringBuilder 转换为String ,再进行调用
        String s = strb.toString();
        String[] s1 = s.split("色");
        for (int i = 0; i < s1.length; i++) {
            System.out.println(s1[i]);
        }
    }

    /**
     *  第一个简单的StringBuilder示例
     */
    private static void one() {
        StringBuilder strb = new StringBuilder();
        System.out.println(strb);
        strb.append("红色");
        System.out.println(strb);
        strb.append("黄色");
        System.out.println(strb);
        strb.append("绿色");
        System.out.println(strb);
        StringBuilder strb2 = new StringBuilder("there must be echoes");
        System.out.println(strb2);
    }

    /**
     *  StringBuilder 导引
     */
    private static void introduce() {
        //  获取 1970年1月1日0时0分0秒 到 现在 所经历过的毫秒值 ( 1秒 = 1000毫秒)
        long start = System.currentTimeMillis();
        System.out.println(start);
        StringBuilder strb = new StringBuilder();
        for (int i=1; i<= 100000; i++) {
            strb.append(i);
        }
        System.out.println(strb);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

String、StringBuilder、StringBuffer对比

String : 是一个不可变的对象,对字符串的任何修改都会产生新的对象 StringBuilder : 可变 线程不安全的 JDK1.5提供 效率较高 StringBuffer : 可变 线程安全的 JDK1.0提供 效率低 如果存在字符串频繁修改的场景 : 推荐使用 StringBuilder

instanceof

二元运算符,左边是对象,右边是类;当该对象是右面类或者子类所创建的对象时,返回 true;否则,返回false。

抽象类

抽象方法 : 使用 abstract 修饰的方法,没有方法体。只有声明,定义的是一种 "规范",就是告诉子类必须要给抽象方法提供具体的实现。注意: 没有方法体用 abstract 修饰 抽象类 : 包含抽象方法的类就是抽象类。通过 abstract 方法定义规范,然后要求子类必须定义具体实现。 image.pngimage.png image.png 注意事项 : 1、有抽象方法的类只能定义成抽象类;抽象方法必须存在于抽象类中。 2、抽象类不能被实例化,即不能用 new 来实例化抽象类,必须通过 new 子类(多态,向上转型)的方式创建对。 3、抽象类只能用来被继承 4、抽象方法必须被子类实现;子类必须重写父类的抽象方法,除非子类也是抽象类; 5、子类可以选择是否重写父类的普通方法; 6、抽象类中可以包含 属性、方法、构造方法 ;但是构造方法不能用来 实例化(new),只能用来被子类调用

接口 - interface

interface : 规范和具体实现的分离 接口中默认全是 全局抽象方法,即无卵是否书写都将由 public abstract 修饰;属性 都是 全局静态常量,不管是否书写都由 public static final 修饰 接口 : 体现的思想是对规则的声明,Java中的接口更多体现的是对行为的抽象。 接口的声明格式 : [访问权限修饰符] interface 接口名 [ extends 父接口1,... ] { 常量定义; 方法定义; } 实现类(子类) 通过 implements 来实现接口中的规范。 **接口介绍 : **

  - 接口用关键字 interface 来定义

public interface 接口名 {}

  - 接口不能实例化
  - 接口和类之间是实现关系,通过 implements 关键字表示 

public class 类名 implements 接口名 {}

  - 接口的子类(实现类)

要么重写接口中的所有抽象方法 要么是抽象类 接口中的成员特点 : 成员变量 : 只能定义常量,因为系统会默认加入三个关键字 public static final 成员方法 : 只能是抽象方法,因为系统会默认加上两个关键字 public abstract 构造方法 : 没有 类和接口之间的各种关系 : 类和类之间 : 继承关系,只支持单继承,不支持多继承,但是可以多层继承 类和接口之间 : 实现关系,可以单实现,也可以多实现,甚至可以在继承一个类的同时,实现多个接口 接口和接口之间 : 继承关系,可以单继承,也可以多继承 注意事项 : 1、 JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。 JDK1.8之后,接口中可以包含普通的静态方法,通过 接口名.静态方法名 的方式调用。 2、接口默认里面的方法均为全局抽象方法; 3、接口不能直接 new 对象,只能通过 new 实现类的方式创建对象; 4、实现类(子类)必须重写接口中的抽象方法,除非实现类(子类)也是抽象类; 5、我们只能继承一个类,但是可以同时实现多个接口; 6、接口也可以继承多个接口,即接口的多继承; 7、接口实现多态的方式和之前一样,接口作为形参 或者 接口作为返回值; 8、接口不能定义 (这句话我也不理解,当没有得了,不影响) 普通属性 : 接口中的属性都是全局静态常量 普通方法 : 接口中的方法均为全局抽象方法 构造方法 : 因为属性都是全局静态常量,不能编写构造方法

抽象类和接口的对比 :

抽象类 : 对事物做抽象(描述事物) 接口 : 对行为抽象(指定规则)

成员变量 : 抽象类 : 可以定义变量,也可以定义常量 接口 : 只能定义常量 成员方法 : 抽象类 : 可以是定义具体方法,也可以定义抽象方法 接口 : 只能定义抽象方法 构造方法 : 抽象类 : 有 接口 : 没有

内部类

内部类就是定义在一个类里面的类;编译成功后是两个类 image.png 创建对象的格式 : image.png image.png 内部类的分类 :

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

静态内部类 : (了解) image.png 局部内部类 : (了解) image.png 匿名内部类 : 概念 : 匿名内部类本质上是一个特殊的局部内部类 (定义在方法内部) 前提 : 需要存在一个借口或类 格式 : new 类名/接口 () { } 作用 : 匿名内部类可以让代码变得更加简洁,在定义一个类的同时对其进行实例化 使用环境 : 匿名内部类可以作为方法的实际参数进行传输

Object类

Object 类是所有类的父类,我们编写的类都默认继承自此类

  • 所有的类,都直接或者间接的继承了 Object 类 (祖宗类)。
  • Object 类的方法是一切子类都可以直接使用的,所以我们要学习 Object 类的方法。

toString 方法: 默认的输出是 : 包名+类名+@ + hash值 image.png equals 方法 : 对象之间进行比较,返回true,或者是false Object 类中的 equals 方法,默认比较的是对象内存地址;通常会重写 equals 方法,让对象之间,比较内容 image.png image.png 注意 : "==" 比较基本数据类型,比较的是值;"==" 比较引用数据类型,比较的是地址; equals本身比较的也是地址,但是可以通过重写来比较内容。

Math类

提供了丰富的数学运算操作。 Math 类中有两个静态常量 : E : 自然对数的基数 PI : 圆周率 image.png

Random类

提供了获取各种随机数的方法

Random random = new Random();
//  0 ~ 19 的随机数
int num = random.nextInt(20);
float v1 = random.nextFloat();
System.out.println(num);
System.out.println(v1);

System类

系统信息类,提供了 : 1、gc() : 垃圾回收的方法; 2、获取当前系统时间毫秒数; 3、当前系统信息。 image.png image.png

BigDecimal类

解决小数运算中,出现的不精确问题 比如 :

double num1 = 0.1;
double num2 = 0.2;
System.out.println(num1 + num2);        //0.30000000000000004

BigDecimal类 的使用 : image.png image.png

包装类

将基础数据类型,包装成类(变成引用数据类型)

基本数据类型对应的包装类
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

用途 : 1、作为和基本数据类型对应的类型存在,方便涉及到对象的操作; 2、包含每种基本数据类型的相关属性方法,如最大值、最小值等,以及相关的操作方法 常用方法 :

  • xxxValue 方法 : 将包装类对象转换为基本数据类型
  • valueOf 方法 : 将基本数据类型 转换为包装类
  • toString 方法 : 将基本数据类型 转换为字符串
  • parseXxx 方法 : 将字符串 转换为 基本数据类型

JDK5版本开始,出现了自动拆装箱 : 自动装箱 : 可以将基本数据类型。直接赋值给包装类的变量 原代码 Integer value = Integer.valueOf(20); 简化为 Integer value = 20; 自动拆箱 : 可以将包装类的数据,直接赋值给基本数据类型变量 原代码 int i = value.intValue(); 简化为 : int i = value; 因为编译器会自动帮忙修改为 int i = value.intValue(); **包装类面试题 : ** 我们直接使用 = 号给数字包装类和 char 包装类赋值 如果取值范围在 -128 ~ 127 ,那么不会产生新的对象,将从缓存数组中取出相同的数值 cache; 如果取值超过 -128 ~ 127,将会 new 一个新的对象,使用 == 比较的时候就是 false. image.png

正则表达式

正则表达式 : 本质上来说就是一个字符串,可以指定一些规则,来校验其他字符串

/**
 *  正则表达式 : 本质上来说就是一个字符串,可以指定一些规则,来校验其他字符串
 *
 *  1、字符类       [] : 单个字符
 *      [abc]               只能是 a,b,或c
 *      [^abc]              除了 a,b,c 之外的任何字符
 *      [a-zA-Z]            a到z A到Z,包括(范围)
 *      [a-d[m-p]]          a到d,或m通过p : ([a-dm-p]联合)
 *      [a-z&&[def]]        只能取 d,e,或f  (交集)
 *      [a-z&&[^bc]]        a到z, 除了 b 和 c : ([ad-z]减法)
 *      [a-z&&[^m-p]]       a到z, 除了 m 到 p : ([a-lq-z]减法)
 *  ---------------------------------------------------------------------------
 *  2、预定义字符类
 *      .               任何字符
 *      \d              一个数字 : [0-9]
 *      \D              非数字 : [^0-9]
 *      \s              一个空白字符 : [\t \n \x0B \f \r]
 *      \S              非空白字符 : [^\s]
 *      \w              [a-zA-Z_0-9]  英文 、 数字 、 下划线
 *      \W              [^\w]  一个非单词字符
 *
 *      \       转义字符
 *  ---------------------------------------------------------------------------
 *  3、数量
 *      X?          X , 一次或0次
 *      X*          X , 零次或多次 (任意次数)
 *      X+          X , 一次或多次
 *      X{n}        X , 正好n次
 *      X{n, }      X , 至少n次
 *      X{n,m}      X , 至少n次但不超过m次
 */

时间

记 1970年1月1日 00:00:00 为基准时间。

Date 类

构造方法 : public Date() : 将当前时间,封装为 Date 日期对象 public Date(long date) : 将时间毫秒值转换成 Date 日期对象 普通方法 : public long getTime() : 返回从 1970年1月1日 00:00:00 走到此刻的总的毫秒数 public void setTime(long time) : 设置日期对象的时间为当前时间毫秒值对应的时间 Date类提供了用于获取日期信息的方法,大多数已经弃用,虽然仍然可以使用,但是不推荐使用 eg : .getDay(); .getHours();

/**
 *  Date 类 : 表示时间类
 *
 *      1、构造方法 :
 *          public Date() :  将当前时间,封装为 Date 日期对象
 *          public Date(long date) :    将时间毫秒值转换成 Date 日期对象
 *      2、常见方法 :
 *          public long getTime() :  返回从 1970年1月1日 00:00:00 走到此刻的总的毫秒数
 *          public void setTime(long time) : 设置日期对象的时间为当前时间毫秒值对应的时间
 */
public static void main(String[] args) {
    // 将当前时间,封装为 Date 日期对象
    Date date1 = new Date();
    System.out.println(date1);

    // 将时间毫秒值转换成 Date 日期对象
    Date date2 = new Date(1000L);
    System.out.println(date2);

    // 返回从 1970年1月1日 00:00:00 走到此刻的总的毫秒数
    System.out.println(date1.getTime());
    System.out.println(date2.getTime());
    // 已弃用的两个方法,可以用,但不推荐使用
    System.out.println(date1.getDay());
    System.out.println(date1.getHours());

    // 返回从 1970年1月1日 00:00:00 走到此刻的总的毫秒数
    Date date3 = new Date();
    date3.setTime(10000L);
    System.out.println(date3);
}

SimpleDateFormat 类

构造方法 : public SimpleDateFormat() : 创建一个日期格式化对象,使用 [默认格式] public SimpleDateFormat(String pattern) : 创建一个日期格式化对象,[手动指定格式] 普通方法 : public final String format(Date date) : 将日期对象,转换为字符串 public Date parse(String source) : 将日期字符串,解析为日期对象 DateFormat 类 和 SimpleDateFormat 类 : DateFormat 类 : 把时间对象转化为指定格式的字符串 DateFormat 类是一个抽象类,一般使用它的子类 SimpleDateFormat 类来实现

/**
 *  SimpleDateFormat 类
 *      用于日期格式化
 *      1、构造方法  :
 *          public SimpleDateFormat() : 创建一个日期格式化对象,使用 [默认格式]
 *          public SimpleDateFormat(String pattern) : 创建一个日期格式化对象,[手动指定格式]
 *      2、普通方法 :
 *          public final String format(Date date) : 将日期对象,转换为字符串
 *          public Date parse(String source) : 将日期字符串,解析为日期对象
 */

// 创建一个日期格式化对象,使用 [默认格式]
SimpleDateFormat dateFormat = new SimpleDateFormat();
// 创建 Date 对象,封装此刻的时间
Date date = new Date();
// 将日期对象,转换为字符串
String dateString = dateFormat.format(date);
System.out.println(dateString);

// 创建一个日期格式化对象,[手动指定格式]
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date = new Date();
String dateString = simpleDateFormat.format(date);
System.out.println(dateString);

String today = "2023年6月18日";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
Date date = simpleDateFormat.parse(today);
System.out.println(date);

Calendar 日历类

提供了关于日期计算的相关功能。注意 : 一月是0,二月是1。 代表的是系统此刻时间对应的日历,通过它可以单独获取、修改时间中的年、月、日、时、分、秒等 创建对象 : public static Calendar getInstance() : 获取当前时间的日历对象 常用方法 : public int get(int field) : 取日历中的某个字段信息 get 方法的参数 : Calendar 类中的静态常量 Calendar.YEAR : 获取年份信息 Calendar.MONTH : 月份是 0~11,需要做 +1 操作 Calendar.DAY_OF_MONTH : 获取日 Calendar.DAY_OF_WEEK : 获取星期,获取星期的时候,需要提前设计一个数组 Calendar.DAY_OF_YEAR : 获取一年中的第几天 public void set(int field, int value) : 修改日历的某个字段信息 public void add(int field, int amount) : 为某个字段增加/减少指定的值 public final Date getTime() : 获取日期对象 public final void setTime(Date date) : 给日历设置日期对象

private static void getMethod() {
    // Calendar calendar : 抽象类
    // Calendar.getInstance() : 获取的是子类对象
    // 1、获取当前时间的日历对象
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar);
    // 2、调用get方法,获取指定字段的信息
    int year = calendar.get(Calendar.YEAR);
    System.out.println(year);
    // 注意 Calendar 类的月份是 0~11 , 想要获取常规的月份,需要对结果进行 +1 操作
    int month = calendar.get(Calendar.MONTH);
    System.out.println(month +1);
    int day = calendar.get(Calendar.DAY_OF_MONTH);
    System.out.println(day);
    // 星期 : 日 一 二 三 四 五 六
    //        1  2 3  4  5 6  7
    char[] weeks = {' ','日','一','二','三','四','五','六'};
    int weekIndex = calendar.get(Calendar.DAY_OF_WEEK);
    System.out.println(weeks[weekIndex]);
    int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
    System.out.println(dayOfYear);
}

private static void setMethod() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, 2022);
    System.out.println(calendar.get(Calendar.YEAR));
    // 设置年月日
    calendar.set(2008,8,8);
    System.out.println(calendar.get(Calendar.YEAR));
    int month = calendar.get(Calendar.MONTH);
    System.out.println(month + 1);
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
}

private static void addMethod() {
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.YEAR, 2);
    System.out.println(calendar.get(Calendar.YEAR));
    calendar.add(Calendar.YEAR, -3);
    System.out.println(calendar.get(Calendar.YEAR));
}

/**
 *  需求 : 键盘录入一个日期字符串,程序输出这个歌日期是一年中的第多少天
 *      1、使用 SimpleDateFormat,将日期字符串转换为日期对象
 *      2、将日期对象,转换为 Calendar 对象
 *      3、调用 get 方法,获取一年中的第多少天
 */
public static void main(String[] args) throws ParseException {
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入一个日期 (格式为yyyy年MM月dd日) : ");
    String time = scanner.nextLine();
    // 1、使用 SimpleDateFormat,将日期字符串转换为日期对象
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
    Date date = simpleDateFormat.parse(time);
    Calendar calendar = Calendar.getInstance();
    // 2、将日期对象,转换为 Calendar 对象
    calendar.setTime(date);
    // 3、调用 get 方法,获取一年中的第多少天
    System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
}

JDK8

image.png image.png

LocalDateTime、LocalDate、LocalTime

LocalDate : 代表本地日期(年、月、日、星期) LocalTime : 代表本地时间(时、分、秒、纳秒) LocalDateTime : 代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒) 对象的创建方式 : 1、.now() : 当前时间 2、.of(...) : 自定义时间 LocalDateTime 转换 LocalDate、LocalTime : 1、 .toLocalDate() 2、 .toLocalTime()

public static void main(String[] args) {
    // 获取此刻的时间对象
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    // 转换
    LocalDate localDate = now.toLocalDate();
    LocalTime localTime = now.toLocalTime();
    System.out.println(localDate);
    System.out.println(localTime);
    // 获取指定的时间对象
    LocalDateTime of = LocalDateTime.of(2020, 10, 6, 8, 8, 8);
    System.out.println(of);

    // 获取指定的时间对象
    System.out.println(now.getYear() + "年");
    System.out.println(now.getMonth() + "月");
    System.out.println(now.getMonthValue() + "月");
    System.out.println(now.getDayOfMonth() + "日");
    System.out.println(now.getHour() + "时");
    System.out.println(now.getMinute() + "分");
    System.out.println(now.getSecond() + "秒");
    System.out.println(now.getNano() + "纳秒");
}

获取

// LocalDateTime
public static void main(String[] args) {
    // 日期  时间
    LocalDateTime nowDateTime = LocalDateTime.now();
    System.out.println("今天是 : " + nowDateTime);
    // 年
    System.out.println(nowDateTime.getYear());
    // 月
    System.out.println(nowDateTime.getMonthValue());
    // 日
    System.out.println(nowDateTime.getDayOfMonth());
    // 时
    System.out.println(nowDateTime.getHour());
    // 分
    System.out.println(nowDateTime.getMinute());
    // 秒
    System.out.println(nowDateTime.getSecond());
    // 纳秒
    System.out.println(nowDateTime.getNano());

    // 日 : 当年的第几天
    System.out.println("dayOfYear : " + nowDateTime.getDayOfYear());
    // 星期
    System.out.println("星期 : " + nowDateTime.getDayOfWeek());
    System.out.println("星期 : " + nowDateTime.getDayOfWeek().getValue());
    // 月份
    System.out.println("月份 : " + nowDateTime.getMonth());
    System.out.println("月份 : " + nowDateTime.getMonth().getValue());
}

// LocalTime
public static void main(String[] args) {
    // 1、获取本地时间对象
    LocalTime nowTime = LocalTime.now();
    // 今天的时间
    System.out.println("今天的时间 : " + nowTime);
    // 时
    int hour = nowTime.getHour();
    System.out.println("hour : " + hour);
    // 分
    int minute = nowTime.getMinute();
    System.out.println("minute : "+ minute);
    // 秒
    int second = nowTime.getSecond();
    System.out.println("second : " + second);
    // 纳秒
    int nano = nowTime.getNano();
    System.out.println("nano : "+ nano);
}

// LocalDate
public static void main(String[] args) {
    // 1、获取本地日期对象
    LocalDate nowDate = LocalDate.now();
    // 今天的日期
    System.out.println("今天的日期 : " + nowDate);
    // 年
    int year = nowDate.getYear();
    System.out.println("year : " + year);
    // 月
    int monthValue = nowDate.getMonthValue();
    System.out.println("month : "+ monthValue);
    // 日
    int dayOfMonth = nowDate.getDayOfMonth();
    System.out.println("dayOfMonth : " + dayOfMonth);
    // 当年的第几天
    int dayOfYear = nowDate.getDayOfYear();
    System.out.println("dayOfYear : "+ dayOfYear);
    // 星期
    System.out.println("星期 : " + nowDate.getDayOfWeek());
    System.out.println("星期 : " + nowDate.getDayOfWeek().getValue());
    // 月份
    System.out.println("月份 : " + nowDate.getMonth());
    System.out.println("月份 : " + nowDate.getMonth().getValue());
}

修改年月日时分秒相关的方法 : LocalDate、LocalTime、LocalDateTime 都是不可变的,调用修改方法返回的是一个新的对象 withYears、withMonths、withDayOfMonth ... 修改时间,返回新的时间对象; plusYears、plusMonths、plusDays ... 把某个时间加多少,返回新的时间对象; minusYears、minusMonths、minusDays ... 把某个时间减多少,返回新的时间对象; equals、isBefore、isAfter 判断2个时间对象,是否相等,在前还是在后

public static void main(String[] args) {
    LocalDateTime nowTime = LocalDateTime.now();

    // 当前时间
    System.out.println(nowTime);
    // minus : 减去
    // minusYears(年)、minusMonths(月)、minusDays(日)、minusWeeks(周)、minusHours(时)、minusMinutes(分)、minusSeconds(秒)、minusNanos(纳秒)
    System.out.println("减一小时" + nowTime.minusHours(1));
    System.out.println("减一分钟" + nowTime.minusMinutes(1));
    System.out.println("减一秒钟" + nowTime.minusSeconds(1));
    System.out.println("减一纳秒" + nowTime.minusNanos(1));
    System.out.println("对比时间,确认方法返回的都是新的实力 >>>" + nowTime);
    System.out.println("------------------------");

    // plus : 加
    // plusYears(年)、plusMonths(月)、plusDays(日)、plusWeeks(周)、plusHours(时)、plusMinutes(分)、plusSeconds(秒)、plusNanos(纳秒)
    System.out.println("加一小时" + nowTime.plusHours(1));
    System.out.println("加一分钟" + nowTime.plusMinutes(1));
    System.out.println("加一秒钟" + nowTime.plusSeconds(1));
    System.out.println("加一纳秒" + nowTime.plusNanos(1));
    System.out.println("------------------------");

    // with : 这里体现出的是,设置效果
    System.out.println("修改的效果 :");
    // withYears(年)、withMonths(月)、withDayOfMonth(日)、withHour(时)、withMinute(分)、withSecond(秒)、withNano(纳秒)
    System.out.println(nowTime.withYear(2020));
    System.out.println(nowTime.withMonth(3));
    System.out.println(nowTime.withDayOfMonth(12));
    System.out.println(nowTime.withHour(20));
    System.out.println(nowTime.withMinute(30));
    System.out.println(nowTime.withSecond(33));
    System.out.println(nowTime.withNano(66));
    System.out.println("------------------------");

    LocalDate myDate = LocalDate.of(2020, 10, 6);
    LocalDate nowDate = LocalDate.now();

    // 2020-10-06 是否在 nowDate 之前 ?
    System.out.println(myDate + "是否在" + nowDate + "之前? >>>" + myDate.isBefore(nowDate));
    // 2020-10-06 是否在 nowDate 之后 ?
    System.out.println(myDate + "是否在" + nowDate + "之后? >>>" + myDate.isAfter(nowDate));
    System.out.println("----------------------");
    // 判断两个时间是否相同
    System.out.println(myDate.equals(nowDate));
}

DateTimeFormatter 日期格式化

用于时间的格式化和解析 对象的获取 : public static DateTimeFormatter ofPattern(String pattern) : 获取格式对象 格式化 : public String format(TemporalAccessor temporal) : 按照指定方式格式化

/**
 *  用于时间的格式化和解析 :
 *      1、对象的获取 :
 *          public static DateTimeFormatter ofPattern(String pattern) : 获取格式对象
 *      2、格式化 :
 *          public String format(TemporalAccessor temporal) : 按照指定方式格式化
 *      3、解析 :
 *          LocalDateTime.parse("要解析的字符串", 格式化对象);
 *          LocalDate.parse("要解析的字符串", 格式化对象);
 *          LocalTime.parse("要解析的字符串", 格式化对象);
 */
public static void main(String[] args) {
    LocalDateTime now = LocalDateTime.now();
    System.out.println("格式化之前 :" + now);

    // 获取格式化对象
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    //  格式化
    String result = formatter.format(now);
    System.out.println("格式化之后 :" + result);

    // 解析
    String time = "2020年07月07日";
    LocalDate parse = LocalDate.parse(time, formatter);
    System.out.println(parse);
}

Instant、ZoneId类、ZonedDateTime

Instant

/**
 *  Instant 类 : 用于表示时间的对象,类似之前学习的Date
 *
 *  Instant 类的常见方法 :
 *      public static Instant now() : 获取当前时间的 Instant 对象(标准时间)
 *      public static Instant ofXxxx(long epochMilli) :根据(秒/毫秒/纳秒) 获取 Instant 对象
 *      public ZonedDateTime atZone(ZoneId zone) : 指定时区
 *      public boolean isXxx(Instant otherInstant) : 判断系列的方法
 *      public Instant minusXxx(long millisToSubtract) : 减少时间系列的方法
 *      public Instant plusXxx(long millisToSubtract) : 增加时间系列的方法
 */
public static void main(String[] args) {
    // 获取当前时间的 Instant 对象(标准时间)
    Instant now = Instant.now();
    System.out.println("当前的时间戳是 :"+ now);

    // 根据(秒/毫秒/纳秒) 获取 Instant 对象
    Instant instant1 = Instant.ofEpochMilli(1000);
    Instant instant2 = Instant.ofEpochSecond(5);
    System.out.println(instant1);
    System.out.println(instant2);
    System.out.println("------------------");

    // 指定时区
    ZonedDateTime zonedDateTime = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));
    System.out.println("带时区的时间 : "+zonedDateTime);
    System.out.println("------------------");

    // 判断系列的方法
    System.out.println(now.isBefore(instant1));
    System.out.println(now.isAfter(instant1));
    System.out.println("------------------");
    // 减少时间系列的方法
    System.out.println("减 1000 毫秒:"+ now.minusMillis(1000));
    System.out.println("减 5 秒钟:"+ now.minusSeconds(5));
    System.out.println("------------------");
    // 增加时间系列的方法
    System.out.println("加 1000 毫秒:"+ now.plusMillis(1000));
    System.out.println("加 5 秒钟:"+ now.plusSeconds(5));
}

ZoneId类

/**
 *  ZoneId类 : 时区类
 *
 *  常见方法 :
 *      1、public static Set<String> getAvailableZoneIds() : 获取Java中支持的所有时区
 *      2、public static ZoneId systemDefault() : 获取系统默认时区
 *      3、public static ZoneId of(String zoneId) : 获取一个指定时区
 */
public static void main(String[] args) {
    // 获取Java中支持的所有时区
    Set<String> set = ZoneId.getAvailableZoneIds();
    System.out.println(set);
    System.out.println(set.size());
    System.out.println("-------------");

    // 获取系统默认时区
    ZoneId zoneId = ZoneId.systemDefault();
    System.out.println(zoneId);
    System.out.println("------------");

    // 获取一个指定时区
    ZoneId of = ZoneId.of("Africa/Nairobi");
    System.out.println(of);

    ZonedDateTime zonedDateTime = Instant.now().atZone(of);
    System.out.println(zonedDateTime);
}

ZonedDateTime

/**
 *  ZonedDateTime 带时区的时间对象:
 *      public static ZonedDateTime now() : 获取当前时间的 ZonedDateTime 对象
 *      public static ZonedDateTime ofXxx(...) :  获取指定时间的 ZonedDateTime 对象
 *      public ZonedDateTime withXxx(时间) : 修改时间系列的方法
 *      public ZonedDateTime minusXxx(时间) : 减少时间系列的方法
 *      public ZonedDateTime plusXxx(时间) : 增加时间系列的方法
 */
public static void main(String[] args) {
    // 获取当前时间的 ZonedDateTime 对象
    ZonedDateTime now = ZonedDateTime.now();
    System.out.println(now);
    System.out.println("----------------------");

    // 获取指定时间的 ZonedDateTime 对象
    ZonedDateTime of = ZonedDateTime.of(2020, 7, 7,
            8, 5, 0, 0, ZoneId.systemDefault());
    System.out.println(of);
    System.out.println("----------------------");

    // 修改时间系列的方法
    System.out.println(now.withYear(2020));
    System.out.println(now.withMonth(7));
    System.out.println(now.withDayOfMonth(7));
    System.out.println("----------------------");
    // 减少时间系列的方法
    System.out.println(now.minusYears(1));
    System.out.println(now.minusMonths(1));
    System.out.println(now.minusDays(1));
    System.out.println("----------------------");
    // 增加时间系列的方法
    System.out.println(now.plusYears(1));
    System.out.println(now.plusMonths(1));
    System.out.println(now.plusDays(1));
    System.out.println("----------------------");
}

Period、Duration、ChronoUnit

ChronoUnit

/**
 *  ChronoUnit 可用于在单个时间单位内测量一段时间,这个工具类是最全的了,可以用于比较所有的时间单位
 */
public static void main(String[] args) {
    // 此刻的日期时间对象
    LocalDateTime today = LocalDateTime.now();
    System.out.println(today);
    // 生日时间
    LocalDateTime birthday = LocalDateTime.of(1997, 10, 6,
            0, 0, 0);
    System.out.println(birthday);

    System.out.println("相差的年数" + ChronoUnit.YEARS.between(birthday,today));
    System.out.println("相差的月数" + ChronoUnit.MONTHS.between(birthday,today));
    System.out.println("相差的周数" + ChronoUnit.WEEKS.between(birthday,today));
    System.out.println("相差的天数" + ChronoUnit.DAYS.between(birthday,today));
    System.out.println("相差的小时" + ChronoUnit.HOURS.between(birthday,today));
    System.out.println("相差的分钟" + ChronoUnit.MINUTES.between(birthday,today));
    System.out.println("相差的秒钟" + ChronoUnit.SECONDS.between(birthday,today));
    System.out.println("相差的毫秒数" + ChronoUnit.MILLIS.between(birthday,today));
    System.out.println("相差的微妙数" + ChronoUnit.MICROS.between(birthday,today));
    System.out.println("相差的纳秒数" + ChronoUnit.NANOS.between(birthday,today));
    System.out.println("相差的半天数" + ChronoUnit.HALF_DAYS.between(birthday,today));
    System.out.println("相差的十年数" + ChronoUnit.DECADES.between(birthday,today));
    System.out.println("相差的世纪(百年)数" + ChronoUnit.CENTURIES.between(birthday,today));
    System.out.println("相差的千年数" + ChronoUnit.MILLENNIA.between(birthday,today));
    System.out.println("相差的纪元数" + ChronoUnit.ERAS.between(birthday,today));
}

Duration

public static void main(String[] args) {
    // 此刻的日期时间对象
    LocalDateTime today = LocalDateTime.now();
    System.out.println(today);
    // 昨天的日期时间对象
    LocalDateTime yesterday = LocalDateTime.of(2023, 6, 23,
            0, 0, 0);
    System.out.println(yesterday);

    Duration duration = Duration.between(yesterday,today);  //第二个参数减去第一个参数
    System.out.println(duration.toDays());              // 两个时间差的天数
    System.out.println(duration.toHours());             // 两个时间差的小时数
    System.out.println(duration.toMinutes());           // 两个时间差的分钟数
    System.out.println(duration.toMillis());            // 两个时间差的毫秒数
    System.out.println(duration.toNanos());             // 两个时间差的纳秒数
}

Period

/**
 *  Period 计算日期间隔 (年月日)
 */
public static void main(String[] args) {
    // 此刻年月日
    LocalDate now = LocalDate.now();
    System.out.println(now);

    // 昨天年月日
    LocalDate yesterday = LocalDate.of(2023, 6, 23);
    System.out.println(yesterday);

    // Period 对象表示时间的间隔对象
    Period period = Period.between(now,yesterday);  //第二个参数减去第一个参数
    System.out.println(period.getYears());          // 间隔多少年
    System.out.println(period.getMonths());         // 间隔的月份
    System.out.println(period.getDays());           // 间隔的天数
    System.out.println(period.toTotalMonths());     // 总月份
}

Arrays 类

数组操作工具类,专门用于操作数组元素 常用方法 :

  - public static String toString(类型[] a) : 将数组元素拼接为带有格式的字符串
  - public static boolean equals(类型[] a, 类型[] b) : 比较两个数组内容是否相同
  - public static int binarySearch(int[] a, int key) : 查找元素在数组中的索引 (二分查找法 : 保证数组的元素是排好序的)

如果查找的元素,在数组中不存在 : 返回 (-(插入点) -1)

  - public static void sort(int[] a) : 对数组进行默认升序排序

集合

概念:对象的容器,存储对象的对象,可代替数组。

List

ArrayList

ArrayList 的扩容 : 1、当创建 ArrayList 集合容器的时候,底层会存在一个长度为 10 个大小的空数组; 2、当需要添加超过数组长度的元素的时候,扩容原数组,创建一个原数组 1.5 倍 大小的新数组; 3、将原数组数据,拷贝到新数组中; 4、将新元素添加到新数组中

public class ArrayListDemo1 {
    /**
     *  ArrayList 集合的使用 :
     *      细节 : 创建 String , StringBuilder , ArrayList 类的对象,打印对象名,都没有看到地址值,而是元素内容
     *      1、构造方法 :
     *          public ArrayList() : 穿件一个空的集合容器
     *      2、集合容器的创建细节 :
     *          ArrayList list = new ArrayList();
     *              现象 : 可以添加任意类型的数据
     *              弊端 : 数据不够严谨
     *          ArrayList<String> list = new ArrayList<>();
     *
     *      3、< > : 泛型
     *          目前 : 使用泛型,可以对集合中存储的数据,进行类型限制
     *          细节 : 泛型中,不允许编写基本数据类型
     *          问题 : 那如果想要在集合中存储 整数、小数、字符。。。这些数据,要怎么写?
     *          解决 : 使用基本数据类型所对应的包装类
     *              byte        Byte
     *              short       Short
     *              int         Integer
     *              long        Long
     *              float       Float
     *              double      Double
     *              boolean     Boolean
     *              char        Character
     *      4、ArrayList 常用的成员方法 :
     *          增 :
     *              public boolean add(E e) : 将指定的元素追加到此列表的末尾。
     *              public void add(int index, E element) : 在指定索引位置,添加对应的元素(插队)
     *          删 :
     *              public E remove(int index) : 根据索引做删除,返回被删除掉的元素
     *              public boolean remove(Object o) : 根据元素做删除,返回是否删除成功的状态
     *              注意 : remove 方法调用以后,ArrayList里 被删除的元素 后面的元素的索引都会往前 进1 , 即索引值会 -1
     *          改 :
     *              public E set(int index, E element) : 修改指定索引位置的元素  为 设置的元素;返回被覆盖掉的元素
     *          查 :
     *              public E get(int index) : 根据索引,获取集合中的元素
     *              public int size() : 返回 集合中元素的个数
     *      5、ArrayList 常用的遍历 :
     *  a
     */
    public static void main(String[] args) {
        firstArrayList();
        //  ArrayList 的 添加方法
        addMethod();
        //  ArrayList 的 删除方法
        removeMethod();
        //  ArrayList 的 修改方法
        setMethod();
        //  ArrayList 的 获取方法
        getMethod();
        //  ArrayList 的 for 循环遍历
        forLoop();
        //
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
    }

    /**
     *  ArrayList 的 for 循环遍历
     */
    private static void forLoop() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        for (int i = 0; i < list.size(); i++) {
            String  str = list.get(i);
            System.out.println(str);
        }
    }

    /**
     *  ArrayList 的 获取方法
     */
    private static void getMethod() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        String s = list.get(2);
        System.out.println(s);
        System.out.println(list);
        System.out.println(list.size());
    }

    /**
     *  ArrayList 的 修改方法
     */
    private static void setMethod() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.set(1,"赵子龙");
        System.out.println(list);
    }

    /**
     *  ArrayList 的 删除方法
     */
    private static void removeMethod() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add(0,"赵子龙");
        list.remove(1);
        list.remove("赵子龙");
        System.out.println(list);
    }

    /**
     *  ArrayList 的 添加方法
     */
    private static void addMethod() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add(0,"赵子龙");
        System.out.println(list);
    }

    /**
     *  ArrayList
     */
    private static void firstArrayList() {
        // 下面注释的代码为不够严谨
//        ArrayList list = new ArrayList();
//        list.add("张三");
//        list.add("李四");
//        list.add("王五");
//        System.out.println(list);
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        System.out.println(list);
    }

}

十六、递归和异常

递归

递归介绍 : 方法直接或者间接调用本身。使用递归必须声明自己何时结束 递归的思路 : 将大问题,层层转化为一个与原问题相似的,规模更小的问题来解决。 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。

/**
 *  递归介绍 : 方法直接或者间接调用本身
 *      递归如果没有控制好种植,会出现递归死循环,导致栈内存溢出现象
 *      一些算法题的实现,都需要使用递归
 */
public static void main(String[] args) {
    // 递归 : 直接自己调用自己
    method();
    // 递归 : 间接自己调用自己
    methodA();
    // 上面两种调用方式都会引发了StackOverflowError异常,栈内存溢出
}

public static void method(){
    method();
}

public static void methodA(){
    methodB();
}
public static void methodB(){
    methodC();
}
public static void methodC(){
    methodA();
}

异常

异常 : 异常指的是程序在编译或者执行过程中,出现的非正常的情况 (错误) 阅读异常信息 : 从下往上看 1、找异常错误位置; 2、异常名称; 3、异常原因。 image.png 异常可分为 : 检查时异常 和 运行时异常 异常处理 : try...catch...finally 异常声明 : throws --- 通常跟在 方法名() 后面 抛出异常 : throw --- 在代码中需要抛出异常的位置,作为一条语句单独使用,抛出的异常必须被捕获或者声明

异常的处理

Java 是采用面向对象的方式来处理异常的 异常的处理方式有两种 : 1、抛出异常;2、捕获异常。 try...catch捕获异常 : 能够将抛出的异常对象捕获,然后执行异常的处理方案 好处 : 异常对象可以被捕获,后续的代码可以继续执行 格式 : try { 可能会出现异常的代码 } catch (异常名称 对象名) { 异常的处理方案 } 可以存在多个catch, 如果使用多个catch,最大的异常需要放到最后。 执行流程 : 1.执行 try {} 中的代码,看是否有异常对象产生 2.没有 : catch 就不会捕获,后续代码继续执行

  1. 有 : catch捕获异常对象,执行 catch {} 中的处理方案,后续代码继续执行 throws 抛出异常 : throws-声明 也就是声明这个方法中有可能出现异常 格式 : public void method() throws 异常1,异常2,异常3...{} 两种处理方式
try...catch捕获异常出现问题,程序可以继续执行
throws 抛出异常出现问题,程序会在错误点停止,不会继续执行

两种处理方式怎么选 : 看正在面临的异常,是否需要暴露出来:

  • 不需要暴露 : try...catch捕获
  • 需要暴露 : 抛出异常 **throw 和 throws 的区别 **:
throw用在方法中,后面跟的时异常对象,其作用时抛出异常对象
throws用在方法名后面,起到声明作用,声明此方法中存在异常,调用者需要进行处理

注意 : 抛出的异常对象如果是编译时异常,必须使用 throws 声明 如果是运行时异常,则不需要写 throws

public class HandleExceptionDemo {
    /**
     *  异常的处理方式 :
     *      1、try...catch捕获异常
     *          好处 : 异常对象可以被捕获,后续的代码可以继续执行
     *          格式 :
     *              try {
     *                  可能会出现异常的代码
     *              } catch (异常名称 对象名) {
     *                  异常的处理方案
     *              }
     *          执行流程 :
     *              1.执行 try {} 中的代码,看是否有异常对象产生
     *              2.没有 : catch 就不会捕获,后续代码继续执行
     *              3. 有 : catch捕获异常对象,执行 catch {} 中的处理方案,后续代码继续执行
     *      2、throws 抛出异常
     *          throws-声明   也就是声明这个方法可能出现异常
     *      --------------------------------------------------------------------------------
     *          问题 : 正在面临的异常,是否需要暴露出来
     *              - 不需要暴露 : try...catch捕获
     *              -  需要暴露 : 抛出异常
     */
    public static void main(String[] args) throws Exception {
        tryCatchDemo();
        throwsDemo();
    }

    private static void throwsDemo() throws ParseException, FileNotFoundException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
        Date date = format.parse("2020年8月10日");
        System.out.println(date);
        FileReader fileReader = new FileReader("D:\\a.txt");
    }

    private static void tryCatchDemo() {
        System.out.println("开始");
        /*
        try {
            int[] arr = null;
            System.out.println(arr[6]);
            System.out.println(10/0);
        } catch (ArithmeticException e) {
            System.out.println("捕获了运算异常");
        } catch (NullPointerException e) {
            System.out.println("捕获了空指针异常");
        }
        */

        try {
            int[] arr = null;
            System.out.println(arr[6]);
            System.out.println(10/0);
        } catch (Exception e) {
            System.out.println("捕获了异常");
        }

        System.out.println("结束");
    }
}

自定义异常

自定义异常的必要性 : 1. Java 无法为这个世界上全部的问题提供异常类;2. 如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常。 自定义异常 : 1、建立自定义异常类,继承异常父类,并书写构造方法 2、在代码中抛出 throw new 自定义异常();或者在 catch中捕获。需要注意的是 : 抛出异常之后,不能在写代码,并且每一句只能抛出一个异常。 自定义异常的分类 : 1、自定义编译时异常 定义一个异常类继承 Exception 并重写构造器 2、自定义运行时异常 定义一个异常类继承 RuntimeException 并重写构造器

public class StudentAgeException extends RuntimeException {
    /**
     *  自定义异常 :
     *      自定义编译时异常 : 创建一个类,继承 Exception
     *      自定义运行时异常 : 创建一个类,继承RunTimeException
     */
    public StudentAgeException() {
    }

    public StudentAgeException(String message) {
        super(message);
    }
}

异常的常见方法

  • Throwable常用方法 :

public String getMessage() 获取异常的错误原因 public void printStackTrace() 展示完整的异常错误信息

  • 子类重写父类的方法时,不能抛出父类没有的异常,或者比父类更大的异常

十七、新特性

接口新特性

JDK8的新特性 : 接口中可以定义有方法体的方法。(默认、静态) JDK9的新特性 : 接口中可以定义私有方法。 JDK8接口特性 允许在接口中定义非抽象方法,但是需要使用关键字 default 修饰,这些方法就是默认方法 作用 : 解决接口升级的问题 接口中默认方法的定义格式 : 格式 : public default 返回值类型 方法名(参数列表) {} 范例 : public default void show() {} 注意事项 : 1、默认方法不是抽象方法。所以不强制重写(但是可以被重写,重写的时候去掉 default 关键字) 2、 public 可以省略,default 不能省略 3、如果实现了多个接口,并且多个接口中存在相同的方法声明,实现类必须对该方法进行重写 接口中允许定义 static 静态方法 接口中默认方法的定义格式 : 格式 : public static 返回值类型 方法名(参数列表) {} 范例 : public static void show() {} 注意事项 : 1、public 可以省略,但是 static 不能省略; 2、静态方法只允许通过接口名进行调用,不允许实现类名或者对象名调用 JDK9接口特性 接口中允许定义 private 私有方法 作用 : 解决接口升级的问题 接口中私有方法的定义格式 : 格式1 : private 返回值类型 方法名(参数列表) {} 范例1 : private void show() {} 格式2 : private static 返回值类型 方法名(参数列表) {} 范例2 : private static void show() {}

Lambda表达式

Lambda表达式是 JDK8 开始的一种新的语法形式 作用 : 简化匿名内部类的代码写法 image.png image.png image.png

十八、设计模式

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 设计模式共有 23 种

适配器设计模式

image.png

模板方法设计模式

image.png

十九、算法

comparable 接口 : 要对某个类的对象之间作比较,就需要实现 Comparable 接口 这个接口只有一个方法 compareTo , 这个方法定义了对象之间的比较规则 eg :

public class Manager implements Comparable {
    int age;

    @Override
    public int compareTo(Object o) {
        Manager manager = (Manager) o;
        if (this.age < manager.age) {
            return -1;
        }
        if (this.age > manager.age) {
            return 1;
        }
        return 0;
    }
}

常见算法 : visualgo.net/en --- 算法学习网站 二分法查找 : 必须是已经排好序的数据才能使用;原理是 : 找中间位置,对半比较。

冒泡排序 :

相邻的两个数进行比较,如果第一个比第二个大,就交换他们两个

/**
 *  冒泡排序 : 相邻的两个数进行比较,如果第一个比第二个大,就交换他们两个
 *      第一轮 : arr[0] - arr[1]  arr[1] - arr[2]  arr[2] - arr[3]  arr[3] - arr[4] 比较4次
 *      第二轮 : arr[0] - arr[1]  arr[1] - arr[2]  arr[2] - arr[3]  比较3次
 *      第三轮 : arr[0] - arr[1]  arr[1] - arr[2]  比较2次
 *      第四轮 : arr[0] - arr[1]  比较1次
 */
public static void main(String[] args) {
    int[] arr = {22,55,44,33,11};

    // 外循环 : 比较的轮数
    for (int i = 0; i < arr.length-1; i++) {
        //  内循环 : 比较的次数
        //  -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;
            }
        }
    }
    System.out.println(Arrays.toString(arr));
}

选择排序 :

从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较

/**
 *  选择排序 : 从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较
 *      第一轮 : arr[0] - arr[1]  arr[0] - arr[2]  arr[0] - arr[3]  arr[0] - arr[4] 比较4次
 *      第二轮 : arr[1] - arr[2]  arr[1] - arr[3]  arr[1] - arr[4]  比较3次
 *      第三轮 : arr[2] - arr[3]  arr[2] - arr[4]  比较2次
 *      第四轮 : arr[3] - arr[4]  比较1次
 */
public static void main(String[] args) {
    int[] arr = {22,55,44,33,11};

    // 外循环 : 比较的轮数
    for (int i = 0; i < arr.length-1; i++) {
        //  内循环 : 比较的次数
        //  -1 : 避免索引越界
        //  -i : 提升效率
        for (int j = i+1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }

    System.out.println(Arrays.toString(arr));
}

二分查找 :

必须是已经排好序的数据才能使用,找中间位置,对半查找。

/**
 *  二分查找 (折半查找) :
 *      前提 : 数组元素必须是排好序的
 *
 *      思路 :
 *          1、定义两个变量记录最小索引和最大索引
 *          2、折半的动作不止一次,应该使用循环
 *              条件 while(min<=max)
 *          3、循环中计算出中间索引
 *          4、加入判断
 *              元素如果大于中间元素 : min = mid + 1;
 *              元素如果小于中间元素 : max = mid - 1;
 *              元素如果等于中间元素 : 将索引返回 (mid)
 */
public static void main(String[] args) {
    int[] arr = {11,22,33,44,55,66,77,88,99,100,110};
    int index = binarySearch(arr, 122);
    System.out.println("查找元素在数组中的位置 : " + index);
}

private static int binarySearch(int[] arr, int i) {
    // 1、定义两个变量记录最小索引和最大索引
    int min = 0;
    int max = arr.length -1;
    int mid;
    // 2、折半的动作不止一次,应该使用循环
    while (min <= max) {
        // 3、循环中计算出中间索引
        mid = (min+max) / 2;
        // 4、比对
        if ( i > arr[mid]) {
            min = mid + 1;
        } else if (i < arr[mid]) {
            max = mid - 1;
        } else {
            // 找到了,返回索引
            return mid;
        }
    }
    // 5、没找到,返回 -1
    return -1;
}

二十、一些平时用不到的知识点

窗体、组件、事件

窗体

窗体对象JFrame JFrame frame = new JFrame(); frame.setVisible(true); // 设置窗体显示可见 frame.setSize(514,595); // 设置窗体大小

public static void main(String[] args) {
    // 创建窗体对象
    JFrame frame = new JFrame();
    // 设置窗体大小
    frame.setSize(500,600);
    // 修改窗体的关闭模式   这里是点击窗口的 X 之后关闭运行程序
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // 设置窗体标题
    frame.setTitle("世界大战");

    // 设置窗体可见    最好放在最后面
    frame.setVisible(true);
}

组件

按钮

public class JButtonDemo {
    /**
     *  JButton 的构造方法 :
     *      1、public JButton() : 创建一个空白的按钮
     *      2、public JButton(String text) : 创建一个带文本的按钮
     *
     *  注意 : 如果取消类窗体的默认布局,就需要手动指定组件的摆放位置了
     */
    public static void main(String[] args) {
        // 创建窗体对象
        JFrame frame = new JFrame();
        // 设置窗体大小
        frame.setSize(500,600);
        // 修改窗体的关闭模式
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置窗体标题
        frame.setTitle("世界大战");
        //  取消窗体的默认布局
        frame.setLayout(null);

        // 1、创建按钮对象
        JButton button = new JButton("按钮啊");
        //指定按钮位置和大小
        button.setBounds(10,10,100,50);
        // 2、将按钮添加到窗体的 [面板对象] 中
        frame.getContentPane().add(button);

        // 设置窗体可见    最好放在最后面
        frame.setVisible(true);
    }
}

文本和图片

public class JLableDemo {
    /**
     *  JLabel 的构造方法
     *      JLabel(String text) : 使用指定的文本创建一个 JLabel 对象
     *      JLabel(Icon image) : 创建一个具有指定图像的 JLabel 对象
     */
    public static void main(String[] args) {
        // 创建窗体对象
        JFrame frame = new JFrame();

        // 设置窗体大小
        frame.setSize(500,600);
        // 修改窗体的关闭模式
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置窗体标题
        frame.setTitle("世界大战");
        //  取消窗体的默认布局
        frame.setLayout(null);

        // JLabel 展示文本
        JLabel label1 = new JLabel("吾日三省吾身");
        label1.setBounds(33,33,100,50);
        frame.getContentPane().add(label1);
        JLabel label2 = new JLabel("吃乎,玩乎,睡乎");
        label2.setBounds(133,33,120,50);
        frame.getContentPane().add(label2);
        // JLabel 展示图片
        //ImageIcon icon = new ImageIcon("D:\\图库\\img.jpg");
        JLabel label_2jpg = new JLabel(new ImageIcon("D:\\图库\\img.jpg"));
        label_2jpg.setBounds(33,88,120,50);
        frame.getContentPane().add(label_2jpg);

        // 设置窗体可见    最好放在最后面
        frame.setVisible(true);
    }
}

事件

动作事件 : ActionListener 键盘事件 : KeyListener image.pngimage.png 焦点 : 程序的注意力 取消按钮焦点 : btn.setFocusable(false); image.png