JavaSE 基础学习

391 阅读26分钟

Java SE

一、Java SE 基础

1.变量

  • 变量就是内存中的存储空间,空间中存储着经常发生改变的数据

  • 定义格式:数据类型 变量名 = 数据值;

  • int salary = 10000

  • 使用:根据变量名进行使用

  • 注意事项

    •  
      变量在作用域范围内才可以使用
      变量名不允许重复定义
      一条语句可以定义多个变量
      变量在使用之前一定要进行赋值
      ​
      

2.标识符

  •  
    * 作用:给类、变量、方法等取名字的符号单词
    ​
    * 命名规则:
         可以由数字、字母、下划线(_)和美元符($)其中一种或多种组成
        不能以数字开头
        不能是关键字或特殊直接量(true,flase,null)
    *      区分大小写
    ​
    * 注意:不需要记忆规则,使用idea自动检查即可
    

3.基本数据类型的分类和使用

  • 整数型

    •  
      byte1个字节,范围-128~127
      short2个字节
      int4个字节
      long8个字节
      
  • 浮点型:

    •  
      float4个字节
      double8个字节
      
  • 字符型

    •  
      char2个字节
      
  • 布尔型

    •  
      boolean1个字节,就两个值truefalse
      

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概述

1. Java语言背景介绍

 
问题:
1.什么是计算机语言,学习它有什么作用?
2.java语言的创始人是谁,在哪一年发布的呢?
3.java目前分为几个平台版本,我们学习的是哪些版本?
4.JavaEE主要是用于什么方向的开发?
  1. Java语言介绍

    • 语言:人与人交流沟通的表达方式
    • 计算机语言:人与计算机沟通交流的一种特殊语言
    • Java语言是Sun公司(==Stanford University Network==)在1995年推出,1996年发布第一版开发工具包==jdk1.0==
    • Java之父:詹姆斯·高斯林

  1. Java语言的三个版本

    • JavaSE:Java语言的==标准版==

      • JavaSE主要用于桌面应用的开发,是其他两个版本的基础
      • 桌面应用:用户只要打开程序,==程序的界面==会让用户在最短的时间内找到他们需要的功能,同时主动带领用户完成他们的工作并得到最好的体验
    • JavaME:Java语言的==小型版==,用于嵌入式消费类电子设备

      • 已经被Android和ios取代,不是我们学习的重点
    • JavaEE:Java语言的企业版,用于Web方向的==网站==开发

      • 网页、网站和服务器

        • 网页:通过浏览器将数据展示在用户面前,跟后台服务器没有交互
        • 网站:通过跟后台服务器的交互,将查询到的真实数据再通过网页展示出来
      • 简单理解:网站=网页+后台服务器

2. Java跨平台原理

 
问题:
1.对于跨平台,这个平台指的是什么呢?
2.java程序是如何做到能够在不同的操作系统上运行的呢?
3.不同平台上的JVM虚拟机是一样的吗?
  • 平台与跨平台

    • 平台:不同的操作系统,比如:Windows、Mac、Linux...
    • 跨平台:java程序可以在任意的操作系统上运行
  • 跨平台的原理

    • Java程序本身不能在不同的系统上直接运行,但是可以每个系统安装一个匹配系统的JVM
    • JVM将Java程序翻译成对应系统可以看懂并且执行的程序
  • 总结:要想跨平台运行java程序,只需要在不同的操作系统中,安装一个与操作系统对应的Java虚拟机(JVM)即可

  • 注意:==Java虚拟机==本身==不允许跨平台==,允许==跨平台==的是==Java程序==

3. 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程序的三个步骤

    1. 编写源代码

      1. 创建文本文件
      2. 修改文件后缀名为.java
      3. 在文件中按照java的语法格式书写代码
    2. 编译源代码

      • 写好的==Java源文件不能直接被JVM识别和执行==。需要用JDK中提供的翻译工具(==javac.exe==)将其翻译成字节码文件(.class文件),这个过程就是==编译==
    3. 运行程序:利用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

4. JDK的下载和安装

 
问题:
1.安装jdk,能否安装在中文路径的文件夹下?
2.jdk的版本这么多,我们基础班学习,选择使用哪个版本?
3.怎么判断jdk已经安装成功了?
4.jdk根目录下的bin目录中主要是存放什么文件的?
  1. Java语言的发展史

    1. 95年推出,96年发布第一个开发工具包jdk1.0
    2. 2009年被Oracle收购
    3. 其余版本,都是功能测试版,半年到一年更新一次
    4. 基础班使用版本:14,因为有一些新特性,可以了解一下。
    5. 目前官方发布的,正在用于开发的大版本有8、11,也叫LTS版本,就是长期维护的版本
    6. 比如9、10、12、13、14、15、16都是维护半年的功能测试版
    7. 下一个大版本官方预计今年9月份之后
  2. JDK的下载和安装

    • 下载

      1. 直接访问:www.oracle.com/java/
      2. 找到download java按钮,鼠标点击,进入下载页
      3. 然后就可以选择版本进行安装,一般只会展示==最新版和稳定版==
      4. 注意:下载之前需要==注册Oracle账号==,用邮箱注册即可
    • 安装(电脑可以安装不同版本的jdk,但是如果安装都是同一个版本,会把之前的卸载)

      1. 双击jdk文件进行安装;
      2. 在选择安装路径的环节,选择英文路径下进行安装,不要安装在带有中文的路径下;
      3. 建议所有和开发相关的软件都安装在统一的路径下,建议在D盘下创建一个develop文件夹统一进行管理
  3. JDK的安装目录(根目录介绍)

