Java SE
一、Java SE 基础
1.变量
- 变量就是内存中的存储空间,空间中存储着经常发生改变的数据
- 定义格式:数据类型 变量名 = 数据值;
- int salary = 10000
- 使用:根据变量名进行使用
- 注意事项
-
变量在作用域范围内才可以使用 变量名不允许重复定义 一条语句可以定义多个变量 变量在使用之前一定要进行赋值
-
2.标识符
-
* 作用:给类、变量、方法等取名字的符号单词 * 命名规则: 可以由数字、字母、下划线(_)和美元符($)其中一种或多种组成 不能以数字开头 不能是关键字或特殊直接量(true,flase,null) * 区分大小写 * 注意:不需要记忆规则,使用idea自动检查即可
3.基本数据类型的分类和使用
-
整数型
-
byte:1个字节,范围-128~127 short:2个字节 int:4个字节 long:8个字节
-
-
浮点型:
-
float:4个字节 double:8个字节
-
-
字符型
-
char:2个字节
-
-
布尔型
-
boolean:1个字节,就两个值true和false
-
4.switch语句
- 1.格式
- 2.switch语句的case穿透现象
- 注意:在switch语句中,如果case控制的语句体后面不写break,将会出现穿透现象
- 现象:当case 开始穿透,后续的case就不会具有匹配效果,内部的语句都会执行,知道看见break,或者将整体switch语句执行完毕,才会结束。
- 应用场景:当发现switch语句中,多个case给出的语句出现了重复的,就可以考虑 使用case穿透来优化代码
5.String
- 1.API:应用程序编程接口(Application Programming Interface )
- Java API:指的就是JDK中提供的各种功能的Java类
Java概述
-
Java语言背景介绍
问题:
1.什么是计算机语言,学习它有什么作用?
2.java语言的创始人是谁,在哪一年发布的呢?
3.java目前分为几个平台版本,我们学习的是哪些版本?
4.JavaEE主要是用于什么方向的开发? -
Java语言介绍
- 语言:人与人交流沟通的表达方式
- 计算机语言:人与计算机沟通交流的一种特殊语言
- Java语言是Sun公司(Stanford University Network)在1995年推出,1996年发布第一版开发工具包jdk1.0
- Java之父:詹姆斯·高斯林
-
Java语言的三个版本
- JavaSE:Java语言的标准版
- JavaSE主要用于桌面应用的开发,是其他两个版本的基础
- 桌面应用:用户只要打开程序,程序的界面会让用户在最短的时间内找到他们需要的功能,同时主动带领用户完成他们的工作并得到最好的体验
- JavaME:Java语言的小型版,用于嵌入式消费类电子设备
- 已经被Android和ios取代,不是我们学习的重点
- JavaEE:Java语言的企业版,用于Web方向的网站开发
- 网页、网站和服务器
- 网页:通过浏览器将数据展示在用户面前,跟后台服务器没有交互
- 网站:通过跟后台服务器的交互,将查询到的真实数据再通过网页展示出来
- 简单理解:网站=网页+后台服务器
- 网页、网站和服务器
- JavaSE:Java语言的标准版
-
Java跨平台原理
问题:
1.对于跨平台,这个平台指的是什么呢?
2.java程序是如何做到能够在不同的操作系统上运行的呢?
3.不同平台上的JVM虚拟机是一样的吗?
- 平台与跨平台
- 平台:不同的操作系统,比如:Windows、Mac、Linux…
- 跨平台:java程序可以在任意的操作系统上运行
- 跨平台的原理
- Java程序本身不能在不同的系统上直接运行,但是可以每个系统安装一个匹配系统的JVM
- JVM将Java程序翻译成对应系统可以看懂并且执行的程序
- 总结:要想跨平台运行java程序,只需要在不同的操作系统中,安装一个与操作系统对应的Java虚拟机(JVM)即可
- 注意:Java虚拟机本身不允许跨平台,允许跨平台的是Java程序
-
JRE和JDK
问题:
1.开发一个java程序的三个步骤是什么?
2.什么是java类,有什么作用?
3.在JRE中提供核心类库,有什么意义呢?
4.JVM、JRE、JDK之间具有什么关系?
-
JRE:Java Runtime Environment,java运行环境,包含JVM虚拟机及Java核心类库,是java语法能够被使用的前提
- 类:java文件在代码中的集合体现(类=java文件/一个java文件/一个java类)
- 类库:存放多个java文件的仓库
- 核心类库:java已经写好的,非常核心的代码仓库。常用‘’词典“
- 核心理解:编写代码的过程中,需要用到java存放在JRE中,已经写好的java文件
-
JDK:Java Development Kit,java软件开发工具包,内部包含了代码的编译工具(javac.exe)和运行工具(java.exe)
- JDK=JRE+开发工具
- JRE=JVM+核心类库
-
开发Java程序的三个步骤
- 编写源代码
- 创建文本文件
- 修改文件后缀名为.java
- 在文件中按照java的语法格式书写代码
- 编译源代码
- 写好的Java源文件不能直接被JVM识别和执行。需要用JDK中提供的翻译工具(javac.exe)将其翻译成字节码文件(.class文件),这个过程就是编译
- 运行程序:利用JDK提供的运行工具(java.exe)运行字节码文件
- 编写源代码
-
课后练习
- 下列关于JDK、JRE、JVM关系描述正确的是( )
- A: JDK是开发工具,JRE是运行环境,JVM是虚拟机。三者没有关联
- B: JDK是运行环境,包含了JRE。JRE是开发工具,包含了JVM。JVM是虚拟机,保证了跨平台
- C: JDK是开发工具,包含了JRE。JRE是运行环境,包含了JVM。JVM是虚拟机,可以保证跨平台
- D: JRE是虚拟机,保证了跨平台。JVM是运行环境,包含了JRE。JDK是开发工具,包含了JVM
- 下列关于JDK、JRE、JVM关系描述正确的是( )
-
JDK的下载和安装
问题:
1.安装jdk,能否安装在中文路径的文件夹下?
2.jdk的版本这么多,我们基础班学习,选择使用哪个版本?
3.怎么判断jdk已经安装成功了?
4.jdk根目录下的bin目录中主要是存放什么文件的? -
Java语言的发展史
- 95年推出,96年发布第一个开发工具包jdk1.0
- 2009年被Oracle收购
- 其余版本,都是功能测试版,半年到一年更新一次
- 基础班使用版本:14,因为有一些新特性,可以了解一下。
- 目前官方发布的,正在用于开发的大版本有8、11,也叫LTS版本,就是长期维护的版本
- 比如9、10、12、13、14、15、16都是维护半年的功能测试版
- 下一个大版本官方预计今年9月份之后
-
JDK的下载和安装
- 下载
- 直接访问:https://www.oracle.com/java/
- 找到download java按钮,鼠标点击,进入下载页
- 然后就可以选择版本进行安装,一般只会展示最新版和稳定版
- 注意:下载之前需要注册Oracle账号,用邮箱注册即可
- 安装(电脑可以安装不同版本的jdk,但是如果安装都是同一个版本,会把之前的卸载)
- 双击jdk文件进行安装;
- 在选择安装路径的环节,选择英文路径下进行安装,不要安装在带有中文的路径下;
- 建议所有和开发相关的软件都安装在统一的路径下,建议在D盘下创建一个develop文件夹统一进行管理
- 下载
-
JDK的安装目录(根目录介绍)
第一个程序
-
常用DOS命令
问题:
1.打开DOS命令提示符操作窗口的步骤是什么?
2.常用的DOS命令有哪些,分别具有什么功能?
3.如何快速的进入某个文件所在目录的对应DOS环境中?
-
学习DOS命令意义
- 为了能够使用JDK中bin目录下的java.exe和javac.exe这两个工具
- 未来学习使用Linux系统,需要提前适应命令行操作界面风格
-
打开DOS的方式想·
- 按下 win+r 键,弹出运行窗口
- 在窗口中输入cmd
- 点击确定
-
常用DOS命令
-
命令补充
命令 说明
mkdir 文件夹名 创建一个文件夹
rmdir [/s] 文件夹名 删除一个[非空]文件夹
del 文件名 删除文件
cd.>要新建的文件名 创建一个空白文件
rename 要重命名的文件名 重命名之后的文件名 修改一个文件的文件名
move 被移动的文件 要移动到的位置[\移动后的文件名] 剪切一个文件到指定路径下,也可以更改剪切后的文件名
copy 被复制的文件 要复制到的位置[\复制后的文件名] 复制一个文件到指定路径下,也可以更改复制后的文件名 -
快速进入bin目录所在的DOS命令提示符
- 找到jdk的bin文件夹,进入
- 在文件夹上方的地址栏输入cmd,回车即可
- DOS命令练习
- 在桌面创建一个文件夹dos-test
- 进入dos-test文件夹
- 创建一个dos.txt文件
- 自己选择一个非C盘的路径,创建一个文件夹dos-copy
- 将dos-test中的文件复制到dos-copy中
- 回到桌面,删除dos-test文件夹
- 退回C盘根路径
- 清除屏幕
- 退出
-
Path环境变量的配置
问题:
1.安装jdk之后,为什么要配置Path环境变量?
2.配置环境变量时,变量JAVA_HOME的值是什么?
3.Path变量的配置,是在用户变量中还是在系统变量中?
4.如何校验jdk的path环境变量是否配置成功? -
配置Path环境变量的意义
可以在任意目录下,都能访问到bin目录中的javac和java工具 -
Path环境变量的配置
-
找到桌面上计算机图标,鼠标右击,选择属性
-
找到高级系统设置,一般在左上方
-
选择高级、环境变量
-
在系统变量中新建一个变量
-
变量名是:JAVA_HOME,变量值是jdk的根目录地址,点击确定
-
再到系统变量框里找到path变量,编辑它
-
在path变量的编辑框中,点击新建,然后输入:%JAVA_HOME%\bin
-
需要注意的是,如果path变量框是上面的样式,是不需要加分号结束的
-
但如果是下方的样式,那么输入%JAVA_HOME%\bin;是需要带分号结束
-
设置好之后,需要一直点击确定结束
-
验证path环境变量是否配置成功,需要重新打开一个dos命令行窗口界面验证,不能使用原有的窗口
-
在dos命令行窗口分别输入java -version,java,javac三个命令验证
-
HelloWorld案例详解
问题:
1.书写Java代码时,class这个单词是用来干什么的?
2.一个Java程序能不能没有main主方法?
3.代码System.out.println(“学习Java的人不是帅哥,就是美女!”);的作用是什么?
4.class前面的public这个单词,有什么作用? -
一个java程序,有且仅有一个main方法,属于固定写法
- 一个java程序可以有很多个类,所以类是java程序的最基本组成单位
- 如果Java程序有很多个类,运行这个程序,从有main方法的类中开始
-
类名必须和文件名保持一致,因为类名前面有public修饰
-
HelloWorld程序说明:
- java在基础班没有丰富的视觉界面显示,只能通过控制台这种简单的界面去呈现内容。你现在打印的这个内容,以后真正的显式地方,是网页上
- 基础班暂时不学习网页内容,这个要到就业班才会学习
IDEA的安装和使用
-
IDEA的概述和安装
-
概述
IDEA全程是IntelliJ IDEA,是用于Java语言开发的集成环境,它是业界公认的目前用于Java程序开发最好的工具。
集成环境:把代码编写、编译、运行、调试等多种功能综合到一起的开发工具 -
下载和安装
下载:https://www.jetbrains.com/idea/download/other.html
安装:双击下一步即可,注意不要安装在中文路径下 -
IDEA中的项目结构
-
Idea项目结构介绍
- project:项目、工程
- module:模块
- package:包
- class:类
-
小结
- project中可以创建多个module
- module中可以创建多个package
- package中可以创建多个class
- 这样的结构划分,是为了方便管理类文件的
- 如果不用这些层级去管理类文件,全部放在同一个文件夹中,以后的项目有大量java类文件,不容易找
- 同一个文件夹下不能出现同名的java类,这样给类取名字就很麻烦了
- java类文件不做分类管理,就好比沃尔玛的商品不做分类,堆在一块
-
IDEA中的第一个代码
操作步骤(2021版):
-
创建Project(项目)
-
创建Module(模块)
project创建好之后,会自动弹出创建module的窗口
如果不通过自动弹出的创建module窗口创建,也可以在project的界面中操作
配置Module
-
创建Package(包)
-
创建class(类)
-
编写代码,运行程序
-
IDEA常用快捷键
//psvm: 一键生成主方法
//sout: 生成输出语句
//ctrl+alt+L: 格式化代码
//alt+Enter: 代码修正提示//ctrl+/: 添加(取消)单行注释
//ctrl+shift+/ : 添加(取消)多行注释//ctrl+D : 复制当前行的代码
//ctrl+X : 剪切
//ctrl+V : 粘贴//alt+1: 打开/隐藏项目结构
//alt+4: 打开/隐藏控制台//fori : 10次的for循环
-
IDEA操作模块
-
删除模块
-
导入模块
直接通过project界面导入已存在的module
通过Project structure设置导入module
最后就是一直选择next下一步即可
-
IDEA打开、关闭项目-类名、包名修改
-
关闭项目
-
打开项目
如果列表中要打开的项目已被移除:
-
修改类名
-
修改包名
基础语法
注释
问题:
1.什么是注释,程序当中的注释有什么作用?
2.java中注释分为几类,分别是什么?
3.注释会不会影响程序的编译和运行?
-
注释的概述
- 在程序指定位置添加的说明性信息
- 对代码进行解释说明,方便我们程序员更好的去阅读代码。
-
注释的分类
- 单行注释
格式:// 注释信息只有一行,并且在双斜线后面 - 多行注释
格式:/ 注释信息可以有很多行,位置被包裹住 / - 文档注释(目前用不上,暂不讲解)
格式:/* 注释信息 /
//练习:给HelloWorld程序添加注释
//这是一个类,类的名字叫A
public class A{
/*
这是程序的主方法,一个java程序有且仅有一个main方法。
*/
public static void main(String[] args){
//这是一个在控制台打印输出内容的语句,小括号中是输出的内容。
//在控制台输出自己的姓名、对喜欢的人想说的话
System.out.println(“好棒哦,notepad真给力”);
}
} - 单行注释
基础语法
-
关键字
问题:
1.java中的“关键字”是什么?
2.Java中的“关键字”有哪些特点?
3.main方法中的名字“main”是不是关键字?
- 概念:被java赋予了特定涵义的英文单词
- 特点:
- 关键字的字母全部都是小写
- 常用的代码编辑器,针对关键字有特殊的颜色标记,非常直观
- main不是关键字,但是也很关键
- java中有48个关键字,和2个保留关键字
-
字面量
问题:
1.Java中的字面量有哪几种类型?
2.'10’这个数据在Java中属于字符字面量吗?
3.能不能使用打印语句去打印空字面量? -
字面量的分类:
- 字符串字面量:被双引号所包裹的内容
- 整数字面量:所有整数
- 小数字面量:所有小数
- 字符字面量:被单引号包裹的内容,里面只能存放单个字符。字符是字符串的组成部分。
- 布尔、字面量:只有两个值,分别是true和false,分别代表真和假、成立和不成立这种对立的意思(以后学习运算符和流程结构时需要用到)
- 空字面量:null。代表不存在的,空的。不能被输出打印。
-
变量
3.1 变量概述
-
概念:在程序运行期间,其值可以发生改变的量。
-
理解:变量就是内存中的存储空间,空间中存储着经常发生改变的数据
-
定义格式
-
变量的使用(变量名进行使用)
//练习
//定义一个int类型的变量,并且赋值为18//使用变量,将变量中的数据打印出来
//再次给变量赋值,替换之前的数据
//再次打印该变量
-
内存图变化
-
第一步:
-
第二步:
3.2 变量的注意事项
- 变量的作用域:
- 从变量声明的那一行开始,到它所在的大括号结束的区域有效
- 注意事项:
- 在变量的作用域内,变量名不允许重复定义
- 一条语句可以定义多个变量,但需要用逗号进行分割
- 变量在使用前一定要进行赋值
-
数据类型
问题:
1.Java中的数据类型有几种?
2.Java中数据类型的转换方式有几种?
4.1 类型分类
-
Java的数据类型
- 基本数据类型(4类8种)
- 引用数据类型(类、接口、数组,比如String)
-
基本数据类型分类
-
案例
//练习:在下面输出语句的后面添加注释,标明打印内容分别属于什么数据类型
System.out.println(‘1’);//
System.out.println(520);//
System.out.println(3.14);//
System.out.println(0.618F);//
System.out.println(5201314L);//
System.out.println(false);//
4.2 类型转换
隐式转换
-
概念:将数据类型中取值范围小的数值或变量,给取值范围大的类型赋值。直接赋值。
int xiao=10;
//int的取值范围比double小,所以可以给double类型直接赋值
double da=xiao;
//总结:小的给大的,天经地义
1.总结:
//举例:200ml的可乐导入1L的瓶子,直接倒水,不会‘溢出’。所谓的数据类型转换就是不同类型的杯子中装水,怎么装更合适。
2.举例: -
数据类型范围从小到大排序
-
隐式转换的细节
-
不同数据类型进行运算,小的数据类型会提升为大的之后,再参与运算
//买早餐案例
//买包子,2元,int类型收
int baoZi = 2;
//买了个鸡蛋,1.5元,double类型接收
double egg = 1.5;
//小类型的baoZi和大类型的鸡蛋相加,包子提升成double类型参与运算:double+double
double zaoCan=baoZi+egg; -
特殊关注:byte、short、char(比int类型范围小的)三种数据进行运算的时候,不管是否有更高的数据类型,都会提升为int,再参与运算
//案例1:byte+short
byte b=10;
short s=29;
//分析:byte+short -> int +int -> int
int num1=m+s;//自案例
//案例2:byte+char
char c=‘a’;
//分析:byte+char -> int+int -> int
int num2=b+c;
//案例3:byte+short+double
double d=3.14;
//分析:byte+short+double -> int+int+double -> double+double+double -> double
double num3=b+s+d; -
强制转换
-
概念:把一个表示数据范围大的数值或变量赋值给另一个表示数据范围小的变量
-
格式:目标数据类型 变量名 = (目标数据类型) 值或变量;
//案例1:
int a=10;
//byte b=a; //编译报错:错误,不兼容的类型,从int转换到byte可能会有损失(精度损失)
//利用强转格式解决
byte b=(byte)a; -
精度损失
//案例1:浮点数强转成整数
//给定一个变量为double类型
double d=520.1314;
//给定一个变量为int类型,比double类型范围小,强制数据类型转换
int i=(int)d;
System.out.println(a);//结果:520
//思考:是否遵循四舍五入?
//double类型变量重新复制
d=0.618;
//再次强转
i=(int)d;
System.out.println(a);//结果:0
//结论:小数强转成整数,会直接舍掉小数部分//案例2:大整数强转成小数
//给定一个变量为int类型
int num1=520;
//强转byte类型,注意byte取值范围:-128~127
byte num2=(byte)num1;
System.out.println(num2);//结果:8
//思考:byte类型最大值为127,为什么结果是8? -
精度损失的原因
-
标识符
问题:
1.什么是标识符,有什么作用?
2.标识符的定义规则是什么?
3.标识符常见的命名规定有哪些? -
概述:给类、变量、方法等起名字的符号
-
硬性规则(必须得遵守,不遵守,程序就报错):
- 由数字、字母、下划线(_)和美元符($)其中一种或多种组成(也可以由汉字、π组成);
- 不能以数字开头;
- 不能和关键字相同;
- 区分大小写
//合法标识符
age
L_ni3
$get//非法标识符
7shang8xia //不能以数字开头
&abc //&不属于标识符的组成
class //不能是关键字 -
常见命名规定(软性规则)
- 小驼峰命名法:给变量、方法命名
- 标识符是一个单词的时候,首字母小写。比如:name
- 标识符由多个单词组成,首个单词全部小写,其余单词首字母大写。比如:firstName
- 大驼峰命名法:给类命名
- 标识符不管多少个单词,每个单词首字母大写,比如:HelloWorld
//练习1:以下哪些变量的命名是符合标识符规则的?在注释后面标注
String name=“张三”;//
int age=17;//
int do=23;//
double π=3.14;//
char d o l l a r = ′ dollar=' dollar=′';//
char 86RMB=‘¥’;////练习2:使用大驼峰或小驼峰式进行命名
//2.1 定义一个类名,该类用来表示一个学生//2.2 定义一个变量名,用来代表人的年龄
//2.3 定义一个变量名,用来代表学生的学号
//2.4 定义一个类名,用来代表第一个变量练习的类
- 小驼峰命名法:给变量、方法命名
-
键盘录入
- 学习键盘录入的目的:
- 可以在程序运行后,将键盘录入的数据获取到程序中操作
- 实现键盘录入的步骤:
-
导包:需要在class的上面写
- import java.util.Scanner;
-
创建Scanner对象,只有sc可以变,其他是固定格式
- Scanner sc=new Scanner(System.in);
-
使用变量接收键盘录入的数据,变量名num可以变,其他固定格式
- int num = sc.nextInt();
-
使用键盘录入的数据,这里是打印数据
- System.out.println(num);
//练习:利用键盘录入,在控制台录入自己的座右铭,并打印
-
运算符
-
运算符和表达式
- 概念
- 运算符:对常量或者变量进行操作的符号
- 表达式:用运算符把常量或变量连接起来符合java语法的式子就可以称之为表达式
- 概念
-
案例
int a=10;
int b=20;
int c=a+b;
// + 是算数运算符,a+b 是表达式,也叫算术表达式。
- 算数运算符
-
种类
-
案例
//案例1:+、-、*
int a=2;
int b=3;
// + 运算
int num1=a+b;
// - 运算
int num2=a-b;
// * 运算
int num3=a*b;
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);//案例2:/
//整数除法
System.out.println(10/2);//结果:5
System.out.println(10/3);//结果:3
//分析:10/3 -> int/int -> int。 所以小数部分直接省去。
//要得到小数,表达式中得有小数
System.out.println(10.0/3);
System.out.println(10/3.0);//案例3:%
//求10除以3的余数: 10 / 3 = 3 ······ 1
System.out.println(10%3);//结果:1//案例4:混合运算
int a=2;
byte b=3;
char c=‘a’;
System.out.println(c+a*b);
//类型分析:char+int+byte -> int+int+int -> int
//顺序分析:先乘后减
//结果:字符怎么加!!! 提升成int是多少呀?
//试着编译:不报错!
- 字符的+操作
- ASCII码表:美国信息交换标准代码
- 是计算机中,字节到字符的一套对应关系。
- 在码表中,每一个字符都有一个与之对应的数字。
- 为什么要有码表呀?
计算机底层所有的数据都是二进制数字,字符也不例外。我们使用电脑能看到的文字都是一个个的字符组成的。那这些字符应该用哪些二进制数字表示呢?如果每个国家都不一样,数据在互联网上就很难在国际上流通了。
所以老美就搞了这么一个标准,大家都共同遵守。
-
常用的字符码表对照
-
运算过程
-
char类型在参与数学运算的时候,先查找码表中对应的数字,再参与运算
char c=‘a’;
System.out.println(c+1); //结果:98
-
- 字符串的+操作
-
概述:字符串的“+”操作不是算数运算,而是字符串拼接运算。
-
特点:在“+”操作的时候,如果出现了字符串,“+”就是连接运算符。当连续进行“+”操作时,从左往右逐个进行。
//案例1:
//做一行爱一行
System.out.println(“Java”+520+1314);
//挑几个我喜欢的数字,我喜欢高一点的女孩子,175…
System.out.println(175+120+66+103+56+“Hello”);
- 案例:数值拆分
- 需求:键盘录入一个三位数,将其拆分为个位、十位、百位后,打印在控制台
- 思路:
- 使用Scanner键盘录入一个三位数;
- 计算个位数:数值 % 10。比如123的个位数是3,123 % 10的结果就是3;
- 计算十位数:数值 / 10 % 10。比如123的十位数是2,123 / 10得12,12 % 10的结果就是2;
- 计算百位数:数值 / 100。比如123的百位数是1,123 / 100得1。
- 公式:
-
个位数:数值 / 10的0次方 % 10;
-
十位数:数值 / 10的1次方 % 10;
-
百位数:数值 / 10的2次方 % 10;
-
千位数:数值 / 10的3次方 % 10;
-
…
//需求:键盘录入一个三位数,将其拆分为个位、十位、百位后,打印在控制台
//1. 使用Scanner键盘录入一个三位数
//1.1 导入Scanner包:import java.util.Scanner;
import java.util.Scanner;
public class Test{
public static void main(String[] args){
//1.2 创建Scanner对象
Scanner sc = new Scanner(System.in);
//1.3 提示用户键盘录入
System.out.println(“亲,请输入一个三位数哦:”);
//1.4 键盘录入数字
int num = sc.nextInt();
//2. 计算个位数:数值 % 10
int ge = num % 10;
//3. 计算十位数:数值 / 10 % 10
int shi = num / 10 % 10;
//4. 计算百位数:数值 / 100
int bai = num / 100;
//5. 假设输入的数字是520,打印内容:整数520的个位为:0,十位为2,百位为:5
//5.1 分析:字符串拼接操作
System.out.println(“整数” + num + “的个位为:” + ge + “,十位为” + shi + “,百位为:” + bai);
}
}
-
- 自增自减运算符
大家都玩微信吧?如果有朋友给你发消息,如果你没看,每发一条消息,红点的消息记录就多一条。说明微信有个程序一直再计数,每次增加1。
System.out.println("女神:在吗?我有事跟你说");
//定义一个int类型的变量记录未读消息数
int count = 1;
System.out.println("---您有" + count + "条未读消息---");
System.out.println("女神:我怀孕了");
count = count + 1;
System.out.println("---您有" + count + "条未读消息---");
System.out.println("女神:可能不是你的,但我还是爱你的");
count = count + 1;
System.out.println("---您有" + count + "条未读消息---");
System.out.println("女神:我想和你结婚,尽快");
System.out.println("开启了好友人认证,你还不是他的好友。请先发送好友申请...");
//问题:每次count都得加1再赋值给自己,特别麻烦,有没有更简单的方法呢?利用java的自增运算符就可以简化
- 介绍
注意事项:
- 可以放在变量的前面,也可以放在变量的后面
- 如果是单独给变量使用,放前放后都一样(常用操作)
- 如果参与运算
- 在前:先对变量进行自增或自减,再拿变量的值参与操作
- 在后:先拿变量原本的值参与运算,然后变量自己再进行自增或自减。变化后的变量值不参与运算
- 只能操作变量,不能操作常量
-
案例演示
//案例1:单独使用
int count=0;
//在前
++count;
System.out.println(count);//结果:1
count++;
System.out.println(count);//结果:2
//无区别,都是自己的值加1//案例2:参与运算 int num=1; //在前: int result=--num;//赋值也算参与运算 System.out.println(result);//结果:0 System.out.println(num);//结果:0 //在后: result=num--; System.out.println(result);//结果:0 System.out.println(num);//结果:-1 //操作常量 ++520//编译报错 520--//编译报错
-
总结
自增自减最后都要给自己加1或者减1,然后会给自己赋值。当然这个赋值运算省略了。说道到赋值,在java中我们已经知道了=是赋值运算符,那除了=之外,还有没有其他的赋值运算符呢?这里可以告诉大家,还有5种赋值运算符。
- 赋值运算符
-
介绍
-
案例演示
案例1:加后赋值
int a=24;
int b=2;
a+=b;// a=a+b;
System.out.println(a);案例2:减后赋值
a-=b;// a=a-b;
System.out.println(a);案例3:乘后赋值
a*=b;// a=a*b;
System.out.println(a);案例4:除后赋值
a/=b;// a=a/b;
System.out.println(a);案例4:取余后赋值
a/=5;// a=a%5;
System.out.println(a); -
注意事项:扩展的赋值运算符隐含了强制类型转换
//案例1
int a=23;
byte b=12;
b=a+b; //编译报错
//分析:int+byte -> int+int -> int。int不能直接赋值给byte
System.out.println(b);//案例2:扩展的赋值运算符
int a=23;
byte b=12;
b+=a;//编译通过
//分析:b+=a -> b=(b的数据类型)(b+a) -> byte=(byte)(byte+int) -> byte=byte
System.out.println(b);
- 关系运算符
在java中,普通的赋值运算符是用=号表示,所以以后int a=23;的实际读法,应该是把23赋值给了int类型的a。话说到这,如果我不是做赋值,就是要判断相等呢?=号都被占用了,哪个符合能用作判断相等的操作呢?
-
介绍
关系运算符是用来判断两个变量(常量、表达式)之间的关系,比如相等关系、不等关系和大小关系。 运算结果都是布尔值,要么是true,要么是false。
-
代码演示
//案例1:操作变量
int a=23;
int b=12;
System.out.println(a>b);//结果:true//案例2:操作常量
System.out.println(3<2);//结果:false//案例3:操作变量和常量
System.out.println(a>=3);//结果:true//案例4:操作表达式
int num1 = 5;
System.out.println(num1 * 2 + 1 != 11);//结果:false
- 逻辑运算符
国家开始推新冠疫苗啦,让全民接种。但是不是所有人都能打的,在年龄上有限制。规定是只给18~59岁的人群注射。
//定义一个变量,代表要接种疫苗的人,叫小明
String name="小明";
//小明今年14岁
int age=14;
//筛选,结果是true就能打,否则不能打
boolean result= 18<=age<=59; //编译报错,不允许这么写。
//如果不能一次性写,那就得写两行代码,在java中,能不能一次判断完呢?
-
介绍
-
作用:用于连接多个比较表达式的条件,得到最终的结果是个布尔值
- 其中&、|、^三种,左右两边不管是变量、常量还是表达式都可以
- 这些变量、常量、表达式最终的结果必须t布尔类型或数字
- !的后面放布尔值,不能放其他类型
-
代码案例
//案例1:操作变量
//有房
boolean fang = true;
//没车
boolean che = false;
//&:左右两边都是true,结果才是true。 要求高
System.out.println(fang & che);//结果:false
//|:左右两边有一个为true,结果就是true。要求低
System.out.println(fang | che);//结果:true//案例2:操作变量和常量
System.out.println(fang & false);//结果:false
System.out.println(fang & true);//结果:true
System.out.println(che | true );//结果:true//案例3:操作常量
System.out.println(true & false);//结果:false
System.out.println(false | true);//结果:true
// ^:左右两边的值不一样,结果才是true
System.out.println(true ^ true);//结果:false
System.out.println(false ^ true);//结果:true//案例4:操作表达式
//今年18岁
int age = 18;
//年龄必须在18到59岁才能打疫苗
System.out.println(age >= 18 & age <= 59);//结果:true
- 短路逻辑运算符
-
介绍
-
与运算:
- 逻辑与:&,无论左边真假,右边都要执行
- 短路与:&&,如果左边为true,右边就执行。如果左边为false,右边不用执行
-
或运算:
- 逻辑或:|,无论左边真假,右边都要执行
- 短路或:||,如果左边为false,右边执行。如果左边为true,右边不执行
-
代码演示
//案例1:&&的短路效果
int a=3;
int b=4;
System.out.println(a>3&&++b>4);
//分析:a>2的结果是false,所以&&后面不执行。b没有做自增运算
System.out.println(“b:”+b); //结果:4//案例2:||的短路效果
int num1=3;
int num2=4;
System.out.println(num1>2||num2–<4);
//分析:num1>2的结果是true,所以||后不执行,num2没有做自减运算
System.out.println(“num2:”+num2); //结果:4
- 三元运算符
-
格式:关系表达式 ? 表达式1:表达式2;
-
执行流程:
- 首先计算关系表达式的结果
- 如果结果是true,则取表达式1的结果做最终结果
- 如果结果是false,则取表达式2的结果做最终结果
-
代码演示
//案例1:求两个变量中的最大值
int a=28;
int b=18;
//分析:先让看a是否大于b,如果a大于b,则a是最大值,将a的值赋值给变量max,否则就是b赋值给max
int max=a>b?a:b;
System.out.println(“最大值是:”+max);//注意事项:表达式1和表达式2最终结果的数据类型必须一致。为什么?如果不一致,三元运算符最后的要赋值的话,拿什么数据类型接收?是不是就无法确定了?
分支语句
- 流程控制语句-顺序结构
-
介绍:java代码的默认执行流程:从上到下,从左往右
-
代码案例
//案例
//从上往下
System.out.println(“我是黑马程序员”);
System.out.println(“我的目标是月薪过万”);
System.out.println(“前提是要努力学习,键盘敲烂”);
//从左往右
System.out.println(“高薪就业!”+“人生巅峰!”+“迎娶白富美!”);
- if分支结构
2.1 第一种格式
-
格式
…
if(关系表达式){
语句体;
}
…//执行流程
//1. 首先计算关系表达式的值,这个结果只能是布尔值
//2. 如果关系表达式的值为true,就执行语句体
//3. 如果关系表达式的值为false,就不执行语句体
//4. if语句结束,继续执行后面的代码内容 -
代码案例
//案例1:小明上网
System.out.println(“今天是周末,天气真好,小明出门玩耍”);
//定义一个int类型变量,代表小明的年龄
int age=19;
System.out.println(“看到了一间网吧,准备进去玩两把”);
System.out.println(“网管问:你成年了吗?”);
//使用if语句进行判断
if(age>=18){
System.out.println(“小明说:我成年了”);
System.out.println(“领卡、卡机、五连跪”);
}
System.out.println(“小明转身回家”); -
注意事项
- 如果语句体只有1条语句,大括号可以不写(不推荐)
- if语句中小括号后面不能加分号,如果加分号,就代表if语句结束了
2.2 第二种格式
-
格式
…
if(关系表达式){
语句体1;
} else {
语句体2;
}
…//执行流程
//1. 首先计算关系表达式的值,这个结果只能是布尔值
//2. 如果关系表达式的值为true,就执行语句体1
//3. 如果关系表达式的值为false,就不执行语句体2
//4. if语句结束,继续执行后面的代码内容 -
代码案例
//案例1:判断一个数是奇数还是偶数
//给定一个待判断的整数
int num=23;
//开始进行判断
//寻找奇数的规律,偶数可以被2整除,意味着偶数对2取余数的结果是0,这个就可以作为判断的条件
if(num % 2==0){
System.out.println(“偶数”);
}else{
System.out.println(“奇数”);
}//案例2:判断两个数谁是最大值
int num1=5;
int num2=3;
//三元运算的方式
int max= num1>num2?num1:num2;
//利用if-else完成
//谁最大,需要判断num1是否大于num2,这就可以作为一个条件
if(num1>num2){
System.out.println(“最大数是:”+num1);
}else{
System.out.println(“最大数是:”+num2);
}
2.3 第三种格式
-
格式
…
if(关系表达式1){
语句体1;
} else if(关系表达式2) {
语句体2;
} else if
…
} else {
语句体n+1;
}
…//执行流程
//1. 首先计算关系表达式1的值,这个结果只能是布尔值
//2. 如果关系表达式1的值为false,就执行关系表达式2
//3. 如果关系表达式2的值为false,就执行关系表达式3
//4. …
//5. 有任何关系表达式的值为true,就执行对应的语句体
//6. 如果没有任何关系表达式的值为true,就执行语句体n+1 -
代码案例
/**
- 案例1:根据学生成绩,程序给出对应的评价
- 90~100:优秀
- 80~89:良好
- 70~79:中等
- 60~69:及格
- 0~59:请努力!
*/
//定义一个变量接收成绩
int score=89;
//需求中有5种条件,每种对应一个评价。刚好和if-else if的结构匹配
if (score >= 90 && score <= 100) {
System.out.println(“优秀”);
} else if (score >= 80 && score <= 89) {
System.out.println(“良好”);
} else if (score >= 70 && score <= 79) {
System.out.println(“中等”);
} else if (score >= 60 && score <= 69) {
System.out.println(“及格”);
} else {
System.out.println(“请努力加油!”);
}
2.4 案例:考试奖励
//需求:键盘录入学生考试成绩,根据成绩,程序给出不同的奖励
//思路:
//1. 考试成绩未知,需要用键盘录入,拿到考试成绩
//1.1 导入Scanner包,在代码的最上方第一行
import java.util.Scanner;
//1.2 创建Scanner对象
Scanner sc=new Scanner(System.in);
//1.3 提示用户键盘录入成绩
int score=sc.nextInt();
//2. 判断录入的学生成绩是否在合法范围之内
if(score>=0&&score<=100){
//合法成绩
//3. 在合法的if块中,判断成绩范围
if(score>=95&&score<=100){
//4. 为每种判断设置对应的奖励
System.out.println("奖励自行车一辆");
} else if(score>=90&&score<=94){
System.out.println("奖励游乐场玩一次");
} else if(score>=80&&score<=89){
System.out.println("奖励变形金刚一个");
} else {
System.out.println("挨顿揍,这个城市又多了一个伤心的人");
}
//注意,下面这个else是外层判断输入成绩是否合法对应if结构,不是内层的。
}else{
//非法成绩
System.out.println("您输入的成绩有误");
}
- switch分支结构
3.1 格式和执行流程
-
格式
switch(表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
…
case 值n:
语句体n;
break;
default:
语句体n+1;
break;
}
/**- 格式说明:
- 表达式:可以取值为byte、short、int、char,JDK5以后可以是枚举,JDK7以后可以是String;
- case:后面跟的值,是要和表达式进行匹配的值。如果匹配的结果是一样的,就执行对应语句体;
- break:表示中断、结束的意思,用来结束switch语句;
- default:表示所有的情况都不匹配的时候,就执行该处语句体的内容,和if语句的else相似。
*/
/**
- 执行流程:
- 1.首先计算表达式的值;
- 2.依次和case后面的值进行比较,如果有对应值的话,就会执行相应语句,在执行的过程中,遇到break就会结
- 束,其他语句体不会再执行;
- 3.如果所有的case后面的值和表达式的值都不匹配,就会执行default里面的语句体,然后程序结束掉
*/
-
注意事项
- case给出的值不允许重复
case后面的 - 值只是常量,不能是变量
- case给出的值不允许重复
3.2 case穿透
-
注意:在switch语句中,如果case控制的语句体后面不写break,将出现穿透现象;
-
现象:当开始出现case穿透,后续的case就不会具有匹配效果,内部的语句不会结束,继续向下执行。直到看到break,或者将整个switch语句执行完毕,switch才会结束
-
应用:当发现switch语句中,多个case给出的语句体出现重复的时候,就可以考虑使用case穿透来优化代码
//案例:键盘录入112,代表当前月份。其中35是春季,68是夏季,911是秋季,12~2是冬季。
//1.使用Scanner键盘录入
//1.1 导包
import java.util.Scanner;
public class Test03 {
public static void main(String[] args) {
//1.2 创建Scanner对象
Scanner sc = new Scanner(System.in);
//1.3 提示用户键盘录入,防止程序要开始录入的时候,用户不知道
System.out.println(“请输入当前月份”);
//1.4 开始键盘录入选择,并用int类型的变量season接收键盘录入的数字值
int season = sc.nextInt();
//2.根据录入的数字值,匹配不同的月份
switch (choice) {
case 3:
case 4:
case 5:
System.out.println(“春天到了,这是个万物复苏的季节”);
break;
case 6:
case 7:
case 8:
System.out.println(“夏天热情似火,路边的小姐姐都很好看”);
break;
case 9:
case 10:
case 11:
System.out.println(“秋天收获劳动的过时,大地的馈赠”);
break;
case 12:
case 1:
case 2:
System.out.println(“冬天里寒风凛凛,小姐姐的身材看不到了”);
break;
default:
System.out.println(“您输入的月份有问题哦!”);
break;
}
}
}
循环语句
循环:重复做某件事情,具有明确的开始和停止标记
- for循环
1.1 格式和执行流程
-
格式
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
//执行流程
//1.执行初始化语句
//2.执行条件判断语句,看起结果是true还是false。
//3.如果是false,循环结束
//4.如果是true,继续执行循环体语句
//5.循环体语句执行结束,执行条件控制语句
//6.回到第二步继续 -
代码演示
1.2 案例:输出数据15和51
-
思路分析:
-
打印1~5:
-
打印5~1:
-
-
代码演示
//打印1~5
//打印的动作是重复的,所以必须把输出语句放到循环内部
//重复5次,并且是从1开始打印,那么就要控制变量在1,2,3,4,5都能取到
for(int i=1;i<=5;i++){
System.out.println(i);
}
//打印5~1
//同上,只是打印从5开始,变量的值取5,4,3,2,1,依次递减
for(int i=5;i>=1;i–){
System.out.println(i);
}//思考:如何只利用一个循环解决?
//分析:总共循环打印10次,可以先让变量取到1~10
for(int i=1;i<=10;i++){
//如果仅仅是直接打印i的值,则无法打印51,打印的是610
//System.out.println(i);
//所以不能直接打印i,必须加条件限制,只有当i<=5的时候可以直接打印
if(i<=5&&i>=1){
System.out.println(i);
}
//如果只有上面的条件限制,则无法阻挡610的打印,思考610和5~1之间的关系
//11-6=5,11-7=4,11-8=3,11-9=2,11-10=1
//找到规律,可以开始判断条件,当i取6~10的时候如此操作
if(i<=10&&i>=6){
System.out.println(11-i);
}
}
1.3 案例:求1~5数据和
-
思路分析
-
代码演示
//定义一个int类型的变量,专门用来接收求和的值,一开始没有任何值,所以是0
int sum=0;
//因为是求15的和,所以要保证能取到15这几个数字,并且求和的话是加了5次,所以循环也能控制成5次
for(int i=1;i<=5;i++){
//每次相加,都是拿累计好的值加新取到的1~5的值,累计值是由sum表示,所以是拿sum和i相加
//sum+i;
//加完之后,累计值要改变,所以还得赋值回给sum
//sum=sum+i;
//这种自己加某个值再赋值给自己的操作,可以使用扩展赋值运算符搞定
sum+=i;
}
//循环结束,可以确定i的每个值都取到了,并且加过了,这个时候的sum已经是最后的结果
System.out.println(“1-5之间的数据和是:”+sum);
1.4 案例:求1~100偶数和
-
思路分析
-
代码演示
//分析:要取到1~100的值,数字有100个,那么得循环100次
//定义一个变量,做累计相加的值的容器
int sum=0;
for(int i=1;i<=100;i++){
//这100个数字,不是所有数字都是偶数,什么样的数字才能被称为偶数?一个数被2整除,没有余数就是偶数
if(i%2==0){
//满足条件的i才会进来,此时i就是偶数,利用上一个案例的知识,可以在此处累计相加
sum+=i;
}
}
//循环结束,就可以打印sum的值
System.out.println(“1-100之间的偶数和是:”+sum);
1.5 案例:水仙花数
-
水仙花数
-
思路分析
-
代码演示
//1. 通过循环能获得100~999这所有的数
for(int i=100;i<=999;i++){
//针对当前i的值,i一定是三位数,所以要拆分成个位、十位、百位
//2.分别定义变量代表个位、十位、百位
int ge=i%10;
int shi=i/10%10;
int bai=i/100;
//3.水仙花数的条件就是:个位数的三次方+十位数的三次方+百位数的三次方等于原来的数
if(gegege+shishishi+baibaibai==i){
//4.满足条件的数就是水仙花数,可以打印
System.out.println(“水仙花数:”+i);
}
}
1.6 案例:每行打印2个水仙花数(统计)
-
需求分析
-
代码实现
//1. 通过循环能获得100~999这所有的数
//2. 定义一个变量,记录打印了多少个数,定义的时候还一个都没有打印,所以初始值是0
int count=0;
for(int i=100;i<=999;i++){
//针对当前i的值,i一定是三位数,所以要拆分成个位、十位、百位
//3.分别定义变量代表个位、十位、百位
int ge=i%10; 521-------1
int shi=i/10%10; 521—52—2
int bai=i/100; 521------5
//4.水仙花数的条件就是:个位数的三次方+十位数的三次方+百位数的三次方等于原来的数
if(gegege+shishishi+baibaibaii){
//5.满足条件的数就是水仙花数,打印的时候注意,第一不要换行,第二要留一个空格隔开
System.out.print(i+" ");
//6.每打印一个数字,count的值就得记录1次,值要加1
count++;
//7.此时就应该马上判断打印了多少个数字,如果是偶数,马上就要开始换行了
//8.判断一个数是否是偶数,只需要对2取余数是0就可以了
if(count%20){
//9.仅仅换行,不打印
System.out.println();
}
}
}
- while循环语句
2.1 格式和执行流程
-
格式
//基本格式
while(条件判断语句){
循环体语句;
}//完整格式
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句;
}//执行流程
//1.执行初始化语句;
//2.执行条件判断语句,看结果是true还是false
//3.如果是false,循环结束。如果是true,则继续执行循环体语句
//4.执行条件控制语句
//5.若循环内部没有使用特殊关键字结束循环,则回到第2步继续 -
代码案例
//案例:打印999次“我爱你的第X天”
//1.有记录次数,并且循环的次数和记录的次数相关,所以初始化语句就可以定义一个int类型的变量
int count=1;
//2.开始循环,当count值一直小于等于999次的时候,就还可以打印
while(count<=999){
System.out.println(“我爱你的第”+count+“天”);
//每打印1次,count的次数就得加1
count++;
} -
注意事项
//1.while后面的小括号后,千万不要写分号,例如
int count=1;
//1.1小括号后面马上接分号,代表没有循环体语句,后面的大括号部分就不属于while循环的范围
//1.2这就会导致count的值一直无法执行到自加操作,会一直满足count<=999,而出现程序卡死的情况
while(count<=999);
{
System.out.println(“我爱你的第”+count+“天”);
//每打印1次,count的次数就得加1
count++;
}
2.2 案例:珠穆朗玛峰
-
需求分析
-
代码实现
//1.需要求次数,那就说明每次循环需要计数一次,那就得在循环外定义一个变量去接收折叠的次数
//循环开始前,没有折叠,所以初始化值是0。注意不能放到循环内去定义变量
int count=0;
//2.要判断停止循环的条件是什么,就是纸张的厚度大于等于珠峰高度的时候
//纸张的高度是随着折叠而变化的,属于变化的量,那就定义一个变量代表纸张厚度
double paper=0.1;
//3.反复折叠属于重复操作,并且不知道折多少次,使用while循环比较合适
while(paper<=8844430){
//4.当纸张厚度小于珠峰的时候就要折叠,折叠的动作是重复的,折叠的后果是纸张厚度要乘以2
paper*=2;
//5.折叠一次,计数器要加1次
count++;
}
//通过不断的循环,paper的厚度一直增加,知道大于等于珠峰高度的时候,条件判断的结果为false,结束循环
//此时就可以打印折叠次数
System.out.println(“折叠”+count+“次,达到珠峰高度”);
- do…while循环
-
格式
//基本格式
do{
循环体语句;
}while(条件判断语句);//完整格式
初始化语句;
do{
循环体语句;
条件控制语句;
}while(条件判断语句);//执行流程
//1.执行初始化语句
//2.执行循环体语句
//3.执行条件控制语句
//4.执行条件判断语句,看结果是true还是false
//5.如果是false,循环结束。如果是true,继续执行
//6.回到第2步继续 -
代码案例
//案例:在控制台输出3次:代码练习了X遍(X代表次数)
//定义一个变量用来记录打印的次数
int count=0;
do{
//进入循环就练习一遍代码,所以次数要加1次
count++;
System.out.println(“代码练习了”+count+“遍”);
//这里不能是<=,因为练了5次,就可以结束了,不能再循环练习
}while(count<5); -
特点
-
do…while循环,无论条件是否满足,都会执行一次循环体语句
-
很少用,了解即可
-
三种循环的区别
- 三种循环的区别
- for、while循环: 必须满足条件才执行(先判断再执行)
- do…while::不管条件是否成立,循环语句体至少执行一次(先执行再判断)
- 三种循环的场景
-
循环开始前,知道次数,使用for循环
-
循环开始前,不知道次数,使用while循环
-
do…while一般不用
//案例1:for循环外尝试使用变量
//循环开始,可以知道循环3次
for(int i=1;i<=3;i++){
//for循环内部使用for循环中定义的变量,没有问题
System.out.println(“i:”+i);
}
//编译报错,因为变量i是for循环中定义,只能在循环中使用,循环结束,i也从内存中消失
System.out.println(“i:”+i);//案例2:将上面的for循环,替换成while循环
//1.将变量i的声明和初始化提取到循环外操作
int i=1;
//2.条件判断保留
while(i<=3){
//可以打印
System.out.println(“i:”+i);
}
//循环外打印循环外定义的变量,可以打印
System.out.println(“i:”+i);
-
- 死循环
-
格式
//1.while死循环
while(true){
循环体语句;
}//2.for死循环
for(;😉{
循环体语句;
}//3.do…while死循环
do{
循环体语句;
}while(true); -
代码演示
//案例1:死循环使用的场景-while
//当重复的动作完全无法判断会执行多少次的时候,并且可能没有上限或下限时,使用while死循环
//例如:键盘录入一个3位数,当录入的数字是一个水仙花数的是时候,打印该数字,并结束程序
//分析:3位数的数字非常多,用户可能一直都无法录入成功,所以无法判断录入的次数,重复的上下限也不好判断
//使用while死循环//1. 导包
import java.util.Scanner;public class TestWhileLoop {
public static void main(String[] args) {
//2.创建Scanner对象
Scanner sc = new Scanner(System.in);
//无法判断录入多少次会成功,并且录入数字的次数,上下限无法确定
//3.使用while死循环
while (true) {
//4.提示用户录入一个三位数
System.out.println(“亲,请输入一个三位数哦:”);
//5.键盘录入一个整数
int num = sc.nextInt();
//6.获取该数字的个位、十位、百位
int ge = num % 10;
int shi = num / 10 % 10;
int bai = num / 100;
//7.判断该数字是否是水仙花数
if (ge * ge * ge + shi * shi * shi + bai * bai * bai == num) {
//8.如果是水仙花数,就能进入,打印该数字
System.out.println(num);
/*
* 9.问题来了,此时我们是想让循环能够结束的,但是现在还做不到。
* 循环依然还是不断执行,无法结束。
* 所以如果java能具备一个可以随时结束循环的操作,死循环就可以完美的使用。
* 在DOS界面中,可以直接利用Ctrl+C强制结束程序而结束循环,这样不推荐
/
}
}
}
}
/*- 总结:死循环可以让重复的动作一直执行下去。
- 所以死循环的使用,必须能够具备一个可以让程序根据情况而随时结束循环的操作。
*/
- 跳转控制语句
-
概述
- 跳过当前循环过程,马上进入下一次循环过程:continue
- 结束当前循环,循环语句结束:break
-
代码演示
//案例1:打印1到10之间的整数,不要把2和4打印出来
for(int i=1;i<=10;i++){
//i等于2和4都不能打印,所以必须加条件判断限制
if(i2||i4){
//当i等于2或者4的时候进来,但是此时是不想要执行后面的打印语句的
//使用continue把当前循环体过程马上结束,后面的打印语句就无法执行了,直接进入下一次循环中
continue;
}
System.out.println(i);
}//案例2:在上一个视频案例中,加上break,让程序可以被结束
…
if (ge * ge * ge + shi * shi * shi + bai * bai * bai == num) {
//如果是水仙花数,就能进入,打印该数字
System.out.println(num);
//已经获得了水仙花数,不需要再重复执行,循环可以结束,利用break
break;
}
…//案例3:学生管理系统
//我们在学习switch的时候,练过一个学生管理系统的案例Scanner sc = new Scanner(System.in);
//1.以下内容,我们是需要能够反复执行,知道用户录入退出系统的时候,才会结束
//2.不知道用户要用多久,所以无法判断循环次数和使用上限,选择while死循环
while(true){
System.out.println(“欢迎使用本学生管理系统”);
//提示用户键盘录入
System.out.println(“请选择功能:1.增加学生 2.删除学生 3.修改学生 4.查询学生 5.退出”);
int choice = sc.nextInt();
//根据录入的数字值,选择执行不同的功能
switch (choice) {
case 1:
System.out.println(“增加学生…”);
break;
case 2:
System.out.println(“删除学生…”);
break;
case 3:
System.out.println(“修改学生…”);
break;
case 4:
System.out.println(“查询学生…”);
break;
default:
System.out.println(“退出系统…”);
//3.退出系统,我们本想着用break结束循环,但是发现无法做到
break;
}
} -
注意事项
- break除了可以用于结束循环语句,也可以用于结束switch语句
- 但是如果一个循环语句内部有switch语句,则switch中的break只能结束switch,无法结束循环
- 循环标号
-
总结:break和continue只能跳出、跳过自己所在的那一层关系,如果想要跳出、跳过指定的一层,可以加入标号
-
示例
标号名:while(true){
switch(表达式){
case 值1:
break 标号;
…
}
} -
代码演示
//给当前循环加上一个标号’loop’,名字可以随便取
loop:while(true){
System.out.println(“欢迎使用本学生管理系统”);
//提示用户键盘录入
System.out.println(“请选择功能:1.增加学生 2.删除学生 3.修改学生 4.查询学生 5.退出”);
int choice = sc.nextInt();
//根据录入的数字值,选择执行不同的功能
switch (choice) {
case 1:
System.out.println(“增加学生…”);
break;
case 2:
System.out.println(“删除学生…”);
break;
case 3:
System.out.println(“修改学生…”);
break;
case 4:
System.out.println(“查询学生…”);
break;
default:
System.out.println(“退出系统…”);
//3.利用结束标号的形式,指定让break结束外层循环语句
break loop;
}
}
Random
-
作用:用于产生一个随机数
-
使用步骤
- 导包:import java.util.Random;
- 创建对象:Random r=new Random();
- 获取随机数:int num=r.nextInt(10);//获取随机数的范围[0,9]
-
代码演示
//案例:有一个摇号机,可以摇出1~16号的球,当摇出6号球的时候,获得一等奖
//1. 导包
import java.util.Random;public class TestRandom {
public static void main(String[] args) {
//2.创建Random对象,这个对象就好比是“摇号机”
Random random = new Random();
//3.号码是不断的获取的,直到获得6号的时候中一等奖
//4.使用while死循环
while (true) {
//5.利用Random对象,获取随机数,随机数范围是1~16
//.nextInt(16)的随机数范围是015,在这个范围上加1,范围就变成了116
int num = random.nextInt(16) + 1;
//6.如果随机数是6,就获得一等奖
if (num == 6) {
System.out.println(“恭喜你获得一等奖,奖品是:李小璐亲自为你做头发”);
//7.结束循环
break;
}
}
}
数组
是一种容器,用来存储(同种数据类型)的多个值。
- 数组定义格式
-
格式
//数组类型变量的声明方式1:
数据类型[] 数组名;
//数组乐行变量的声明方式2:
数据类型 数组名[]; -
代码演示
//声明一个用来存放int类型数据的数组
int[] arrs;
//或
int arrs[];//声明一个用来存放double类型数据的数组
double[] nums;
//或
double nums[];//声明一个用来存放String类型数据的数组
String[] strs;
//或
String strs[];//注意:数组类型变量和基本数据类型的变量一样,都必须先初始化,才能使用
-
数组的动态初始化
-
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
-
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
-
格式
//格式
数据类型[] 变量名= new 数据类型[数组长度];
//范例
int[] arr= new int[3]; -
代码演示
//案例:
//利用数组的冬天初始化,创建一个int类型的数组,可以存放5个int类型的值
int[] arr=new int[5];
//同上,创建一个可以存放3个byte类型的数组
byte[] bts=new byte[3];
//分别打印这两个数组
System.out.println(arr); //结果:[I@10f87f48
System.out.println(bts); //结果:[B@b4c966a
//直接打印数组,无法获取数组中的数据
//打印的值是该数组容器的内存地址值/**
- [:代表数组
- I:代表是int类型
- @:分隔符
- 10f87f48:16进制内存地址值
*/
-
数组元素访问
-
索引
- 索引是数组中空间的编号
- 索引从0开始
- 索引是连续的
- 索引逐一增加,每次加1
- 最大的索引值是数组长度减1
- 作用:访问数组容器中的空间位置
- 索引是数组中空间的编号
-
代码演示
//访问数组内部存储的数据:通过索引访问
//数组名[索引]//代码演示:取数据
//动态初始化一个长度为5的int类型数组
int[] arr=new int[5];
//访问该数组中索引为3的位置的数据
System.out.println(arr[3]);//结果:0
//访问int数组中索引为5的位置的数组
System.out.println(arr[5]);//运行错误,因为数组长度是5,索引最大只能到4//动态初始化一个String类型的数组,长度为3
String[] strs=new String[3];
System.out.println(strs[2]);//结果:null//总结
/**- 初始化数组之后,哪怕没有给数组存数据,系统也会默认给数组分配初始值。
- 基本数组类型:
- 整数类型的数组,初始化值是0;
- 小数类型的数组,初始化值是0.0;
- 字符类型的数组,初始化值是’ ';
- 布尔类型的数组,初始化值是false
- 引用数据类型:
- 初始化值是null
- 了解:如果是数组类型的数组,那初始化值就是一个地址值
*/
//代码演示:存数据
//数组名[索引]=数据值;
//套用格式
arr[0]=2;
arr[3]=4;
System.out.println(arr[0]);//结果:2
System.out.println(arr[3]);//结果:4
-
一个数组内存图
-
栈内存:方法运行时,进入的内存,局部变量都存放于这块内存中
-
堆内存:new出来的内容都会进入堆内存,并且会存在地址值
-
方法区:字节码文件(.class文件)加载时进入的内存
-
本地方法栈:调用操作系统相关资源
-
寄存器:交给CPU去使用
-
两个数组内存图
int[] arr1 = new int[2];
System.out.println(arr1);
arr1[0] = 11;
arr1[1] = 22;
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(“---------------”);
int[] arr2 = new int[3];
System.out.println(arr2);
arr1[0] = 33;
arr1[1] = 44;
arr1[2] = 55;
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(arr1[2]); -
多个数组指向相同内存图
int[] arr1 = new int[2];
arr1[0] = 11;
arr1[1] = 22;
int[] arr2 = arr1;
arr1[0] = 33;
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(“---------------”);
System.out.println(arr2[0]);
System.out.println(arr2[1]); -
数组的静态初始化
-
静态初始化:初始化时指定每个数组元素的初始值,由系统决定数组长度
-
格式范例
//完整格式
//数据类型[] 数组名=new 数据类型[]{数据1,数据2,数据3,…,数据n};
//简化格式
//数据类型[] 数组名={数据1,数据2,数据3,…,数据n};//完整格式范例
int[] arr = new int[]{23, 14, 9};
System.out.println(arr[0]);//结果:23
System.out.println(arr[1]);//结果:14
System.out.println(arr[2]);//结果:9//简化格式范例
int[] arr2 = {66,88};
System.out.println(arr[0]);//结果:66
System.out.println(arr[1]);//结果:88 -
两种初始化的使用场景
- 动态初始化:只明确元素个数,不明确具体数值,推荐使用动态初始化。
- 要存的数据,在创建数组前还不知道是什么,比如需要键盘录入的数据。只知道要录入几个。
- 静态初始化:需求中已经明确了要操作的具体数据,直接静态初始化即可
- 要存的数据,在数组创建的时候已经有了,比如将全班学员的成绩存入数组
- 动态初始化:只明确元素个数,不明确具体数值,推荐使用动态初始化。
- 数组操作的两个常见问题
-
索引越界异常:访问了数组中不存在的索引,造成索引越界异常
public class Demo01 {
public static void main(String[] args) {
int[] arr = new int[]{23, 14, 9};
System.out.println(arr[3]);
}
} -
空指针异常:访问的数组已经不再指向堆内存的数据,造成空指针异常
-
null:空值,代表不存在。表示不指向任何有效对象。
public class Demo01 {
public static void main(String[] args) {
int[] arr = new int[]{23, 14, 9};
System.out.println(arr[1]);
arr = null;
System.out.println(arr[1]);
}
}
-
- 数组遍历
-
格式
//数组定义及初始化
int[] arr={…};
//…
//遍历数组
for(int i=0;i<arr.length;x++){
//arr[i],获取到的就是数组对应索引为i的数据
//由于i的值从0开始,逐一增加,所以每次循环就能获得一个数组数据,循环结束,数组数据也都拿了一遍
// arr[i];
//至于拿出来的数据是直接打印,还是用一个变量接收,用作后面使用,完全看需求决定
} -
注意
- 遍历数组,是指取出数组中所有数据的一个过程,不能局限理解为就是打印数组数据
-
数组获取最大值
求最值的思路:
1.假设数组中的0索引元素为最大值max(擂主)
2.让其他的元素和max比较,把较大的值赋值给max(打赢的站在擂台上)
3.最终max就是最大值(最后站在擂台上的就是最大值)//案例:求数组中的最小值,并打印
//定义一个数组,静态初始化
int[] arr={1,3,46,8,2,5,9,7};//1.假设数组中的0索引元素为最小值(擂主)
int min=arr[0];//2.让其他的元素和min比较,把较小的值赋值给min(打赢的站在擂台上)
for (int i = 1; i < arr.length; i++) {
if(arr[i]<min){
//3.arr[i]比上一个小一点的守擂的min还要小,所以就让arr[i]去守擂
min=arr[i]; //打赢的站在擂台上
}
}
//4.最终min就是最小值(最后站在擂台上的就是最小值)
System.out.println(“最小值为:”+min); -
数组元素求和
-
需求:键盘录入5个整数,存储到数组中,并对数组求和
-
思路
- 创建键盘录入对象,准备键盘录入数字
- 定义一个求和变量,准备记录累加后的值
- 动态初始化一个长度为5的int数组,准备存储键盘录入的数据
- 将键盘录入的数值存储到数组中
- 遍历数组,取出每一个元素,并求和
- 输出总和
-
代码演示
//1.创建键盘录入对象,准备键盘录入数字
Scanner sc = new Scanner(System.in);
//2.定义一个求和变量,准备记录累加后的值
int sum = 0;
//3.动态初始化一个长度为5的int数组,准备存储键盘录入的数据
int[] arr = new int[5];
//4.由于数组有多长录入几次,就是遍历数组录入
for (int i = 0; i < arr.length; i++) {
//5.提示用户录入数字
System.out.println(“请录入一个整数:”);
int num = sc.nextInt();
//6.将键盘录入的数值存储到数组中,
arr[i] = num;
}//7.遍历数组,求和
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
//8.输出总和
System.out.println(“数组中所有元素的和是:”+sum);
- 数组基本查找
-
需求:已知一个数组==arr = {19,28,37,46,50};==键盘录入一个数据,查找该数据在数组中的索引,并在控制台输出找到的索引值
-
分析思路
- 分析:
- 键盘录入一个数据后,让这个数据和数组中的每一个元素进行比较,如果数据值相等,返回该数据值对应的索引即可。
- 但是,加入录入了一个数组中不存在的数据,这个时候,就没有任何内容输出了,很明显是有问题的,在实际开发中,如果对应的索引不存在,我们一般都是返回一个负数,而且经常用-1来标识。
- 分析:
-
思路:
-
代码演示
int[] array={10,20,30,40,15,60,15,80};
//1.键盘录入需要查找的元素
Scanner sc=new Scanner(System.in);
//提示用户录入数据
System.out.println(“请录入需要查找的数据:”);
int key=sc.nextInt();int index=-1; //记录查找的索引,规定-1表示没有找到元素
//2.遍历数组中的元素和key进行比较
for (int i = 0; i < array.length; i++) {
if(array[i]key){
index=i;
//一旦找到了,后面的数据就不需要再遍历了,直接结束循环即可
break;
}
}
//判断index的值,是否等于-1
if(index-1){
System.out.println(“对不起,没有这个元素”);
}else{
System.out.println(key+“元素在数组中的索引为:”+index);
}
- 评委打分
-
需求
-
思路
-
代码实现
//1.定义数组,用于存储评委的分数
int[] array=new int[6];//2.循环的采用键盘录入的方式,代表评委打分
Scanner sc=new Scanner(System.in);
for (int i = 0; i < array.length; i++) {
//2.1 提示用户录入分数
System.out.println(“请输入第”+(i+1)+“评委的分数:”);
int num = sc.nextInt();
//2.2 把分数存入数组中
array[i]=num;
}//3.求数组元素的最大值
//3.1 把数组中的0索引元素假设为最大值
int max=array[0];
for (int i = 1; i < array.length; i++) {
//3.2 把数组中元素较大的值赋值给max
if(array[i]>max){
max=array[i];
}
}
System.out.println(“最大值为:”+max);//4.求数组元素的最小值
int min=array[0];
for (int i = 1; i < array.length; i++) {
//4.1 把数组中元素较小的值赋值给min
if(array[i]<min){
min=array[i];
}
}
System.out.println(“最小值为:”+min);//5.求数组元素的和
int sum=0;
for (int i = 0; i < array.length; i++) {
sum+=array[i];
}
System.out.println(“所有元素的和为:”+sum);//6.求平均值
double avg=(sum-max-min)*1.0/(array.length-2);
System.out.println(“最终得分:”+avg);
二维数组
- 概述
- 概述:二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器
- 为什么要有二维数组:
- 假设给一个学校做一个学生管理系统,该学校有6个年级,每个年级10跟班,每个班60个学生。需要用数组存放这些学生的数据
- 如果我们把这些学生数据存放在一个数组里面,这个数组的数据过于庞大,你要到里面找对应学生的成绩会很困难
- 如果一个班级成绩装一个数组,通过班级去找学生,会简单一点
- 但是这些数组如果不统一管理,还要判断学生是哪个年级
- 所以如果用一个长度为6的数组,每个索引位置存放一个年纪的数据,那管理起来就很方便了
- 比如我要找3年级2班的张三成绩,那就是先找到三年级,再找到2班,然后再到2班里面去遍历出张三的成绩
-
动态初始化
//格式1:数据类型[][] 变量名 = new 数据类型[m][n];
//m表示这个二维数组,可以存放多少个一维数组。n表示每一个一维数组,可以存放多少个元素
int[][] arr = new int[2][3];
System.out.println(arr);//结果:[[I@10f87f48
System.out.println(arr[0]);//结果:[I@b4c966a
System.out.println(arr[1]);//结果:[I@2f4d3709
//以上结果表明,二维数组中存储的数据还是数组,所以打印的就是地址值
System.out.println(arr[0][0]);//结果:0
System.out.println(arr[0][1]);//结果:0
System.out.println(arr[0][2]);//结果:0
//以上结果表明,二维数组中存储的是一维数组,可以通过二维数组和一维数组的索引拿到存储的数据值
//可以存值,就可以赋值
arr[1][0] = 11;
arr[1][1] = 22;
arr[1][2] = 33; -
访问元素的细节问题
int[] arr1 = {11, 22, 33};
int[] arr2 = {44, 55, 66};
int[] arr3 = {77, 88, 99, 100};
int[][] arr = new int[3][3];
//此时二维数组索引2位置指向的数组是一个长度为3的数组,此时给该数组索引为3的位置赋值会索引越界
arr[2][3] = 101;
arr[0] = arr1;
arr[1] = arr2;
//通过赋值操作,让原本指向长度为3的数组指向了一个长度为4的数组,该数组索引最大值是3
arr[2] = arr3;
//由于已经更换了指向的数组,所以可以通过二维索引3找到对应的值
System.out.println(arr[2][3]); -
静态初始化
//格式:数据类型[][] 变量名={{元素1,元素2,…},{元素1,元素2,…},…};
//范例:int[][] arr={{11,22},{33,44}};//代码案例
int[] arr1 = {11, 22, 33};
int[] arr2 = {44, 55, 66};
int[][] arr = {{11, 22, 33}, {44, 55, 66}};
System.out.println(arr[0][1]);
int[][] array = {arr1, arr2};//结果:22
System.out.println(arr[1][0]);//结果:44 -
案例:遍历
-
需求:已知一个二维数组arr = {{11, 22, 33}, {33, 44, 55,}};遍历该数组,取出所有元素并打印
-
思路:
-
代码实现
int[][] arr = {{11, 22, 33}, {33, 44, 55,}};
//1.先遍历二维数组,把里面的一维数组拿出来
for (int i = 0; i < arr.length; i++) {
//2.根据拿出的一维数组,再遍历这个一维数组
for (int j = 0; j < arr[i].length; j++) {
//3.打印对应一维数组中的值
System.out.println(arr[i][j]);
}
} -
案例:求和
-
需求:某公司季度和月份统计的数据如下:单位(万元)
- 第一季度:22 , 66 , 44
- 第二季度:77 , 33 , 88
- 第三季度:25 , 45 , 65
- 第四季度:11 , 66 , 99
-
思路:
-
代码实现
//1.定义求和变量,准备记录最终累加结果
int sum = 0;
//2.使用二维数组来存储数据,每个季度是一个一维数组,再将4个一维数组装起来
int[][] arr = {{22, 66, 44}, {77, 33, 88}, {25, 45, 65}, {11, 66, 99}};
//3.遍历二维数组,取出所有元素,累加求和
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
//4.打印最终累加结果
System.out.println(sum);
方法
- 概述
- 概述:就是一段具有独立功能的代码块,不调用就不执行
- 作用:
- 如果程序里面有好几段内容是需要实现相同功能,不使用方法的话,会导致有大量重复的代码。这种重复代码每次都要重新写一遍。所以如果不用方法,代码的重复度太高,复用性太差
- 方法的出现,把重复代码变成类似于‘共享单车’的存在,谁有需要就直接用。提高了代码的复用性
- 前提:
- 方法必须是先创建才可以使用,该过程称为方法定义
- 方法创建后并不是直接运行的,需要手动在代码中调用后才可以执行,该过程称为方法调用
- 方法的定义和调用
-
格式
//方法定义格式(无参数、无返回值的公共静态方法)
public static void 方法名(){
//方法体:就是需要复用(被反复使用)的逻辑代码
}
//范例
public static void printHello(){
System.out.println(“Hello method!”);
}//方法调用:方法名();
//范例:
public static void main(String[] args) {
printHello();
} -
注意事项
-
方法必须先定义后调用,否则程序将报错
-
方法与方法之间是平级关系,不能嵌套定义
-
- 方法的调用过程
- 方法没有被低调用的时候,都在方法区中的字节码文件(.class)中存储
- 方法被调用的时候,需要进入到栈内存中运行
-
练习:奇偶数判断
-
需求
-
思路
-
代码演示
public static void main(String[] args){
//3.调用方法
method();
}//1.定义一个方法,功能为:判断一个数是否为奇数或者偶数
public static void method(){
//2.判断奇偶数逻辑
int a=10;
if(a%2==0){
System.out.println(“偶数”);
}else{
System.out.println(“奇数”);
}
} -
带参数方法的定义和调用
-
为什么要有带参数方法
- 当方法内部逻辑有用到需要根据不同用户,不同需求去变化的值的时候,就可以定义带参数方法,把这种可能会改变的值用方法的参数替代
-
带参数方法的定义
//单个参数
public static void 方法名(数据类型 变量名){方法体;}
//范例
public static void method(int num){方法体;}//多个参数
public static void 方法名(数据类型 变量名1,数据类型 变量名2,…){方法体;}
//范例
public static void getMax(int num1,int num2){方法体;}//注意
//1.方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序都将报错
//2.方法定义时,多个参数之间使用逗号分隔 -
带参数方法的调用
-
代码练习
/*
- 练习1:定义一个方法,接收一个int类型的参数,判断该数字是是奇数还是偶数,在控制台打印出来。
- 在主方法中调用
*/
/*
- 练习2:定义一个方法,接收两个int类型的数字,判断哪个数字是最大值,打印最大值
- 在主方法中调用
*/
-
形参和实参
-
概念
- 形参:形式参数,是指方法定义中的参数
- 实参:实际参数,方法调用中的参数
-
带参数方法的练习:打印n~m之间所有的奇数
-
需求:设计一个方法(print)用于打印n到m之间所有的奇数
-
思路:
-
代码演示
- 带返回值方法的定义和调用
-
为什么要有带返回值的方法
- 我们经常会根据一个方法产出的结果,来去组织另外一段代码逻辑,为了拿到这个方法产生的结果,就需要定义带有返回值的方法
-
带返回值方法的定义
-
带返回值方法的调用
-
代码演示
//案例:计算两个数的乘积
public static void main(String[] args) {
//3.调用方法,因为方法定义了两个参数,都是整数,所以这里要给两个整数的实参
//4.因为方法有返回值,所以可以在方法调用处使用一个变量接收这个方法调用完的返回值
//5.方法返回值什么类型,接收的变量就应该是什么类型
int result = cheng(2, 3);
System.out.println(result);//结果:6
}
//1.两个整数的乘积,结果还是整数,所以返回值类型应该为int
public static int cheng(int num1,int num2) {
//2.通过return关键,返回乘积
return num1 * num2;
}
- 带返回值方法的练习:求两个数的最大值
-
需求:设计一个方法可以获取两个数的较大值,数据来自于参数
-
思路:
-
代码实现
-
扩展练习
//仿照课堂案例,求三个数的最大值
- 方法通用格式
-
格式
-
代码演示
- 方法的注意事项
-
方法不能嵌套定义
-
方法的返回值类型为void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写,如果要写return语句,后面不能跟具体的数据
-
return语句下面,不能编写代码,因为永远执行不到,属于无效代码
-
return语句,如果要返回值,只能带回一个结果
//案例:没有返回值的方法,可以省略return不写
public static void eat(){
System.out.println(“吃饭”);
//return的其中一个作用,是结束整个方法,但是不可以带返回值
return;
//return 3; 方法本身没有规定返回值,在此处就不能带返回值,因为你也不知道返回什么类型比较合适
}//案例:计算器加法运算
public static int add(int num1,int num2){
// return的第二个作用,就是返回一个值
return num1+num2;
}//案例:return语句下面,不能编写代码
public static void drink(int age){
if(age<8){
System.out.println(“喝白开水”);
//此处是个if判断语句,按照逻辑推断,如果进入if语句中,下面的代码逻辑肯定是不想再执行
//如果此处不加以限制,if执行结束,代码依然会执行:喝红牛
//所以此处可以加上return,直接结束方法
return;
//注意,说的return下面不能加代码,是指同一个逻辑代码块(大括号)中而已
}
System.out.println(“喝红牛”);
}
- 方法重载
- 概念:在同一个类中,方法名相同,参数列表不同(参数顺序不同也算不同,变量名不同不算)的多个方法,形成了方法的重载。
- 方法签名:JVM调用方法的时候是通过方法签名去区分的,方法签名包括方法名,参数数量、类型和顺序
- 注意:参数顺序不同虽然也可以构成方法重载,但是不推荐,没有意义
- 方法重载练习
-
需求:使用方法重载的思想,设计比较两个整数是否相同的方法,兼容全整数类型(byte,short,int,long)
-
思路:
-
代码练习
- 方法参数传递:基本数据类型
-
方法的形参在内存当中也就是一个变量而已
-
一个方法在传递参数的时候,如果是基本数据类型,那么传递的就是该变量所记录的具体的数值
public static void main(String[] args) {
int number = 100;
System.out.println(“main方法中,调用change方法前:” + number);//结果:100
//基本数据类型,传递的是number的数值,而非变量
change(number);
//打印的变量,依然还是main方法中的变量,此变量的值未有任何改变,依然是100
System.out.println(“main方法中,调用change方法后:” + number);//结果:100
}//方法的形参相当于是这个方法中的一个局部变量,属于change方法,和main方法中的变量不是同一个
public static void change(int number) {
//在未执行下方赋值操作时,从main方法传递过来的是值100,将100赋值给了change方法的变量number
//此时修改的是change方法中的变量number值,对main方法中的number无影响
number = 200;
System.out.println(“在change方法中的:” + number);//结果:200
}
- 方法参数传递:引用数据类型
-
方法传递,如果传入的是引用数据类型,传进去的就是该引用数据类型的内存地址
public static void main(String[] args) {
//定义一个数组,数组是引用数据类型
int[] arr = {23, 12, 44, 77};
//该数组在堆内存中的一个空间存放,变量arr持有的是这个空间的地址
System.out.println(“在main方法中,调用change方法前:” + arr[1]);//结果:12
//arr是引用数据类型变量,传入的就是arr持有的数组在堆内存的地址,而非数组本身
change(arr);
System.out.println(“在main方法中,调用change方法后:” + arr[1]);//结果:0
}public static void change(int[] arr) {
//调用方法,将传递过来的地址赋值给了change方法中的变量arr,change方法中的arr也持有这个地址
//通过持有的地址,可以找到堆内存中的数组,所以可以对其修改值
arr[1] = 0;
//打印的就是修改之后的0值
System.out.println(“在change方法中的:” + arr[1]);//结果:0
}
- 案例:数组遍历
-
需求:设计一个方法,用于数组遍历,要求遍历的结果是在一行上的。例如:[11,22,33,44,55]
-
思路:
-
代码演示
public static void main(String[] args) {
//1.静态初始化一个数组
int[] arr = {11, 22, 33, 44, 55};
printArr(arr);
}//2.定义一个方法,对数组进行遍历。因为是打印,所以是不需要返回值的
public static void printArr(int[] arr) {
//3.要打印数组中所有数据,必须要先遍历数组
for (int i = 0; i < arr.length; i++) {
//4.将数组中每个元素取出来
int num = arr[i];
//5.打印数组中该元素的值,但是因为有格式要求,所以不要换行打印
//6.当i=0和i是最后一个索引的时候,打印格式要加上中括号
if (i == 0) {
System.out.print(“[” + num + ", ");
} else if (i == arr.length - 1) {
System.out.print(num + “]”);
} else {
//7.打印的数字之间要用逗号和空格隔开
System.out.print(num + ", ");
}
}
}
- 案例:获取数组最大值
-
需求:设计一个方法用于获取数组中元素的最大值
-
思路:
-
代码演示:
- 案例:方法同时获取数组最大值和最小值
-
需求:设计一个方法,该方法能够同时获取数组的最大值,和最小值
-
思路:
-
代码演示:
基础练习
- 逢七跳过
案例需求
朋友聚会的时候可能会玩一个游戏:逢七过。
规则是:从任意一个数字开始报数,当你要报的数字包含7或者是7的倍数时都要说:过。
为了帮助大家更好的玩这个游戏,这里我们直接在控制台打印出1-100之间的满足逢七必过规则的数据。
这样,大家将来在玩游戏的时候,就知道哪些数据要说:过。
代码实现
/*
思路:
1:数据在1-100之间,用for循环实现数据的获取
2:根据规则,用if语句实现数据的判断:要么个位是7,要么十位是7,要么能够被7整除
3:在控制台输出满足规则的数据
*/
public class Test1 {
public static void main(String[] args) {
//数据在1-100之间,用for循环实现数据的获取
for(int x=1; x<=100; x++) {
//根据规则,用if语句实现数据的判断:要么个位是7,要么十位是7,要么能够被7整除
if(x%10==7 || x/10%10==7 || x%7==0) {
//在控制台输出满足规则的数据
System.out.println(x);
}
}
}
}
- 数组元素求和
案例需求
有这样的一个数组,元素是{68,27,95,88,171,996,51,210}。求出该数组中满足要求的元素和,
要求是:求和的元素个位和十位都不能是7,并且只能是偶数
代码实现
package com.itheima.test;
public class Test2 {
/*
有这样的一个数组,元素是{68,27,95,88,171,996,51,210}。求出该数组中满足要求的元素和,
要求是:求和的元素个位和十位都不能是7,并且只能是偶数
*/
public static void main(String[] args) {
// 1. 定义数组
int[] arr = {68, 27, 95, 88, 171, 996, 51, 210};
// 2. 求和变量
int sum = 0;
// 3. 遍历数组
for (int i = 0; i < arr.length; i++) {
// 4. 拆分出个位和十位
int ge = arr[i] % 10;
int shi = arr[i] / 10 % 10;
// 5. 条件筛选
if (ge != 7 && shi != 7 && arr[i] % 2 == 0) {
sum += arr[i];
}
}
// 6. 打印结果
System.out.println(sum);
}
}
- 判断两个数组是否相同
案例需求
定义一个方法,用于比较两个数组的内容是否相同
代码实现
/*
思路:
1:定义两个数组,分别使用静态初始化完成数组元素的初始化
2:定义一个方法,用于比较两个数组的内容是否相同
3:比较两个数组的内容是否相同,按照下面的步骤实现就可以了
首先比较数组长度,如果长度不相同,数组内容肯定不相同,返回false
其次遍历,比较两个数组中的每一个元素,只要有元素不相同,返回false
最后循环遍历结束后,返回true
4:调用方法,用变量接收
5:输出结果
*/
public class Test3 {
public static void main(String[] args) {
//定义两个数组,分别使用静态初始化完成数组元素的初始化
int[] arr = {11, 22, 33, 44, 55};
//int[] arr2 = {11, 22, 33, 44, 55};
int[] arr2 = {11, 22, 33, 44, 5};
//调用方法,用变量接收
boolean flag = compare(arr,arr2);
//输出结果
System.out.println(flag);
}
//定义一个方法,用于比较两个数组的内容是否相同
/*
两个明确:
返回值类型:boolean
参数:int[] arr, int[] arr2
*/
public static boolean compare(int[] arr, int[] arr2) {
//首先比较数组长度,如果长度不相同,数组内容肯定不相同,返回false
if(arr.length != arr2.length) {
return false;
}
//其次遍历,比较两个数组中的每一个元素,只要有元素不相同,返回false
for(int x=0; x<arr.length; x++) {
if(arr[x] != arr2[x]) {
return false;
}
}
//最后循环遍历结束后,返回true
return true;
}
}
- 查找元素在数组中出现的索引位置
案例需求
已知一个数组 arr = {19, 28, 37, 46, 50}; 键盘录入一个数据,查找该数据在数组中的索引。
并在控制台输出找到的索引值。如果没有查找到,则输出-1
代码实现
/*
思路:
1:定义一个数组,用静态初始化完成数组元素的初始化
2:键盘录入要查找的数据,用一个变量接收
3:定义一个索引变量,初始值为-1
4:遍历数组,获取到数组中的每一个元素
5:拿键盘录入的数据和数组中的每一个元素进行比较,如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
6:输出索引变量
*/
public class Test4 {
public static void main(String[] args) {
//定义一个数组,用静态初始化完成数组元素的初始化
int[] arr = {19, 28, 37, 46, 50};
//键盘录入要查找的数据,用一个变量接收
Scanner sc = new Scanner(System.in);
System.out.println("请输入要查找的数据:");
int number = sc.nextInt();
//调用方法
int index = getIndex(arr, number);
//输出索引变量
System.out.println("index: " + index);
}
//查找指定的数据在数组中的索引
/*
两个明确:
返回值类型:int
参数:int[] arr, int number
*/
public static int getIndex(int[] arr, int number) {
//定义一个索引变量,初始值为-1
int index = -1;
//遍历数组,获取到数组中的每一个元素
for(int x=0; x<arr.length; x++) {
//拿键盘录入的数据和数组中的每一个元素进行比较,如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
if(arr[x] == number) {
index = x;
break;
}
}
//返回索引
return index;
}
}
- 数组元素反转
案例需求
已知一个数组 arr = {19, 28, 37, 46, 50}; 用程序实现把数组中的元素值交换,
交换后的数组 arr = {50, 46, 37, 28, 19}; 并在控制台输出交换后的数组元素。
代码实现
/*
思路:
1:定义一个数组,用静态初始化完成数组元素的初始化
2:循环遍历数组,这一次初始化语句定义两个索引变量,判断条件是开始索引小于等于结束索引
3:变量交换
4:遍历数组
*/
public class Test5 {
public static void main(String[] args) {
//定义一个数组,用静态初始化完成数组元素的初始化
int[] arr = {19, 28, 37, 46, 50};
//调用反转的方法
reverse(arr);
//遍历数组
printArray(arr);
}
/*
两个明确:
返回值类型:void
参数:int[] arr
*/
public static void reverse(int[] arr) {
//循环遍历数组,这一次初始化语句定义两个索引变量,判断条件是开始索引小于等于结束索引
for (int start = 0, end = arr.length - 1; start <= end; start++, end--) {
//变量交换
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
}
/*
两个明确:
返回值类型:void
参数:int[] arr
*/
public static void printArray(int[] arr) {
System.out.print("[");
for (int x = 0; x < arr.length; x++) {
if (x == arr.length - 1) {
System.out.print(arr[x]);
} else {
System.out.print(arr[x] + ", ");
}
}
System.out.println("]");
}
}
- 评委打分
案例需求
在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。
代码实现
思路:
1:定义一个数组,用动态初始化完成数组元素的初始化,长度为6
2:键盘录入评委分数
3:由于是6个评委打分,所以,接收评委分数的操作,用循环改进
4:定义方法实现获取数组中的最高分(数组最大值),调用方法
5:定义方法实现获取数组中的最低分(数组最小值) ,调用方法
6:定义方法实现获取数组中的所有元素的和(数组元素求和) ,调用方法
7:按照计算规则进行计算得到平均分
8:输出平均分
- 随机产生验证码
案例需求
请从26个英文字母(大小写都包含),以及数字0-9中,随机产生一个5位的字符串验证码并打印在控制台
效果:uYq8I,3r4Zj
代码实现
import java.util.Random;
public class Test {
public static void main(String[] args) {
// 1. 将所需要用到的字符存入数组
char[] datas = initData();
Random r = new Random();
String result = "";
// 2. 随机取出5个字符
for (int i = 1; i <= 5; i++) {
int index = r.nextInt(datas.length);
char c = datas[index];
result += c;
}
// 3. 打印验证码
System.out.println(result);
}
private static char[] initData() {
char[] chs = new char[62];
int index = 0;
for (char i = 'a'; i <= 'z'; i++) {
chs[index] = i;
index++;
}
for (char i = 'A'; i <= 'Z'; i++) {
chs[index] = i;
index++;
}
for (char i = '0'; i <= '9'; i++) {
chs[index] = i;
index++;
}
return chs;
}
}
面向对象基础
- 类和对象
1.1 面向对象编程思想
-
面向对象编程(oop)
- 是一种以对象为中心的编程思想,通过指挥对象实现具体的功能
-
需求:洗衣服
-
对象:客观存在的事物。例如厨师、洗衣机这些都是客观存在的事物,并且都有自己能够完成的功能。这些事物就可以通过java代码的形式描述成为程序中的对象。然后就可以指挥这些对象去调用里面一个个的功能
-
小结
- 客观存在的任何一种事物,都可以看作为程序中的对象
- 使用面向对象思想可以将复杂的问题简单化
- 将我们从执行者的位置,变成了指挥者
-
代码演示
//面向过程:解决数组遍历问题
int[] arr = {11, 22, 33, 44, 55, 66};
//1. 打印左括号,不能换行
System.out.print(“[”);
//2. 遍历数组,取出数组中每一个值
for (int i = 0; i < arr.length; i++) {
//3. 判断是否是最后一个元素
if (i == arr.length - 1) {
//4.如果是最后一个元素,除了打印元素值,还要加上括号
System.out.println(arr[i] + “]”);
} else {
//5. 如果不是最后一个元素,打印数值不能换行,而且还要用空格隔开
System.out.print(arr[i] + " ");
}
}
//总结:面向过程的思想,总共分为了5个步骤,每一个步骤都需要自己实现//面向对象:解决数组遍历问题
public class OopTest {
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44, 55, 66};
//1.先想谁可以实现数组遍历的功能
//2.想起了数组操作员,创建数组操作员对象
//3.利用对象解决问题
数组操作员 二狗 = new 数组操作员();
二狗.遍历打印数组(arr);
}
}class 数组操作员 {
public static void 遍历打印数组(int[] arr) {
//1. 打印左括号,不能换行
System.out.print(“[”);
//2. 遍历数组,取出数组中每一个值
for (int i = 0; i < arr.length; i++) {
//3. 判断是否是最后一个元素
if (i == arr.length - 1) {
//4.如果是最后一个元素,除了打印元素值,还要加上括号
System.out.println(arr[i] + “]”);
} else {
//5. 如果不是最后一个元素,打印数值不能换行,而且还要用空格隔开
System.out.print(arr[i] + " ");
}
}
}
}
1.2 类和对象的关系
-
什么是类
- 类是对现实生活中一类具有共同属性和行为的事物的抽象
- 类是对事物,也就是对象的一种描述,可以将类理解为一张设计图,根据设计图,可以创建出具体存在的事物。
- 根据类去创建对象
-
类的组成
- 属性:该事物的各种特征
- 例如黑马学生事物的属性:姓名、年龄、毕业院校…
- 行为:该事物存在的功能(能够做的事情)
- 例如黑马学生事物的行为:学习、Java编程开发…
- 属性:该事物的各种特征
-
什么是对象?
- 是能够看得到摸得着的真实存在的实体
1.3 类的定义
-
类的组成:属性和行为
- 属性:在代码中通过成员变量来体现(类中方法外的变量)
- 行为:在代码中通过成员方法来体现(和前面的方法相比,去掉static关键字即可)
-
类的定义步骤:
-
定义类
-
编写类的成员变量
-
编写类的成员方法
public class 类名{
//成员变量
//变量1的数据类型 变量1;
//变量2的数据类型 变量2;
//…//成员方法 //方法1 //方法2 //...
}
-
-
代码实现
//视频案例:学生类
public class Student {
//1.属性:姓名,年龄
//成员变量:跟之前定义的变量格式一样,只不过位置发生了改变,从方法中跑到了类中方法外//姓名是一段内容,可以使用字符串类型去表示 String name = "张三"; //年龄是一个整数,可以使用int类型去表达 int age = 23; //2.行为:学习 //成员方法:跟之前定义的方法一样,只不过去掉了static public void study() { System.out.println("好好学习,天天向上"); } //3.不建议在这种用来描述事物的类中写main主方法,主方法一般单独写一个测试类去实现
}
/**
- 练习:老师类
- 属性:姓名,年龄,学科
- 行为:工作
*/
1.4 对象的创建和使用
-
创建对象
- 格式:类名 对象名=new 类名();
- 范例:Student stu=new Student();
-
使用对象
- 使用成员变量
- 格式:对象名.变量名
- 范例:stu.name
- 使用成员变量
-
使用成员方法
- 格式:对象名.方法名()
- 范例:stu.study();
-
代码演示
//创建学生类对象,并且给其属性赋值。获取其属性值,调用其方法
public class TestStudent {
public static void main(String[] args) {
//1. 创建学生类对象,把对象赋值给学生类型的变量stu
Student stu = new Student();
//2. 使用成员变量
System.out.println(stu.name);//结果:null
System.out.println(stu.age);//结构:0
//3. 就算没有给成员变量赋值,也可以使用,整数基本数据类型默认是0,字符串类型默认是null
//4. 给成员变量赋值
stu.name = “张三”;
stu.age = 23;
System.out.println(stu.name);//结果:张三
System.out.println(stu.age);//结果:23
//5.使用成员方法
stu.study();
//6.打印对象
System.out.println(stu);//结果:com.itheima.test.Student@b4c966a
//打印对象,默认打印的是:全类名(包名+类名)+ 地址哈希值
}
}
public class Student {
String name;
int age;
public void study() {
System.out.println(“好好学习,天天向上”);
}
}
1.5 案例:手机类的创建和使用
-
需求:定义一个手机类,然后定义一个手机测试类,在收集测试类中通过对象完成成员变量和成员方法的使用
-
分析:
- 手机应该有哪些属性?
- 品牌
- 价格
- …
- 手机应该有哪些行为?
- 打电话
- 发短信
- …
- 手机应该有哪些属性?
-
思路
-
代码实现
public class Phone {
//成员变量:品牌、价格
String brand;
int price;//成员方法:打电话 public void call(String name) { System.out.println("给" + name + "打电话"); } //成员方法:发短信 public void sendMessage() { System.out.println("群发短信"); }
}
//测试类
public class TestPhone {
public static void main(String[] args) {
//1. 创建对象
Phone phone = new Phone();
//2. 给成员变量赋值
phone.brand = “大米”;
phone.price=2999;
//3. 打印赋值后的成员变量
System.out.println(phone.brand + “…” + phone.price);
//4. 调用成员方法
phone.call(“张三”);
phone.sendMessage();
}
}
- 对象内存图
2.1 单个对象内存图
- 有new就在堆内存开辟空间,对象就是堆内存的一个块空间,存储有对象的属性值和方法调用地址
- 对象的变量名存储的其实是对象在堆内存空间的地址值,jvm虚拟机可以根据地址值找到对象空间
- 能找到对象空间,从而能获取对象的属性数据,调用对象的方法
2.2 两个对象内存图
- 有几个new,就会在堆内存开辟几个对象空间
- 同一个类的不同对象空间中属性名字都是一样的,但是其存储的属性数据相互独立
- 同一个类的不同对象空间中方法地址一样,所以调用的方法也是一样的
2.3 两个引用指向同一个对象内存图
-
代码执行到Student stu2=stu1;的时候,通过s1指向的堆内存中对象的地址,将s2也指向这个地址,所以s1和s2都指向同一个对象
-
代码执行到stu1=null;的时候,stu1原本持有的是堆内存中学生对象的地址,由于置null,此指向切断了。s1再也无法找到堆内存中该学生对象
-
在执行完stu2=null;之后,就没有变量再指向堆内存中的学生对象,此对象无法再被使用到。所以垃圾回收器会在空闲的时候将这个学生对象的空间给清理掉
-
当堆内存中,对象或数组产生的地址,通过任何方式都不能被找到后,就会判定为内存中的"垃圾",垃圾会被Java垃圾回收器,空闲的时候自动进行清理
- 成员变量和局部变量的区别
- 成员变量:类中方法外定义的变量
- 局部变量:方法中的变量
- 成员变量和局部变量的区别
- 封装
4.1 private关键字
问题:
1.为什么说通过对象名给其属性赋值具有安全隐患问题?
2.private关键字可以用来修饰哪些内容?
3.使用private修饰属性之后,还需要做什么操作?
- 概述:
- 是一个权限修饰符
- 可以修饰成员(成员变量和成员方法)
- 特点:
- 被private修饰的成员只能在本类中才能访问,其他包,其他类都不能访问
- 针对private修饰的成员变量,如果需要被其他类使用,要提供相应的操作
- 提供"get变量名()"方法,用于获取成员变量的值,方法用public修饰
- 提供"set变量名(参数)"方法,用于设置成员变量的值,方法用public修饰
4.2 private关键字的使用
- 一个标准类的编写:
-
把成员变量用private修饰
-
提供对应的setXxx()/getXxx()方法
/**
-
学生类:
-
属性:姓名,年龄
-
需求:
-
1.利用private对类的属性进行封装
-
2.给属性提供设置值和获取值的方法
-
3.在测试类中测试
*/
public class Student {
//1.为了以后别人不能随意给我的属性赋值,就给这两个成员变量加上private
private int age;
private String name;//2.加上了private之后,这两个属性的变量,以后就只能在当前这个Student类中被访问,外类无法访问
//3.外类无法访问,这个变量定义的就没有意义了,所以还要对外提供对这两个变量的访问方式
//提供set和get方法,给外界使用
//4.提供给属性设置值的方法
//设置年龄值,目的是给本类的age变量赋值,赋的值应该是int类型
//这个值是别人调用方法的时候传过来的,所以应该作为形式参数声明
public void setAge(int a) {
//声明了形式参数,别人调用的时候就得传一个int值过来,那这个值目的是给age变量赋值
age = a;
}//有了赋值的,就应该要有取值的
public int getAge() {
//这里是把age变量的值返回给方法调用处,直接return
return age;
}public void setName(String n) {
name = n;
}public String getName() {
return name;
}public void show() {
//这个方法只是做展示对象数据的作用,也没有返回值
System.out.println(name + “…” + age);
}
}
public class Test03 {
public static void main(String[] args) {
Student stu = new Student();
stu.show();
stu.setAge(17);
stu.setName(“张三”);
stu.show();
System.out.println(stu.getAge());
System.out.println(stu.getName());
}
} -
-
4.3 this关键字
问题:
1.类方法的形式参数名和类属性名出现重名,会有什么问题?
2.this关键字有哪些作用?
3.在方法中打印this关键字,打印的内容代表谁?
-
概述:
- 代表所在类的对象引用(对象在堆内存当中的地址值)
- 方法被哪个对象调用,this就代表哪个对象
-
作用:可以调用本类的成员(变量、方法),解决局部变量和成员变量的重名问题
-
注意:如果局部变量和成员变量重名,Java使用的是就近原则
//练习:使用this关键字,优化老师类的set方法
public class Teacher {
//属性:姓名、年龄、学科
//1.利用private修饰各个属性
private String name;
private int age;
private String obj;//2.行为:工作 public void work() { System.out.println("传道受业解惑"); } //3.针对属性,增加set\get方法。并且使用this优化get方法 public void setName(String name) { this.name=name; } public String getName() { return name; } public void setAge(int age) { this.age=age; } public int getAge() { return age; } public void setObj(String obj) { this.obj=obj; } public String getObj() { return obj; }
}
4.4 this内存原理
- 结论:
- 方法被哪个对象调用,方法中的this就代表哪个对象的引用
4.5 封装
问题:
1.封装的思想指的是什么?
2.将一个类的属性私有化就是封装吗?
3.在程序中引入封装思想,有什么好处?
- 封装是面向对象的三大特征之一(封装,继承,多态)
- 隐藏实现细节,进对外暴露公共的访问方式(方法)
- 封装常见的体现
- 私有成员变量(隐藏),提供setXxx和getXxx方法(暴露公共的访问)
- 将代码抽取到方法中(隐藏了实现细节),这是对代码的一种封装
- 将属性抽取到类中,这是对数据的一种封装
- 封装的好处:
- 提高了代码的安全性(private和set/get)
- 提高了代码的复用性(方法,可以重复使用)
- 构造方法
5.1 构造方法的格式和执行时机
问题:
1.没有给一个类定义构造方法,为什么也能够调用?
2.能不能在构造方法中使用return关键字返回一个值?
3.构造方法是在什么时候就会被调用?
-
概述:构建、创造对象的时候,所调用的方法
-
格式:
-
方法名和类名相同,大小写也要一致;
-
没有返回值类型,连void都没有;
-
没有具体的返回值(不能由return带回结果数据)
//格式:
public class 类名{
//…
public 类名(参数列表){
构造方法体;
}
//…
}
//2.范例:
public class Person{
private String name;
private int age;
public Person(){}
}
-
-
执行时机:
- 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
- 不能手动调用构造方法。只能使用new关键字调用
5.2 构造方法的作用
问题:
1.构造方法除了创建对象,还有什么作用?
2.给一个类提供了有参数的构造方法,还会有默认空参的构造吗?
-
创造属于类的对象
-
用于给对象的数据==(属性)==进行初始化
//案例:
public class Student {
private String name;
private int age;public Student(String name, int age) { this.name = name; this.age = age; } public void show() { System.out.println(name + "..." + age); }
}
//练习:修改Person类,能够让Person类通过构造方法给对象属性赋值。并在测试类中验证
5.3 构造方法的注意事项
问题:
1.无论什么情况下,系统都会提供一个默认构造方法吗?
2.以后在写一个标准类的时候,构造方法应该如何写?
- 构造方法的创建
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
- 构造方法的重载
- 如果自定义了带参数构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
- 推荐的使用方式
- 无论是否使用,都手动书写无参数构造方法,和带参数构造方法
- 总结:
- 无参构造和有参构造都要写
5.4 案例:标准类的代码编写和使用
- 需求:
- 成员变量:使用private修饰
- 构造方法:
- 提供一个无参构造方法
- 提供一个带多个参数的构造方法
- 成员方法
- 提供每一个成员变量对应的setXxx()/getXxx()
- 提供一个显示对象信息的show()
- 创建对象并为其成员变量赋值的两种方式
-
无参构造方法创建对象后使用setXxx()赋值
-
使用带参构造方法直接创建带有属性值的对象
/**
-
因为程序是为了现实服务的,以后假设我们写了一个学生管理系统,系统中就存在一个数据叫学生数据
-
而仅仅用基本数据类型的数据无法完全描述学生数据,因为学生数据中有学号、姓名、年龄、分数等等
-
这些数据里面有各种数据类型:int、String等
-
这个时候就可以使用面向对象思想,用一个类去描述这类信息
*/
public class Student {
//1.定义类的属性,学生有哪些属性?
//学号
private String id;
//姓名
private String name;
//年龄
private int age;
//分数
private int score;
//2.为了不让外接随意更改我的属性值,给我一些非法的值,比如分数给一个-100分,全部用private修饰
//3.属性被封装了,但是这些属性值,未来外接还是要使用的呀,那怎么用呢?提供对应的set\get方法//5.提供构造方法
public Student(String id, String name, int age, int score) {
//这里给属性赋值,那么构造方法就应该有形式参数
this.id = id;
this.name = name;
this.age = age;
this.score = score;
}public Student() {
}//4.针对所有的属性,都有对应方法给这些属性设置值和获取他们的值
public String getId() {
return id;
}public void setId(String id) {
this.id = id;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getAge() {
return age;
}public void setAge(int age) {
this.age = age;
}public int getScore() {
return score;
}public void setScore(int score) {
this.score = score;
}public void show() {
System.out.println(id + “…” + name + “…” + age + “…” + score);
}
}
public class Test01 {
public static void main(String[] args) {
//1.创建一个学生对象:类名 变量名=new 构造方法();
Student stu1 = new Student();
//2.对象现在只有默认值,没有使用的价值,开始赋值
//使用常规的set方法赋值。格式:对象名.方法名(值);
stu1.setId(“001”);
stu1.setName(“张三”);
stu1.setAge(23);
stu1.setScore(98);
//3.现在stu1对象已经有了值,展示看看
stu1.show();
//代表值赋值成功,以后你可以在程序中使用对象去存储比较复杂的数据值
//4.但是上面的代码还是复杂了一点,赋值操作台频繁
//有一种简单的赋值操作,就是利用构造方法赋值,给这个类提供一个带参数的构造方法
Student stu2 = new Student(“002”, “李四”, 22, 100);
stu2.show();
//5.明明有了构造方法可以赋值,为什么还要有set方法?
//因为一用构造方法,就是一个新的对象,因为构造方法不能修改属性值,只能创建对象的时候给它赋值一次
//而set方法可以反复修改同一个对象的值,作用不一样
}
} -
-
- API
1.1 API概述-帮助文档的使用
问题:
1.什么是API,使用API文档有什么好处?
2.如何使用API文档,应该看文档的哪些内容?
- 什么是API
- API (Application Programming Interface) :应用程序编程接口
- 官方写好的一个个可以被我们使用的对象工具的模板(类),每个类里面都有提供给我们的属性和功能
- 什么是API文档:
- 这么多的类和功能,我们不可能记得住,需要使用文档去查询他们的使用方式,这个文档就是API文档
- API帮助文档使用:
- 打开帮助文档
- 找到索引选项卡中的输入框
- 在输入框中输入Random
- 看类在哪个包下,因为不同包下可能有同名类
- 看类的描述,要明白这个类是不是我们想要的工具
- 看构造方法,如果是我们要的,那我们得知道如何创建它的对象
- 看成员方法,我们要知道这个工具具体有哪些功能,使用的时候需不需要给条件
1.2 键盘录入字符串
问题:
1.Scanner键盘录入字符串总共有几种方式?
2.Scanenr使用next()方法录入字符串会存在什么问题?
3.是否需要解决nextLine()方法存在的问题?
-
Scanner类录入字符串的方法:
- next():遇到了空格,就不再录入数据了,结束标记:空格,tab键
- nextLine():可以将数据完整的接收过来,结束标记:回车换行符
-
注意事项:
- next()方法录入字符串,字符串不能带空格,否则信息将录入不全
- nextLine()方法录入字符串,不要和nextInt()方法连用,否则会直接跳过,直接结束
-
nextLine()和录入其他数据的问题解决方案:
- 以后录入字符串都用next();
- 如果非要录入带空格的字符串,如果是和录入其他数据混用,在录入其他数据之后,马上写一个sc.nextLine();不用变量接收。目的是消费掉回车
-
总结:
- 今天核心是API文档的使用,所以这个小结只是利用Scanner举例
- 看文档的过程中,也会发现有自己不懂的内容,比如方法的参数中出现了一些没有学过的类,这通常都不需要关注,以后会接触
- 看文档注意,先明确自己的需求,然后看方法名,猜测一下哪个方法是自己想要的。结合方法的参数和返回值一起去推测,参数告诉你执行这个功能需要什么条件,返回值告诉你执行完这个功能,我能给你什么数据
-
案例练习:
- 需求:
- 已有学生类如下,请根据属性内容,补全其构造方法和setter\getter方法
- 控制台提示录入4名学生的各项信息,将录入的信息封装成学生对象存入数组
- 在控制台打印4名学生的信息
- 效果图:
-
键盘录入学生信息:
-
打印所有学生信息:
-
- 需求:
-
代码材料:
public class Student {
//学生id
private String id;
//学生姓名
private String name;
//学生年龄
private int age;
//学生评语
private String estimate;
} -
代码实现:
//1.要键盘录入四名学生信息,存入数组,数组长度是4
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建一个长度为4的学生数组
Student[] stus = new Student[4];
//2.开始录入4名学生信息,录入的操作是重复的,重复的次数是明确的,使用for
for (int i = 0; i < stus.length; i++) {
//3.提示用户录入信息
System.out.println(“请输入第” + (i + 1) + “名学生信息”);
System.out.println(“请输入学生学号:”);
String id = sc.next();
System.out.println(“请输入学生姓名:”);
String name = sc.next();
System.out.println(“请输入学生年龄:”);
int age = sc.nextInt();
//加一个nextLine消费回车
sc.nextLine();
System.out.println(“请输入学生评语:”);
String estimate = sc.nextLine();
//4.学生信息录入了,但是都是零散的数据,要把这些零散数据统一管理
//根据信息创建学生对象
Student stu = new Student(id, name, age, estimate);
//5.存入数组
stus[i] = stu;
}
//6.循环结束,所有学生信息都存入了数组,开始遍历打印所有学生信息
for (int i = 0; i < stus.length; i++) {
//7.取出学生对象
Student student = stus[i];
System.out.println(“学号:” + student.getId() + “,姓名:” + student.getName() + “,年龄:” + student.getAge() + “,评语:” + student.getEstimate());
}
- String类
2.1 String概述
问题:
1.如果使用的是java.lang包下的类,是否需要进行导包?
2.在创建String类对象的时候,它有什么特殊的地方?
3.String类的length()方法返回的长度是根据什么得到的?
- String 类在java.lang包下,所以使用的时候不需要导包
- String 类代表字符串,,Java 程序中所有的双引号字符串,都是 String 类的对象
- 字符串不可变,它们的值在创建后不能被更改,如果给一个字符串变量重新赋值了一个字符串常量,不是修改了对象,而是重新指向了一个新的对象
2.2 String类常见构造方法
问题:
1.有多少种常见的字符串对象创建方式?
2.哪种字符串创建方式,实际上是创建了两个字符串对象?
常用的构造方法
示例代码
//案例:分别用以上4种方式创建字符串对象,并且打印
2.3 创建字符串对象的区别对比
问题:
1.如何比较两个字符串对象在内存中的地址是否相同?==
2.在什么情况下,字符串不会重新创建,而是直接复用?赋值一个已经存在的字符串常量
3.字符串常量在内存中的哪个位置进行存储?字符串常量池
-
通过构造方法创建
通过 new 创建的字符串对象,每一次 new 都会申请一个堆内存空间,虽然内容相同,但是地址值不同 -
直接赋值方式创建
以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护//案例:分别用构造方法创建的字符串和用“”方式给出的字符串,使用==进行比较
//用字符串常量赋值
String s1 = “hello”;
String s2 = “hello”;
//以上两个字符串对象在字符串常量池,s1和s2指向的地址相同
System.out.println(s1 == s2);//结果:trueString s3 = new String(“abc”);
String s4 = new String(“abc”);
//以上两个字符串对象不在字符串常量池,就直接在堆内存中
//s3和s4指向的地址不相同,有几个new,就有几个地址
System.out.println(s3 == s4);//结果:false
2.4 String特点:常见面试题
-
字符串变量直接赋值字符串常量,指向的地址是字符串常量池中的对象
-
字符串变量赋值的是一个字符串类型变量和其他字符串的拼接
- 底层在堆内存中会有StringBuilder对象做拼接,得到StringBuilder对象,然后调用它的toString方法得到一个String对象,这个String对象是在堆内存中,只是拿到了常量池中的字符串值
-
字符串白能量赋值的是两个字符串常量拼接,会有常量优化机制,指向的还是常量池中的那个拼接后的字符串对象
//定义两个变量,接收相同字符串常量
String s1 = “abc”;
String s2 = “abc”;
System.out.println(s1 == s2);//true。都是指向常量池的"abc"字符串String s3 = “ab”;
String s4 = s3 + “c”;
//底层在堆内存中会有StringBuilder对象做拼接,得到StringBuilder对象,然后调用它的toString方法
//得到String对象,这个String对象是在堆内存中,只是拿到了常量池中的字符串值
//所以s3指向的是常量池中的字符串对象,s4指向的是堆内存中的字符串对象,地址不一样
System.out.println(s4 == s1);//flase。String s4=“ab”+“c”;
//如果字符串拼接都是用字符串常量,会有常量优化机制,底层不会用StringBuilder做拼接
//所以s1和s4都还是指向常量池中的字符串
System.out.println(s4 == s1);//true。//给一个变量加上final关键字,就相当于这个变量变成了常量
final String s5 = “ab”;
String s6 = s5 + “c”;
System.out.println(s6 == s1);//true
2.5 字符串的比较
问题:
1.在实际开发中,字符串的比较一般使用什么方式?
2.如果要忽略大小写去比较两个字符串内容是否相同,用哪个方法?
- == 比较基本数据类型:比较的是具体的值
- == 比较引用数据类型:比较的是对象地址值
String类 : public boolean equals(String s) 比较两个字符串内容是否相同、区分大小写
代码 :
//equals练习:使用equals方法分别比较字符串常量、变量以及使用new创建的字符串对象
//equalsIgnoreCase练习:使用方法比较两个大小写不同的字符串
2.6 用户登录案例
案例需求 :
- 已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
实现步骤 :
- 已知用户名和密码,定义两个字符串表示即可
- 键盘录入要登录的用户名和密码,用 Scanner 实现
- 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
- 字符串的内容比较,用equals() 方法实现
- 用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循
代码实现 :
//1.用户登录功能,实际上是用你录入的信息和系统中已存在的正确信息比较
//2.定义一对正确的用户名和密码
String usr = "admin";
String pwd = "123";
Scanner sc = new Scanner(System.in);
//3.开始键盘录入用户名和密码,有3次机会,重复录入,并且知道次数,使用for
for (int i = 0; i < 3; i++) {
System.out.println("请输入用户名:");
String username = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
//4.有了键盘录入的信息,开始比较
if (username.equals(usr) && password.equals(pwd)) {
System.out.println("登录成功");
//登录成功,结束循环
break;
} else {
if (i==2) {
System.out.println("您今日登录次数已达上限,请明日再来");
break;
}
System.out.println("登录失败,您还有" + (2 - i) + "次机会");
}
}
2.7 遍历字符串案例
案例需求 :
键盘录入一个字符串,使用程序实现在控制台遍历该字符串
实现步骤 :
- 键盘录入一个字符串,用 Scanner 实现
- 遍历字符串,首先要能够获取到字符串中的每一个字符, public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的
- 遍历字符串,其次要能够获取到字符串的长度, public int length():返回此字符串的长度
- 遍历打印
核心方法:
- length():这是返回字符串的长度,和数组的length不同,数组的那个是属性,这个是方法,要带小括号
- charAt(int index):返回字符串对应索引的字符,字符串索引也是从0开始
- toCharArray():返回的是字符串对应的字符数组
代码实现 :
//1.键盘录入一个字符串
System.out.println("请输入:");
Scanner sc = new Scanner(System.in);
String str = sc.next();
//2.先获取字符串长度,然后遍历,使用length()方法获取字符串长度
for (int i = 0; i < str.length(); i++) {
//3.要根据i的值获取字符串中的字符,推荐使用charAt方法
System.out.println(str.charAt(i));
}
System.out.println("===========================");
//4.直接现将字符串转换成字符数组,推荐使用toCharArray
char[] chars = str.toCharArray();
//5.遍历字符数组
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
2.8 统计字符次数案例
案例需求 :
键盘录入一个字符串,使用程序实现在控制台遍历该字符串
实现步骤 :
- 键盘录入一个字符串,用 Scanner 实现
- 将字符串拆分为字符数组 , public char[] toCharArray( ):将当前字符串拆分为字符数组并返回
- 遍历字符数
- 操作字符串中字符,一般情况下,先将字符串转换成字符数组,然后遍历操作
- 对于大写字母、小写字母、数字字符,这些字符对应的ASCII码表是连续的,判断范围可以直接用>=和<=
代码实现 :
//1.创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String str = sc.next();
//2.要统计字符串中大小写字符,数字字符的个数,你得先把字符串转换成数组
char[] chars = str.toCharArray();
//定义计数器,记录大小写字符和数字字符的个数
int bigCount = 0;
int smallCount = 0;
int numCount = 0;
//3.遍历字符数组
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
//4.拿到字符之后,该判断这个字符是属于哪一个区间
if (c >= '0' & c <= '9') {
//5.统计小写字符出现的次数
numCount++;
} else if (c >= 'a' && c <= 'z') {
smallCount++;
//因为除了大小写字母和数字字符,还有其他字符,所以不能直接用else
} else if (c >= 'A' & c <= 'Z') {
bigCount++;
}
}
//6.循环结束,打印各个字符的个数
System.out.println(numCount);
System.out.println(smallCount);
System.out.println(bigCount);
2.9 手机号屏蔽-字符串截取
案例需求 :
以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:1561234
实现步骤 :
- 键盘录入一个字符串,用 Scanner 实现
- 截取字符串前三位
- 截取字符串后四位
- 将截取后的两个字符串,中间加上进行拼接,输出结果
- substring(int index):从字符串中截取,从index索引位置一直截取到最后
- substring(int start,int end):截取字符串,从start开始到end结束,但是含头不含尾
代码实现 :
//1.使用键盘录入
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号:");
String telPhone = sc.next();
//2.假设录入的字符串是13912341234,接下来开始针对这个字符串进行截取操作
//如果要替换中间四个数字,变为*,可以截取前三个和后四个,中间拼接****
//使用substring方法,截取前三个,调用方法截取后,调用方法的字符串不变,只是返回一个新的字符串
String start = telPhone.substring(0, 3);
//3.拿结尾的四个
String end = telPhone.substring(7);
//4.最后把头+****+尾进行拼接
System.out.println(start + "****" + end);
2.10 敏感词替换-字符串替换
案例需求 :
键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换
实现步骤 :
-
键盘录入一个字符串,用 Scanner 实现
-
替换敏感词
String replace(CharSequence target, CharSequence replacement)
将当前字符串中的target内容,使用replacement进行替换,返回新的字符串CharSquence:以后如果你看到方法的形式参数是它,说明就丢字符串进去就可以了。它是字符串的干爹。
-
输出结果
代码实现 :
//1.创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一句话:");
String str = sc.next();
//2.把字符串中非法字符串使用***替换,核心方法是replace
str = str.replace("TMD", "***");
//3.打印替换后的字符串
System.out.println(str);
课后练习:
/**
* 需求:
* 1.键盘录入一个初始字符串,例如:I love heima,heiheimama love me
* 2.再使用键盘录入一个目标字符串,可以将初始字符串中的目标字符串删除
* 3.在控制台打印处理后的字符串内容,例如输入目标字符串:heima,控制台输出:
* I love , love me
*/
2.11 切割字符串
案例需求 :
以字符串的形式从键盘录入学生信息,例如:“张三 , 23”
从该字符串中切割出有效数据,封装为Student学生对象
实现步骤 :
- 编写Student类,用于封装数据
- 键盘录入一个字符串,用 Scanner 实现
- 根据逗号切割字符串,得到(张三)(23)
- String[] split(String regex) :根据传入的字符串作为规则进行切割
- 注意:字符串regex如果是==.,请使用.==
- 将切割后的内容存入字符串数组中,并将字符串数组返回
- String[] split(String regex) :根据传入的字符串作为规则进行切割
- 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象
- 调用对象getXxx方法,取出数据并打印。
代码实现 :
//1.键盘录入
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String str = sc.nextLine();
//2.针对字符串做切割操作,以逗号座位分隔进行切割,按照题意,切出来有2个部分
String[] strs = str.split(",");
//结果返回的是一个字符串数组,说明切出来的是多个字符串,根据题意,切出来2个
System.out.println(strs[0]);
System.out.println(strs[1]);
//3.一般情况下,在工作中,如果我们获取到了零散的数据,我们通常都会使用一个对象将其封装起来
//专门用来封装数据的类,一般放在domain包下
//创建学生对象,存储数据
Student stu = new Student(strs[0], strs[1]);
System.out.println(stu.getName() + "的年龄是" + stu.getAge());
2.12 String方法小结
String类的常用方法 :
方法名 返回值类型 说明
equals(Object anObject) boolean 比较字符串的内容,严格区分大小写
equalsIgnoreCase(String anotherString) boolean 比较字符串的内容,忽略大小写
length() int 返回此字符串的长度
charAt(int index) char 返回指定索引处的 char 值
toCharArray() char[] 将字符串拆分为字符数组后返回
substring(int beginIndex, int endIndex) String 根据开始和结束索引进行截取,得到新的字符串(包含头,不包含尾)
substring(int beginIndex) String 从传入的索引处截取,截取到末尾,得到新的字符串
replace(CharSequence target, CharSequence replacement) String 使用新值,将字符串中的旧值替换,得到新的字符串
split(String regex) String[] 根据传入的规则切割字符串,得到字符串数组
- StringBuilder类
3.1 StringBuilder类概述
问题:
1.使用StringBuilder有什么好处?
2.如何获取1970-01-01 00:00:00到系统当前时间所经历的毫秒值?
3.将一段代码抽取到方法中的快捷键是什么?
-
概述 : StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的内容是可变的
-
作用:提高字符串的操作效率
-
System.currentTimeMillis():获取1970年1月1日0时0分0秒到当前时间所经历过的毫秒值
-
代码练习:
//练习:分别用String和StringBuilder操作字符串,对比两者操作的时间
public class Test01 {
public static void main(String[] args) {
//1.对比String和StringBuilder操作字符串消耗的时间
method1();
method2();
}public static void method1() { //2.在操作字符串之前,获取系统当前时间的毫秒值 long start = System.currentTimeMillis(); String s = ""; for (int i = 0; i < 50000; i++) { s += i; } //操作之后,再去获取系统的毫秒值 long end = System.currentTimeMillis(); System.out.println(end - start); } public static void method2() { //2.在操作字符串之前,获取系统当前时间的毫秒值 long start = System.currentTimeMillis(); StringBuilder builder = new StringBuilder(); for (int i = 0; i < 50000; i++) { builder = builder.append(i); } //操作之后,再去获取系统的毫秒值 long end = System.currentTimeMillis(); System.out.println(end - start); }
}
3.2 StringBuilder类的构造方法
问题:
1.打印用空参构造方法创建的StringBuilder对象,会有什么结果?
2.打印用带参构造方法创建的StringBuilder对象,会有什么结果?
常用的构造方法
方法名 说明
public StringBuilder() 创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象
示例代码
public class StringBuilderDemo01 {
public static void main(String[] args) {
//public StringBuilder():创建一个空白可变字符串对象,不含有任何内容
StringBuilder sb = new StringBuilder();
System.out.println("sb:" + sb);
System.out.println("sb.length():" + sb.length());
//public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象
StringBuilder sb2 = new StringBuilder("hello");
System.out.println("sb2:" + sb2);
System.out.println("sb2.length():" + sb2.length());
}
}
3.3 StringBuilder常用的成员方法
问题:
1.StringBuilder有哪几种常见的功能方法?
2.StringBuilder对象是否可以添加不同的数据类型到容器中?
3.StringBuilder的append方法返回对象自己,有什么作用?
-
添加和反转方法
方法名 说明
public StringBuilder append(任意类型) 添加数据,并返回对象本身
public StringBuilder reverse() 返回相反的字符序列
public int length() 返回长度(字符出现的个数)
public String toString() 把StringBuilder转换为String -
示例代码
//需求:创建一个StringBuilder对象,分别调用几个成员方法,观察效果
3.4 StringBuilder提高效率的原理
-
原理图:
-
字符串的加法拼接:
-
StringBuilder拼接:
-
-
StringBuilder类和String类的区别:
- String类:内容是不可变的
- StringBuilder类:内容是可变的
3.5 对称字符串案例:String和StringBuilder之间的相互转换
-
需求:键盘接收一个字符串,程序判断该字符串是否是对称字符串,并在控制台打印是或不是
-
思路:
-
代码实现:
//1.键盘录入
Scanner sc = new Scanner(System.in);
System.out.println(“请输入一个对称字符串:”);
String str = sc.nextLine();
//2.要判断一个字符串是不是对称字符串,把这个字符串反转一下,然后对比内容
//如果反转后的内容和反转前的内容一样,就属于对称字符串,比如123321
//要把字符串进行反转,这个时候我们就要想,字符串对象自己能不能做?
//查了api,发现不能做。这个时候要想,和字符串相关的工具还有哪些?想到了StringBuilder
//就去查api,发现了一个reverse方法可以做到
//3.通过构造方法把String变成StringBuilder
StringBuilder sb = new StringBuilder(str);
//4.调用reverse反转
sb.reverse();
//5.将反转后的字符串内容和原字符串内容比较
//注意,这里要保证都是字符串类型比较,所以sb要转成String
if (str.equals(sb.toString())) {
System.out.println(“是对称字符串”);
} else {
System.out.println(“不是对称字符串”);
} -
StringBuilder转换为String
public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String -
String转换为StringBuilder
public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder
3.6 StringBuilder拼接字符串案例
-
需求 :
- 定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
- 并在控制台输出结果。例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
-
实现步骤 :
- 定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
- 定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
返回值类型 String,参数列表 int[] arr - 在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
- 调用方法,用一个变量接收结果
- 输出结果
-
代码实现 :
public class Test03 {
public static void main(String[] args) {
//1.静态初始化
int[] arr = {1, 2, 3};
String str = getStr(arr);
System.out.println(str);
}public static String getStr(int[] arr) { //2.要操作字符串,就要创建StringBuilder对象,去做拼接 //拼接的数据从数组中来,所以还要遍历数组 StringBuilder sb = new StringBuilder("["); for (int i = 0; i < arr.length; i++) { //3.直接拼接不太好,因为字符串里面有特殊的格式,以中括号开始,而且是拼接数据之前 //开始拼接数字,但是有区别,最后一个跟中括号的结束 if (i == arr.length - 1) { //是最后一个元素,拼接的时候不能拼逗号 sb.append(arr[i]).append("]"); } else { sb.append(arr[i]).append(","); } } //4.方法返回的是字符串,要转一下 return sb.toString(); }
}
- ArrayList
1.1 集合和数组的区别对比
问题:
1.相对于数组,集合容器有什么特点?
2.在什么情况下,更推荐使用集合容器存放数据?
- 集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变
- 集合和数组的区别
- 共同点:都是存储数据的容器
- 不同点:数组的容量是固定的,集合的容量是可变的
1.2 ArrayList的构造方法和添加方法
问题:
1.ArrayList集合的大小可变,底层是通过什么实现的?数组
2.通过空参构造创建的ArrayList集合对象,初始容量是多少?10
3.ArrayList集合可以存放多种数据类型的数据吗?可以
4.如何指定ArrayLList集合只存储特定的数据类型?加一个泛型
public ArrayList() 创建一个空的集合对象
public boolean add(E e) 将指定的元素追加到此集合的末尾
public void add(int index,E element) 在此集合中的指定位置插入指定的元素
ArrayList :
可调整大小的数组实现
<E> : 是一种特殊的数据类型,泛型。
泛型可以代表一种不确定的类型,类型的确定在声明这个类的变量的时候
注意,不是所有的类都可以加泛型哦。目前你只在ArrayList后面加泛型
怎么用呢 ?
在出现E的地方我们使用引用数据类型替换即可
举例:ArrayList<String>, ArrayList<Student>
-
练习:
/**
- 创建一个可以存储字符串类型数据的ArrayList集合对象
- 向集合中添加三个元素:hello world java
- 向集合中2索引处添加一个JavaSE
*/
ArrayList list = new ArrayList<>();
list.add(“李小璐”);
list.add(“白百何”);
list.add(“马蓉”);
//ArrayList集合对象可以直接打印
System.out.println(list);
//向集合中2索引处添加一个JavaSE
list.add(2,“JavaSE”);
System.out.println(list);
1.3 ArrayList类常用方法
问题:
1.调用ArrayList集合删除的功能,可以返回哪些数据类型?
2.调用ArrayList集合的修改指定位置元素的方法,返回值是什么?
成员方法 :
public boolean remove(Object o) 删除指定的元素,返回删除是否成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数
示例代码 :
//练习:创建一个集合,用来存储和管理学生对象数据
//增加数据
//删除数据
System.out.println("======删除数据======");
//指定位置删除
System.out.println("======修改数据======");
System.out.println("======获取数据======");
System.out.println("======获取集合长度======");
1.4 案例:ArrayList存储字符串并遍历
案例需求 :
创建一个存储字符串的集合,存储3个字符串元素,使用程序实现在控制台遍历该集合
实现步骤 :
- 创建集合对象
- 往集合中添加字符串对象
- 遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
- 遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
- 遍历集合的通用格式
- 往集合中添加字符串对象
代码实现 :
//1.创建集合
ArrayList<String> hanzimen = new ArrayList<>();
//2.使用add方法添加3个字符串
hanzimen.add("王宝强");
hanzimen.add("贾乃亮");
hanzimen.add("吴签");
//3.使用循环遍历集合。集合提供了size()方法,可以获取集合的长度
for (int i = 0; i < hanzimen.size(); i++) {
//4.使用集合get方法可以获取集合中的元素,根据索引获取
String hanzi = hanzimen.get(i);
System.out.println(hanzi);
}
1.5 案例:ArrayList存储学生对象并遍历
案例需求 :
创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
实现步骤 :
- 定义学生类
- 创建集合对象
- 创建学生对象
- 添加学生对象到集合中
- 遍历集合,采用通用遍历格式实现
- 创建集合对象
代码实现 :
//1.创建集合,用于存储学生对象,这里存储的数据是学生对象,类型指定为Student
//注意,如果没有Student类,要先去创建Student类
ArrayList<Student> stus = new ArrayList<>();
//在一个类中使用了另外一个包下的类,就需要先导包才能使用,idea可以自动导包
//2.创建学生对象,封装学生数据
Student stu1 = new Student("张三", 23, 98.8, "男");
Student stu2 = new Student("李四", 24, 96.8, "女");
Student stu3 = new Student("王五", 20, 100, "男");
//3.使用集合容器,用add方法添加数据
stus.add(stu1);
stus.add(stu2);
stus.add(stu3);
//4.集合中有数据了,开始遍历集合
for (int i = 0; i < stus.size(); i++) {
//5.从集合中取出索引对应的学生对象,使用get方法
Student stu = stus.get(i);
//6.拿出来的是学生对象,不能直接打印,得调用学生对象的获取属性的方法
System.out.println(stu.getName() + "..." + stu.getAge());
}
1.6 案例:键盘录入学生信息到集合
案例需求 :
创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
学生的姓名和年龄来自于键盘录入
实现步骤 :
- 定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型
- 创建集合对象
- 键盘录入学生对象所需要的数据
- 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
- 往集合中添加学生对象
- 遍历集合,采用通用遍历格式实现
代码实现 :
public class Test05 {
public static void main(String[] args) {
//1.创建集合,用来存储Student对象
ArrayList<Student> stus = new ArrayList<>();
//2.键盘录入学生信息,封装成学生对象,使用循环录入也可以,但是比较麻烦
//为了提高代码的复用性,可以把录入学生数据的这些代码使用方法封装起来
//6.利用写好的方法获取3次学生对象
Student stu1 = getStudent();
Student stu2 = getStudent();
Student stu3 = getStudent();
//7.将对象存储到集合中
stus.add(stu1);
stus.add(stu2);
stus.add(stu3);
//8.遍历集合,打印学生数据
for (int i = 0; i < stus.size(); i++) {
//9.通过集合get方法获取集合中存储的学生对象
Student stu = stus.get(i);
//10.通过学生对象的get方法获取属性
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
//3.定义一个获取学生对象的方法,这个方法返回值就是Student类型
public static Student getStudent() {
//4.创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
System.out.println("请输入学生年龄:");
int age = sc.nextInt();
System.out.println("请输入学生分数:");
double score = sc.nextDouble();
System.out.println("请输入学生性别:");
String sex = sc.next();
//5.有了零散的学生数据,封装成学生对象管理
Student stu = new Student(name, age, score, sex);
//返回学生对象
return stu;
}
}
1.7 案例:集合删除元素
案例需求 :
创建一个存储String的集合,内部存储(test,张三,李四,test,test)字符串,删除所有的test字符串,删除后,将集合剩余元素打印在控制台
实现步骤 :
- 创建集合对象
- 调用add方法,添加字符串
- 遍历集合,取出每一个字符串元素
- 加入if判断,如果是test字符串,调用remove方法删除
- 打印集合元素
代码实现:
//1.创建集合
ArrayList<String> strs = new ArrayList<>();
//2.存储几个字符串,用于测试
strs.add("test");
strs.add("张三");
strs.add("李四");
strs.add("test");
strs.add("test");
//3.删除集合中的test字符串,遍历集合,将里面的元素一个个取出来
for (int i = 0; i < strs.size(); i++) {
//4.使用get方法获取集合中的字符串
String s = strs.get(i);
//5.判断拿出来字符串s是否内容是test,如果是就删除
//这里要注意,为了防止空指针异常,使用字符串常量去调用equals方法
/*if (s.equals("test")) {
//这里不建议这么写,容易出现空指针
}*/
if ("test".equals(s)) {
//如果是test,就删除,调用集合的remove方法
strs.remove(i);
//6.集合删除一个元素后,后面的所有元素会往前挪动一位,如果此时索引不做操作
//就会导致所以继续往后,挪过来的第一个元素就会漏掉,应该让索引减1
i--;
}
}
//7.打印集合,看看是否删除
System.out.println(strs);
1.8 案例:集合数据筛选
案例需求 :
定义一个方法,方法接收一个集合对象(泛型为Student),方法内部将年龄低于18的学生对象找出并存入集合对象,方法返回新集合
实现步骤 :
代码实现:
public class Test07 {
public static void main(String[] args) {
//7.创建学生对象和集合,用于测试
ArrayList<Student> stus = new ArrayList<>();
stus.add(new Student("张三",23,98.0,"男"));
stus.add(new Student("李四",12,98.0,"男"));
stus.add(new Student("王五",15,98.0,"男"));
//8.调方法测试
ArrayList<Student> newStus = getStus(stus);
//打印新集合
for (int i = 0; i < newStus.size(); i++) {
Student stu = newStus.get(i);
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
//1.定义一个方法,用于获取我们要的集合
public static ArrayList<Student> getStus(ArrayList<Student> stus) {
//2.方法内部遍历传过来的集合,把低于18岁的学生存入新集合
//创建一个新的集合
ArrayList<Student> newStus = new ArrayList<>();
//3.遍历传过来的集合
for (int i = 0; i < stus.size(); i++) {
//4.从集合中获取学生对象,并判断年龄
Student stu = stus.get(i);
if (stu.getAge() < 18) {
//5.把这个学生对象存入新集合
newStus.add(stu);
}
}
//6.返回新的集合对象
return newStus;
}
}
2.学生管理系统
2.1 学生管理系统实现步骤
- 案例需求
针对目前我们的所学内容,完成一个综合案例:学生管理系统!该系统主要功能如下:
添加学生:通过键盘录入学生信息,添加到集合中
删除学生:通过键盘录入要删除学生的学号,将该学生对象从集合中删除
修改学生:通过键盘录入要修改学生的学号,将该学生对象其他信息进行修改
查看学生:将集合中的学生对象信息进行展示
退出系统:结束程序 - 实现步骤
- 定义学生类,包含以下成员变量
学生类: Student成员变量:
学号:sid
姓名:name
年龄:age
生日:birthday
构造方法:
无参构造
带四个参数的构造成员方法:
每个成员变量对应给出get/set方法 - 学生管理系统主界面的搭建步骤
2.1 用输出语句完成主界面的编写
2.2 用Scanner实现键盘录入数据
2.3 用switch语句完成操作的选择
2.4 用循环完成再次回到主界面 - 学生管理系统的添加学生功能实现步骤
3.1 用键盘录入选择添加学生
3.2 定义一个方法,用于添加学生
显示提示信息,提示要输入何种信息
键盘录入学生对象所需要的数据
创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
将学生对象添加到集合中(保存)
给出添加成功提示
3.3 调用方法 - 学生管理系统的查看学生功能实现步骤
4.1 用键盘录入选择查看所有学生信息
4.2 定义一个方法,用于查看学生信息
显示表头信息
将集合中数据取出按照对应格式显示学生信息,年龄显示补充“岁”
4.3 调用方法 - 学生管理系统的删除学生功能实现步骤
5.1 用键盘录入选择删除学生信息
5.2 定义一个方法,用于删除学生信息
显示提示信息
键盘录入要删除的学生学号
调用getIndex方法,查找该学号在集合的索引
如果索引为-1,提示信息不存在
如果索引不是-1,调用remove方法删除并提示删除成功
5.3 调用方法 - 学生管理系统的修改学生功能实现步骤
6.1 用键盘录入选择修改学生信息
6.2 定义一个方法,用于修改学生信息
显示提示信息
键盘录入要修改的学生学号
调用getIndex方法,查找该学号在集合的索引
如果索引为-1,提示信息不存在
如果索引不是-1,键盘录入要修改的学生信息
集合修改对应的学生信息
给出修改成功提示
6.3 调用方法 - 退出系统
使用System.exit(0);退出JVM
- 定义学生类,包含以下成员变量
2.2 学生类的定义
package com.itheima.domain;
/**
* 该类用于存储和管理本系统的学生数据
*/
public class Student {
//属性:学号、姓名、年龄、生日,分别用成员变量代表
//为了提高安全性,使用private修饰属性
private String sid;
private String name;
private int age;
private String birthday;
//标准类的书写,写完了属性,就要写构造方法,空参和满参
public Student() {
}
public Student(String sid, String name, int age, String birthday) {
this.sid = sid;
this.name = name;
this.age = age;
this.birthday = birthday;
}
//属性被private修饰了,要给他们添加设置值和获取值的方法,以供外界使用
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
2.3 菜单搭建
/**
* 本类就是用于完成学生管理系统的核心功能,所以要加上主方法
*/
public class StudentManager {
public static void main(String[] args) {
//1.程序从这里开始,软件一旦运行,首先展示的页面就是它第一个需要完成的功能,菜单显示
//菜单显示:提示用户根据展示的信息录入选择,在根据选择执行不同的功能,这个过程可能有很多次
//技术体系:while死循环+switch选择结构
//2.展示菜单页面,用输出语句
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//5.到这一步,该选择只能完成1次,不符合软件的需求,要能够重复选择执行,不知道重复的次数
//使用while死循环,不用把创建键盘录入对象放进来,反复创建对象比较消耗内存
lo:
while (true) {
System.out.println("--------欢迎来到学生管理系统--------");
System.out.println("1 添加学生");
System.out.println("2 删除学生");
System.out.println("3 修改学生");
System.out.println("4 查看学生");
System.out.println("5 退出");
System.out.println("请输入您的选择:");
//3.录入选择,录入字符串,因为这样的话,你录入错了,也不会报错
String choice = sc.next();
//4.根据录入的内容,执行不同的分支,这是switch结构
switch (choice) {
case "1":
System.out.println("添加");
break;
case "2":
System.out.println("删除");
break;
case "3":
System.out.println("修改");
break;
case "4":
System.out.println("查看");
break;
case "5":
System.out.println("感谢您的使用");
//注意,break可以被switch和循环消费,这里要指定结束循环,使用标号的方式
break lo;
default:
System.out.println("您的输入有误,请检查后重试");
break;
}
}
}
}
2.4 添加学生:基本实现
public static void main(String[] args) {
//2.1 我们的学生数据是放到集合中存储的,先创建ArrayList集合
ArrayList<Student> stus = new ArrayList<>();
......
case "1":
// System.out.println("添加学生");
//2.2 定义一个方法来处理添加学生的逻辑
addStudent(stus);
break;
......
}
public static void addStudent(ArrayList<Student> stus) {
//2.3 提示用户键盘录入学生信息
Scanner sc = new Scanner(System.in);
System.out.println("请输入学号:");
String sid = sc.next();
System.out.println("请输入姓名:");
String name = sc.next();
System.out.println("请输入年龄:");
int age = sc.nextInt();
System.out.println("请输入生日:");
String birthday = sc.next();
//2.4 拥有了零散的学生信息,必须封装到学生对象中,方便管理
Student stu = new Student(sid, name, age, birthday);
//2.5 有了学生数据,将这个学生对象丢进通过方法的参数传递过来的集合中
stus.add(stu);
//方法需不需要返回集合对象?不需要,因为集合对象是引用数据类型,你对她的操作,主方法也能看到更改
}
2.5 查看学生代码实现
public static void main(String[] args) {
......
case "4":
//System.out.println("查看学生");
queryStudents(stus);
break;
......
}
/**
* 查看学生
*
* @param stus
*/
public static void queryStudents(ArrayList<Student> stus) {
//3.1 如果执行查询学生,不能马上就开始遍历,因为有可能传过来的集合是个空的
//先判断集合是否是空的,如果是空的,就可以提示用户,然后结束方法
if (stus.size() == 0) {
System.out.println("无数据,请添加后再查询");
//直接使用return结束方法,方法弹栈
return;
}
//3.2 在遍历之前,先把格式上的表头打印出来,让你知道打印的每一列分别是什么数据
System.out.println("学号\t\t姓名\t\t年龄\t\t生日");
//3.3 如果没有进入if语句,说明集合不是空的,可以打印。另外也不会结束方法
for (int i = 0; i < stus.size(); i++) {
//3.4 从集合中拿出学生对象
Student student = stus.get(i);
//3.5 开始打印数据
System.out.println(student.getSid() + "\t" + student.getName() + "\t" + student.getAge() + "\t\t" + student.getBirthday());
}
}
2.6 判断学号是否存在的方法定义
/**
* 定义一个方法用来返回学号在集合中对应的索引位置
* 需要提供集合、被查询的学号
* 返回的是索引
*/
public static int getIndex(ArrayList<Student> list, String sid) {
//4.1 定义一个变量代表要返回的索引值,现在没有开始判断,假设这个索引不存在,给个不存在的初始化值
int index = -1;
//4.2 遍历集合,拿出里面的学生对象
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
//4.3 从学生对象中拿出学号
String id = stu.getSid();
//4.4 开始判断从学生对象中拿出来的id是否和你传递过来的id内容相同
if (id.equals(sid)) {
//4.5 如果相同,说明学生集合中有你传过来的学号对应的学生,用集合中的索引替换index
index = i;
}
}
//4.6 循环结束,如果if语句一直没有进去过,index就是-1,那就是没找到
return index;
}
2.7 删除学生代码实现
public static void main(String[] args) {
......
case "2":
//System.out.println("删除学生");
deleteStudent(stus);
break;
......
}
/**
* 删除学生
* @param stus
*/
public static void deleteStudent(ArrayList<Student> stus) {
//5.1 提示用户录入要删除的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要删除的学号:");
String delSid = sc.next();
//5.2 你输入的学号不一定就存在,如果不存在重新输入,存在才能删除,先判断输入的学号是否存在
//获取学号对应的索引的逻辑已经写好,调用getIndex方法即可
int index = getIndex(stus, delSid);
//5.3 判断index的值,如果index是-1,就说明没找到,否则就找到了
if (index == -1) {
//5.4 没找到,提示用户
System.out.println("查无此人,请重新输入");
} else {
//5.5 找到了,就可以根据索引,直接从集合中删除学生对象
stus.remove(index);
System.out.println("删除成功!");
}
}
2.8 修改学生代码实现
public static void main(String[] args) {
......
case "3":
//System.out.println("修改学生");
updateStudent(stus);
break;
......
}
/**
* 修改学生
* @param stus
*/
public static void updateStudent(ArrayList<Student> stus) {
//6.1 键盘录入需要修改的学生学号,判断是否存在,不存在重新输入。存在,就开始修改
//逻辑和删除一样,直接复制代码
//6.2 提示用户录入要修改的学号
Scanner sc = new Scanner(System.in);
System.out.println("请输入要修改的学号:");
String updateSid = sc.next();
int index = getIndex(stus, updateSid);
//6.3 判断index的值,如果index是-1,就说明没找到,否则就找到了
if (index == -1) {
//6.4 没找到,提示用户
System.out.println("查无此人,请重新输入");
} else {
//6.5 找到了,就要开始修改,你要录入修改的内容
System.out.println("请输入新的学生姓名:");
String name = sc.next();
System.out.println("请输入新的学生年龄:");
int age = sc.nextInt();
System.out.println("请输入新的学生生日:");
String birthday = sc.next();
//6.6 有了学生数据,重新封装到学生对象中
Student stu = new Student(updateSid, name, age, birthday);
//6.7 把这个学生对象,改到集合中,使用集合的set方法
stus.set(index, stu);
System.out.println("修改成功!");
}
}
2.9 解决添加学生学号重复的问题
public static void addStudent(ArrayList<Student> stus) {
//2.3 提示用户键盘录入学生信息
Scanner sc = new Scanner(System.in);
//7.1 输入学号,如果存在就得重新输入学号,因为不能添加已存在的学生,无法判断输入多少次成功
String sid;
while (true) {
System.out.println("请输入学号:");
sid = sc.next();
//7.2 调用getIndex方法,判断你输入的学号是否存在
int index = getIndex(stus, sid);
if (index == -1) {
//不存在,可以继续输入,结束这个死循环
break;
}
}
System.out.println("请输入姓名:");
String name = sc.next();
System.out.println("请输入年龄:");
int age = sc.nextInt();
System.out.println("请输入生日:");
String birthday = sc.next();
//2.4 拥有了零散的学生信息,必须封装到学生对象中,方便管理
Student stu = new Student(sid, name, age, birthday);
//2.5 有了学生数据,将这个学生对象丢进通过方法的参数传递过来的集合中
stus.add(stu);
System.out.println("添加成功!");
//方法需不需要返回集合对象?不需要,因为集合对象引用数据类型,你对她的操作,主方法也能看到更改
}