导航:
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外/黑马旅游卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计源码+-CSDN博客
推荐视频:
黑马会计师Java教程_哔哩哔哩
尚硅谷Java入门视频教程_哔哩哔哩官方
推荐书籍:
《Java编程思想(第4版)》
《Java核心技术·卷I(原书第12版):开发基础》
目录
零、言引
0.1 背景和写作目的
0.2 本期更新内容
一、环境准备
1.1 JDK8
1.1.1 下载
1.1.2 安装
1.1.3 配置环境变量
1.1.4 验证
1.1.5知识加油站:JDK、JRE、JVM、Java的区别
1.1.6 知识加油站:Java8新特性
1.2记事本体验Hello World
二、Java编译器:IDEA
2.1 下载安装配置
2.1.1 下载安装
2.1.2配置
2.1.2.1 编码配置UTF-8
2.1.2.2配置Maven路径
2.1.3 安装插件
2.1.3.1 基础插件
2.1.3.2 高级插件
2.1.5编写Hello World
2.1.6常用快捷键
2.2 断点调试
2.2.1 断点
2.2.2 调试 p>
2.2.3 知识加油站:高级断点调试
2.2.3 丢帧(退帧)
2.2.4 返回强制
2.2.5流流调试
2.2.6 评估表达式:ALT+F8< /p>
2.2.7 多线程调试
三、Java基本概念和语法
3.1 基本数据类型
3.1.1 概述
3.1.2 知识加油站:基本数据类型和引用类型
3.1.3 知识加油站:数据类型的基本内存空间
3.2 内存
3.2.1 创建
3.2.1.1 数据库的两种创建方式
3.2.1.2 知识加油站:内存的创建原理
3.2.2初始化
3.2.2.1 静态初始化
3.2.2.2 动态初始化
3.2.3 访问
3.2.3.1 基本访问方式
3.2.3.2 高级访问方式:迭代器、Stream流、toString
3.2.4 操作
3.2.4.1 仓库和字符串的相互转换
3.3 流程控制语句
3.3.1 概述
3.3.2 IF分支语句
3.3.2.1 基本语法
3.3.2.2 练习
3.3.3 switch分支语句
3.3.3.1 基本语法
3.3.3.2 练习
3.4 修饰符
3.4.1 访问权限修饰符:公共、受保护、默认、私有
3.4.2 静态
3.4.2.1 基本介绍
3.4.2.2 知识加油站:类变量
3.4.3 摘要
3.4.3.1 基本介绍
3.4.3.2 知识加油站:接口和抽象类的区别
3.4.6 最终版
3.4常用关键字
3.4.1 这个
3.4.2 超级
3.4.3 知识加油站:这个和超级的区别
四面向、对象编程(OOP)
4.0 概述
4.1 类和对象
4.1.1 基本介绍
4.1.2 知识加油站:内部类
4.1.3 知识加油站:创建对象的几种方法
4.2方法
4.2.1 基本介绍
4.2.2基本用法
4.2.2.1定义
4.2.2.2 调用
4.2.2.3 返回值
4.2 .3 重载方法
4.2.3.1 重载加载
3.2.3.2 重载和重写的区别
3.2.4 可变参数
3.2.5构造方法
4.3 接口和抽象类
4.3.1 概述
4.3.2接口
4.3.3抽象类
4.3.4 知识加油站:抽象类和接口的区别
4.4 面对对象三特性
4.4.1 封装
4.4.2 继承
4.4.3 多态< /p>
五、常用类
5.1 String类
5.1.1 基本介绍
5.1.2 基本协议
5.1.2.1 创建
5.1.2.2 访问
5.1.2.3 连接
5.1.2.4 子串
5.1.2.5删除
5.1.2.6替换
5.1.2.7 获取长度
5.1.2.8 比较
5.1.2.8 知识加油站:==与equals()的区别
5.1.2.9 分割
5.1.2.10 转换大小写
5.1.2.11 字符串和数字的相互转换
5.1.2.12 带宽和字符串的相互转换
5.1.3知识加油站
5.1.3.1 字符串和字符数组的区别
5.1.3.2 字符串常量池
5.1.3.3 String不可被继承、不可修改的原因
5.1.3.4 new String("abc")创建的字符串对象数量
5.2 StringBuilder类
5.2.1 基本介绍
5.2.2 知识加油站:String、StringBuffer、Stringbuilder的区别
5.3 扫描仪类
5.4 对象类
5.4.1 基本介绍
5.4.2 知识加油站:JVM垃圾恢复的便捷性分析算法
5.4.3 知识加油站:hashCode ()和equals()的区别
5.5系统类
5.6 整数类
5.6.1 基本介绍
5.6.2 知识加油站:包装类的自动拆装箱与自动装箱
5.6.3 知识加油站:什么情况下用包装类?什么情况下用基本数据类型?
5.6 .4 知识加油站:包装类和基本数据类型直接如何比较?(浮点数等号比较精度丢失问题)
5.6.5 知识加油站:Integer a1=127;Integer a2=127; a1==a2原因
5.7 数组类
5.6.1 排序
5.6.2 查找和判断
5.6.3批量填充
5.6.4 转换字符串、链表
5.6.5 拷贝
5.8 日期类
5.8.1常用方法
5.8.2 代码示例
5.8.3知识加油站:日期类的线程安全问题
5.8.4 格式化日期:
5.8.4.1 SimpleDateformat类:线程不安全
5.8.4.2 DateTimeFormatter类:线程安全
5.9 Math类
5.10 随机
5.10.1 基本介绍
5.10.2 代码示例
1.提供一套完整的Java学习路线。< /strong>
本专栏旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时期成长为高级开发。
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpRingBoot+SpringCloud+瑞吉外卖/黑马旅游/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码
2.遵循开源精神,贡献自身力量。
Java语言拥有一个非常活跃的社区,在创作者的成长过程中,从很多文章中学习到有价值的知识,所以也希望能够帮助到其他人。
3.温故知新,提高技术深度。
人的记忆力有时候是不可靠的,所以在做事的过程中要尽量有记录、有结果,这样随着自己的成长,技术深度的提升,可以不断地强化它们,净化自己可以有很多新的决策。
本期更新了以下内容:
清晰除视觉文字,内容更加精炼。新增知识加油站,达到深入浅出。优化大纲,调整章节顺序。图、文、代码块优化,提高必备性。下载jdk8(JDK8就是JDK1.8)
JDK8或者JDK1.8是由于JDK1.5/JDK5命名改变方式后面继承的新旧命令方式问题。所以JDK8或者JDK1.8也是同一个东西。
下载地址:Java Downloads | Oracle
选择windows64版本exe下载
需要登录才能下载:
登录后会自动下载:
下一步: < /p>
设置安装路径:
点击下一步,将安装完成。
此电脑右键属性
高级系统设置:
环境变量: p>
设置环境变量:
验证是否安装成功:
打开Windows的运行(可用win+R快捷键)按打开),输入cmd
验证Java版本:
java -version
验证Java编译命令是否可用:
javac
这里仅简单介绍,具体下面章节会详细介绍。
Java8新特性:
Lambda表达式:Lambda表达式可以被视为一个对象,必须有上下文环境,作用是实现单个方法的接口。该特性可以将功能视为方法参数,或者将代码视为数据。上下文环境意思是能证明它是对象,例如实现方法或类的实数省略情况:形参类型、返回类型可以省略,单参数可以省略小键盘,单语句可以省略return、分号和大引号(全省略或完全不简洁)方法引用:引用已存在的Lambda表达式,达到相同的效果。引用已有Java类或对象(实例)的静态方法、实例方法、对象方法(System.out) ::println;)、构造器方法。可以与Lambda联合使用,方法引用可以使语言的构造更简洁、简化生成代码。接口默认方法:允许在接口中定义默认方法,默认方法必须使用默认构造函数。默认方法是接口中有方法体的方法,用于向现有的接口添加新的功能,而无需删除现有的实现。实现类可以直接调用默认方法,也可以重写默认方法。Stream API:新添加的Stream API(java.util.stream)支持对元素流进行函数式操作。Stream API 集成在 Collections API 中,可以对集合进行批量操作(流流的生成、操作、收集),例如filter()过滤、distinct ()去重、map()处理、sorted()排序等操作。Date Time API新增LocalDate、LocalTime、DateTimeFormatter等类:加强对日期与时间的处理。LocalDate、LocalTime可以获取本地时间。线程安全的DateTimeFormatter代替线程不安全的SimpleDateFormat,用于将日期和字符串之间进行格式转换。HashMap底层引入红黑树:之前版本HashMap底层是“队列+链表” ,当头插法的值链表长度大于等于8时,链表会转为红黑树,红黑树查询稳定性O(logn),是近似平衡二叉树,层数最高2logn。ConcurrentHashMap降低锁的粒度:JDK1.8采用支架锁,锁粒度是之前的支架段,JDK1.8采用synchronized+CAS,锁粒度是槽(头节点)CompletableFuture:是Future的实现类,JDK8引入,用于异步编排。JVM方法区的实现方式由永久代改为元空间:元空间属于本地内存,由操作系统直接管理,不再受JVM管理。同时内存空间可以自动扩容,避免内存溢出默认情况。下元空间可以无限使用本地内存,也可以通过-XX:MetaspaceSize限制内存大小。1.新增txt文件,输入内容如下,将文件命名为hello.java
public class hello{ public static void main(String[] args){ System.out.println("hello,world~~~~~~"); }}
2.在当前目录下打开cmd命令行,编译、运行Java代码:
编译: < /strong>
#javac指令编译java代码为hello.class文件javac hello.java
运行:
#java指令运行hello.class文件。.class可以省略java hello.class
可以看到,命令行会输出
扩展:
1.如何打开命令行?
方法一:在文件地址栏输入cmd,回车,可以快速在当前目录打开命令行:
< p>方法二:win+R快捷键,输入cmd,回车,然后用cd命令到达指定目录:2.javac指令和java指令是什么?
在Java中,
javac
和java
是两个关键的命令行工具,用于编译和运行Java程序。javac:
javac是Java编译器的命令。于将Java源代码文件(以.java为扩展名)编译成字节码文件(以.class为扩展名)。
语法:
javac
例如,要编译一个名为
MyProgram.java
pre>的Java源文件,可以使用以下命令:
javac MyProgram.java
javac的常见选项:
javac -d:指定生成的类文件存放的目录。javac -cp 或 -classpath:指定查找用户类文件和注释处理程序的位置。javac -source:指定要使用的来源代码版本。javac -target:生成的类文件的目标字节码版本。 java:
java 是Java虚拟机(JVM)的命令。用
语法:
java
例如,如果你有一个名为
MyProgram.class
已编译的Java程序,可以使用以下命令来运行它:
java MyProgram
java的常见选项:
java -cp 或 -classpath:指定查找用户类文件的位置。java -Xmx:设置JVM的最大堆内存大小。java -Xms:设置JVM的初始堆内存大小。
其他版本 - IntelliJ IDEA
安装一直点击下一步即可,只有两点需要注意:
1.设置安装路径:
2.创建桌面快捷方式:
< p>注意:所有设置都必须要关闭项目后,再进行设置,这样才是全局设置。
先关闭项目再点击设置< /p>
这一步初学者去可以直接略,在后面学到Maven后再配置。
设置里搜索Maven,然后配置主路径、仓库路径、配置路径
Maven配置依赖和插件后自动刷新:
IDEA推荐安装以下插件,方便开发,初学者可以只安装第一个插件,后面学习再安装:
1.中文(简体)语言包/中文语言包
对于汉化IDEA,官方已经加汉化做的很好了,例如checkout升降签出,rebase译为变基。当然。习惯了英文可以继续用英文。
2.阿里巴巴Java编码指南
提供代码检查,针对不符合编程的情况规范的代码,会进行提示:
/** * 没有作者注释 */public class Test { public static void main(String[] args) { int a=123; System.out.println("hello");//不要使用行尾注释 }}
下面插件建议获取Maven和Mybatis后再安装:
< strong>1.Maven helper
安装后在代码中右键,可以选择Maven模块,会出现压缩包,编译等选择,另外Maven helper可以解决依赖冲突问题。
2.MybatisX
使用MybatisX插件后,对应的mapper.xml,mapper.java出现小图标鸟,编写接口定义方法之后,会自动在xml中生成语句语句,提高Mybatis框架的开发效率。
3.RESTfulToolkit-fix
RestfulToolkit-fix是一套RESTful服务开发辅助工具集,可以根据URL直接跳转到对应的Controller方法定义,在Controller的方法上添加了能够复制请求URL和方法参数的功能。
安装后可以通过ctrl+\快捷键,搜索url,插件会帮助找到url对应的Controller。
模糊全局匹配URL:
Windows 快捷键:Ctrl + \ 或者 Ctrl + Alt + N。MacOS 快捷键:Command + \ 或者 Command + option + N。 blockquote>5.私人注释
用于在串口代码中添加注释,在阅读一些框架和中间件源码时使用比较方便。
在任何你想添加的注释中的位置点击Alt + Enter鼠标移出点击即可保存
已有私人注释点击Alt + Enter即可快速编辑
Alt + p可快速添加或者编辑私人注释
Alt + o 显示私人注释的其他操作
右键菜单私人注释查看操作2.1.5 编写Hello World
1.创建空项目
2.新建模块
注意SDK开发工具包选JDK8
3.新建包
4.新建类
然后psvm回车自动生成静态main方法,sout回车自动生成System.out.println()输出方法。
package package1;/** * @author xxx */public class Test { public static void main(String[] args) { System.out.println("hello world~~~~"); }}
运行:
如果控制台中文乱码,就在设置里把文件编码页都改成utf-8。
2.1.6 常用键盘
格式化:ctrl+alt+L
主要方法psvm回车,输出sout回车,内容提示ctrl+alt+space 。alt+insert生成构造、setget方法。
补全代码:Ctrl+Alt+v或.var或.for
例如写new Dog();按快捷键会自动补全声明Dog dog=new Dog();或者写new Dog().var回车会自动补全成Dog dog=new Dog();或者写lists .for回车会自动生成for(List
list:lists){} 万能快捷键:alt+enter
获取警告、报错提示自动改正。
查找:ctrl+f
替换:ctrl+r
替换所有与选中内容相同的文本
ctrl+b:抓取
或者ctrl+鼠标左键、或者鼠标左键,执行到该类的定义页面。如果选中的是标识符,可以查找页面内所有该标识符位置。
alt+左键:整列编辑
ctrl+d:复制颈部行并粘贴
ctrl+x:修复颈部行
Ctrl+h:查看该类继承关系:
ctrl+alt+m:抽取选中代码为方法< /p>
Ctrl+f12:查看类中所有方法。
评估表达式:ALT+F8
查看本地历史记录:
idea是会自动保存各文件历史记录的,右键文件-查看本地历史记录即可:
2.2断点调试
2.2.1 断点
调试按钮:运行按钮:普通断点:如果断点打在普通代码行上,点击“debug”会自动运行到该行暂停;
方法断点:如果断点打在方法上,点击“debug”就会自动运行到该方法入口处暂停;
接口断点:如果断点打在接口方法上,点击“debug”就会自动运行到实现类对应方法入口处暂停;
字段断点:如果断点打在字段上,点击“debug”会自动修改运行到该字段的代码行处暂停(在断点处右键)设置成访问时也暂停);
条件断点:在断点处右键,可以输入布尔类型的条件,例如i==0、user.getName() !=null&&"zhangsan".equals(user.getName())。
示例:当i为10时暂停代码运行:
debug可以看到变量信息:
异常断点:在异常时暂停代码运行。在断点处右键更多,设置断点为异常断点,程序将在发生异常时暂停。
2.2.2调试
打断点后面代码运行到这一步会停止:下面红色方框是最常用的两个调试按钮:
蓝色代码行代表此时调试运行到这一行(这一行尚未运行),能看到上一行的结果。
调试的五个核心图标分别是:< /p>
“Step over”:步过。往下运行一行代码并跳过当前方法的调用。 “Step into”:乔丹。进入方法内部并继续逐行执行。适用于自定义方法或第三方方法,但无法进入JDK方法的内部。注意如果蓝色字体行不是方法,则此按钮间接step over。“Force step into”:强制唤醒(不常用)。强制进入方法的内部,即使常规的“Step into”操作无法进入方法内部时也可以使用。适用于无法通过常规方式进入的方法。例如Symtem.out.println()等JDK方法内部。“Step out”:步出。退出当前方法,即执行完成当前方法后返回到调用该方法的位置。注意如果本方法是main方法,则将直接步出该main方法。“Resume Program”:运行到点处。继续运行程序直到下一个断点位置或程序结束。可用于暂停状态下的程序恢复运行。2.2.3知识加油站:高级断点调试
2.2.3 丢帧(退帧)
退帧:回退到该方法之前被调用。
当我们调试从 A 方法进入 B 方法时,通过降帧(退帧)返回到可以调用 B 方法前面,这样我们就可以再调用一次 B 方法。
通常用于当我们快速执行 B 方法后,发现某个重要流程被我们跳过了,想再看一下,则此时可以先退回到A方法,然后再次进入B方法。
2.2.4 强制返回
右键并点击“强制返回”后,此方法栈将直接终止,恢复到上个方法栈。 p>
使用场景:需要结束当前断点,并且不希望接下来的程序操作数据库时,使用强制返回。
注意:如果点击红色方格或重新调试虽然也终止,但其实是运行完成剩余代码之后终止。
强制返回:接下来的程序将不再继续执行。终止:接下来的程序将走完,然后再终止程序。
下面示例:在断点处强制返回,将不打印那行文字;终止则打印。
2.2.5 Stream流调试
在调试中,断点到达Stream流,往往直接会跳过,而我们有时候是需要看Stream流的处理逻辑的,所以就需要对Stream流进行调试。
调试方法:在stream流处打断点,调试后点击“跟踪当前流链”:
< p>示例:Stream流过滤出长度大于5单词:public class Test { public static void main(String[] args ) { // 创建一个列表 List
Words = Arrays.asList("apple", "banana", "orange", "grape", "watermelon"); // 使用 Stream 进行过滤,只选择长度大于 5 的单词 List FilteredWords = Words.stream() .filter(word -> word.length() > 5) .collect(Collectors.toList()); System.out.println("过滤的单词:" +filteredWords); }} 点击“跟踪当前流链”即可看到过滤效果:
2.2.6 评估表达式:ALT+F8 h5>
在if处打断点,调试后点击“evaluate expression”,可以在评估框下测试另一个分支:
2.2.7 多线程调试
多线程环境,打断点并右键设置Thread或All:
Thread:暂停进入断点的线程,不影响其他线程执行。线程依次调试(即你如果给多个线程都加断点,第一个线程调试期间其他线程将保持断点暂停状态)ALL:暂停所有线程。只调试第一个暂停线程(即你如果给多个线程都加断点,那么只有第一个断点对应的线程会正常调试,其他线程会并发运行)
三、Java基本概念和语法
p>
3.1 基本数据类型< /h3>
3.1.1 概述
Java 的八种基本数据类型分别是:
整型的byte、short、int、long;字符型的char;浮点型的float、double;布尔型的boolean。代码示例:
public class Test { public static void main(String[] args) { // 1.整型字节byteData=120;短短数据 = 30000; int intData = 2000000000;长长数据 = 9000000000000000000L; // 2. 字符型 char charData = 'A'; // 3.浮点型 float floatData = 3.14f;双双数据 = 123.456; // 4. 布尔型 boolean booleanData = true; // 访问和输出变量值 System.out.println("整型:"); System.out.println("字节数据:" + 字节数据); System.out.println("短数据:" + 短数据); System.out.println("intData:" + intData); System.out.println("longData: " + longData); System.out.println("\n字符型:"); System.out.println("字符数据:" + 字符数据); System.out.println("\n浮点型:"); System.out.println("floatData: " + floatData); System.out.println("doubleData: " + doubleData); System.out.println("\n布尔型:"); System.out.println("booleanData: " + booleanData); // 操作变量 intData++; // 增加 intData 的值 doubleData *= 2; // 将 doubleData 的值乘以 2 // 修改输出后的值 System.out .println("\n操作后的整型和浮点型变量:"); System.out.println("intData: " + intData); System.out.println("doubleData: " + doubleData); }}
结果:
3.1 .2 知识加油站:基本数据类型和引用类型
基本数据类型
基本数据类型共有八大类,这八大数据类型又可分为四个小类,分别是整数类型(byte/short/int/long)、浮点类型(float、double)、Character类型(char)和布尔类型(boolean)。
引用类型
引用类型包括批量引用、类引用、接口引用,还有一种特殊的空类型,所谓数据引用类型就是对一个对象的引用,对象包括实例和备份数组。
区别:
特征 基本数据类型 引用类型 存储方式 直接存储数据值 存储对象的引用,实际数据存储在堆内存中 默认值 有默认值,不可为null 有默认值为null 属性方式 直接属性 使用new关键字创建对象 内存分配 栈上分配 在堆上分配 大小 固定大小,与具体类型有关 大小不固定,由对象本身及其内容决定 效率 更高效,直接操作数据 相对较低,需要间接操作对象引用 tr>比较 用==比较 通常使用equals方法比较 范围 有限,具体范围取决于数据类型 无限,取决于系统的内存大小 提交方式 值传递,传递的是实际的数据值 引用传递,传递的是对象的引用 实例 int num = 42;
String str = new String("Hello");
JVM存储位置 方法参数和局部变量:存在本地方法栈的局部变量表;
最终常量、静态变量:存在类常量池
堆 3.1.3 知识加油站:基本数据类型的内存空间
对于基本数据类型,您需要了解终结类型所受的内存空间,这是面试官喜欢追问的问题:
- byte:1字节(8位),数据范围为`-2^7 ~ 2^7-1`。-短:2字节(16位),数据范围为`-2^15 ~ 2^15- 1`。- int:4字节(32位),数据范围为`-2^31 ~ 2^31-1`。- long:8字节(64位),数据范围为`-2^63 ~ 2^63-1`。c语言里long占4字节,long long占8字节。- float:4字节(32位),数据范围大约是 `-3.4*10^38 ~ 3.4*10^ 38`。- double:8字节(64位),数据范围大约是 `-1.8*10^308 ~ 1.8*10^308`。 - char:2字节(16位),数据范围为`\u0000 ~ \uffff`,unicode编码英文和中文都占两个字节。c语言使用ASCII编码char占1个字节,不能存汉字。ASCII编码是Unicode的一个子集,它们因此存在一些字符码值是可靠的。 - boolean:Java规范没有明确的规定,不同的JVM有不同的实现机制。3.2 内存
3.2.1 创建 h4>
3.2.1.1 数据库的三种创建方式
一维数据库:< /p>
存储架构有两种方式。
方式一(推荐,符合阿里规范):方式二:// a和b都是一维数据库 int[] a,b;
//c和d都是一维备份,不推荐物种命名方法int c [],d[];
二维数组:
int[][ ] x;
阿里规范约:
【强制】类型与中强度紧棒完整来表示吞吐量。
正例:定义吞吐量 int[] arrayDemo;
反例:在 main 参数中,使用 String args[] 来定义
3.2.1.2知识加油站:内存的创建原理
JVM内存模型:
什么是JVM的内存模型?详细阐述了Java中局部变量、常量、类名等信息在JVM中的存储位置-CSDN博客
存储在JVM的堆中,是一片连续的存储空间,下标依次为0,1,2,3,4...
集群在JVM中的创建过程:
main方法进入方法栈执行创建快照,JVM会在堆内存中开辟空间,存储快照在内存中会有自己的内存地址,以十六进制数表示快照中有3个元素,默认值为0JVM将存储器的内存地址赋值给类型变量数组变量保存引用内存中的地址,而不是一个具体数值,因此称为引用数据类型。3.2.2初始化
Java内存初始化有两种方式,分别是静态初始化、动态初始化。 p> 静态初始化:不指定阵列容量,由JVM自身识别动态初始化:指定阵列容量
3.2.2.1 静态初始化
静态初始化:不指定数据库容量,由JVM自己识别
格式:数据类型[] 数据库名=new 数据类型 {元素1,元素2,元素3...};
示例:
// 静态初始化:不指定长度,由系统猜测// 简写格式(推荐)int[] c={1,2,3};/ / 完整格式int[] ff=new int[]{1,2,3};
3.2.2.2 动态初始化
动态初始化:指定数据库容量
格式:数据类型[] 数据库名=新数据类型[ 数据库的容量];
示例:
//动态初始化:指定长度int[] ff=new int[3];
前>3.2.3 访问
3.2.3.1 基本访问方式
通过下标访问仓库元素:
仓库仓储在JVM的堆中,是一片连续的存储空间,下标依次为0,1,2,3,4...
使用集群的索引(下标)来访问特定位置的元素。集群的索引从0开始,一直到集群长度减一。
int[] 数字 = {1, 2, 3, 4, 5};int 元素 = 数字[2]; // 访问索引为 2 个元素,即内存中的第三个元素System.out.println(element); // 输出:3
for遍历吞吐量:
使用循环结构(如
for
或foreach
)遍历吞吐量,访问每个元素。int[]numbers = {1, 2, 3, 4, 5};/ / 使用 for 循环 for (int i = 0; i
结果:
3.2.3.2 高级访问方式:迭代器、Stream流、toString
路径:迭代器 strong>
对于集合类(如
ArrayList
),可以使用迭代器来访问元素。ArrayList
list = new ArrayList<>();list.add(1);list.add(2);list.add(3);迭代器<Integer> iterator = list.iterator();while (iterator.hasNext()) { int element = iterator.next(); System.out.println(element);} 结果:
遍历:Java 8 的 Stream
使用 Java 8 引入的 Stream API 进行吞吐量传输和操作。
int[]numbers = {1, 2, 3, 4 , 5};// 使用 Stream.forEachArrays.stream(numbers).forEach(System.out::println);
打印全部:数组类的 toString 方法 strong>
使用
Arrays
类的toString
方法将整个集群转换为字符串。int[] numbers = {1, 2, 3, 4, 5};//输出:[1, 2, 3, 4, 5]System.out.println(Arrays.toString(numbers)); //直接输出仓库会输出地址:[I@5b444398System.out.println(a);
3.2.4 操作
备份本身的方法很少,只有equals()、stream()等简单的方法,一些对备份的高级操作,可以将备份转为String或集合,操作后再转回备份。
3.2.4.1 数据库和字符串的相互转换
数据库转字符串:
Arrays.toString(阵列名)
示例:
< pre>int[]numbers = {1, 2, 3, 4, 5};//输出:[1, 2, 3, 4, 5]System.out.println( Arrays.toString(numbers));//直接输出仓库会输出地址:[I@5b444398System.out.println(a);
字符串转仓库: strong>
方法名:
stringToIntArray(String str)、stringToCharArray(String str)等
示例代码:
// 字符串转整型仓储int[] intArray = stringToIntArray("1 2 3 4 5");// 字符串转字符数组 char[] charArray = stringToCharArray("Hello") ;
3.2.4.2 吞吐量和集合的相互转换
吞吐量转列表:List
List转磁盘:arrayToList(T[] array) T[] listToArray(List
设置转盘:list, Class elementType) Set
设置转盘:< /strong>arrayToSet(T[] array) T[] setToArray(Set
set, Class elementType) 示例:
// 1. 吞吐量转List String[] array = {"apple", "banana", "orange"}; List
listFromArray = Arrays.asList(array); System.out.println("从数组中获取列表:" + listFromArray); // 2. List转吞吐量 List FruitList = new ArrayList<>(List.of("apple", "banana", "orange")); String[] arrayFromList = FruitList.toArray(new String[0]); System.out.println("列表中的数组:" + Arrays.toString(arrayFromList)); // 3. List转Set Set setFromList = new HashSet<>(fruitList); System.out.println("从列表中设置:" + setFromList); // 4. Set转List Set FruitSet = new HashSet<>(Set.of("apple", "banana", "orange")); List listFromSet = new ArrayList<>(fruitSet); System.out.println("来自集合的列表:" + listFromSet); // 5. Set转阵列 String[] arrayFromSet = FruitSet.toArray(new String[0]); System.out.println("来自集合的数组:" + Arrays.toString(arrayFromSet)); // 6. 备份转集 Set setFromArray = new HashSet<>(Arrays.asList(array)); System.out.println("从数组设置:" + setFromArray); } 转为集合后,可以通过集合的api操作各元素。例如:
< p>判断库存是否包含某个元素:示例代码:
//判断整型阵列是否包含要素 int[] array = {1, 2, 3, 4, 5};boolean isEle = Arrays.asList(array).contains("a") ;System.out.println(isEle);
3.3 流程控制语句
3.3.1 概述
控制流程语句分类:
顺序结构分支结构(if、switch)循环结构(for、while、 do…while)3.3.2 IF分支语句
3.3.2.1 基本语法
格式一:如果...就...
if (表达式表达式) { 语句体;}
执行流程:
首先计算关系表达式的值,如果关系表达式的值为true就执行语句体,如果关系表达式的值为false则不执行语句体继续执行后面的语句内容格式2:如果...就...,否则...
if (表达式) { 语句体1;} else {语句体2;}
执行流程:
首先计算关系表达式的值,如果表达式的值为true就执行语句体1如果关系表达式的值为假就执行语句体2 继续执行后面的语句内容格式3:如果...就...,如果...就...,否则...
if (关系表达式1) { 语句体1;} else if (关系表达式2) { 语句体2;}// ...else { 语句体n+1;}
执行流程:
首先计算关系表达式1的值如果为true就执行语句体1;如果为false就计算关系表达式2的值如果为true就执行语句体2 ;如果为假就计算关系表达式3的值 ...如果没有任何表达式关系为真就执行语句体n+13.3.2.2 练习
如果年龄小于20岁,则打印老年人,如果年龄大于60岁,则打印老年人,否则打印
public class AgeCategory { public static void main(String[] args) { // 声明年龄变量 int Age = 35; // 判断年龄范围并打印相应信息 if (age < 20) { System.out.println("年轻人"); } else if (age > 60) { System.out.println("老年人"); } else { System.out.println("中年人"); } }}
3.3.3切换分支语句
3.3.3.1 基本语法
格式:
switch (表达式) { case 值1: 语句体1;休息; case值2:语句体2;休息; // ... 默认:语句体n+1;休息; //最后一个可以省略}
格式说明:
表达式:取值byte、short、int、char,JDK5以后可以是枚举,JDK7以后的可以是Stringcase:后面跟要跟表达式比较的值break:表示中断结束的意思,用于结束switch语句default:表示所有情况不匹配的时候,就执行该处内容,和if语句中的else类似执行流程:
首先计算表达式的值和case后面的值进行比较,如果有对应值,则执行相应的语句,在执行过程中,遇到break就会结束,如果所有case的值和表达式的值不匹配,就会执行default里面的语句体,然后程序结束注意事项: strong>在switch语句中,如果case控制的语句后面不写break,将会出现“墨水”现象。即
3.3.3.2练习
写一段Java代码,输入数字几,就输出几周:
import java.util.Scanner;public class DayOfWeek { public static void main(String[] args) { //创建Scanner对象用于输入Scanner Scanner = new Scanner(System.in); // 提示用户输入一个数字代表星期几 System.out.print("请输入一个数字(1-7)代表星期几:"); // 读取用户输入的数字 int dayNumber = Scanner.nextInt(); // 使用Switch语句判断并输出对应的星期几 switch (dayNumber) { case 1: System.out.println("星期日");休息;情况2:System.out.println("星期一");休息;情况3:System.out.println("星期二");休息;案例4:System.out.println("星期三");休息;案例5:System.out.println("星期四");休息;案例 6: System.out.println("星期五");休息;案例7:System.out.println("星期六");休息; default: System.out.println("输入无效,应为1-7之间的数字。"); } // 关闭扫描仪scanner.close(); }}
3.4 修饰符
< h4 id="%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E4%BF%AE%E9%A5%B0%E7%AC%A6">3.4。 1 访问权限修饰符:public、protected、default、privatepublic : 对所有类可见。使用对象:类、接口、变量、方法
protected : 对同包可见、对不同包子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
默认 :同包可见。使用对象:类、接口、变量、方法。
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
< caption id="accesscontrol-levels">
修饰符 当前类 相同包内 子孙类(相同包) 子孙类(不同包) 其他包 public
是 Y Y Y Y 受保护
< /td>Y Y Y Y/N(说明) N tr>默认
Y Y Y N td> N 私有
Y N N N N 私有
在同一类内部可见,保护成员不被其他类使用。可以修饰变量、方法。注意:不能修饰类(外部类)
私有变量不能被其他类直接访问,但可以通过get和set方法间接访问:
“get变量名()”方法:获取成员变量的值,用public方法“set变量名(参数)”方法”方法:设置成员变量的值,方法用public构造函数示例:
public class Phone { int price ;//堆内存中的成员变量 private int Age;公共无效 setAge(int a) { 年龄 = a; }//或者用this// public void setAge(int Age) {// this.age = Age;// } public int getAge() { return Age; } }}//使用public class hello { public static void main(String args[]) { Phone p = new Phone(); p.setAge(12); System.out.println(p.getAge()); }}
3.4.2 静态
3.4.2.1基本介绍
静态成员变量被所有对象共享,可用类名调用。局部变量不能被声明为
public class Phone { static intprice;//成员变量在堆内存中}//使用public class hello { public static void main(String args []) { 电话.price=4; //fun();会报错,静态方法只能访问静态方法或变量。 } public fun(){};}
静态方法只能访问静态变量和方法。非静态方法都可以访问。
静态方法中不能使用该关键字,因为在静态方法的局部变量表中并不存在该变量。
3.4.2.2 知识加油站:类变量< /strong>
static可以修饰什么?
Java类中包含了成员、方法、构造器、初始化块和内部类(包括接口) 、枚举)5种成员。
static关键字可以修饰成员变量、方法、初始化块和内部类,不能修饰构造器。
静态访问规则:
被静态修饰器的成员先于对象存在,所以又称为类变量。
类成员不能访问实例成员,即静态不能访问非静态,静态中也没有这个关键字。这是随着对象的创建而存在的
类加载过程中的类变量是如何创建的?
在类加载过程中的链接准备阶段,JVM会给类变量赋予零值,初始化阶段为类变量赋初值,执行静态代码块。
确保代码符合JAVA虚拟机规范和安全约束。包括文件格式验证、元数据验证、字节码验证、符号引用验证。 文件格式验证:验证字魔数:是否魔数0xCAFEBABE起始版本号:版本号是否在JVM兼容范围常量类型:类常量池里常量类型是否合法索引值:索引值是否指向不存在或不符合类型的常量。元数据验证:元数据是字节码里类的全名、方法信息、字段信息、继承关系等。标识符:验证类名接口名标识符有没有符合规范 >接口实现方法:有没有实现接口的所有方法抽象类实现方法:有没有实现抽象类的所有抽象方法final类:是不是继承了最终类。指令验证:主要校验类的方法体,通过数据流和控制流分析,保证方法在运行时不会破坏虚拟机安全。类型转换: strong>保证方法体中的类型转换是否有效。例如把某类强转成没有继承关系的类跳转指令:保证跳转指令不会跳转到方法体以外的字符号引用验证:确保后面解析阶段能正常执行。 类全限定名地址:验证类全限定名是否能找到对应的类字节码文件地址:引用指向地址是否存在实例引用权限:是否可以引用准备:为类变量(即静态变量)分配内存并赋予零值。解析:将方法池区-运行时常量内的符号引用(类的名称、成员)名、标识符)转为直接引用(实际内存地址,不包含任何抽象信息,因此可以直接使用)。类加载流程:加载、链接(验证、准备、解析)、初始化。这个过程是在类加载子系统完成的。
加载:生成类的Class对象。
通过一个类的全限定名获取此类定义二进制字节流(即编译时生成的类字节码文件)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。包括创建运行时常量池,将类常量池的部分符号引用注入运行时常量池。在内存中生成一个代表该类的java.lang.Class对象,作为方法区该类各种数据的访问入口。注意类的类对象是运行时生成的,类的字节码文件是编译时生成的。链接:将类的二进制数据合并到JRE中。该过程分为以下3个阶段:
< strong>验证:初始化:类变量赋初值、执行静态语句块。
公共抽象类动物{抽象无效m(); //抽象方法abstract void n(); //抽象方法 } class Dog extends Animal{ //非抽象子类 //实现父类所有抽象方法 void m(){ ......... } void n(){ ...... ... }}abstract class Cat extends Animal{}//抽象子类,不需要重写抽象父类的抽象方法
设计目的:
接口作为系统与婴儿交换的窗口,体现了一种规范。它只能定义抽象方法及常量,而不允许存在初始化块、构造器、成员变量。抽象类作为系统中多个子类的共同父类,它体现了一种模板式设计,它可以被引入系统实现过程中的中间产品,必须进一步的完善。相同点:
实例化:接口和抽象类都不能被实例化,它们都位于继承树的下面,用于被其他类实现和继承抽象方法:接口和抽象类都可以有抽象方法、实现接口或继承抽象类的普通子类都必须实现这些抽象方法不同点:
普通方法:接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则可以包含普通方法。普通成员变量:接口里只能定义静态常量(会自动添加静态final,final常量必须显示的指定初始值) ,不能普通成员变量;抽象类里既可以定义普通成员变量,也可以定义静态常量构造器:接口里不包含构造器;抽象类可以包含构造器,但定义抽象类的构造器不是用于创建对象,而是让其子类调用这些构造器来完成抽象类的初始化操作初始化块:接口里不能包含初始化块,抽象类则可以包含初始化操作静态代码块和实例代码块)单继承多实现:一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足①this指代当前对象的引用 strong>。通过这个可以获取当前对象中的成员变量、方法。
常可以用于方法的形参与成员变量同名时进行区分,
public class Phone { private int Age;//如果这个方法是static的,底部报错。//因为this指向当前对象的引用,不是指向当前类的引用。static方法是类方法,类方法不创建对象就可以通过类名调用。 } public int getAge() { 返回年龄; }}
②this指代构造方法的调用
package package1;public class Dog { 私有整数年龄; public Dog() { System.out.println("无参构造方法。。"); } public Dog(int Age) { //先执行一次带参构造方法 this(); System.out.println("带参构造方法,年龄:"+age); this.age = 年龄; } public static void main(String[] args) { // 带参构造方法创建对象 Dog狗=新狗(23); }}
这个指代构造方法的调用时,有以下几点需要注意:
①指代仅包括父类特征的当前对象的引用。可以看做是父类的引用。
通过super可以获取当前对象的父对象的成员变量、方法。
示例:
以age变量为例,父类的age变量是3,子类的年龄变量是4,子类方法的年龄局部变量是5。
public class Animal { public String name;整数年龄=3; public void eat() { //吃东西方法的具体实现 System.out.println("吃东西"); }} //子类 public class Dog extends Animal{ int age=4; public void show(){ int Age=5;//输出5。访问上一行的局部变量 System.out.println(age); //4。通过this访问当前对象的成员变量age System.out.println(this.age);//3。通过super访问当前对象的父对象的成员变量age System.out.println(super.age) ; }}
②指代父类构造方法的调用
通过super(),可以调用父类的各个构造方法。
示例:
public class Animal { public String name;整数年龄 =; 3; public void eat() { //吃东西方法的具体实现 System.out.println("吃东西"); } public Animal(String name) { System.out.println("动物类带参构造方法"+name); this.name = 名称; } public void sleep() { // 睡觉方法的具体实现 }}public class Dog extends Animal { public Dog(int Age,String name) {//调用父类的带参构造方法 super("小白"); System.out.println("带参构造方法"+age+","+name); } public static void main(String[] args) { new Dog(23,"小黑"); }}
结果:
this和super的区别:
this是当前对象的引用,super是当前对象的父对象的引用this()是构造方法中调用本类其他的构造方法,super()是当前对象构造方法中去调用自己父类的构造方法。静态中没有this和super关键字。this指向当前实例,super指向当前实例注意:子类所有无参、带参构造方法第一行都会隐式或显式地加super()。this()和super()方法不能显式地共存,但可以隐式的共存,且都只能显式地出现在构造方法的第一个一行。
如果都不加,则系统会隐式加super();如果加super()或super(隐带参),系统不会再式加super();如果加this() ,则系统会隐式在this()前加super();面向对象(面向对象,即OOP)是一种程序设计的范式,它基于对象的概念,将数据和操作数据的行为封装在对象中,以模拟现实世界的问题和解决方案。
核心概念:
对象(Object): 对象是现实世界中的实体或概念,在程序中被抽象为具有状态(属性)和行为(方法)的实例。类(Class): 类是对象的模板,它定义了对象的属性和方法。类是对象的抽象,实际的对象是根据封装(Encapsulation):封装对象的属性和方法封装在一个单元内部,对外部对象的具体实现细节。通过隐藏封装,对象的内部实现对外部是不可见的,只有公共接口对外部可见。继承(继承): 继承允许一个类(子)类)继承另一个类(父类)的属性和方法。子类可以继承父类的属性、重写父类的方法,从而减少代码量。多态(Polymorphism):多多态的实现方式包括方法重载和方法重写。总结起来就是一句话:类是对象的抽象,对象是类的具体实现。
示例:
例如我声明一个Person类,有姓名和年龄两个属性;
然后我就可以通过这个类创建两个对象,分别是Alice和Bob,他们的年龄不一样。
public class Person { // 变量成员 String name;年龄; // 构造方法 public Person(String name, int Age) { this.name = name; this.age = 年龄; } // 成员方法 public void work() { System.out.println(name + "正在工作。"); } public void Study() { System.out.println(name + "正在学习。"); }}
public class Test { public static void main(String[] args) { // 创建 Person 类的对象 Person person1 = new Person (“爱丽丝”,25);人 person2 = new Person("鲍勃", 30); //调用对象的方法 person1.work(); person2.study(); }}
结果:
Alice 正在工作。Bob 正在工作。
内部类:在一个类中定义类。
划分:
成员内部类类(成员位置)匿名局部内部类(成员方法内)匿名内部类(方法内)匿名内部类:一个继承了了其他类或者实现了了其他接口的子类对象。
内部类可以直接访问外部类外部、公有成员。外部类要访问内部类成员要创建对象。
public class Outer { int num=10;//定义成员内部类:在成员位置定义类 public class Inner{ // 一般私有,用外部类访问内部类更安全 public void show(){ System.out.println("innershow"+num); // 内部类可直接访问外部类成员。 } }//外部类访问成员内部类 public void fun(){ Inner in=new Inner();在.show(); }//局部内部类:在成员方法内部定义类 public void fun2(){ class Inner2{ //成员内部类不能public和private void show(){ System.out.println("成员内部类"); } } Inner2 in=new Inner2();在.show(); }//匿名内部类:在成员方法内定义子类,实现接口或继承抽象类 public void fun3(){ Phone p=new Phone() { //自己写的Phone接口 @Override public void show() { System.out.println("实现接口的匿名内部类"); } }; //注意是一条语句有分号p.show(); }}// 内部类创建对象(一般内部类封装,使用外部类访问内部类)public class Test { public static void main(String[] args) { Outer.Inner i=new Outer().new Inner() ; i.show(); }}
概述:
< strong>new:例如Person person1 = new Person();反射:先获取类的Class对象,通过newInstance()方法创建对象;对象的clone()方法: 类实现Cloneable接口,重写clone()方法,编写浅拷贝或者深拷贝的逻辑。然后调用对象的clone()方法就可以克隆出对象。反序列化:反序列化对象时,JVM会创建一个单独的对象。需要让类实现Serialized接口,通过ObjectInputStream类的readObject()方法从磁盘中反序列化对象。反序列化创建对象是深拷贝。详细:
使用 new
关键字:
人 person1 = 新 Person();
这是最常见的创建对象的方式,使用new
关键字直接调用类的构造方法。
引用:
通过引用机制,可以在运行时获取类的信息,动态创建对象。
Class> clazz = Person.class;Person person2 = (Person) clazz.newInstance();
对象的 clone()
方法:
要实现克隆,类必须实现 Cloneable
接口,并重写 clone()
方法。这种方式可以实现对象的浅拷贝或深拷贝。
public class Person Implements Cloneable { // 其他类定义 @Override protected Object clone() throws CloneNotSupportedException { return super.clone() ; }}//创建对象Person person3 = (Person) person1.clone();
反序列化:
通过反序列化,可以将对象的状态从持久性存储中重新创建出来。需要让类实现 Serialized
接口,并使用 ObjectInputStream
类的 readObject() code> 方法从文件或网络中反序列化对象。
//反序列化对象try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) { Person person4 = (Person) ois.readObject();} catch (IOException | ClassNotFoundException e) { e.printStackTrace();}
方法(Method) ):一组执行特定任务的代码块。它可以在类中定义一次,然后在本方法、其他方法中被多次调用。
作用:
例如小明要吃多顿饭,每顿饭吃不同的食物,我们可以将“吃饭”这个行为抽象成方法,从而减少代码量:
public class Test { private static String name = "小明"; /** * 吃饭方法 * * @param food */ public static void eat(String food) { System.out.println("====="); System.out.println(name + "正在吃" + 食物); System.out.println("====="); } public static void main(String[] args) { eat("西瓜"); eat("白菜"); eat("可乐"); eat("番茄"); }} code>
结果:
如果不用方法,将需要多写很多代码,结论性变差:
< code class="cb9a-bc16-63b7-388f language-java">public class Test { private static String name = "小明"; /** * 吃饭方法 * * @param food */ public static void eat(String food) { System.out.println( "====="); System.out.println(name + " 正在吃 " + 食物); System.out.println("====="); } public static void main(String[] args ) { System.out.println("====="); System.out.println(name + "正在吃西瓜" ); System.out.println("====="); System.out .println("====="); System.out.println(名称 +; “正在吃白菜”); System.out.println("======"); System.out.println("======"); System.out.println(name + "正在吃可乐"); System.out.println("======"); System.out.println("======"); System.out.println(name + "正在吃番茄"); System.out.println("======"); }}
在Java中,方法的定义包括以下几个要素:
修饰符: 方法可以有访问修饰符,例如public
、private
、protected
或默认(包内) 返回类型:方法可以返回一个值,指定返回值的数据类型,如果方法不返回任何值,可以使用void
。方法名称: 方法名是方法的标识符,用于在程序中调用方法。参数列表: 方法可以接受零个或多个参数,参数用于向方法传递数据。方法体:方法体包含实际执行的代码块,实现方法的功能。 // 方法的定义 public int add(int num1, int num2) { int sum = num1 + num2; return sum;}
在程序中,可以通过方法名和参数列表来调用方法。方法调用是程序执行的一个重要步骤,它使代码变得更加可重用。
//方法的调用 int result = add(5, 3);System.out.println("Result: " + result);
方法可以返回一个值,也可以是void
,表示不返回任何值。如果返回方法值,必须使用 return
语句返回对应类型的值。
//方法的返回值 public int add(int num1, int num2) { int sum = num1 + num2;返回总和;}
重载(过载):指一个类中可以有多个具有相同方法名的方法,但这些方法的参数类型不同、个数不同、顺序不同
注意:方法返回值和访问修饰符可以不同。
示例:
< pre>public class hello { public static void main(String args[]) { f(); } } public static void f() { System.out.println("3f"); } public static void f(int a) { //重载,注意返回值同,参数不同 System.out.println(a); }//下面两个注释的方法就不是重载,会报错// public static int f(){ //返回值不同// System.out.println("hello");// }// void f (){ // 修饰符不同 // return 666;// }}
示例:求和的数学类:
public class MathOperations { // 求和方法,接受两个整数参数 public int sum(int num1, int num2) { return num1 + num2; } } // 重载的求和方法,接受三个整数参数 public int sum(int num1, int num2, int num3) { 返回 num1 + num2 + num3; } // 重载的求和方法,接受两个双精度分数参数 public double sum(double num1, double num2) { return num1 + num2; } public static void main(String[] args) { // 创建 MathOperations 对象 MathOperations math = new MathOperations(); // 使用不同的方法进行求和 int result1 = math.sum(5, 10); int result2 = math.sum(3, 7, 12);双结果3 = math.sum(2.5, 3.5); // 打印结果 System.out.println("两个整数之和: " + result1); System.out.println("三个整数之和:" + result2); System.out.println("两个双精度数之和:" + result3); }}
重载要求发生在同一个类中,多个方法之间方法名相同且参数列表不同。
重载与返回类型和访问修饰符无关。方法名返回相同类型不同会直接报错。
重写:方法名、参数列表、返回类型与父类相同重写发生在父类子类或接口实现类中,若子类方法想要和父类方法构成重写关系,则它的方法名、参数列表、返回类型必须与父类方法相同。
重写时:
返回值类可以是原返回值类的子类。例如工厂方法设计模式里,抽象工厂类的createObject()方法返回值是抽象产品类,具体工厂类的createObject()方法返回值是具体产品类访问权限不能比其父类严重严重流量异常不能比父类更广泛思考:构造方法不能重写?
答案:构造方法不能重写。
Java 5以后引入了可变参数(Varargs),允许方法接受可变数量的参数。可变参数在方法的参数列表中使用简洁号 ...
表示。< /p>
// 可变参数的定义 public void printNumbers(int...numbers) { for (int num :numbers) { System.out.print(num + “”); }}
注意:
可变参数必须是方法的最后一个参数。例如 void (int a,int... b),正确而void (int... a,int b)会报错。一个方法最多只能有一个可变参数。可变参数在方法内部被当作批量处理。
< /p>
示例:求和的数学类:
public class MathOperations { // 求和方法(内存量) public static int sum(int[]numbers) { int result = 0; for (int num : 数字) { 结果 += num;返回结果; } // 求和方法(可变参数) public static int sum(int...numbers) { int result = 0; for (int num : 数字) { 结果 += num;返回结果; } // 求和方法(双精度浮点数) public static double sum(double[]numbers) { double result = 0; for (double num : 数字) { 结果 += num;返回结果; } // 求和方法(可变参数) public static double sum(double...numbers) { double result = 0; for (double num : 数字) { 结果 += num;返回结果; } public static void main(String[] args) { // 示例:整数求和 int[] intArray = {1, 2, 3,4, 5}; int intSum = sum(intArray); System.out.println("整数和:" + intSum); // 示例:可变参数整数求和 int varArgsIntSum = sum(1, 2, 3, 4, 5); System.out.println("VarArgs 整数和:" + varArgsIntSum); // 示例:双精度浮点数求和 double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};双精度求和 = sum(doubleArray); System.out.println("双倍求和:" + doubleSum); // 示例:可变参数双精度浮点数求和 double varArgsDoubleSum = sum(1.1, 2.2, 3.3, 4.4, 5.5); System.out.println("VarArgs 双和:" + varArgsDoubleSum); }}
构造方法是一种特殊的方法,与类同名,没有返回类型。
每次创建对象时,都会默认执行一次构造方法。
特点:
与类同名,没有返回类型;构造方法在对象创建时执行,用于设置对象的初始状态。都可以有一个或多个构造方法,但通常至少有一个默认构造方法(无参数)。默认构造方法:如果在类中没有明确定义任何构造方法,Java会自动为该类提供一个默认的无参数构造方法。默认这个构造方法执行时不进行特定的初始化操作。< strong>重载:和普通方法一样,构造方法也支持重载,即在同一个类中可以定义多个同名但参数列表不同的构造方法。简单的构造方法:
public class Phone { public Phone() {//创建对象时会直接构造运行方法,输出hhh System.out.println( “呵呵”); }}
示例:
public class Car { private String Brand;私有字符串模型;私有 int 年份; // 默认构造方法 public Car() { System.out.println("默认构造函数被调用。"); } // 带参数的构造方法 public Car(String Brand, String model, intyear) { this.brand = Brand; this.model = 模型; this.year = 年; System.out.println("调用了参数化构造函数。"); } // Getter 和 Setter 方法(简洁) public static void main(String[] args) { // 使用默认构造方法创建对象汽车defaultCar = new Car(); // 使用带参数的构造方法创建对象 Car customCar = new Car("Toyota", "Camry", 2023); }}
接口:对行为的抽象,如吃饭、睡觉
接口的特点:
接口没有构造隐方法。接口中的方法会被指定为公共抽象方法,不能定义静态方法。接口中的变量会被隐式的指定为public static final变量,不能定义私有成员。因为是final所以也显式赋初值。接口和接口多继承,接口和类多实现。接口的实现类:除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。公共接口电话 { public static Final int Price=4; // 修饰符可简洁 public Abstract void show(); // 修饰符可简洁}publicclass PhoneImpl Implements Phone{ public void show(){ //必须是public,否则报错 System.out.println("hello"); }}
抽象类:对事物的抽象,如动物类,小狗类。
抽象类包含抽象方法的类,它不能被实例化,通常用作其他类的基类。
特点:抽象类可以包含抽象方法、具体方法、字段和构造方法。
使用场景:
建模共性行为:当多个类具有相同的行为时,可以将这些行为提取到一个抽象类中,以便实现代码规范子类: 抽象类可以用于规定子类应该实现的一组方法,强制子类提供这些方法的实现。示例:
public 抽象类 Animal { private String name;公共动物(字符串名称){ this.name = name; } // 抽象方法 public Abstract void makeSound(); // 具体方法 public void eat() { System.out.println(name + " is eat"); }}公共类狗扩展动物{公共狗(字符串na我){ 超级(名字); } // 实现抽象方法 @Override public void makeSound() { System.out.println("Woof! Woof!"); }}公共类猫扩展动物{公共猫(字符串名称){超级(名称); } // 实现抽象方法 @Override public void makeSound() { System.out.println("喵!喵!"); }}
设计目的:
接口作为系统与婴儿交互的窗口,提供了一种规范。它只能定义抽象方法及常量,而不允许存在初始化块、构造器、成员变量。抽象类作为系统中多个子类的共同父类,它体现的是一种模板式设计,它可以被系统实现过程中的中间产品,必须呼吸更进一步的完善。相同点:
实例化:接口和抽象类都不能被实例化,它们都继承位于树的下面,用于被其他类实现和继承抽象方法:接口和抽象类都可以有抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法不同点:
普通方法:接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则可以包含普通方法。普通成员变量:接口里只能定义静态常量(会自动加static final,final常量必须显示的指定初始值),不能定义成员普通变量;抽象类里既可以定义普通成员变量,也可以定义普通成员变量静态常量构造器:接口里不包含构造器;抽象类可以包含构造器,但抽象类的构造器不是用于创建对象,而是让其子类调用这些构造器来完成抽象类所属的初始化操作初始化块:接口里不能包含初始化块,抽象类则可以包含初始化块(静态代码块和实例代码块)单继承多实现: strong>一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足面向对象的三大基本特征是:封装、继承、多态。
封装:通过私人修饰符,将类的某物隐藏类的内部的一些信息,不允许外部程序直接访问。
封装对象的状态和行为包装在一个类的中表面隐藏实现的细节,可以通过访问修饰符控制成员的访问权限,让外部程序通过该类提供的方法来实现对内部信息的操作和访问。
示例:将价格、年龄等信息封装到几个类中,外部不能直接访问,只能通过get和set方法访问。
public class Dog{intprice;//堆内存中的成员变量 private intage;公共无效 setAge(int 年龄) { this.age = 年龄; } public int getAge() { 返回年龄; }}
优点:安全性和复用性。
安全性:通过方法来控制成员变量的操作,提高了代码的安全性复用性:把代码用方法进行封装,提高了代码的复用性,降低了耦合性。继承:继承是指一个类通过从另一个类继承其属性和方法。这使得子类具有其父类的行为和属性,同时可以扩展或修改这些行为和属性满足特定的需求。
优点:提高代码复用性,维护性,实现代码共享。
缺点:高关联性,有侵入性,父类改变子类也改变。
< strong>特点:
子类拥有父类非私有的属性、方法。可以拥有自己的属性和方法,即子类可以对父类进行扩展。可以用自己的方式实现父类的方法。< /p>注意: Java不支持多继承,但支持静态继承。
单继承是子类只能继承一个父类。相对于实现是一个子类可以实现多个接口。所以java是单继承多实现。
子类所有构造方法会默认先运行super();
公共类动物 { 公共圣戒指名称;整数年龄=3; public Animal(String name, int age) { //初始化属性值 } public void show() { //吃东西方法的具体实现 } public void sleep() { //睡觉方法的具体实现 } } //子类公共类企鹅扩展动物{int年龄= 4;公共企鹅(){ 超级(); //不写也默认运行}@Override //注解重写,检查重写是否正确。例如修饰符(子类重写方法的访问权限要≥父类)、函数名错误。 public void show() { //重写父类中show(),如果去掉public会报错。想再用super.show();整数年龄=5; System.out.println(年龄); //5、子类可以访问父类非原生成员变量 System.out.println(this.age);//4 System.out.println(super.age);//3 }}
pre>使用implements关键字可以改变java具有多个继承的特性
public interface A { public void eat(); public void sleep();} 公共接口 B { public void show();} 公共类 C 实现 A,B {}
4.4.3 多态
多态:相同的行为具有多种不同的表现形式或形态。例如同一个接口,使用不同的实例而执行不同的操作。使程序更灵活、易于扩展。
多态最常用的是接口引用指向实现类对象,这样当之后程序需要更新的时候,只需修改修改需要新后面的实现类即可,左边就不用了,从而提升耦合。
简单一句话,多态是:通过接口引用指向实现类对象。
在Spring框架中,甚至可以配置或注解连实例化的新也没用了,从而提高了连接的层次。
示例:
List
a=new ArrayList (); 这样写的话,等号右边换成Vector 或 LinkedList时,就可以很少修改代码量,降低连接。
向上转换:父类引用指向子类对象。编译看左边(调用子类特有变量、方法会报错),运行看右边(优先运行子类重写后面的方法)。
Animal a=new Cat();
< strong>向下转换:子类引用指向父类对象。编译看右边,运行看右边。
public static void main(String[ ] args) { 动物 a = new Cat(); // 向上转型 a.eat(); //调用的是 Cat 的 eat Cat c = (Cat)a; // 转型 c.work(); //调用的是猫的工作}
五、常用类
5.1 String类
5.1.1 基本介绍
什么是字符串? strong>
String是一类,用于存储字符串,内部封装了一系列用于操作字符串的方法,底层是final修饰的char数组。
JDK9开始,为了节省内存,进而减少垃圾回收次数,String底层由char数组改成了byte[]。
Java的String和c++的string区别:
java中字符串一个汉字长度是1;c++中字符串一个汉字长度是2。5.1.2基本实现
5.1.2.1创建
创建字符串的对称方式:
创建字符串有两种方式,一种是使用字符串直接量,另一种是使用new+构造器。采用new的方式会多创建一个对象来,占用了更多的建议内存,所以采用直接量的方式来创建字符串。
字符串直接量创建:JVM会使用常量池来管理这个字符串;新建:JVM会先使用常量池来管理字符串直接量(若已有字符串则直接返回引用,若没有则初始化化后再返回引用),重新调用St环类的构造器来创建一个新的String对象,新创建的String对象会被保存在堆内存中。字符串常量池源码占用了共享元设计模式。// String 直接创建String s1 = "Runoob"; // String 对象创建 String s2 = new String("Runoob"); // 引用属性的方法创建字符串 s3 = s1;
5.1.2.2 访问
通过索引访问字符:charAt()
String str = "Hello, World!";char firstChar = str.charAt(0);System.out.println ("第一个字符:" + firstChar);
访问子串:substring()
String str = "0123456789ABCDEFG";//取出索引 7 到 11 的子串 String substring = str.substring(7, 12); System.out.println("Substring: " + substring);
替换字符串每个字母:
使用循环遍历字符串:使用增强for循环遍历字符串:String str = "hello world";for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); System.out.println(c);}
使用while循环遍历字符串:String str = "hello world";for (char c : str.toCharArray()) { System.out.println(c); }
使用迭代器遍历字符串:String str = "hello world";int i = 0;while (i < str.length( )) { char c = str.charAt(i); System.out.println(c); i++;}
String str = "hello world";Iterator
iterator = str.chars().mapToObj(c -> (char) c).iterator();while (iterator.hasNext()) { char c = 迭代器.next(); System.out.println(c);} 结果:
5.1.2.3 连接
字符串可以通过“+”号拼接,拼连接过程中可以将数字型转为字符串。
示例:
String s1,s2;//拼接字符串、数字、字符 s1="我的名字是".concat("s1"); s2=“s2:”; s2+="abc";//字符串拼接数字,数字会转成字符串 s2+=123; s2+='c'; System.out.println(s1); System.out.println(s2);
结果:
字符串连接字符阵列:
//连接字符串 String s= "Hello"; s= s+ ", World!";//连接字符备份 char[]greeting = {'H', 'e', 'l', 'l', 'o'}; char[] 后缀 = {',', ' ', 'W', 'o', 'r', 'l', 'd', '!'}; char[] 结果 = new char[greeting.length + suffix.length]; System.arraycopy(问候语, 0, 结果, 0, 问候语.length); System.arraycopy(后缀, 0,结果,问候语.长度,后缀.长度); System.out.println(结果);
5.1.2.4 子串
在Java中,可以使用 substring() 方法获取字符串的子串: p>
substring(int beginIndex): 返回从指定索引开始到字符串补充的子串。
String originalString =“你好,世界!”;字符串子字符串=originalString.substring(7); // 从索引 7 开始到字符串组成的子串System.out.println(substring); // 输出结果为 "World!"
substring(int beginIndex, int endIndex): 返回从指定索引开始到指定索引结束的子串(不)包括 endIndex 处的字符)。
String originalString = "Hello, World!";String substring = originString.substring(7, 12); // 从索引 7 开始到索引 12 结束的子串System.out.println(substring); // 输出结果为 "World"
注意:
因为String是不可变的,对字符串修改的任何操作都会返回一个新的字符串。所以substring方法是创建了一个字符子串,而不是原来的字符串。
5.1.2.5删除
Java中字符串没有直接根据索引删除的方法,所以删除字符串中指定索引的字母时,可以通过子串substring()删除。
示例:删除字符串中下标是6的字母
String str = "Hello, World!";String newStr = str.substring(0, 5) + str.substring(7);System.out.println("修改后的字符串:" + newStr );
结果:
5.1.2.6 替换
在Java中,可以使用replaceAll()方法替换字符中的字符:
replaceAll(String regex, String replacement):使用给定的替换字符串替换输入字符串中所有匹配正则表达式的部分。
String originalString = "Hello, World!";String ReplacedString = originalString.replaceAll("o", "0");System.out.println(replacedString); // 输出结果为“Hell0, W0rld!”
在上面的例子中,所有的字母“o”都被替换为数字“0”。
replaceAll(String regex, Function
replacement): 使用给定的函数替换输入字符串中所有匹配正则表达式的部分。该方法允许更灵活的替换逻辑,并且可以基于匹配的结果进行自定义的替换。String originalString = "你好,世界!"; String ReplacedString = OriginalString.replaceAll("o", match -> match.group().toUpperCase()); System.out.println(replacedString); // 输出结果为“HellO, WOrld!”
在上面的例子中,将匹配到的字母“o”替换为大写的“O”。
练习:将字符串中所有的“Java”都替换为“Python”:
String origin = "你好,Java!Java 很有趣。Java 很强大。"; // 将所有的 "Java" 替换为 "Python" String ModifiedString = Original.replaceAll("Java", "Python"); System.out.println("原点最终字符串: " + 原始); System.out.println("修改后的字符串: " + ModifiedString);
5.1.2.7 获取长度
通过length()方法可以获取字符串的长度。
示例:获取字符串的长度
public class Test { public static void main(String[] args) { String text = "Java Programming"; // 返回字符串的长度 int length = text.length(); System.out.println(length); }}
结果: p>
5.1.2.8 比较
字符串内容的相互比较一般用equals()方法。
Java中所有类都直接或间接继承了Object类,在Object类中,equals()方法是Java中用于比较对象的引用是否一致(即两个内存地址是否相同)。
在 String 类中,equals() 方法被重写,用于比较两个字符串的内容是否一致。
在 String 类中,equals() 方法被重写,用于比较两个字符串的内容是否一致。 p>
示例:比较两个字符串内容是否符合
public class Test { public static void main(String[] args) { String str1 = "Hello";字符串str2 =“你好”; // 比较字符串内容是否符合 boolean isEqual = str1.equals(str2); System.out.println(isEqual); }}
结果:
注意:不要努力使用==进行比较,==比较的是地址。
String底层是常量池,使用享元设计模式,新创建的字符串会维护在常量,接下来再创建这个字符串,就直接从常量池取。
验证:
//比较地址//只要new,就在堆内存开辟空间。直接赋值字符串在常量池里。 //常量池里无“hello”对象,创建“hello”对象,str1指向常量池“hello”对象。 String str1 = "hello"; //先检查字符串常量池中是否有“hello”,如果字符串常量池中没有,则创建一个,然后str1指向字符串常量池中的对象,如果有,则直接将str1指向“hello”; //常量池里有“hello”对象,str2直接指向常量池“hello”对象。 String str2 = "hello";//堆中new创建了一个对象。如果“hello”在常量池中不存在,Jvm还会在常量池中创建这个对象“hello”。 String str3 = new String("hello");字符串 str4 = new String("你好"); // 下面输出true,因为str1和str2指向的是常量池中的同一个内存地址 System.out.println(str1 == str2); //下面输出false,str1常量池旧地址,str3是new出的新对象,指向一个全新的地址 System.out.println(str1 == str3); // 下面输出false,因为它们引用不同 System.out.println(str4 == str3);//比较内容 下面 // 输出true,因为String类的equals方法重写过比较,是字符串值 System. out.println(str4.equals(str3));
结果:
5.1.2.8 知识加油站:==与equals()的区别
== 比较数据类型时,比较的是基本两个数值是否正确; 比较引用类型是,比较对象的内存地址是否正确。equals() 没有重写时,Object默认以==来实现,即比较两个对象的内存地址是否正确;重写以后,按照重写的逻辑进行比较。示例:String中源码重写的equals()方法:
如果地址相同,则一定能够;如果对比的元素不是String类型,则一定不可能;解决String底层的内存,逐个对比字符是否足够;5.1.2.9 分割
split()该方法是Java中String类的一个方法,用于将字符串分割成字符串数组,根据给定的正则表达式作为分隔符。该方法有两个重载的版本:
< strong>split(String regex): 使用给定的正则表达式作为分隔符,将字符串分割为字符串数组。
String Sentence = "Hello, World!你好吗?";String[]words=sentence.split(""); // 使用空格作为分隔符 for (String word : Words) { System.out.println(word);}
上述代码会输出每个单词:
Hello,World!Howareyou?
split(String regex, int limit):使用给定的正则表达式作为分隔符,将字符字符串分割为字符串阵列,限制分割的次数。
String Sentence = "apple,orange,banana,grape";String[]fruits=sentence.split(",", 2); // 使用分隔符作为分隔符,限制分割次数为 2for (Stringfruit :fruits) { System.out.println(fruit);} code>
上述代码会输出:
appleorange,banana,grape
需要注意的是,split()方法的参数是正则表达式,因此在整理正则表达式时,可能需要注意转义字符的使用。例如,如果要以点号作为分隔符,由于点号在正则表达式中有特殊含义,需要使用双反斜杠 \ 进行转义。
String Sentence = "one.two. Three";String[] parts = Sentence.split("\\."); // 使用点号作为分隔符,需要转义for (String part : parts) { System.out.println(part);}
上述代码会输出:
< code>onetwothird总的来说,split()方法是在字符串处理中常用的方法,可以根据需要灵活重组字符串分割成多个部分。
//根据指定字符串分割 String s="1,2,3"; String[] arr=s.split(", "); for (String s1 : arr) { System.out.println(s1); }
结果:
< /p>
5.1.2.10 转换大小写
String text = "Java 编程";String lowerCase = text.toLowerCase();String upperCase = text. toUpperCase();
5.1.2.11 字符串和数字的相互转换
1.字符串转整数:
使用
Integer.parseInt()
方法:String strNumber = "123";int intValue = Integer.parseInt(strNumber);System.out.println("解析的整数:" + intValue);
使用
Integer.valueOf()
方法:String strNumber = "123";Integer integerValue = Integer.valueOf(strNumber);System.out.println("整数值: " + 整数值);
2.整数转字符串:
使用
String.valueOf()
方法:int intValue = 123;String strNumber = String.valueOf(intValue);System.out.println("字符串值: " + strNumber);
使用
Integer.toString()
code> 方法:int intValue = 123;String strNumber = Integer.toString(intValue);System.out.println("字符串值: " + strNumber) ;
5.1.2.12 < strong> 堆栈和字符串的互相转换
堆栈转字符串:
数组.toString(阵列名)
示例:
int[]numbers = {1, 2, 3, 4, 5};//输出:[1, 2, 3, 4, 5]System.out.println(Arrays.toString(numbers));//直接输出备份会地址输出:[I@5b444398System.out.println( A);
字符串转储:
方法名:
stringToIntArray(String str)、stringToCharArray(String str)等 code>
示例代码:
//字符串转整型阵列int[] intArray = stringToIntArray("1 2 3 4 5 ");// 字符串转字符数组 char[] charArray = stringToCharArray("Hello");
5.1.2.13 格式化数字为字符串
double number = 123.456789; // 格式化浮点数为字符串,获取这两个小数 String formattedString = String.format("%.2f", number); System.out.println(formattedString);
结果:
5.1.3知识加油站
5.1.3.1 字符串和字符数组的区别
可变性:字符串是修改不可变的。一旦创建,字符串的内容就不能被。任何对字符串的底层都会创建一个新的字符串对象。而字符数组是可变的。你可以直接修改字符数组的元素。 方法数量:String类提供了许多用于处理字符串的方法,如拼接、比较、截取、转换大小写等。而字符队列只有toString()、equals()等简单的队列通用方法。性质:String是类(基础是字节备份),Charles 磁盘是备份。 创建方式:String str = "Hello";char[] charArray = {'H', 'e', 'l', 'l', 'o'};连接:字符串通过“+”连接,字符队列通过System.arraycopy()连接。< strong>使用场景:String不可变,所以适用于不需要间隙修改字符内容的情况。字符集群适用于需要间隙修改字符内容的情况5.1.3.2 字符串常量池< /h5>
常量池:Java虚拟机有一个常量池机制,它会直接把字符串常量放入常量池中,从而实现复用。
Java字符串存储原理:
创建字符串常量时,JVM会通过equals()检查字符串常量池中是否存在该字符串;若字符串常量池中存在该字符串,则直接返回实例引用;若不存在,先实例化该字符串,并且装入字符串的引用放入字符串常量池中,以便于下次使用时,直接取用,达到缓存快速使用的效果。 < p>5.1.3.3 字符串不可被继承、不可修改的原因
String为什么不可被继承?
因为String类底层的内存是由final修饰的,所以String类不可被继承。
String字符串为什么不可被变?
因为String底层char类型的值数组是private final修饰的。
final修饰:导致value不能指向新的数组(但无法保证该引用指针指向的真实数组不可变);private修饰,且没有外部引用任何值的修改方法:导致价值这个引用指向了基础架构不可变;不可变的优点:压根不会被改变,所以线程安全、节省空间、效率高。
5.1.3.4 新字符串("abc" )创建的字符串对象数量
答案:一个或两个。
原因:
首先,new string 由于新的关键字,所以草莓肯定会在堆中直接创建一个字符串对象。
其次,如果字符串常量池中不存在“abc”(通过等于比较)这个字符串的引用,头像在字符串常量池中创建一个字符串对象。如果已存在则不创建。注意布拉格说的在字符串常量池创建对象,最终对象还是在堆中创建,字符串常量池只放引用。
< p>5.2 StringBuilder类
5.2.1基本介绍
字符串拼接字符串后原字符串还存在于内存中,浪费内存。
StringBuffer类的对象能够被多次修改,并且不会产生新的未使用对象,所以涉及到字符串拼接,优先用 StringBuffer 。
//构造 StringBuilder sb= new StringBuilder("abc");//String转StringBuilder sb.append("d").append("e").append("f");//StringBuilder转String String s=sb.toString(); // 烧烤sb.reverse();
5.2.2 知识加油站:String、StringBuffer、Stringbuilder的区别
String: 不可变字符序列,效率低,但是复用率高、线程安全。
不可变是指String对象创建之后,直到这个对象的情况,对象中的字符序列都不能被改变。
复用率高是指String类型对象创建出来后返回常量池管,可以随时从常量池调用同一个String对象。StringBuffer和StringBuider在创建对象后一般要转化成String对象才调用。
StringBuffer和StringBuilderStringBuffer和Stringbuilder都是字符序列可变的字符串,方法也一样,有共同的父类AbstractStringBuilder。
StringBuffer :可变字符序列、效率最高(增减)、线程安全StringBuilder:可变字符序列、效率最高、线程不5.3 Scanner类
Scanner类用于从各种输入源(例如控制台)中获取基本数据类型和字符串,如int、double、String等。常用于从控制台、文件等读取数据。
常用方法:
nextInt()、nextDouble()、next():获取输入的整数、浮点数、字符串(不包括空格)等。nextLine():获取一行输入(包括空格)。hasNextInt()、hasNextDouble()、hasNext():判断下一个输入是否为整数、浮点数、字符串。使用Delimiter(String pattern): 设置分隔符模式,用于指定不同类型数据之间的分隔符,默认为空白字符。示例:
从控制台输入整数、浮点数、字符串,并在控制台打印。
import java.util .Scanner;public class Test { public static void main(String[] args) { // 创建 Scanner 对象,关联 System.in(标准输入流) Scanner Scanner = new Scanner(System.in); // 从控制台读取整数 System.out.print("请输入一个整数:"); int intValue = Scanner.nextInt(); System.out.println("您输入:" + intValue); // 从控制台读取浮点数 System.out.print("Enter a double: ");双 doubleValue = Scanner.nextDouble(); System.out.println("您输入的是:" + doubleValue); // 从读取字符串 System.out.print("输入字符串:"); String stringValue = Scanner.next(); System.out.println("您输入:" + stringValue);// 关闭 Scanner 对象 Scanner.close(); }}
结果:
5.4 对象类 h3>
5.4.1 基本介绍
在Java中,Object类是所有类的根类,所有其他类都直接或间接继承自Object类。
Object类定义了一些基本的方法,这些方法可以被所有对象继承和使用:
toString() 方法: 返回对象的字符串表示。再不重写的情况下,toString() 返回的是对象的类名和散点
public class MyClass { private int value; 列码的十六进制表示。公共 MyClass(int value) { this.value = value; }//自定义转字符串逻辑 @Override public String toString() { return "MyClass{" + "value=" + value + '}'; }}// 使用 toString() 方法MyClass obj = new MyClass(42);// toString将根据自己重新的逻辑返回字符串而不是对象的类名和散列码的十六进制表示System.out .println(obj.toString()); // 输出结果为 "MyClass{value=42}"
equals(Object obj) 方法: 比较对象是否可用。默认情况下,equals() 方法比较对象的引用即内存地址),重写后自定义可以比较逻辑。
public class Person { private String 名称;私有整数年龄; // ... 其他代码 ...//自定义比较逻辑 @Override public boolean equals(Object obj) { if (this == obj) return true; } if (obj == null || getClass() != obj.getClass()) 返回 false;人人 = (人) obj; return 年龄 == person.age && Objects.equals(name, person.name); }}
hashCode()方法:返回对象的散列码。hashCode()方法的默认实现返回对象的内存地址的散列码。通常这种情况下,如果 equals() 方法被覆盖,那么也应该同时覆盖 hashCode() 方法。
@Overridepublic int hashCode() { return Objects.hash( name,age);}
getClass() 方法: 返回对象的类。该方法基于静态,返回类的 Class 对象,该对象包含有关对象的类的信息。
我的类 obj = new MyClass(42);Class> clazz = obj.getClass();System.out.println(clazz.getName()); // 输出结果为 "MyClass"
clone() 方法:创建并返回对象的拷贝。要实现clone()方法,类必须实现Cloneable接口
public class CloneableClass 实现 Cloneable { private int value;公共 CloneableClass(int value) { this.value = value; } @Override protected Object clone() 抛出 CloneNotSupportedException { return super.clone(); }}
finalize() 方法: 在对象被垃圾收集器回收之前调用。通常不推荐使用 Finalize() 方法,因为它的行为不是确定的,并且可能会导致一些问题。
@Overrideprotected void Finalize() throws Throwable { // 执行清理工作 // ... super.finalize() ;}
5.4.2 知识加油站:JVM垃圾回收的可达性分析算法
JVM垃圾回收的可达性分析算法可用于对象类的最终确定() 方法。
影响性分析算法:
以根对象集合(GC Roots)的每个跟对象为起始点,根据引用后续搜索,将所有与GC Roots直接或间接有引用关系的对象在对象头的Mark Word里标记为无效对象,即不需要回收的有引用关系对象。搜索过程所遍历的路径称为“引用链”。
GC Roots:即GC根节点集合,是一组必须激活的引用。可作为GC Roots的对象:
栈引用的对象:Java方法栈、本地方法栈中的参数引用、局部变量引用、临时变量引用等。临时变量是方法里的中间操作结果。方法区中常量、静态变量引用的对象;所有被同步锁持有的对象;所有线程对象;所有跨代引用对象;JVM内部的引用:如基本数据类型对应的Class对象,常驻的异常对象,以及应用程序类类加载器;非可达对象被恢复需要两次标记:
第一次标记后筛选非达标对象:第一次被标记后,会进行一次筛选,筛选的条件是该对象是否有必要执行finalize( )方法,是否有机会自救。如果对象没有覆盖或者已被JVM调用过finalize()方法,则没有自救或已自救过,那么这个对象需要被恢复;如果对象覆盖并没被JVM调用经过finalize()方法,该对象将被放置在一个名为F-Queue的队列中,并在稍后由一条由虚拟机自动建立的、低调度优先级的Finalizer线程去执行它们的finalize()方法。次标记F-Queue里的未自救对象:稍后,收集器将第二个F-Queue中的对象进行次小规模的标记。如果对象要在finalize()中成功拯救自己——只需重新与引用链上的任何对象一个对象建立关联即可,比如说把自己(this)赋值给某个引用类型的类变量对象的成员变量,那在或者第二次标记时会被移出“即将恢复”的F-Queue。如果对象这个时候还没有逃脱,那基本上它真的要被回收了。finalize() 方法:
finalize() 方法是对象逃脱死亡命运的最后一次机会,需要注意的是,任何一个对象的finalize()方法都只能被系统自动一次调用,如果对象面临下一次恢复,它的finalize()方法不会被再次执行。
<另外,finalize()方法的运行代价昂贵,不确定性大,无法保证各个对象的调用顺序,目前已被官方明确声明为不使用的语法。5.4.3 知识加油站:hashCode()和equals()的区别
< strong>用途:
hashCode()方法的主要用途是获取哈希码;equals()主要用来比较两个对象是否可用。为什么覆盖equals()必须重写hashcode()?
因为两者之间有两个约定,如果对象的哈希码也一定。
所以等于()方法重写时,通常也要将hashCode()进行重写,使得这两个方法始终满足相关的约定。例如HashSet机制排序底层就是通过计算哈希码进行排序的,如果只重写equals( )将达不到根据哈希码排序的效果。
如果两个对象满足,它们一定有相同的哈希码;但如果两个对象的哈希码相同,它们却不一定
哈希冲突:由于哈希码是一个有限的整数,因此有可能会出现不同的对象计算出相同的哈希码的情况例如某类里有两个int型成员变量,重写后equals()比较两个变量是否可用,hashcode()是两个变量的和,A对象变量是2和3,B对象变量是1和4,加起来都是5,它们的架构稳定而不是相等。
5.5系统类
System类是Java标准库中的一个工具类,提供了与系统相关的一些操作。
它包含一些静态方法和字段,用于访问系统属性、标准输入输出、垃圾回收等。
常用方法和字段:
PrintStream、PrintStream等IO流详细看后面的I/ O流。
out 字段: 是 PrintStream 类的一个实例,用于标准输出。可以使用 System.out.println() 来向标准输出打印信息。
System.out.println("Hello, World!"); // 将“你好,世界!”输出到标准输出
err字段: 是PrintStream类的一一个实例,用于标准错误输出。可以使用 System.err.println() 来向标准错误输出打印错误信息。
System.err.println( “这是一条错误消息。”); // 将错误信息输出到标准错误输出
in 字段: 是InputStream类的一个实例,用于标准输入。可以使用 Scanner 或 BufferedReader 等类从标准输入读取用户输入的信息。
Scanner Scanner = new Scanner(System.in);System.out.print("输入您的姓名: " );String name = Scanner.nextLine();
currentTimeMillis() 方法: 返回当前时间与1970年1月1日午夜之间的毫秒数。通常用于测量代码的执行时间。
long startTime = System.currentTimeMillis();// 执行一些操作 long endTime = System.currentTimeMillis(); long elapsedTime = endTime - startTime;
arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 方法:用于复制负载。< /p>
int[] sourceArray = {1, 2, 3, 4, 5};int[] destinationArray = new int[5];System.arraycopy(sourceArray, 0, destinationArray, 0, sourceArray.length);// 现在destinationArray中包含了sourceArray的内容
getProperty(String key) 方法: 获取系统属性。可以用于获取一些系统相关的信息,比如网络类型、Java版本等。
String osName = System. getProperty("os.name");System.out.println("操作系统: " + osName);
exit(int status) 方法: 终止当前运行的Java虚拟机。status参数为一个整数,通常用于指示程序的退出状态。非零值通常表示发生了错误。
System.退出(0); // 正常退出程序System.exit(1); // 异常退出程序
gc()方法: 强制调用垃圾回收器。虽然Java具有自动垃圾回收功能,但可以使用System.gc()来显式地触发垃圾回收。
System.gc(); // 强制调用垃圾回收器
练习:获取循环十万次的运行时长。
public class Test { public static void main(String[] args) { long开始=System.currentTimeMillis(); for(int i=0;i<100000;i++){} long end=System.currentTimeMillis(); System.out.println("for循环十万次的运行时长:"+(end-start)+"毫秒"); }}
结果:
5.6 Integer类 h3>
5.6.1 基本介绍
整数类是 Java 中用于表示整数的包装类,它提供了许多方法来对整数进行操作和转换。
与基本数据类型相比,包装类的优点:可以还有更多的方法操作改数据。
//装箱:基本数据类型转为包装类 Integer a=Integer.valueOf(32); Integer a2=32;//拆箱:包装类转为基本数据类型 int b=a.intValue();//数字转StringString s=String.valueOf(12);//String转数字int c=Integer. parseInt(s);//String转Integer转数字int c=Integer.valueOf(s).intValue();
5.6.2 知识加油站:包装类的自动拆装箱与自动安装
包装类:包装类的主要作用是用于操作箱基本数据类型,将基本数据类型转换为对象,让基本数据类型拥有对象的特征,例如封装方法、泛型(基本数据类型不能作为泛型参数)、反射。
自动装箱是指把一个基本类型的数据直接赋值给对应的封装类型;
自动装箱是指把一个基本类型的数据直接赋值给对应的封装类型;
>自动拆箱是指把一个包装类型的对象直接赋值给对应的基本类型;
向上转换:布尔型外部的基本数据类型相互比较或损坏时会向上转换:byte,short,char→int→long→float→double。原理是将低字节数的数据转换类型转换为高字节数的数据类型,可以保证数据精度不丢失。c语言转换顺序:char→short→int→long→float→double
5.6.3 知识加油站:什么情况下用包装类?什么情况下用基本数据类型?
包装类适用场景: < /p> 数据实体类属性必须使用包装类型:《阿里规范约》规定,所有的 POJO 类属性必须使用包装类型,而不是基本数据类型。因为数据库的查询结果可能为 null,因为自动拆箱,用基本数据类型接收有NPE风险(NullPointerException空指针异常)。RPC方法的返回值和参数必须使用包装类:《阿里规约》规定,RPC方法的返回值和参数必须使用包装数据类型。因为相比基本数据类型,包装类的空值可以显示额外的信息。例如远程调用获取商品价格,如果使用包装类,空表示获取失败,0表示价格为0;而如果使用基本数据类型,即使获取失败返回值也是0,你就不可能知道是价格0还是获取失败了。
基本数据类型适用场景:
局部变量尽量使用基本数据类型:《阿里规约》建议,所有因为包装类对象是引用类型,JVM中,数据类型存储在方法栈中,引用数据类型存储堆内存实际对象的地址值,如果局部变量定义为引用数据类型还得根据这个地址值访问值,性能差(每次要new),而且内存空间,毕竟它的作用只是域方法内。5.6.4知识加油站:包装类和基本数据类型直接如何比较?(浮点数等号比较丢失精度问题)
包装类和基本数据类型:直接通过==比较。
Integer integer = new Integer(3000);双b=3000;//true,满足 System.out.println(b==integer);
整型: < /p> 相同整型包装类必须通过equals()比较。虽然两个通过自动装箱创建的、在服务器范围内的数值的相同整型包装类可以通过==比较(例如Integer) a=1,b=1,则a==b),但《阿里规约》规定整型包装类必须通过equals()比较。包装类和各类型基本类型可以通过==比较。不同整型型包装类必须转成相同类再通过equals()比较。整型基本数据类型用==比较。
浮点型:
浮点包装类先都转为BigDecimal,再进行侵犯、比较。
浮点基本类型直接比较,要报表桌面,两浮点分数差值在此范围内,认为是足够的。
浮点数正确比较方法:
基本数据类型:
浮点 a = 1.0f - 0.9f;浮点 b = 0.9f - 0.8f;浮点 diff = 1e-6f;if (Math.abs(a - b) < diff) { System.out.println("a、b是否");}
包装类:
//为了保证公平//BigDecimal推荐参入为String的构造方法,或使用BigDecimal的valueOf方法//valueOf方法内部其实执行了Double的toString,而Double的toString按double的实际能表达的对尾数的精度进行了截断 BigDecimal a = new BigDecimal("1.0"); BigDecimal b = BigDecimal.valueOf(0.9); BigDecimal c = new BigDecimal("0.8"); BigDecimal x = a.subtract(b); BigDecimal y = b.subtract(c); if (x.equals(y)) { System.out.println("a、b正好"); }
5.6.5 知识加油站:Integer a1=127;Integer a2=127;a1==a2原因
享元模式:
Integer 内部有共享元模式设计,【-128,127】范围内的数字会被存储,使用自动装箱方式赋值时,Java 默认通过 valueOf() 方法对 127 这个数字进行装箱操作,触发存储机制,使a1和a2指向同一个内存地址。
Byte、Short、Integer、Long存储区间【-128,127】。字符包装类型存储区间[0,127]。浮点型和布尔型没用共享元模式,Integer a = 127; 没有存储区间。整数 b = 127;整数c = 128;整数 d = 128; System.out.println(a==b); //true System.out.println(c==d); //false
5.7 数组类
数组
类包含了一系列用于操作阵列的静态方法。可以对阵列进行排序、搜索、比较、转换、填充等。以下是Arrays
类的一些常用方法:5.6.1 排序
排序( T[] a)
:对内存进行升序排序。int[]numbers = {5, 2, 8, 1 , 6};Arrays.sort(numbers);
sort(T[] a, Comparator super T> c)
:: strong> 使用指定的比较器对吞吐量进行排序。String[] names = {"John", "Alice", "Bob", "Eve" };Arrays.sort(names, Comparator.reverseOrder());
5.6.2 查找和判断
binarySearch(T[] a, T key)
:在已排序的阵列中使用二分查找算法查找指定元素的索引。int[] 数字 = {1, 2, 3, 4, 5, 6};int index = Arrays.binarySearch(numbers, 3);
equals(T[] a, T[] a2)
:比较多个集群是否可用。int[] arr1 = {1, 2, 3};int[] arr2 = {1, 2, 3};boolean isEqual = Arrays.equals(arr1, arr2);
5.6.3批量填充
fill(T[] a, T val)
:使用指定的值填充内存的所有元素。int[ ] 数字 = new int[5];Arrays.fill(numbers, 42);
5.6.4 转换字符串、链表< /strong>
toString(T[] a)
: 返回仓库元素的字符串。int[] 数字 = {1, 2, 3, 4, 5};String arrayString = Arrays.toString(numbers);
asList(T... a)
:将集群转换为固定大小的列表。String[] names = {"John", "Alice", "Bob"};List
nameList = Arrays.asList(names); 5.6.5 拷贝
copyOf(T[] Original, int newLength)
: 指定复制容量的吞吐量。int[] numeric = {1, 2, 3, 4, 5};int[] CopyNumbers = Arrays.copyOf(numbers, 3);
5.8 Date类
Date类是Java中用于表示日期和时间的类,位于java.util包中。在Java 8及之前的版本中,Date类主要是日期时间处理类,但在 Java 8 引入了 java.time 包,推荐使用新的日期时间 API(java.time 包中的 LocalDate、LocalTime、LocalDateTime 等类)。尽管如此,我们仍然可以了解 Date 类的基本使用。
5.8.1常用方法
getTime()
:返回自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数。toString()
: 返回日期对象的字符串表示。after(Date when): 判断定某个日期是否在指定日期之后before(Date when):判断某个日期是否返回在指定日期之前a.compareTo(b):对两个日期进行如果比较a时间在b之后,则1如果a时间在b之前,则返回-1 如果a==b,则返回05.8.2 代码示例
import java.util.Date;public class Test { public static void main(String[ ] args) { // 创建当前日期和时间的 Date 对象 Date currentDate = new Date(); // 输出当前日期和时间 System.out.println("当前日期和时间: " + currentDate); // 获取毫秒表示的时间 long timestamp = currentDate.getTime(); System.out.println("时间戳:" + 时间戳); // 通过时间戳创建 Date 对象 Date newDate = new Date(timestamp); System.out.println("新日期:" + newDate); }}
输出结果:
5.8.3知识加油站:Date类的线程安全问题
Date类的缺点:
线程不安全:Date类可变,在多线程环境中使用时需要额外的同步措施。解决方案: 使用局部变量:局部变量不会被多个线程同时访问到。加锁:通过同步锁或者锁锁,保证线程同步。ThreadLocal:ThreadLocal可以保证每个线程都可以得到单独的一个 SimpleDateFormat 的对象,那么自然也不存在竞争问题了DateTimeFormatter:如果是Java8应用,可以使用DateTimeFormatter代替SimpleDateFormat,这是一个线程安全的格式化工具类获取时间不方便:Date类的年份是从1900年开始的开始的,月份从 0 开始。没有时区:Date 类不提供国际化,没有时区支持,因此 Java 引入了 java.util.Calendar 和 java.util.TimeZone 类,但它们也一样存在上述所有的问题。需要格式化:需要配合SimpleDateformat类清理时间,而且SimpleDateformat类也是线程不安全的,如果使用线程安全的DateTimeFormatter类清理时间,则需要JDK版本在5.8.4 格式化日期:
5.8.4.1 SimpleDateformat类:线程不安全
SimpleDateformat类用于格式化和解析日期。
public static void main(String[] args) throws ParseException { //抛出只是把异常发送,延迟处理。用trycatch处理比较好 //Date转String Date d=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss" ); String str=sdf.format(d); System.out.println(str); //字符串转日期 d=sdf.parse(str); System.out.println(d); }
< /pre>日期格式模式:
SimpleDateFormat
使用一组模式字母来定义日期时间格式。以下是一些常见的的模式字母:y
: 年份(如“yy”表示年份的后三个,“yyyy”表示完整的年份)。< code>M:月份(1-12,"MM" 表示两个数字,"MMM" 表示缩写,"MMMM" 表示全名)。d
: 日期(1-31,"dd" 表示两人数字)。H
:(0-23," HH" 表示两位数字)。m
: 分钟(0-59,"mm" 表示两位数字)。s
: 卫浴(0-59,"ss" 表示他们数字)。5.8.4.2 DateTimeFormatter类:线程安全
DateTimeFormatter类是Java 8引入的日期时间API(java) .time 包)的一部分,用于格式化和解析日期时间对象。
特点:
不可变且线程安全支持新的日期时间类适用于Java 8 及以上版本。异常处理:在解析字符串时,如果字符串的格式与指定的模式不匹配,会抛出 DateTimeParseException 异常,因此需要异常处理。常用方法:
1.删除指定的日期时间:
format(TemporalAccessor temporal)
: 删除指定的日期时间对象。DateTimeFormatter 格式化程序 =DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime dateTime = LocalDateTime.now();String formattedDateTime = formatter.format(dateTime);
2.解析字符串为日期时间:
< pre>parse(CharSequence text)
: 解析输入的文本,返回一个解析后的日期时间对象。DateTimeFormatter 格式化程序 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String dateString = "2023-12-01 15:30:00";LocalDateTime parsedDateTime = formatter.parse(dateString, LocalDateTime::from);
3.获取当前格式化/解析器的模式字符串。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");字符串模式 = formatter.toString(); // 返回 "yyyy-MM-dd HH:mm:ss"
代码示例:将当前时间删除为字符串
<代码类=“语言”uage-java">import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;public class Test { public static void main(String[] args) { // 创建 DateTimeFormatter 对象,指定日期时间格式模式 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 获取当前日期时间 LocalDateTime currentDateTime = LocalDateTime.now(); // 格式化日期时间为字符串 String formattedDateTime = currentDateTime.format(formatter ); System.out.println("格式化日期和时间: " + formattedDateTime); }}5.9 数学类
数学类是数学数学工具类,提供了一系列用于执行基本数学破坏的静态方法。
基本使用:
public class Test { public static void main(String[] args) { // 基本数学侵犯 doubleabsoluteValue = Math.abs(-5.5); // 返回绝对值,结果为 5.5 double ceilValue = Math.ceil(4.3) ); // 返回不小于参数的最小整数值,结果为 5.0 double FloorValue= Math.floor(4.9); // 返回不大于参数的最大整数值,结果为 4.0 double maxValue = Math.max(10.2, 5.8); // 返回两个参数中的峰值,结果为 10.2 double minValue = Math.min(3.5, 7.1); // 简单地返回两个参数,结果为 3.5 long roundValue = Math.round(3.8); // 返回最接近参数的整数值,四舍五入,结果为 4 // 指数侵犯 double expValue = Math.exp(2.0); // 返回 e 的指数值,结果为 7.3890560989306495 double logValue = Math.log(10.0); // 返回以 e 为底的对数值,结果为 2.302585092994046 double powValue = Math.pow(2.0, 3.0); // 返回 2 的 3 次方,结果为 8.0 // 平方根和立方根 double sqrtValue = Math.sqrt(25.0); // 返回参数的平方根,结果为 5.0 double cbrtValue = Math.cbrt(27.0); // 返回参数的立方根,结果为 3.0 // 三角函数 double sinValue = Math.sin(Math.PI / 6); // 返回参数的正弦值,结果为 0.5 double cosValue = Math.cos(Math.PI / 3); // 返回参数的余弦值,结果为 0.5 double tanValue = Math.tan(Math.PI / 4); // 返回参数的正切值,结果为 1.0 // 角度和弧度转换 double DegreesValue = Math.toDegrees(Math.PI / 2); // 将弧度转换为角度,结果为 90.0 double radiansValue = Math.toRadians(180.0); // 将角度转换为弧度,结果为 π // 随机数生成 double randomValue = Math.random(); // 返回一个大于等于 0.0 且小于 1.0 的随机浮点 // 输出结果 System.out.println("绝对值: " +absoluteValue); System.out.println("上限值:" + ceilValue); System.out.println("下限值:" + FloorValue); System.out.println("最大值:" + maxValue); System.out.println("最小值:" + minValue); System.out.println("舍入值:" + roundValue); System.out.println("指数值:" + expValue); System.out.println("日志值:" + logValue); System.out.println("战力值:" + powValue); System.out.println("平方值:"; + sqrt值); System.out.println("Cbrt 值:" + cbrtValue); System.out.println("正弦值:" + sinValue); System.out.println("Cos值:" + cosValue); System.out.println("正切值:" + tanValue); System.out.println("度数值:" + DegreesValue); System.out.println("弧度值:" + radiansValue); System.out.println("随机值:" + randomValue); }}
结果:
5.10 随机
5.10.1 基本介绍
< p>java.util.Random类:主要用于生成α随机数。α随机:Random类产生的数字是α随机的,在相同的种子数(seed)下的相同次数产生的随机数是相同的。
基本使用方法:
创建 Random 对象:< /p>
Random random = new Random();
生成随机整数:
//生成一个循环0(包含)和指定范围(不包含)之间的intint randomNumber = random.nextInt(10); // 生成0到9之间的整数
生成随机浮点数:
//生成一个整数0 (包含)和1(不包含)之间的浮点数double randomDouble = random.nextDouble();
生成随机布尔值:
boolean randomBoolean = random.nextBoolean();
生成随机字节集群:
byte [] randomBytes = 新字节[10];random.nextBytes(randomBytes); // 将随机字节填充到指定的字节阵列中
设置值(可选):
// 如果需要重复生成相同的随机数序列,可以设置相同的种子值 long seed = 1234;Random seededRandom = new Random(seed);
5.10.2 代码示例
不指定种子: < /p>
随机 random = new Random();// 生成0到10(不包括10)之间的随机整数int num = random.nextInt(10); // 生成-1到10(不包括10)之间的随机整数int num2 = random.nextInt(10)-1;System.out.println("生成0到10(不包括10)之间的随机整数:"+num); // 生成随机浮点数 double randomDouble = random.nextDouble(); System.out.println("随机双精度数:" + randomDouble); // 生成随机布尔值 boolean randomBoolean = random.nextBoolean(); System.out.println("随机布尔值:" + randomBoolean); // 生成随机字节数组 byte[] randomBytes = new byte[5]; random.nextBytes(randomBytes); System.out.println("随机字节: " + Arrays.toString(randomBytes));
指定种子: < /p>
相同的种子数(seed)下的次数相同,产生的随机数是相同的。
public class Test { public static void main(String[] args) { // 指定种子为42长种子=42;随机 randomWithSeed = new Random(种子); // 生成随机整数 int randomNumber1 = randomWithSeed.nextInt(100); System.out.println("随机数1:" + randomNumber1); // 再次生成随机整数,因为种子相同,结果应该相同 int randomNumber2 = randomWithSeed.nextInt(100); System.out.println("随机数2:" + randomNumber2); // 创建另一个 Random 对象,没有指定种子 Random randomWithoutSeed = new Random(); // 生成随机整数,因为没有指定种子,结果不受前面的影响 int randomNumber3 = randomWithoutSeed.nextInt(100); System.out.println("随机数3:" + randomNumber3); }}
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)原创由知识百科栏目发布,感谢您对的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)原创”