第一个程序

1. 常用DOS命令

 
问题:
1.打开DOS命令提示符操作窗口的步骤是什么?
2.常用的DOS命令有哪些,分别具有什么功能?
3.如何快速的进入某个文件所在目录的对应DOS环境中?
  • 学习DOS命令意义

    • 为了能够使用JDK中bin目录下的java.exe和javac.exe这两个工具
    • 未来学习使用Linux系统,需要提前适应命令行操作界面风格
  • 打开DOS的方式想·

    1. 按下 win+r 键,弹出运行窗口

    • 在窗口中输入cmd
    • 点击确定
  • 常用DOS命令

  • 命令补充
命令说明
mkdir 文件夹名创建一个文件夹
rmdir [/s] 文件夹名删除一个[非空]文件夹
del 文件名删除文件
cd.>要新建的文件名创建一个空白文件
rename 要重命名的文件名 重命名之后的文件名修改一个文件的文件名
move 被移动的文件 要移动到的位置[\移动后的文件名]剪切一个文件到指定路径下,也可以更改剪切后的文件名
copy 被复制的文件 要复制到的位置[\复制后的文件名]复制一个文件到指定路径下,也可以更改复制后的文件名
  • 快速进入bin目录所在的DOS命令提示符
  1. 找到jdk的bin文件夹,进入
  2. 在文件夹上方的地址栏输入cmd,回车即可
  • DOS命令练习

    • 在桌面创建一个文件夹dos-test
    • 进入dos-test文件夹
    • 创建一个dos.txt文件
    • 自己选择一个非C盘的路径,创建一个文件夹dos-copy
    • 将dos-test中的文件复制到dos-copy中
    • 回到桌面,删除dos-test文件夹
    • 退回C盘根路径
    • 清除屏幕
    • 退出

2. Path环境变量的配置

 
问题:
1.安装jdk之后,为什么要配置Path环境变量?
2.配置环境变量时,变量JAVA_HOME的值是什么?
3.Path变量的配置,是在用户变量中还是在系统变量中?
4.如何校验jdk的path环境变量是否配置成功?
  1. 配置Path环境变量的意义

    可以在任意目录下,都能访问到bin目录中的==javac==和==java==工具

  2. Path环境变量的配置

  • 找到桌面上计算机图标,鼠标右击,选择属性
  • 找到高级系统设置,一般在左上方

  • 选择高级、环境变量

  • 在系统变量中新建一个变量

  • 变量名是:JAVA_HOME,变量值是jdk的根目录地址,点击确定

  • 再到系统变量框里找到path变量,编辑它

  • 在path变量的编辑框中,点击新建,然后输入:%JAVA_HOME%\bin

  • 需要注意的是,如果path变量框是上面的样式,是==不需要加分号结束==的
  • 但如果是下方的样式,那么输入%JAVA_HOME%\bin;是==需要带分号结束==

  • 设置好之后,需要一直点击确定结束
  • 验证path环境变量是否配置成功,需要==重新打开一个dos命令行窗口界面验证==,不能使用原有的窗口
  • 在dos命令行窗口分别输入java -versionjavajavac三个命令验证

3. HelloWorld案例详解

 
问题:
1.书写Java代码时,class这个单词是用来干什么的?
2.一个Java程序能不能没有main主方法?
3.代码System.out.println("学习Java的人不是帅哥,就是美女!");的作用是什么?
4.class前面的public这个单词,有什么作用?
  1. 一个java程序,有且仅有一个main方法,属于固定写法

    • 一个java程序可以有很多个类,所以类是java程序的最基本组成单位
    • 如果Java程序有很多个类,运行这个程序,从有main方法的类中开始
  2. 类名必须和文件名保持一致,因为类名前面有public修饰

  3. HelloWorld程序说明:

  • java在基础班没有丰富的视觉界面显示,只能通过控制台这种简单的界面去呈现内容。你现在打印的这个内容,以后真正的显式地方,是网页上
  • 基础班暂时不学习网页内容,这个要到就业班才会学习

IDEA的安装和使用

1. IDEA的概述和安装

  1. 概述

    IDEA全程是IntelliJ IDEA,是用于Java语言开发的集成环境,它是业界公认的目前用于Java程序开发最好的工具。

    集成环境:把代码编写、编译、运行、调试等多种功能综合到一起的开发工具

  2. 下载和安装

    下载:www.jetbrains.com/idea/downlo…

    安装:双击下一步即可,注意不要安装在中文路径下

2. IDEA中的项目结构

  1. Idea项目结构介绍

    1. project:项目、工程
    2. module:模块
    3. package:包
    4. class:类

  2. 小结

    • project中可以创建多个module

    • module中可以创建多个package

    • package中可以创建多个class

    • 这样的结构划分,是为了方便==管理类文件==的

      • 如果不用这些层级去管理类文件,全部放在同一个文件夹中,以后的项目有大量java类文件,不容易找
      • 同一个文件夹下不能出现同名的java类,这样给类取名字就很麻烦了
      • java类文件不做分类管理,就好比沃尔玛的商品不做分类,堆在一块

3. IDEA中的第一个代码

操作步骤(2021版):

  1. 创建Project(项目)

  1. 创建Module(模块)

project创建好之后,会自动弹出创建module的窗口

如果不通过自动弹出的创建module窗口创建,也可以在project的界面中操作

配置Module

  1. 创建Package(包)

  1. 创建class(类)

  1. 编写代码,运行程序

4. IDEA常用快捷键

 
//psvm:  一键生成主方法
//sout:   生成输出语句
//ctrl+alt+L:   格式化代码
//alt+Enter:    代码修正提示
​
//ctrl+/:   添加(取消)单行注释
//ctrl+shift+/ : 添加(取消)多行注释
​
//ctrl+D :  复制当前行的代码
//ctrl+X :  剪切
//ctrl+V :  粘贴
​
//alt+1:    打开/隐藏项目结构
//alt+4:    打开/隐藏控制台
​
//fori :  10次的for循环 

5. IDEA操作模块

  1. 删除模块

  1. 导入模块

直接通过project界面导入已存在的module

通过Project structure设置导入module

最后就是一直选择==next==下一步即可

6. IDEA打开、关闭项目-类名、包名修改

  1. 关闭项目

  1. 打开项目

如果列表中要打开的项目已被移除:

  1. 修改类名

  1. 修改包名

基础语法

注释

 
问题:
1.什么是注释,程序当中的注释有什么作用?
2.java中注释分为几类,分别是什么?
3.注释会不会影响程序的编译和运行?
  1. 注释的概述

    • 在程序指定位置添加的说明性信息
    • 对代码进行解释说明,方便我们程序员更好的去阅读代码。
  2. 注释的分类

    1. 单行注释

      格式:==//== 注释信息只有一行,并且在双斜线后面

    2. 多行注释

      格式:==/== 注释信息可以有很多行,位置被包裹住 ==/==

    3. 文档注释(目前用不上,暂不讲解)

      格式:==/ **== 注释信息 ==*/==

 
//练习:给HelloWorld程序添加注释
//这是一个类,类的名字叫A
public class A{
    /*
        这是程序的主方法,一个java程序有且仅有一个main方法。
    */
    public static void main(String[] args){
        //这是一个在控制台打印输出内容的语句,小括号中是输出的内容。
        //在控制台输出自己的姓名、对喜欢的人想说的话
        System.out.println("好棒哦,notepad真给力");
    }
}

基础语法

1. 关键字

 
问题:
1.java中的“关键字”是什么?
2.Java中的“关键字”有哪些特点?
3.main方法中的名字“main”是不是关键字?
  • 概念:被java赋予了特定涵义的英文单词

  • 特点:

    • 关键字的字母全部都是小写
    • 常用的代码编辑器,针对关键字有特殊的颜色标记,非常直观
    • main不是关键字,但是也很==关键==
  • java中有48个关键字,和2个保留关键字

2. 字面量

 
问题:
1.Java中的字面量有哪几种类型?
2.'10'这个数据在Java中属于字符字面量吗?
3.能不能使用打印语句去打印空字面量?
  1. 字面量的分类:

    • 字符串字面量:被双引号所包裹的内容
    • 整数字面量:所有整数
    • 小数字面量:所有小数
    • 字符字面量:被单引号包裹的内容,里面只能存放单个字符。字符是字符串的组成部分。
    • 布尔、字面量:只有两个值,分别是==true==和==false==,分别代表真和假、成立和不成立这种对立的意思(以后学习运算符和流程结构时需要用到)
    • 空字面量:null。代表不存在的,空的。不能被输出打印。

3. 变量

3.1 变量概述

  1. 概念:在程序运行期间,其值可以发生改变的量。
  2. 理解:变量就是内存中的存储空间,空间中存储着经常发生改变的数据
  3. 定义格式

  1. 变量的使用(变量名进行使用)
 
//练习
//定义一个int类型的变量,并且赋值为18//使用变量,将变量中的数据打印出来//再次给变量赋值,替换之前的数据//再次打印该变量
  1. 内存图变化
  • 第一步:

  • 第二步:

3.2 变量的注意事项

  • 变量的作用域:

    • 从变量声明的那一行开始,到它所在的大括号结束的区域有效
  • 注意事项:

    • 在变量的作用域内,变量名不允许重复定义
    • 一条语句可以定义多个变量,但需要用逗号进行分割
    • 变量在使用前一定要进行赋值

4. 数据类型

 
问题:
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.举例:
  • 数据类型范围从小到大排序

  1. 隐式转换的细节

    • 不同数据类型进行运算,小的数据类型会提升为大的之后,再参与运算
     
    //买早餐案例
    //买包子,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,再参与运算
 
//案例1byte+short
byte b=10;
short s=29;
//分析:byte+short -> int +int -> int
int num1=m+s;
​
//自案例
//案例2byte+char
char c='a';
//分析:byte+char -> int+int -> int
int num2=b+c;
//案例3byte+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?
  • 精度损失的原因

5. 标识符

 
问题:
1.什么是标识符,有什么作用?
2.标识符的定义规则是什么?
3.标识符常见的命名规定有哪些?
  1. 概述:给类、变量、方法等起名字的符号

  2. 硬性规则(必须得遵守,不遵守,程序就报错):

    1. 由==数字、字母、下划线(_)和美元符($)==其中==一种或多种==组成(也可以由汉字、π组成);
    2. 不能以数字开头;
    3. 不能和关键字相同;
    4. 区分大小写
 
//合法标识符
age
L_ni3
$get
​
//非法标识符
7shang8xia //不能以数字开头
&abc    //&不属于标识符的组成
class   //不能是关键字
  1. 常见命名规定(软性规则)

    • 小驼峰命名法:给变量、方法命名

      • 标识符是一个单词的时候,首字母小写。比如:name
      • 标识符由多个单词组成,首个单词全部小写,其余单词首字母大写。比如:firstName
    • 大驼峰命名法:给类命名

      • 标识符不管多少个单词,每个单词首字母大写,比如:HelloWorld
 
//练习1:以下哪些变量的命名是符合标识符规则的?在注释后面标注
String name="张三";//
int age=17;//
int do=23;//
double π=3.14;//
char $dollar='$';//
char 86RMB='¥';////练习2:使用大驼峰或小驼峰式进行命名
//2.1 定义一个类名,该类用来表示一个学生//2.2 定义一个变量名,用来代表人的年龄//2.3 定义一个变量名,用来代表学生的学号//2.4 定义一个类名,用来代表第一个变量练习的类

6. 键盘录入

  • 学习键盘录入的目的:

    • 可以在程序运行后,将键盘录入的数据获取到程序中操作
  • 实现键盘录入的步骤:

    • 导包:需要在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. 算数运算符

  • 种类

  • 案例
 
//案例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是多少呀?
//试着编译:不报错!

2. 字符的+操作

  • ASCII码表:美国信息交换标准代码

    • 是计算机中,字节到字符的一套对应关系。
    • 在码表中,每一个字符都有一个与之对应的数字。
  • 为什么要有码表呀?

计算机底层所有的数据都是二进制数字,字符也不例外。我们使用电脑能看到的文字都是一个个的字符组成的。那这些字符应该用哪些二进制数字表示呢?如果每个国家都不一样,数据在互联网上就很难在国际上流通了。

所以老美就搞了这么一个标准,大家都共同遵守。

  • 常用的字符码表对照

  • 运算过程

    • char类型在参与数学运算的时候,先查找码表中对应的数字,再参与运算
 
char c='a';
System.out.println(c+1); //结果:98

3. 字符串的+操作

  • 概述:字符串的“==+==”操作不是算数运算,而是字符串拼接运算。
  • 特点:在“==+==”操作的时候,如果出现了字符串,“==+==”就是连接运算符。当连续进行“==+==”操作时,从左往右逐个进行。
 
//案例1:
//做一行爱一行
System.out.println("Java"+520+1314);
//挑几个我喜欢的数字,我喜欢高一点的女孩子,175...
System.out.println(175+120+66+103+56+"Hello");
​

4. 案例:数值拆分

  • 需求:键盘录入一个三位数,将其拆分为个位、十位、百位后,打印在控制台

  • 思路:

    • 使用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);
    }
}

5. 自增自减运算符

大家都玩微信吧?如果有朋友给你发消息,如果你没看,每发一条消息,红点的消息记录就多一条。说明微信有个程序一直再计数,每次增加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. 介绍

注意事项:

  • 可以放在变量的前面,也可以放在变量的后面

  • 如果是单独给变量使用,放前放后都一样(常用操作)

  • 如果参与运算

    • 在前:先对变量进行自增或自减,再拿变量的值参与操作
    • 在后:先拿变量原本的值参与运算,然后变量自己再进行自增或自减。变化后的变量值不参与运算
  • 只能操作变量,不能操作常量

  1. 案例演示

     
    //案例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--//编译报错
  2. 总结

自增自减最后都要给自己加1或者减1,然后会给自己赋值。当然这个赋值运算省略了。说道到赋值,在java中我们已经知道了=是赋值运算符,那除了=之外,还有没有其他的赋值运算符呢?这里可以告诉大家,还有5种赋值运算符。

6. 赋值运算符

  • 介绍

  • 案例演示
 
案例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);

7. 关系运算符

在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

8. 逻辑运算符

国家开始推新冠疫苗啦,让全民接种。但是不是所有人都能打的,在年龄上有限制。规定是只给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

9. 短路逻辑运算符

  • 介绍

  • 与运算:

    • 逻辑与:&,无论左边真假,右边都要执行
    • 短路与:&&,如果左边为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

10. 三元运算符

  • 格式:关系表达式 ? 表达式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最终结果的数据类型必须一致。为什么?如果不一致,三元运算符最后的要赋值的话,拿什么数据类型接收?是不是就无法确定了?
​

分支语句

1. 流程控制语句-顺序结构

  • 介绍:java代码的默认执行流程:从上到下,从左往右

  • 代码案例
 
//案例
//从上往下
System.out.println("我是黑马程序员");
System.out.println("我的目标是月薪过万");
System.out.println("前提是要努力学习,键盘敲烂");
//从左往右
System.out.println("高薪就业!"+"人生巅峰!"+"迎娶白富美!");

2. 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("您输入的成绩有误");
}
​

3. switch分支结构

3.1 格式和执行流程

  • 格式
 
switch(表达式){
    case1:
        语句体1;
        break;
    case2:
        语句体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后面的

    • 值只是常量,不能是变量

3.2 case穿透

  • 注意:在switch语句中,如果case控制的语句体后面不写break,将出现==穿透==现象;
  • 现象:当开始出现case==穿透==,后续的case就不会具有匹配效果,内部的语句不会结束,继续向下执行。直到看到break,或者将整个switch语句执行完毕,switch才会结束
  • 应用:当发现switch语句中,多个case给出的语句体出现重复的时候,就可以考虑使用case穿透来优化代码
 
//案例:键盘录入1~12,代表当前月份。其中3~5是春季,6~8是夏季,9~11是秋季,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;
        }
    }
}

循环语句

循环:重复做某件事情,具有明确的开始和停止标记

1. 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的值,则无法打印5~1,打印的是6~10
    //System.out.println(i);
    //所以不能直接打印i,必须加条件限制,只有当i<=5的时候可以直接打印
    if(i<=5&&i>=1){
        System.out.println(i);
    }
    //如果只有上面的条件限制,则无法阻挡6~10的打印,思考6~10和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;
//因为是求1~5的和,所以要保证能取到1~5这几个数字,并且求和的话是加了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(ge*ge*ge+shi*shi*shi+bai*bai*bai==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(ge*ge*ge+shi*shi*shi+bai*bai*bai==i){
        //5.满足条件的数就是水仙花数,打印的时候注意,第一不要换行,第二要留一个空格隔开
        System.out.print(i+" ");
        //6.每打印一个数字,count的值就得记录1次,值要加1
        count++;
        //7.此时就应该马上判断打印了多少个数字,如果是偶数,马上就要开始换行了
        //8.判断一个数是否是偶数,只需要对2取余数是0就可以了
        if(count%2==0){
            //9.仅仅换行,不打印
            System.out.println();
        }
    }
}

2. 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+"次,达到珠峰高度");

3. 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);
​
  • 特点
  1. do...while循环,无论条件是否满足,都会执行一次循环体语句
  2. 很少用,了解即可

4. 三种循环的区别

  • 三种循环的区别

    • 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);
​

5. 死循环

  • 格式
 
//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强制结束程序而结束循环,这样不推荐
               */
            }
        }
    }
}
/**
* 总结:死循环可以让重复的动作一直执行下去。
* 所以死循环的使用,必须能够具备一个可以让程序根据情况而随时结束循环的操作。
*/

6. 跳转控制语句

  • 概述

    • 跳过当前循环过程,马上进入下一次循环过程:continue
    • 结束当前循环,循环语句结束:break
  • 代码演示

 
//案例1:打印1到10之间的整数,不要把2和4打印出来
for(int i=1;i<=10;i++){
    //i等于2和4都不能打印,所以必须加条件判断限制
    if(i==2||i==4){
        //当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,无法结束循环

7. 循环标号

  • 总结:break和continue只能跳出、跳过自己所在的那一层关系,如果想要跳出、跳过指定的一层,可以加入标号
  • 示例
 
标号名:while(true){
    switch(表达式){
        case1:
            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)的随机数范围是0~15,在这个范围上加1,范围就变成了1~16
            int num = random.nextInt(16) + 1;
            //6.如果随机数是6,就获得一等奖
            if (num == 6) {
                System.out.println("恭喜你获得一等奖,奖品是:李小璐亲自为你做头发");
                //7.结束循环
                break;
            }
        }
    }

数组

是一种==容器==,用来存储(==同种数据类型==)的多个值。

1. 数组定义格式

  • 格式
 
//数组类型变量的声明方式1:
数据类型[] 数组名;
//数组乐行变量的声明方式2:
数据类型 数组名[];
  • 代码演示
 
//声明一个用来存放int类型数据的数组
int[] arrs;
//或
int arrs[];
​
//声明一个用来存放double类型数据的数组
double[] nums;
//或
double nums[];
​
//声明一个用来存放String类型数据的数组
String[] strs;
//或
String strs[];
​
//注意:数组类型变量和基本数据类型的变量一样,都必须先初始化,才能使用

2. 数组的动态初始化

  1. 初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
  2. 动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
  3. 格式
 
//格式
数据类型[] 变量名= new 数据类型[数组长度];
//范例
int[] arr= new int[3];
  1. 代码演示
 
//案例:
//利用数组的冬天初始化,创建一个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进制内存地址值
*/

3. 数组元素访问

  • 索引

    • 索引是数组中空间的编号

      • 索引从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

4. 一个数组内存图

  1. 栈内存:方法运行时,进入的内存,局部变量都存放于这块内存中
  2. 堆内存:new出来的内容都会进入堆内存,并且会存在地址值
  3. 方法区:字节码文件(.class文件)加载时进入的内存
  4. 本地方法栈:调用操作系统相关资源
  5. 寄存器:交给CPU去使用

5. 两个数组内存图

 
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]);

6. 多个数组指向相同内存图

 
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]);

7. 数组的静态初始化

  • 静态初始化:初始化时指定每个数组元素的初始值,由系统决定数组长度
  • 格式范例
 
//完整格式
//数据类型[] 数组名=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 = {6688};
System.out.println(arr[0]);//结果:66
System.out.println(arr[1]);//结果:88
  • 两种初始化的使用场景

    • 动态初始化:只明确元素个数,不明确具体数值,推荐使用动态初始化。

      • 要存的数据,在创建数组前还不知道是什么,比如需要键盘录入的数据。只知道要录入几个。
    • 静态初始化:需求中已经明确了要操作的具体数据,直接静态初始化即可

      • 要存的数据,在数组创建的时候已经有了,比如将全班学员的成绩存入数组

8. 数组操作的两个常见问题

  • 索引越界异常:访问了数组中不存在的索引,造成索引越界异常
 
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]);
    }
}

9. 数组遍历

  • 格式
 
//数组定义及初始化
int[] arr={......};
//...
//遍历数组
for(int i=0;i<arr.length;x++){
    //arr[i],获取到的就是数组对应索引为i的数据
    //由于i的值从0开始,逐一增加,所以每次循环就能获得一个数组数据,循环结束,数组数据也都拿了一遍
    // arr[i];
    //至于拿出来的数据是直接打印,还是用一个变量接收,用作后面使用,完全看需求决定
}
  • 注意

    • 遍历数组,是指取出数组中所有数据的一个过程,不能局限理解为就是打印数组数据

10. 数组获取最大值

 
求最值的思路:
    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); 

11. 数组元素求和

  • 需求:键盘录入5个整数,存储到数组中,并对数组求和

  • 思路

    1. 创建键盘录入对象,准备键盘录入数字
    2. 定义一个求和变量,准备记录累加后的值
    3. 动态初始化一个长度为5的int数组,准备存储键盘录入的数据
    4. 将键盘录入的数值存储到数组中
    5. 遍历数组,取出每一个元素,并求和
    6. 输出总和
  • 代码演示

 
//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);

12. 数组基本查找

  • 需求:已知一个数组==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); 
}

13. 评委打分

  • 需求

  • 思路

  • 代码实现
 
//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);

二维数组

1. 概述

  • 概述:二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器

  • 为什么要有二维数组:

    • 假设给一个学校做一个学生管理系统,该学校有6个年级,每个年级10跟班,每个班60个学生。需要用数组存放这些学生的数据
    • 如果我们把这些学生数据存放在一个数组里面,这个数组的数据过于庞大,你要到里面找对应学生的成绩会很困难
    • 如果一个班级成绩装一个数组,通过班级去找学生,会简单一点
    • 但是这些数组如果不统一管理,还要判断学生是哪个年级
    • 所以如果用一个长度为6的数组,每个索引位置存放一个年纪的数据,那管理起来就很方便了
    • 比如我要找3年级2班的张三成绩,那就是先找到三年级,再找到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;

3. 访问元素的细节问题

 
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]);

1620030796518

4. 静态初始化

 
//格式:数据类型[][] 变量名={{元素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

5. 案例:遍历

  1. 需求:已知一个二维数组arr = {{11, 22, 33}, {33, 44, 55,}};遍历该数组,取出所有元素并打印
  2. 思路:

1620031378645

  1. 代码实现
 
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]);
    }
}

6. 案例:求和

  1. 需求:某公司季度和月份统计的数据如下:单位(万元)

    • 第一季度:22 , 66 , 44
    • 第二季度:77 , 33 , 88
    • 第三季度:25 , 45 , 65
    • 第四季度:11 , 66 , 99
  2. 思路:

  1. 代码实现
 
//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);

方法

1. 概述

  • 概述:就是一段具有独立功能的代码块,不调用就不执行

  • 作用:

    • 如果程序里面有好几段内容是需要实现相同功能,不使用方法的话,会导致有大量重复的代码。这种重复代码每次都要重新写一遍。所以如果==不用方法==,代码的==重复度太高,复用性太差==
    • 方法的出现,把重复代码变成类似于‘共享单车’的存在,谁有需要就直接用。提高了代码的复用性
  • 前提:

    • 方法必须是先创建才可以使用,该过程称为==方法定义==
    • 方法创建后并不是直接运行的,需要手动在代码中调用后才可以执行,该过程称为==方法调用==

2. 方法的定义和调用

  • 格式
 
//方法定义格式(无参数、无返回值的公共静态方法)
public static void 方法名(){
    //方法体:就是需要复用(被反复使用)的逻辑代码
}
//范例
public static void printHello(){
    System.out.println("Hello method!");
}
​
//方法调用:方法名();
//范例:
public static void main(String[] args) {
    printHello();
}
  • 注意事项

    • 方法必须先定义后调用,否则程序将报错

    • 方法与方法之间是平级关系,不能嵌套定义

3. 方法的调用过程

  • 方法没有被低调用的时候,都在方法区中的字节码文件(.class)中存储
  • 方法被调用的时候,需要进入到栈内存中运行

4. 练习:奇偶数判断

  1. 需求

  1. 思路

  1. 代码演示
 
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("奇数");
    }
}

5. 带参数方法的定义和调用

  • 为什么要有带参数方法

    • 当方法内部逻辑有用到需要根据不同用户,不同需求去变化的值的时候,就可以定义带参数方法,把这种可能会改变的值用方法的参数替代
  • 带参数方法的定义

 
//单个参数
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类型的数字,判断哪个数字是最大值,打印最大值
* 在主方法中调用
*/
​
​

6. 形参和实参

  1. 概念

    • 形参:形式参数,是指方法==定义==中的参数
    • 实参:实际参数,方法==调用==中的参数

7. 带参数方法的练习:打印n~m之间所有的奇数

  • 需求:设计一个方法(print)用于打印n到m之间所有的奇数
  • 思路:

  • 代码演示

8. 带返回值方法的定义和调用

  • 为什么要有带返回值的方法

    • 我们经常会根据一个方法产出的结果,来去组织另外一段代码逻辑,为了拿到这个方法产生的结果,就需要定义带有返回值的方法
  • 带返回值方法的定义

  • 带返回值方法的调用

  • 代码演示
 
//案例:计算两个数的乘积
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;
}

9. 带返回值方法的练习:求两个数的最大值

  • 需求:设计一个方法可以获取两个数的较大值,数据来自于参数
  • 思路:

  • 代码实现
  • 扩展练习
 
//仿照课堂案例,求三个数的最大值
​
​

10. 方法通用格式

  • 格式

  • 代码演示

11. 方法的注意事项

  • 方法不能嵌套定义
  • 方法的返回值类型为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("喝红牛");
}

12. 方法重载

  • 概念:在同一个类中,方法名相同,参数列表不同(==参数顺序不同也算不同,变量名不同不算==)的多个方法,形成了方法的重载。
  • 方法签名:JVM调用方法的时候是通过==方法签名==去区分的,方法签名包括方法名,参数数量、类型和顺序
  • 注意:参数顺序不同虽然也可以构成方法重载,但是不推荐,没有意义

13. 方法重载练习

  • 需求:使用方法重载的思想,设计比较两个整数是否相同的方法,兼容全整数类型(byte,short,int,long)
  • 思路:

  • 代码练习

14. 方法参数传递:基本数据类型

  • 方法的形参在内存当中也就是一个变量而已
  • 一个方法在传递参数的时候,如果是基本数据类型,那么传递的就是该变量所记录的具体的数值
 
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
}

15. 方法参数传递:引用数据类型

  • 方法传递,如果传入的是引用数据类型,传进去的就是该引用数据类型的内存地址
 
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
}

16. 案例:数组遍历

  • 需求:设计一个方法,用于数组遍历,要求遍历的结果是在一行上的。例如:[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 + ", ");
        }
    }
}

17. 案例:获取数组最大值

  • 需求:设计一个方法用于获取数组中元素的最大值
  • 思路:

  • 代码演示:

18. 案例:方法同时获取数组最大值和最小值

  • 需求:设计一个方法,该方法能够同时获取数组的最大值,和最小值
  • 思路:

  • 代码演示:

基础练习

1. 逢七跳过

案例需求

​ 朋友聚会的时候可能会玩一个游戏:逢七过。​ 规则是:从任意一个数字开始报数,当你要报的数字包含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);
            }
        }
    }
}

2. 数组元素求和

案例需求

​ 有这样的一个数组,元素是{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);
    }
}

3. 判断两个数组是否相同

案例需求

​ 定义一个方法,用于比较两个数组的内容是否相同

代码实现

 
/*
    思路:
        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;
    }
}

4. 查找元素在数组中出现的索引位置

案例需求

​ 已知一个数组 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;
    }
}

5. 数组元素反转

案例需求

​ 已知一个数组 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. 评委打分

案例需求

​ 在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。​ 选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。

代码实现

思路:

1:定义一个数组,用动态初始化完成数组元素的初始化,长度为6

2:键盘录入评委分数

3:由于是6个评委打分,所以,接收评委分数的操作,用循环改进

4:定义方法实现获取数组中的最高分(数组最大值),调用方法

5:定义方法实现获取数组中的最低分(数组最小值) ,调用方法

6:定义方法实现获取数组中的所有元素的和(数组元素求和) ,调用方法

7:按照计算规则进行计算得到平均分

8:输出平均分

7. 随机产生验证码

案例需求

请从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.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. 对象内存图

2.1 单个对象内存图

  • 有new就在堆内存开辟空间,对象就是堆内存的一个块空间,存储有对象的属性值和方法调用地址
  • 对象的变量名存储的其实是对象在堆内存空间的地址值,jvm虚拟机可以根据地址值找到对象空间
  • 能找到对象空间,从而能获取对象的属性数据,调用对象的方法

2.2 两个对象内存图

  • 有几个new,就会在堆内存开辟几个对象空间
  • 同一个类的不同对象空间中属性名字都是一样的,但是其存储的属性数据相互独立
  • 同一个类的不同对象空间中方法地址一样,所以调用的方法也是一样的

2.3 两个引用指向同一个对象内存图

  • 代码执行到Student stu2=stu1;的时候,通过s1指向的堆内存中对象的地址,将s2也指向这个地址,所以s1和s2都指向同一个对象

  • 代码执行到stu1=null;的时候,stu1原本持有的是堆内存中学生对象的地址,由于置null,此指向切断了。s1再也无法找到堆内存中该学生对象
  • 在执行完stu2=null;之后,就没有变量再指向堆内存中的学生对象,此对象无法再被使用到。所以垃圾回收器会在空闲的时候将这个学生对象的空间给清理掉
  • 当堆内存中,==对象==或==数组==产生的地址,通过任何方式都不能被找到后,就会判定为内存中的"垃圾",垃圾会被Java垃圾回收器,空闲的时候自动进行清理

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

  • 成员变量:类中方法外定义的变量
  • 局部变量:方法中的变量
  • 成员变量和局部变量的区别

4. 封装

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. 构造方法

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方法可以反复修改同一个对象的值,作用不一样
    }
}

1. 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());
}

2. String类

2.1 String概述

 
问题:
1.如果使用的是java.lang包下的类,是否需要进行导包?
2.在创建String类对象的时候,它有什么特殊的地方?
3.String类的length()方法返回的长度是根据什么得到的?
  1. String 类在==java.lang==包下,所以使用的时候不需要导包
  2. String 类代表==字符串==,,==Java 程序中所有的双引号字符串,都是 String 类的对象==
  3. ==字符串不可变,它们的值在创建后不能被更改==,如果给一个字符串变量重新赋值了一个字符串常量,不是修改了对象,而是重新指向了一个新的对象

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);//结果:true
​
String 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 用户登录案例

案例需求 :

  • 已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示

实现步骤 :

  1. 已知用户名和密码,定义两个字符串表示即可
  2. 键盘录入要登录的用户名和密码,用 Scanner 实现
  3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
  4. 字符串的内容比较,用equals() 方法实现
  5. 用循环实现多次机会,这里的次数明确,采用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 遍历字符串案例

案例需求 :

​ 键盘录入一个字符串,使用程序实现在控制台遍历该字符串

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 遍历字符串,首先要能够获取到字符串中的每一个字符, public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的
  3. 遍历字符串,其次要能够获取到字符串的长度, public int length():返回此字符串的长度
  4. 遍历打印

核心方法:

  • 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 统计字符次数案例

案例需求 :

​ 键盘录入一个字符串,使用程序实现在控制台遍历该字符串

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 将字符串拆分为字符数组 , public char[] toCharArray( ):将当前字符串拆分为字符数组并返回
  3. 遍历字符数
  4. 操作字符串中字符,一般情况下,先将字符串转换成字符数组,然后遍历操作
  5. 对于大写字母、小写字母、数字字符,这些字符对应的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 手机号屏蔽-字符串截取

案例需求 :

​ 以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽​ 最终效果为:156********1234

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 截取字符串前三位
  3. 截取字符串后四位
  4. 将截取后的两个字符串,中间加上进行拼接,输出结果
  5. substring(int index):从字符串中截取,从index索引位置一直截取到最后
  6. 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),则使用***替换

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 替换敏感词 String replace(CharSequence target, CharSequence replacement) 将当前字符串中的target内容,使用replacement进行替换,返回新的字符串 CharSquence:以后如果你看到方法的形式参数是它,说明就丢字符串进去就可以了。它是字符串的干爹。
  3. 输出结果

代码实现 :

 
//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学生对象

实现步骤 :

  1. 编写Student类,用于封装数据

  2. 键盘录入一个字符串,用 Scanner 实现

  3. 根据逗号切割字符串,得到(张三)(23)

    1. String[] split(String regex) :根据传入的字符串作为规则进行切割

      • 注意:字符串regex如果是==.==,请使用==.==
    2. 将切割后的内容存入字符串数组中,并将字符串数组返回

  4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象

  5. 调用对象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[]根据传入的规则切割字符串,得到字符串数组

3. 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]
  • 实现步骤 :

    1. 定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
    2. 定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。 返回值类型 String,参数列表 int[] arr
    3. 在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
    4. 调用方法,用一个变量接收结果
    5. 输出结果
  • 代码实现 :

 
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();
    }
}

​ 1. 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 :

​ 可调整大小的数组实现

​ : 是一种特殊的数据类型,泛型。

​ 泛型可以代表一种不确定的类型,类型的确定在声明这个类的变量的时候

​ 注意,不是所有的类都可以加泛型哦。目前你只在ArrayList后面加泛型

怎么用呢 ?

​ 在出现E的地方我们使用引用数据类型替换即可

​ 举例:ArrayList, ArrayList

  • 练习:
 
/**
 * 创建一个可以存储字符串类型数据的ArrayList集合对象
 * 向集合中添加三个元素:hello  world  java
 * 向集合中2索引处添加一个JavaSE
 */
ArrayList<String> 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个字符串元素,使用程序实现在控制台遍历该集合

实现步骤 :

  1. 创建集合对象

    1. 往集合中添加字符串对象

      1. 遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
      2. 遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
      3. 遍历集合的通用格式

代码实现 :

 
//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. 定义学生类

    1. 创建集合对象

      1. 创建学生对象
      2. 添加学生对象到集合中
      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个学生对象,使用程序实现在控制台遍历该集合

​ 学生的姓名和年龄来自于键盘录入

实现步骤 :

  1. 定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型
  2. 创建集合对象
  3. 键盘录入学生对象所需要的数据
  4. 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
  5. 往集合中添加学生对象
  6. 遍历集合,采用通用遍历格式实现

代码实现 :

 
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字符串,删除后,将集合剩余元素打印在控制台

实现步骤 :

  1. 创建集合对象
  2. 调用add方法,添加字符串
  3. 遍历集合,取出每一个字符串元素
  4. 加入if判断,如果是test字符串,调用remove方法删除
  5. 打印集合元素

代码实现:

 
//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;
    }
}