Java学习——黑马程序员

Java学习——黑马程序员(更)

编辑时间:2023/10/27
来源:b站黑马程序员

Java入门

1.Java应用六大领域:
桌面应用开发,企业级应用开发,移动应用开发,科学计算,大数据开发,游戏开发。
2.Java的主要特性
面向对象、安全性、多线程、简单易用、开源、跨平台。
3.Java三大版本
JavaSE Java语言版本(标准版),用于桌面应用开发,需要其他两个版本的基础
JavaME Java语言的(小型版),用于嵌入式电子设备或小型移动设备。
JavaEE Java语言的(企业版),用于web方向的网站开发。

4.java的主要特性
面向对象、跨平台、开源、安全性、多线程、简单用

编程:Java程序写的Java代码,c程序员写的c代码,Python程序员写的py代码
编译:把Java.c.py的代码做转化让机器认识的过程
运行:让机器执行编译后的指令
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5.JRE和JDK
JVM(java Virtual Machine):java虚拟机。真正运行Java顺序的地方

1.JDK是什么?有哪些内容组成
JDK是Java开发工具包
JVM虚拟机:Java程序运行的地方
核心类库:Java已经写好的东西,可以直接使用
开发工具:javac(编译工具)、Java(运行工具)、jdb(调试工具)、jhat(内存分析工具)… …
2.JRE是什么?有哪些内容组成
JRE是java运行环境
JVM、核心类库、运行工具
3.JDK、JRE、JVM三者包含关系
JDK包含JRE
JRE包含JVM

6.IDEA
1.IDEA结构分类

  • project项目 工程
  • moudle模块
  • package包
  • class类

Java入门——常用的CMD命令

1.打开CMD
CMD:在windows中利用命令行的方式操作计算机
快捷键:win+R ——>输入CMD——>回车

2.常见CMD命令
盘符名称+冒号 说明:盘符切换

E:

dir 说明:查看的钱路径下的内容

dir

cd目录 说明:进入到单级文件夹
cd 目录1\目录2…

cd a.txt

cd… 说明:回退到上一级目录

cd..

cd \ 说明:回退到盘符目录

cd \

cls 说明:清屏

cls

exit 说明:退出命令行提示窗口

exit

3.利用CMD打开qq练习
配置环境变量:我们想要在任意目录下都可以打开指定的软件,可以把软件的路径配置到环境变量中。
将qq的路径记录到系统环境变量的path路径下,让后在cmd直接输入qq.exe回车。

Java入门——运行第一个HelloWorld案件

1.Java安装目录介绍
在这里插入图片描述
2.cmd编译运行
编译:Javac是JDK提供编译的工具,我们可以通过这个工具把当前路径下的HelloWorld.java文件编译成class文件
运行:Java也是JDK 提供的一个工具作用是用来运行代码的。运行是当前路径下的HelloWorld.class文件,在运行的时候是不加后缀名的。

javac HelloWorld.java
java HelloWorld

Java基础概念

Java基础概念——注释和关键字

注释:注释就是对代码进行解释说明的文字;可分为单行注释多行注释和文档注释;注释使用的细节为注释的内容不参与编译和运行,仅仅是对代码的解释说明,注意注释不要嵌套。

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

注意:如果我们要对代码进行解释,那么就可以使用注释。 当注释的内容比较少,一行就写完了,可以用单行注释。 如果注释的内容比较多,需要写在多行,那么可以使用多行注释。注意点 注释的内容不会参与编译和运行的,仅仅是对代码的解释说明而已。 所以,不管在注释当中写什么内容,都不会影响代码运行的结果。

关键字:被Java赋予了特定语义的英文单词
关键字的字母都全部小写,常用的代码编辑器对关键字有特殊标记。

abstract	assert	boolean	break	byte
case	catch	char	class	const
continue	default	do	double	else
enum	extends	final	finally	float
for	goto	if	implements	import
instanceof	int	interface	long	native
new	package	private	protected	public
return	strictfp	short	static	super
switch	synchronized	this	throw	throws
transient	try	void

Java基础概念——字面量

在这里插入图片描述
注意:null不能直接打印,除非是将它用字符串串起来才能打印"null"

拓展点:
1.区分技巧

  • 不带小数点的数字都是整数类型的字面量。 只要带了小数点,那么就是小数类型的字面量。
  • 只要用双引号引起来的,不管里面的内容是什么,不管里面有没有内容,都是字符串类型的字面量。
  • 字符类型的字面量必须用单引号引起来,不管内容是什么,但是个数有且只能有一个。 字符类型的字面量只有两个值,true、false。
  • 空类型的字面量只有一个值,null。

2.\t 制表符 :缩进、对齐、大空格
在这里插入图片描述

Java基础概念——变量

1.基本用法
变量的定义格式数据类型 变量名 =数据值
数据类型:限定了变量能存储数据的类型
变量名:存储空间的名字
数据值:真正存在变量中的数据
等号:赋值作用,把右边的数值赋给左边的变量
2.变量的使用方式
输出打印、参与计算、修改记录值
3.变量的注意事项
只能存放一个值、变量名不允许重复定义、一条语句可以定义多个变量、变量是使用之前一定要进行赋值

Java基本概念——计算机中的存储

1.计算机存储规则:计算机用的是二进制形式进行存储数据。
在这里插入图片描述

2.进制转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三原色小结:

  1. 计算机中事务颜色采用光学三原色
  2. 分别为红绿蓝。也称为RGB
  3. 可以写成十进制(255,255,255)
  4. 也可以写成十六进制(FFF,FFF,FFF)

在这里插入图片描述

Java基础概念——数据类型

分类

  1. 基本数据类型
  2. 引用数据类型

基本数据类型分类
在这里插入图片描述

小结:
1.Java语言的数据类型分为:基本数据类型,引用数据类型
2.基本数据类型有8种
3.byte的取值分为-128~127
4.大小关系:double>float>long>int>short>byte
5.long类型变量:需要加入L标识(大小写都可以)
float类型变量:需要加入F标识(大小写都可以)

public class VariableDemo3{
    public static void main(String[] args){
        //1.定义byte类型的变量
        //数据类型 变量名 = 数据值;
        byte a = 10;
        System.out.println(a);

        //2.定义short类型的变量
        short b = 20;
        System.out.println(b);

        //3.定义int类型的变量
        int c = 30;
        System.out.println(c);

        //4.定义long类型的变量
        long d = 123456789123456789L;
        System.out.println(d);

        //5.定义float类型的变量
        float e = 10.1F;
        System.out.println(e);

        //6.定义double类型的变量
        double f = 20.3;
        System.out.println(f);

        //7.定义char类型的变量
        char g = 'a';
        System.out.println(g);

        //8.定义boolean类型的变量
        boolean h = true;
        System.out.println(h);

    }
}

Java基础概念——标识符

硬性要求:
必须由数字、字母、下划线_、美元符号$组成。
数字不能开头
不能是关键字
区分大小写的。
软件建议:
1 小驼峰命名法
适用于变量名和方法名
如果是一个单词,那么全部小写,比如:name
如果是多个单词,那么从第二个单词开始,首字母大写,比如:firstName、maxAge
2 大驼峰命名法
适用于类名
如果是一个单词,那么首字母大写。比如:Demo、Test。
如果是多个单词,那么每一个单词首字母都需要大写。比如:HelloWorld

Java基础概念——键盘录入

使用步骤:
第一步:
​ 导包:其实就是表示先找到Scanner这个类在哪。
第二步:
​ 创建对象:其实就表示申明一下,我准备开始用Scanner这个类了。
第三步:
​ 接收数据:也是真正干活的代码。

代码示例:

//导包,其实就是先找到Scanner这个类在哪
import java.util.Scanner;
public class ScannerDemo1{
	public static void main(String[] args){
		//2.创建对象,其实就是申明一下,我准备开始用Scanner这个类了。
		Scanner sc = new Scanner(System.in);
		//3.接收数据
		//当程序运行之后,我们在键盘输入的数据就会被变量i给接收了
		System.out.println("请输入一个数字");
		int i = sc.nextInt();
		System.out.println(i);
	}
}

Java基础概念——键盘录入进阶

一,键盘录入涉及到的方法如下:

 next()、nextLine()、nextInt()、nextDouble()。

1)next()、nextLine():
可以接受任意数据,但是都会返回一个字符串。
比如:键盘录入abc,那么会把abc看做字符串返回。
键盘录入123,那么会把123看做字符串返回。
代码示例:

Scanner sc = new Scanner(System.in);
String s = sc.next();//录入的所有数据都会看做是字符串
System.out.println(s);
代码示例:
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();//录入的所有数据都会看做是字符串
System.out.println(s);

2)nextInt():
只能接受整数。
比如:键盘录入123,那么会把123当做int类型的整数返回。
键盘录入小数或者其他字母,就会报错。
代码示例:

Scanner sc = new Scanner(System.in);
int s = sc.nextInt();//只能录入整数
System.out.println(s);
3)nextDouble():
 能接收整数和小数,但是都会看做小数返回。
 录入字母会报错。
代码示例:
Scanner sc = new Scanner(System.in);
double d = sc.nextDouble();//录入的整数,小数都会看做小数。
						//录入字母会报错
System.out.println(d);

二,方法底层细节 :
第一个细节:
next(),nextInt(),nextDouble()在接收数据的时候,会遇到空格,回车,制表符其中一个就会停止接收数据。
代码示例:

Scanner sc = new Scanner(System.in);
double d = sc.nextDouble();
System.out.println(d);
//键盘录入:1.1 2.2//注意录入的时候1.1和2.2之间加空格隔开。
//此时控制台打印1.1
//表示nextDouble方法在接收数据的时候,遇到空格就停止了,后面的本次不接收。
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
System.out.println(i);
//键盘录入:1 2//注意录入的时候1和2之间加空格隔开。
//此时控制台打印1
//表示nextInt方法在接收数据的时候,遇到空格就停止了,后面的本次不接收。
Scanner sc = new Scanner(System.in);
String s = sc.next();
System.out.println(s);
//键盘录入:a b//注意录入的时候a和b之间加空格隔开。
//此时控制台打印a
//表示next方法在接收数据的时候,遇到空格就停止了,后面的本次不接收。

第二个细节:
next(),nextInt(),nextDouble()在接收数据的时候,会遇到空格,回车,制表符其中一个就会停止接收数据。但是这些符号 + 后面的数据还在内存中并没有接收。如果后面还有其他键盘录入的方法,会自动将这些数据接收。
代码示例:

Scanner sc = new Scanner(System.in);
String s1 = sc.next();
String s2 = sc.next();
System.out.println(s1);
System.out.println(s2);
//此时值键盘录入一次a b(注意a和b之间用空格隔开)
//那么第一个next();会接收a,a后面是空格,那么就停止,所以打印s1是a
//但是空格+b还在内存中。
//第二个next会去掉前面的空格,只接收b
//所以第二个s2打印出来是b
第三个细节:
nextLine()方法是把一整行全部接收完毕。
代码示例:
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(s);
//键盘录入a b(注意a和b之间用空格隔开)
//那么nextLine不会过滤前面和后面的空格,会把这一整行数据全部接收完毕。

三、混用引起的后果
上面说的两套键盘录入不能混用,如果混用会有严重的后果。
代码示例:

Scanner sc = new Scanner(System.in);//①
int i = sc.nextInt();//②
String s = sc.nextLine();//③
System.out.println(i);//④
System.out.println(s);//⑤

当代码运行到第二行,会让我们键盘录入,此时录入123。
但是实际上我们录的是123+回车。
而nextInt是遇到空格,回车,制表符都会停止。
所以nextInt只能接受123,回车还在内存中没有被接收。
此时就被nextLine接收了。
所以,如果混用就会导致nextLine接收不到数据。
四、结论(如何使用)
键盘录入分为两套:
next()、nextInt()、nextDouble()这三个配套使用。
如果用了这三个其中一个,就不要用nextLine()。
nextLine()单独使用。
如果想要整数,那么先接收,再使用Integer.parseInt进行类型转换。
代码示例:

Scanner sc = new Scanner(System.in);
String s = sc.next();//键盘录入123
System.out.println("此时为字符串" + s);//此时123是字符串
int i = sc.nextInt();//键盘录入123
System.out.println("此时为整数:" + i);
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();//键盘录入123
System.out.println("此时为字符串" + s);//此时123是字符串
int i = Integer.parseInt(s);//想要整数再进行转换
System.out.println("此时为整数:" + i);

运算符

运算符:
​ 就是对常量或者变量进行操作的符号。

​ 比如: + - * /

表达式:
​ 用运算符把常量或者变量连接起来的,符合Java语法的式子就是表达式。

​ 比如:a + b 这个整体就是表达式。

​ 而其中+是算术运算符的一种,所以这个表达式也称之为算术表达式。

运算符——算术运算符详解和综合练习

分类+ - * / %
运算特点:
1.+ - */ :跟小学数学中一模一样没有任何区别.
2.整数相除结果只能得到整除,如果结果想要是小数,必须要有小数参数。
3.小数直接参与运算,得到的结果有可能是不精确的。
案例:

System.out.println( 10 / 3);//3
System.out.println(10.0 / 3);//3.3333333333333335

4.%:取模、取余。
他做的也是除法运算,只不过获取的是余数而已。
案例:

System.out.println(10 % 2);//0
System.out.println(10 % 3);//1

应用场景:

//可以利用取模来判断一个数是奇数还是偶数
System.out.println(15 % 2);//1  奇数

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

公式:

​ 获取任意一个数上每一位数。

个位:数字 % 10

十位:数字 / 10 % 10

百位:数字 / 100 % 10

千位:数字 / 1000 % 10

。。。以此类推。。。
代码示例:

//1.键盘录入一个三位数
//导包 --- 创建对象 --- 接收数据
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个三位数");
int number = sc.nextInt();//123

//2.获取这个三位数的个位、十位、百位并打印出来
//公式:
//针对于任意的一个数而言
//个位: 数字 % 10
int ones = number % 10;
//十位: 数字 / 10 % 10
int tens = number / 10 % 10;
//百位: 数字 / 100 % 10
int hundreds = number / 100  % 10;

//输出结果
System.out.println(ones);
System.out.println(tens);
System.out.println(hundreds);

运算符——隐式转换和强制转换

1.隐式转换概念:
也叫自动类型提升。就是把一个取值范围小的数据或者变量,赋值给另一个取值范围大的变量。程序自动帮我们完成的。

简单记忆:
​ 就是小的给大的,可以直接给。
两种提升规则:
1.取值范围小的,和取值范围大的进行运算,小的会先提升为大的,再进行运算。
2.byte、short、char三种类型的数据在运算的时候,都会直接先提升为int,然后再进行运算。
3.取值范围从小到大的关系:
​ byte <short< int <long <float <double

隐式转换的练习
请看下面案例是否有误,如果有问题,请说出原因,如果没有问题,请说出运算过程和运算结果

2.强制转换概念
​ 如果要把一个取值范围大的数据或者变量赋值给另一个取值范围小的变量。是不允许直接操作。如果一定要这么干,就需要加入强制转换。

书写格式:目标数据类型 变量名 = (目标数据类型)被强转的数据;

简单理解:

​ 要转成什么类型的,那么就在小括号中写什么类型就可以了。

案例:

public class OperatorDemo2 {
    public static void main(String[] args) {
        double a = 12.3;
        int b = (int) a;
        System.out.println(b);//12
    }
}

注意点:

​ 强制转换有可能会导致数据发生错误。(数据的精度丢失)

运算符——字符串和字符的加操作

1.字符串的+操作
核心技巧:

  • 当+操作中出现字符串时,此时就是字符串的连接符,会将前后的数据进行拼接,并产生一个新的字符串。
  • 当连续进行+操作时,从左到右逐个执行的。

2.字符的+操作
规则:
​ 当+操作中出现了字符,会拿着字符到计算机内置的ASCII码表中去查对应的数字,然后再进行计算。

案例:

char c = 'a';
int result = c + 0;
System.out.println(result);//97

运算符——算术运算符的总结

1.分类:

+ - * / % 这些操作跟小学数学几乎是一模一样的。
2.注意点:

1./ 和 % 的区别:他们两个都是做除法运算,/取结果的商。% 取结果的余数。
2.整数操作只能得到整数,如果想要得到小数,必须有浮点数参与运算。
3.算术运算符的高级用法:是以+为例进行的讲解,其余减法,乘法,除法的运算规则也是一样的。
3.特例:字符串只有+操作,没有其他操作。

运算符——自增自减运算符

分类:
++ 自增运算符
-- 自减运算符
++:就是把变量里面的值+1
--:就是把变量里面的值-1
使用方式:
放在变量的前面,我们叫做先++。 比如:++a
放在变量的后面,我们叫做后++。 比如:a++
注意点:
​ 不管是先++,还是后++。单独写在一行的时候,运算结果是一模一样的。
案例:

//++
int a = 10;
a++;//就是让变量a里面的值 + 1
System.out.println(a);//11
++a;//就是让变量a里面的值 + 1
System.out.println(a);//12

运算符——赋值运算符和关系运算符

1.赋值运算符:最为常用的: =

运算过程:就是把等号右边的结果赋值给左边的变量

案例:

public class OperatorDemo6 {
    public static void main(String[] args) {
        //1.最为简单的赋值运算符用法
        int a = 10;//就是把10赋值给变量a
        System.out.println(a);

        //2.如果等号右边需要进行计算。
        int b = 20;
        int c = a + b;//先计算等号右边的,把计算的结果赋值给左边的变量
        System.out.println(c);

        //3.特殊的用法
        a = a + 10;//先计算等号右边的,把计算的结果赋值给左边的变量
        System.out.println(a);//20
    }
}

2.扩展赋值运算符
分类:+=、-=、*=、/=、%=

运算规则:
​ 就是把左边跟右边进行运算,把最终的结果赋值给左边,对右边没有任何影响。

案例:

public class OperatorDemo7 {
    public static void main(String[] args) {
        //扩展赋值运算符
        int a = 10;
        int b = 20;
        a += b;//把左边和右边相加,再把最终的结果赋值给左边,对右边没有任何影响
        // 相当于 a = a + b;
        System.out.println(a);//30
        System.out.println(b);//20
    }
}

注意点:
​ 扩展的赋值运算符中隐层还包含了一个强制转换。

+=为例。

a += b ;实际上相当于 a = (byte)(a + b);
public class OperatorDemo8 {
    public static void main(String[] args) {
        byte a = 10;
        byte b = 20;
        //a += b;
        a = (byte)(a + b);
        System.out.println(a);//30
    }
}

3.关系运算符
又叫比较运算符,其实就是拿着左边跟右边进行了判断而已。

分类:
符号 解释
==就是判断左边跟右边是否相等,如果成立就是true,如果不成立就是false
!= 就是判断左边跟右边是否不相等,如果成立就是true,如果不成立就是false
> 就是判断左边是否大于右边,如果成立就是true,如果不成立就是false
>=就是判断左边是否大于等于右边,如果成立就是true,如果不成立就是false
<就是判断左边是否小于右边,如果成立就是true,如果不成立就是false
<=就是判断左边是否小于等于右边,如果成立就是true,如果不成立就是false
注意点:
关系运算符最终的结果一定是布尔类型的。要么是true,要么是false
在写==的时候,千万不要写成=

运算符——四种逻辑运算符

& 和 | 的使用:
&:逻辑与(而且)

​ 两边都为真,结果才是真,只要有一个为假,那么结果就是假。

|:逻辑或(或者)

​ 两边都为假,结果才是假,只要有一个为真,那么结果就是真。

代码示例:

// &  //两边都是真,结果才是真。
System.out.println(true & true);//true
System.out.println(false & false);//false
System.out.println(true & false);//false
System.out.println(false & true);//false

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

// | 或  //两边都是假,结果才是假,如果有一个为真,那么结果就是真。
System.out.println(true | true);//true
System.out.println(false | false);//false
System.out.println(true | false);//true
System.out.println(false | true);//true

^(异或)的使用:
​ 在以后用的不多,了解一下即可。

计算规则:如果两边相同,结果为false,如果两边不同,结果为true

代码示例:

//^   //左右不相同,结果才是true,左右相同结果就是false
System.out.println(true ^ true);//false
System.out.println(false ^ false);//false
System.out.println(true ^ false);//true
System.out.println(false ^ true);//true

!(取反)的使用:
​ 是取反,也叫做非。

计算规则:false取反就是true,true取反就是false

温馨提示:取反最多只用一个。

代码示例:

System.out.println(!false);//true
System.out.println(!true);//false

System.out.println(!!false);//注意点:取反最多只用一个。

运算符——短路逻辑运算符

分类&& ||

&&
​ 运算结果跟&是一模一样的,只不过具有短路效果。

||
​ 运算结果跟|是一模一样的。只不过具有短路效果。

逻辑核心:
​ 当左边不能确定整个表达式的结果,右边才会执行。

​ 当左边能确定整个表达式的结果,那么右边就不会执行了。从而提高了代码的运行效率。
注意事项

  • &|,无论左边true false,右边都要执行。
  • &&||,如果左边能确定整个表达式的结果,右边不执行
  • &&:左边为false,右边不管是真是假,整个表达式的结果一定是false
  • ||:左边为true,右边不管是真是假,整个表达式的结果一定是true
  • 在这两种情况下,右边不执行提高了效率
  • 最常用的逻辑运算符:&&,||,!

运算符——三元运算符和运算符等级

三元运算符:又叫做三元表达式或者问号冒号表达式。

格式关系表达式 ? 表达式1 :表达式2 ;

计算规则:
计算关系表达式的值。
如果关系表达式的值为真,那么执行表达式1。
如果关系表达式的值为假,那么执行表达式2。
注意点:
​ 三元运算符的最终结果一定要被使用,要么赋值给一个变量,要么直接打印出来。

案例:

//1.定义三个变量记录和尚的身高
int height1 = 150;
int height2 = 210;
int height3 = 165;

//2.利用三元运算符求出两个数中的较大值。
int temp = height1 > height2 ? height1 : height2;

//3.求出最终的结果
int max = temp > height3 ? temp : height3;

System.out.println(max);

其他的运算符
在这里插入图片描述

运算符的优先级
在这里插入图片描述

运算符——原码反码补码

1.原码
原码:十进制数据的二进制表现形式,最左边是符号位,0为正,1为负
反码:正数的补码反码是其本身,负数的反码是符号位保持不变,其余位取反
补码:正数的补码是其本身,负数的补码是其反码的基础上+1

原码的弊端
原码:十进制数的二进制形式,最左边是符号位,0为正,1为负
利用原码对正数进行计算不会有问题的
但是如果是负数计算,结果就出错,实际运算的结果,跟我们预期的结果是相反的
2.反码
反码出现的目的
反码:为了解决原码不能计算负数的问题而出现的
计算规则:正数的反码不变,负数的反码在原码的基础上,符号位不变,数值取反,0变1,1变0
反码的弊端:负数运算的时候,如果结果不跨0,是没有任何问题的,但是如果结果跨0,跟实际结果会有1的偏差
3.补码
补码出现的目的
为了解决负数计算时跨0的问题而出现的
补码的计算规则
正数的补码不变,负数的补码在反码的基础上+1。另外补码还能记录一个特殊值-128,该数据在1字节下,没有原码和反码
补码注意点
计算机中的存储和计算都是以补码的形式进行的

判断和循环

判断和循环——流程控制语句

在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。

1.1 流程控制语句分类
​ 顺序结构

​ 判断和选择结构(if, switch)

​ 循环结构(for, while, do…while)

1.2 顺序结构
顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。

判断和循环——if的格式

1. if语句格式1
格式:

if (关系表达式) {
    语句体;	
}

执行流程:

①首先计算关系表达式的值

②如果关系表达式的值为true就执行语句体

③如果关系表达式的值为false就不执行语句体

④继续执行后面的语句内容

2 if语句格式2
格式:

if (关系表达式) {
    语句体1;	
} else {
    语句体2;	
}

执行流程:

①首先计算关系表达式的值

②如果关系表达式的值为true就执行语句体1

③如果关系表达式的值为false就执行语句体2

④继续执行后面的语句内容

3 if语句格式3
格式:

if (关系表达式1) {
    语句体1;	
} else if (关系表达式2) {
    语句体2;	
}else {
    语句体n+1;
}

执行流程:

①首先计算关系表达式1的值

②如果值为true就执行语句体1;如果值为false就计算关系表达式2的值

③如果值为true就执行语句体2;如果值为false就计算关系表达式3的值

④…

⑤如果没有任何关系表达式为true,就执行语句体n+1。

判断和循环——Switch语句

1 格式

switch (表达式) {
	case 1:
		语句体1;
		break;
	case 2:
		语句体2;
		break;
	...
	default:
		语句体n+1;
		break;
}

2 执行流程:

  • 首先计算出表达式的值
  • 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结 束。
  • 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。

练习:运动计划

代码示例:

package a01switch选择语句;

import java.util.Scanner;

public class SwitchDemo2 {
    public static void main(String[] args) {
        //1.键盘录入一个整数表示星期
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个整数表示星期");
        int week = sc.nextInt();

        //2.书写一个switch语句去跟week进行匹配
        switch (week){
            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;
            case 6:
                System.out.println("爬山");
                break;
            case 7:
                System.out.println("好好吃一顿");
                break;
            default:
                System.out.println("输入错误,没有这个星期");
                break;
        }
    }
}

3 switch的扩展知识:
default的位置和省略情况

default可以放在任意位置,也可以省略case穿透,不写break会引发case穿透现象

switch在JDK12的新特性

int number = 10;
switch (number) {
    case 1 -> System.out.println("一");
    case 2 -> System.out.println("二");
    case 3 -> System.out.println("三");
    default -> System.out.println("其他");
}

判断和循环——for循环语句

for循环结构
​ 循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体语句,当反复 执行这个循环体时,需要在合适的时候把循环判断条件修改为false,从而结束循环,否则循环将一直执行下去,形 成死循环。

for循环格式:

for (初始化语句;条件判断语句;条件控制语句) {
	循环体语句;
}

格式解释:

  • 初始化语句: 用于表示循环开启时的起始状态,简单说就是循环开始的时候什么样
  • 条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去
  • 循环体语句: 用于表示循环反复执行的内容,简单说就是循环反复执行的事情 条件控制语句:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去

执行流程:

①执行初始化语句

②执行条件判断语句,看其结果是true还是false

​ 如果是false,循环结束

​ 如果是true,继续执行

③执行循环体语句

④执行条件控制语句

⑤回到②继续

代码示例:

//1.确定循环的开始条件
//2.确定循环的结束条件
//3.确定要重复执行的代码

//需求:打印5次HelloWorld
//开始条件:1
//结束条件:5
//重复代码:打印语句

for (int i = 1; i <= 5; i++) {
    System.out.println("HelloWorld");
}
for循环练习-输出数据
需求:在控制台输出1-55-1的数据
示例代码:
public class ForTest01 {
    public static void main(String[] args) {
		//需求:输出数据1-5
        for(int i=1; i<=5; i++) {
			System.out.println(i);
		}
		System.out.println("--------");
		//需求:输出数据5-1
		for(int i=5; i>=1; i--) {
			System.out.println(i);
		}
    }
}

判断和循环——while循环语句

1.while循环
格式:

初始化语句;
while(条件判断语句){
	循环体;
	条件控制语句;
}

练习:珠穆朗玛峰

//1.定义一个变量表示珠穆朗玛峰的高度
int height = 8844430;
//2.定义一个变量表示纸张的厚度
double paper = 0.1;

//定义一个计数器(变量),用来统计折叠的次数
int count = 0;

//3.循环折叠纸张
//只有纸张的厚度 < 穆朗玛峰的高度 循环才继续,否则循环就停止
//坑:只有判断为真,循环才会继续
while(paper < height){
    //折叠纸张
    paper = paper * 2;
    count++;
}

//4.打印一下纸张的厚度
System.out.println(count);//27

2.do…while循环

格式:

初始化语句;
do{
    循环体;
    条件控制语句;
}while(条件判断语句);

特点:

​ 先执行,再判断。

3.区别:

  • ​ for和while循环,是先判断,再执行。
  • do…while是先执行,再判断。
  • 当知道循环次数或者循环范围的时候,用for循环。
  • 当不知道循环次数,也不知道循环范围,但是知道循环的结束条件时,用while循环。

判断和循环——循环语句进阶

1.无限循环
概念:
​ 又叫死循环。循环一直停不下来。

for格式:
for(;;){
    System.out.println("循环执行一直在打印内容");
}

解释:

初始化语句可以空着不写,表示循环之前不定义任何的控制变量。

条件判断语句可以空着不写,如果不写,默认表示true,循环一直进行。

条件控制语句可以空着不写,表示每次循环体执行完毕后,控制变量不做任何变化。

while格式:
while(true){
    System.out.println("循环执行一直在打印内容");
}

解释

​ 小括号里面就不能省略了,true一定要写出来,否则代码会报错。

do…while格式:

do{
    System.out.println("循环执行一直在打印内容");
}while(true);
解释:

​ 小括号里面就不能省略了,true一定要写出来,否则代码会报错。

无限循环的注意事项:
最为常用的格式:while
无限循环下面不能再写其他代码了,因为永远执行不到。
2.条件控制语句
break
continue
break:
​ 不能单独存在的。可以用在switch和循环中,表示结束,跳出的意思。

代码示例:

//1.吃1~5号包子
for (int i = 1; i <= 5; i++) {
    System.out.println("在吃第" + i + "个包子");
    //2.吃完第三个的时候就不吃了
    if(i == 3){
        break;//结束整个循环。
    }
}
continue:

​ 不能单独存在的。只能存在于循环当中。

​ 表示:跳过本次循环,继续执行下次循环。

代码示例:

//1.吃1~5号包子
for (int i = 1; i <= 5; i++) {
    //2.第3个包子有虫子就跳过,继续吃下面的包子
    if(i == 3){
        //跳过本次循环(本次循环中,下面的代码就不执行了),继续执行下次循环。
        continue;
    }
    System.out.println("在吃第" + i + "个包子");
}

3. Random
Random跟Scanner一样,也是Java提前写好的类,我们不需要关心是如何实现的,只要直接使用就可以了。

使用步骤:
导包

import java.util.Random;

导包的动作必须出现在类定义的上边。
创建对象

Random r = new Random ();

上面这个格式里面,只有r是变量名,可以变,其他的都不允许变。
生成随机数

int number = r.nextInt(随机数的范围);

上面这个格式里面,只有number是变量名,可以变,其他的都不允许变。
随机数范围的特点:从0开始,不包含指定值。比如:参数为10,生成的范围[0,10)

代码示例:

//1.导包
import java.util.Random;

public class RandomDemo1 {
    public static void main(String[] args) {
        //2.创建对象
        Random r = new Random();
        //3.生成随机数
        int number = r.nextInt(100);//包左不包右,包头不包尾
        //0 ~ 99
        System.out.println(number);

    }
}

4. 逢七过

需求:
朋友聚会的时候可能会玩一个游戏:逢7过
游戏规则:从任意一个数字开始报数,当你要报的数字是包含7或者是7的倍数时都要说过:过
使用程序在控制台打印出1-100之间的满足逢七必过规则的数据
举例:1 2 3 4 5 6 过 8 9 10 11 12 13 过 15 16 过 18 …

代码示例:

/*朋友聚会的时候可能会玩一个游戏:逢7过
        游戏规则:从任意一个数字开始报数,当你要报的数字是包含7或者是7的倍数时都要说过:过
        需求:使用程序在控制台打印出1-100之间的满足逢七必过规则的数据*/
//分析:
//个位7  十位7   7倍数
//1 2 3 4 5 6 过 8 9 10 11 12 13 过 15 16 过 18 19 20 过....
//69 过 过 过 过 过 过... 80
//1.得到1~100之间的每一个数字
//开始:1
//结束:100
for (int i = 1; i <= 100; i++) {
    //2.判断每一个数字,如果符合规则,就打印过,如果不符合规则就打印真实的数字
    if(i % 10 == 7 || i / 10 % 10 == 7  ||  i % 7 == 0){
        System.out.println("过");
        continue;
    }
    System.out.println(i);
}

5. 平方根

需求:
键盘录入一个大于等于2的整数 x ,计算并返回 x 的 平方根 。结果只保留整数部分 ,小数部分将被舍去 。

代码示例:

/*需求:键盘录入一个大于等于2的整数 x ,计算并返回 x 的 平方根 。
        结果只保留整数部分 ,小数部分将被舍去 。*/


//分析:
//平方根   16的平方根4
//         4的平方根2


// 10
// 1 * 1 = 1 < 10
// 2 * 2 = 4 < 10
// 3 * 3 = 9 < 10
// 4 * 4 = 16 > 10
//推断:10的平方根是在3~4之间。


// 20
// 1 * 1 = 1 < 20
// 2 * 2 = 4 < 20
// 3 * 3 = 9 < 20
// 4 * 4 = 16 < 20
// 5 * 5 = 25 > 20
//推断:20的平方根是在4~5之间。


//在代码当中
//从1开始循环,拿着数字的平方跟原来的数字进行比较
//如果小于的,那么继续往后判断
//如果相等,那么当前数字就是平方根
//如果大于的,那么前一个数字就是平方跟的整数部分


//1.键盘录入一个整数
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数");
int number = sc.nextInt();
//2.从1开始循环判断
//开始:1 结束: number
for (int i = 1; i <= number; i++) {
    //用i * i 再跟number进行比较
    if(i * i == number){
        System.out.println(i + "就是" + number + "的平方根");
        //一旦找到了,循环就可以停止了,后面的数字就不需要再找了,提高代码的运行效率。
        break;
    }else if(i * i > number){
        System.out.println((i - 1) + "就是" + number + "平方根的整数部分");
        break;
    }
}

6.判断是否为质数

需求:
​键盘录入一个正整数 x ,判断该整数是否为一个质数。

代码示例:

//需求:键盘录入一个正整数 x ,判断该整数是否为一个质数。

//质数:
//如果一个整数只能被1和本身整除,那么这个数就是质数。否则这个数叫做合数
//7 = 1 * 7 质数
//8 = 1 * 8  2 * 4 合数


//分析:
//1.键盘录入一个正整数
//number
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个正整数");
int number = sc.nextInt();//9

//定义一个变量,表示标记
//标记着number是否为一个质数
//true: 是一个质数
//false : 不是一个质数

//表示最初就认为number是一个质数
boolean flag = true;


//2.判断
//写一个循环,从2开始判断,一直判断到number-1为止
//看这个范围之内,有没有数字可以被number整除
for (int i = 2; i < number; i++) {
    //i 依次表示这个范围之内的每一个数字
    //看number是否能被i整除就可以了
    if(number % i == 0){// 9 % 2 = 1
        flag = false;
        //System.out.println(number + "不是一个质数");
        break;
    }/*else{
                System.out.println(number + "是一个质数");
            }*/
}

//只有当这个循环结束了,表示这个范围之内所有的数字都判断完毕了
//此时才能断定number是一个质数
if(flag){
    System.out.println(number + "是一个质数");
}else{
    System.out.println(number + "不是一个质数");
}

7. 猜数字小游戏

需求:
程序自动生成一个1-100之间的随机数,在代码中使用键盘录入去猜出这个数字是多少?
要求:
使用循环猜,一直猜中为止。
思路分析:
生成一个1-100之间的随机数
使用键盘录入去猜出这个数字是多少
把反复猜的代码写在循环中

代码示例:

//1.生成一个1-100之间的随机数
Random r = new Random();
int number = r.nextInt(100) + 1;// 0 ~ 99 + 1 --- 1 ~ 100
System.out.println(number);

//2.使用键盘录入去猜出这个数字是多少?
Scanner sc = new Scanner(System.in);
while(true){
    System.out.println("请输入一个整数");
    int guessNumber = sc.nextInt();
    //3.比较
    if(guessNumber > number){
        System.out.println("您猜的数字大了");
    }else if(guessNumber < number){
        System.out.println("您猜的数字小了");
    }else{
        System.out.println("恭喜你,猜中了");
        break;
    }
}

数组

数组——什么是数组

  1. 数组是一种容器,可以存储同种数据类型的多个值。
  2. 数组容器在存储数据的时候要考虑隐式转换考虑。

例如:

  • int类型可以转为byte short int 但是不能转double和boolean
  • double 类型的数组容器可以转为byte short int long float double
  • 建议:容器的类型,和存储的数据类型保持一致

数组——数组定义

格式一:数据类型[]数组名

范例:int [] array

格式二:数据类型[] 数组名

范例:int array[]

数组——数组静态初始化

初始化:就是在内存中,为数组容器开辟空间,并将数据寻如容器中的过程
完整格式:数据类型[] 数组名 =new数据类型[]{元素1,元素2,元素3,... ...};

范例:int[] array=new int[]{11,22,33};
范例:double[] array=new double[]{11.1,11.2};

数组——动态初始化

动态初始化:初始化时只是指定数组的长度,由系统分配初始值
格式:数据类型[]数组名=new 数据类型[数组长度]

范例:int[]arr=new int[3];

数组——数组动态初始化和静态初始化的区别

动态初始化:手动指定数组长度,由系统给出默认初始化值。
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组长度。

注意:只明确元素的个数,不明确具体数值,推荐使用动态初始化;需求中已经明确了具体数据,直接静态初始化即可。

数组——数组的地址值

int[]arr={1,2,3,4,5};
system.out.println(arr);

拓展
解释地址值格式含义[D@776ec8df
[:表示当前一个数组
D:表示当前数组里面的元素都是double类型的
@:表示一个间隔符号(固定模式)
776ec8df:才是数组真正的地址值,(十六进制)

数组——索引

索引:下标、角标
索引从0开始,连续加1增长不间断

数组——数字遍历

数组遍历:将数组中所有的严内容取出来,取出来之后可以(打印、求和、判断…)
注意:遍历是指取出所有数据的过程,不要局限的理解为遍历就是 打印

数组——java内存分配

栈 方法运行时使用的内存,比如main方法执行,进入方法栈中执行
堆 存储对象或者数组,可以用new来创建,都存储在堆内存
方法区 存储可以运行的class文件
本地方法栈 JVM在使用操作系统功能的时候使用,和我们开发无关
寄存器 给CPU使用,和我们开发无关
注意:从JDK8开始,取消方法区,新增原件,把原来的方法区多种功能进行拆分,有的放到堆中,有的功能在元空间中。
当连个数组指向同一个小空间时,其中一个数组堆小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。
在这里插入图片描述

数组——二维数组

什么是二维数组?
数组里面存数组
二维数组的应用场景
当我们需要把数据分组管理

二维数组的静态初始化
格式:数据类型[][] 数据名=new数据类型[][]{{元素1,元素2},{元素1,元素2}};
范例:int[][]arr={{11,22},{33,44}}intarr[][]={{11,22},{33,44}}
二维数组的获取元素
arr[i][j]表示:
arr二维数组
i二维数组的索引,获取出来的是里面的一维数组
j表示一维数组中的索引,获取出来的就是真正的元素
例如:
int arr[][]={{11,22},{33,44},{11,22,33,44}}
arr[0]表示二维数组中的第一个一维数组
arr[0][0]表示二维数组中的第一个一维数组的第一个元素

二维数组的动态初始化
格式数据类型[][] 数组名=new 数据类型[m][n]
m表示这个二维数组,可以存放多少个一维数组
n表示每一个一维数组,可以存放多少个元素
范例:int[][]arrnew int[2][3]
该数组可以存放2个一维数组 ,每一个一维数组中可以存放3个int类型元素
二维数组的内存图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法

方法——什么是方法

  • 方法的概念:
    ​ 方法(method)是程序中最小的执行单元
  • 实际开发中什么时候用到方法?
    重复的代码,具有独立功能的代码可以抽取到方法中
  • 实际开发中,方法有什么好处?
    可以提高代码的复用性;可以提高代码的可维护性
  • 注意:
    方法必须先创建才可以使用,该过程成为方法定义;方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用

方法——最简单的方法定义和调用

1 无参数方法定义和调用
定义格式:

public static void 方法名 (   ) {
	// 方法体;
}

范例:

public static void method (    ) {
	// 方法体;
}

2 调用格式:

方法名();
范例:
method();

注意

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

3 无参数方法的练习
需求:设计一个方法用于打印两个数中的较大数
思路:
①定义一个方法,用于打印两个数字中的较大数,例如getMax()
②方法中定义两个变量,用于保存两个数字
③使用分支语句分两种情况对两个数字的大小关系进行处理
④在main()方法中调用定义好的方法
代码:

public class MethodTest {
    public static void main(String[] args) {
        //在main()方法中调用定义好的方法
        getMax();
    }

    //定义一个方法,用于打印两个数字中的较大数,例如getMax()
    public static void getMax() {
        //方法中定义两个变量,用于保存两个数字
        int a = 10;
        int b = 20;

        //使用分支语句分两种情况对两个数字的大小关系进行处理
        if(a > b) {
            System.out.println(a);
        } else {
            System.out.println(b);
        }
    }
}

方法——带参数的方法定义和调用

1 带参数方法定义和调用
定义格式:

参数:由数据类型和变量名组成 - 数据类型 变量名

参数范例:

int a

public static void 方法名 (参数1) {
	方法体;
}

public static void 方法名 (参数1, 参数2, 参数3...) {
	方法体;
}

范例:

public static void isEvenNumber(int number){
    ...
}
public static void getMax(int num1, int num2){
    ...
}

注意:

方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错

方法定义时,多个参数之间使用逗号( ,)分隔
调用格式:

方法名(参数);

方法名(参数1,参数2);

范例:

isEvenNumber(10);

getMax(10,20);

方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将报错
2 形参和实参
形参:方法定义中的参数
​ 等同于变量定义格式,例如:int number

实参:方法调用中的参数
​ 等同于使用变量或常量,例如: 10 number

3 带参数方法练习
需求:设计一个方法用于打印两个数中的较大数,数据来自于方法参数 }
思路:
①定义一个方法,用于打印两个数字中的较大数,例如getMax()
②为方法定义两个参数,用于接收两个数字
③使用分支语句分两种情况对两个数字的大小关系进行处理
④在main()方法中调用定义好的方法(使用常量)
⑤在main()方法中调用定义好的方法(使用变量)
代码:

public class MethodTest {
    public static void main(String[] args) {
        //在main()方法中调用定义好的方法(使用常量)
        getMax(10,20);
        //调用方法的时候,人家要几个,你就给几个,人家要什么类型的,你就给什么类型的
        //getMax(30);
        //getMax(10.0,20.0);

        //在main()方法中调用定义好的方法(使用变量)
        int a = 10;
        int b = 20;
        getMax(a, b);
    }

    //定义一个方法,用于打印两个数字中的较大数,例如getMax()
    //为方法定义两个参数,用于接收两个数字
    public static void getMax(int a, int b) {
        //使用分支语句分两种情况对两个数字的大小关系进行处理
        if(a > b) {
            System.out.println(a);
        } else {
            System.out.println(b);
        }
    }
}

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

什么时候用到返回值方法?
方法的返回值就是方法运行的最终结果,如果调用处要根据方法的结果,去编写另外一个代码的逻辑。为了在调用处拿到方法产生的结果,就需要定义带有返回值的方法。

1 带返回值方法定义和调用
定义格式

public static 数据类型 方法名 ( 参数 ) { 
	return 数据 ;
}

范例

public static boolean isEvenNumber( int number ) {           
	return true ;
}
public static int getMax( int a, int b ) {
	return  100 ;
}

注意:
方法定义时return后面的返回值与方法定义上的数据类型要匹配,否则程序将报错
2 调用格式

//调用格式
方法名 ( 参数 ) ;
数据类型 变量名 = 方法名 ( 参数 ) ;
//直接调用
方法名(实参);
//赋值调用
整数类型 变量名 =方法名(实参);
//输出调用
System.out.println(方法名(实参));

范例

isEvenNumber ( 5 ) ;
boolean  flag =  isEvenNumber ( 5 ); 

注意:
方法的返回值通常会使用变量接收,否则该返回值将无意义

3 带返回值方法练习
需求:

​ 键盘录入两个圆的半径(整数),比较两个圆的面积。

代码示例:

import java.util.Scanner;

public class MethodDemo10 {
    public static void main(String[] args) {
        //需求:键盘录入两个圆的半径(整数),比较两个圆的面积。
        //键盘录入圆的半径
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入圆的半径");
        int radii1 = sc.nextInt();

        System.out.println("请输入第二个圆的半径");
        int radii2 = sc.nextInt();
        double area1 = getArea(radii1);
        double area2 = getArea(radii2);
        if(area1 > area2){
            System.out.println("第一个圆更大");
        }else{
            System.out.println("第二个圆更大");
        }
    }

    //心得:
    //1.我要干嘛?   求圆的面积
    //2.我干这件事情,需要什么才能完成?        半径
    //3.方法的调用处,是否需要继续使用方法的结果    要比较
    public static double getArea(int radii) {
        double area = 3.14 * radii * radii;
        return area;
    }
}

方法——方法的小结

1 方法的注意事项

  • 方法不调用就不执行
  • 方法和方法之间是平级关系,方法不能嵌套定义
  • 方法的编写与执行顺序无关
  • 方法的返回值类型为void,说明方法没有返回值可以省略return语句,如果没写return后面不能跟具体数据
  • return语句下面,不能编写代码,因为永远执行不到属于无效代码

return关键字

  • 方法没有返回值:可以省略不写。如果书写,表示结束方法
  • 方法有返回值:必须要写,表示结束方法和返回结果

示例代码:

public class MethodDemo {
    public static void main(String[] args) {

    }

    public static void methodOne() {
		public static void methodTwo() {
       		// 这里会引发编译错误!!!
    	}
    }
}

void表示无返回值,可以省略return,也可以单独的书写return,后面不加数据

示例代码:

public class MethodDemo {
    public static void main(String[] args) {

    }
    public static void methodTwo() {
        //return 100; 编译错误,因为没有具体返回值类型
        return;	
        //System.out.println(100); return语句后面不能跟数据或代码
    }
}

2 方法的通用格式
格式:

public static 返回值类型 方法名(参数) {
   方法体; 
   return 数据 ;
}

解释:

  • public static 修饰符,目前先记住这个格式

  • 返回值类型 方法操作完毕之后返回的数据的数据类型

  • 如果方法操作完毕,没有数据返回,这里写void,而且方法体中一般不写return

  • 方法名 调用方法时候使用的标识

  • 参数 由数据类型和变量名组成,多个参数之间用逗号隔开

  • 方法体 完成功能的代码块

  • return 如果方法操作完毕,有数据返回,用于把数据返回给调用者

  • 定义方法时,要做到两个明确
    明确返回值类型:主要是明确方法操作完毕之后是否有数据返回,如果没有,写void;如果有,写对应的数据类型
    明确参数:主要是明确参数的类型和数量

  • 调用方法时的注意:
    void类型的方法,直接调用即可
    非void类型的方法,推荐用变量接收调用

方法——方法的重载

1方法重载概念
方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载

  1. 多个方法在同一个类中
  2. 多个方法具有相同的方法名
  3. 多个方法的参数不相同,类型不同或者数量不同

注意:

重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式
重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
正确范例:

public class MethodDemo {
	public static void fn(int a) {
    	//方法体
    }
    public static int fn(double a) {
    	//方法体
    }
}

public class MethodDemo {
	public static float fn(int a) {
    	//方法体
    }
    public static int fn(int a , int b) {
    	//方法体
    }
}

错误范例:

public class MethodDemo {
	public static void fn(int a) {
    	//方法体
    }
    public static int fn(int a) { 	/*错误原因:重载与返回值无关*/
    	//方法体
    }
}

public class MethodDemo01 {
    public static void fn(int a) {
        //方法体
    }
} 
public class MethodDemo02 {
    public static int fn(double a) { /*错误原因:这是两个类的两个fn方法*/
        //方法体
    }
}

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

思路:

①定义比较两个数字的是否相同的方法compare()方法,参数选择两个int型参数
②定义对应的重载方法,变更对应的参数类型,参数变更为两个long型参数
③定义所有的重载方法,两个byte类型与两个short类型参数
④完成方法的调用,测试运行结果
代码:

public class MethodTest {
    public static void main(String[] args) {
        //调用方法
        System.out.println(compare(10, 20));
        System.out.println(compare((byte) 10, (byte) 20));
        System.out.println(compare((short) 10, (short) 20));
        System.out.println(compare(10L, 20L));
    }

    //int
    public static boolean compare(int a, int b) {
        System.out.println("int");
        return a == b;
    }

    //byte
    public static boolean compare(byte a, byte b) {
        System.out.println("byte");
        return a == b;
    }

    //short
    public static boolean compare(short a, short b) {
        System.out.println("short");
        return a == b;
    }

    //long
    public static boolean compare(long a, long b) {
        System.out.println("long");
        return a == b;
    }

}

方法——方法的三个练习

1 数组遍历
需求:设计一个方法用于数组遍历,要求遍历的结果是在一行上的。例如:[11, 22, 33, 44, 55]

思路:

①因为要求结果在一行上输出,所以这里需要在学习一个新的输出语句

System.out.print(“内容”);

System.out.println(“内容”); 输出内容并换行

System.out.print(“内容”); 输出内容不换行

System.out.println(); 起到换行的作用

②定义一个数组,用静态初始化完成数组元素初始化

③定义一个方法,用数组遍历通用格式对数组进行遍历

④用新的输出语句修改遍历操作

⑤调用遍历方法

代码:

public class Test1 {
    public static void main(String[] args) {
      /*  //先打印数据,再进行换行
        System.out.println("aaa");
        //只打印不换行
        System.out.print("bbb");
        System.out.print("ddd");
        //不打印任何内容,只换行
        System.out.println();
        System.out.print("cc");*/
        //设计一个方法用于数组遍历,要求遍历的结果是在一行上的。例如:[11, 22, 33, 44, 55]
        int[] arr = {1,2,3,4,5};
        printArr(arr);
    }
    //1.我要遍历数组
    //2.需要什么?  数组
    //3.调用处是否需要使用方法的结果。
    public static void printArr(int[] arr){
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            if(i == arr.length - 1){
                System.out.println(arr[i] + "]");
            }else{
                System.out.print(arr[i] + ", ");
            }
        }
    }
}

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

思路:

①定义一个数组,用静态初始化完成数组元素初始化
②定义一个方法,用来获取数组中的最大值,最值的认知和讲解我们在数组中已经讲解过了
③调用获取最大值方法,用变量接收返回结果
④把结果输出在控制台
代码:

public class MethodTest02 {
    public static void main(String[] args) {
        //定义一个数组,用静态初始化完成数组元素初始化
        int[] arr = {12, 45, 98, 73, 60};

        //调用获取最大值方法,用变量接收返回结果
        int number = getMax(arr);

        //把结果输出在控制台
        System.out.println("number:" + number);
    }

    //定义一个方法,用来获取数组中的最大值
    /*
        两个明确:
            返回值类型:int
            参数:int[] arr
     */
    public static int getMax(int[] arr) {
        int max = arr[0];

        for(int x=1; x<arr.length; x++) {
            if(arr[x] > max) {
                max = arr[x];
            }
        }
        return max;
    }
}

3 获取索引
需求:

​ 定义一个方法获取数字,在数组中的索引位置,将结果返回给调用处,如果有重复的,只要获取第一个即可。

代码示例:

package com.itheima.demo;

public class Test4 {
    public static void main(String[] args) {
        //定义一个方法获取数字,在数组中的索引位置,将结果返回给调用处
        //如果有重复的,只要获取第一个即可

        int[] arr = {1,2,3,4,5};
        int index = contains(arr, 3);
        System.out.println(index);
    }

    //1. 我要干嘛?判断数组中的某一个数是否存在
    //2. 需要什么?数组 数字
    //3. 调用处是否需要继续使用?返回
    //获取number在arr中的位置
    public static int contains(int[] arr, int number) {
        //遍历arr得到每一个元素
        for (int i = 0; i < arr.length; i++) {
            //拿着每一个元素跟number比较
            if(arr[i] == number){
                //如果相等,表示找到了
                return i;
            }
        }
        //当循环结束之后,如果还不能返回索引,表示数组中不存在该数据
        //可以返回-1
        return -1;
    }
}

方法——方法练习:拷贝数组

需求:定义一个方法copyOfRange(int[]arr,int to)
功能:将数组arr中从索引from(包含from)开始,到索=索引to(不包含to)得元素复制到新的数组中,将新数组返回

public class test {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        int[] copyarr = copyOfRange(arr, 3, 7);
        for (int i = 0; i < copyarr.length; i++) {
            System.out.println(copyarr[i] + " ");
        }

    }

    public static int[] copyOfRange( int[] arr, int from, int to) {
        int[] newArr = new int[to - from];
        int index = 0;
        for (int i = from; i < to; i++) {
            newArr[0] = arr[i];
            index++;
        }
        return newArr;
    }
}

方法——方法的基本内存原理

方法的内存

  1. 方法调用的基本内存原理
  2. 方法传递基本数据类型的内存原理
  3. 方法传递引用数据类型的内存原理

Java的内存分配

  • 栈:方法运行时使用的内存,方法进栈运行,运行完毕就出栈
  • 堆:new出来的,都在堆内存中开辟了一小空间
  • 方法区:存储可以运行的class文件
  • 本地方法栈:JVM在使用中操作系统功能的时候使用,和我们开发无关
  • 寄存器:给cpu使用,和我们开发无关

方法调用的基本内存原理
方法调用进栈执行,栈的运行特点是先进后出(弹夹压子弹)

方法——什么是基本数据类型和引用数据类型

数据类型的分类
基本数据类型:整数类型、浮点数类型、布尔类型、字符类型
引用数据类型:除了基本数据类型的其他类型
内存角度解释:
基本数据类型:
数据值是存储在自已的空间中
特点:赋值给其他类型,也是赋的真实的值
引用数据类型:
数据值是存储在其他空间中,自已空间中存储的是地址值
特点:自已空间中存储的是地址值

方法——方法值的传递

方法传递基本数据类型的内存原理:
传递基本数据类型时,传递得失真实的数据,形参的改变,不影响实际参数的值
方法传递引用数据类型的内存原理:
传递引用数据类型时,传递的是地址值,形参的改变,影响实际参数的值
在这里插入图片描述

综合练习

练习一:飞机票需求

机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。 按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。

代码示例:

package com.itheima.test;
import java.util.Scanner;
public class Test1 {
    public static void main(String[] args) {
        /* 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。
        按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)头等舱7折,经济舱6.5折。*/
        //分析:
        //1.键盘录入机票原价、月份、头等舱或经济舱
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入机票的原价");
        int ticket = sc.nextInt();
        System.out.println("请输入当前的月份");
        int month = sc.nextInt();
        System.out.println("请输入当前购买的舱位 0 头等舱 1 经济舱");
        int seat = sc.nextInt();
        //2.先判断月份是旺季还是淡季
        //ctrl + alt + M 自动抽取方法
        if (month &gt;= 5 &amp;&amp; month &lt;= 10) {
            //旺季 //3.继续判断当前机票是经济舱还是头等舱
            //ticket = getPrice(ticket, seat, 0.9, 0.85);
            ticket = getTicket(ticket, seat, 0.9, 0.85);
        } else if ((month &gt;= 1 &amp;&amp; month &lt;= 4) || (month &gt;= 11 &amp;&amp; month &lt;= 12)) {
            //淡季
            //ticket = getPrice(ticket, seat, 0.7, 0.65);
            ticket = getTicket(ticket, seat, 0.7, 0.65);
        } else {
            //表示键盘录入的月份是一个非法数据
            System.out.println("键盘录入的月份不合法");
        }
        System.out.println(ticket);
    }
    public static int getTicket(int ticket, int seat, double v, double v2) {
        if (seat == 0) {
            //头等舱
            ticket = (int) (ticket * v);
        } else if (seat == 1) {
            //经济舱
            ticket = (int) (ticket * v2);
        } else {
            System.out.println("没有这个舱位");
        }
        return ticket;
    }
    //1.我要干嘛?根据舱位和折扣来计算最终的票价
    //2.我干这件事,需要什么才能完成?原价 舱位 头等舱的折扣 经济舱的折扣
    //3.方法的调用处是否需要继续使用这个结果  需要
    /*  public static int getPrice(int ticket, int seat, double v0, double v1) {
        if (seat == 0) {
            //头等舱
            ticket = (int) (ticket * v0);
        } else if (seat == 1) {
            //经济舱
            ticket = (int) (ticket * v1);
        } else {
            System.out.println("没有这个舱位");
        }
        return ticket;
    }*/
}

练习二:打印素数 判断101~200之间有多少个素数,并输出所有素数。备注:素数就是质数
代码示例:

package com.itheima.test;
public class Test2 {
    public static void main(String[] args) {
        //判断 101 ~ 200 之间有多少个素数,并打印所有素数
        //思路一: 2 ~ 99
        //定义变量i ,赋值100
        //判断i是否为质数
        //定义一个变量用来统计有多少个质数
        int count = 0;
        //外循环:遍历101~200这个范围,依次得到这个范围之内的每一个数字
        for (int i = 101; i &lt;= 200; i++) {
            //i 依次表示循环中的每一个数字
            //继续判断i是否为一个质数
            boolean flag = true;
            //内循环:判断当前数字是否为一个质数。
            for (int j = 2; j &lt; i; j++) {
                //j 表示2~99之间的每一个数字
                if(i % j == 0){
                    flag = false;
                    //跳出单层循环,内循环
                    break;
                }
            }
            if(flag){
                System.out.println("当前数字"+i+"是质数");
                count++;
            }
        }
        System.out.println("一共有" + count + "个质数");
        /* int i = 7;
        boolean flag = true;
        for (int j = 2; j &lt; i; j++) {
            //j 表示2~99之间的每一个数字
            if(i % j == 0){
                flag = false;
                break;
            }
        }
        if(flag){
            System.out.println("当前数字是质数");
        }else{
            System.out.println("当前数字不是一个质数");
        }*/
    }
}

练习三:
验证码需求: 定义方法实现随机产生一个5位的验证码验证码格式: 长度为5 前四位是大写字母或者小写字母 最后一位是数字
代码示例:

package com.itheima.test;
import java.util.Random;
public class Test3 {
    public static void main(String[] args) {
        /*   需求:
            定义方法实现随机产生一个5位的验证码
            验证码格式:
            长度为5
            前四位是大写字母或者小写字母
            最后一位是数字
     */
        //方法:
        //在以后如果我们要在一堆没有什么规律的数据中随机抽取
        //可以先把这些数据放到数组当中
        //再随机抽取一个索引
        //分析:
        //1.大写字母和小写字母都放到数组当中
        char[] chs = new char[52];
        for (int i = 0; i &lt; chs.length; i++) {
            //ASCII码表
            if(i &lt;= 25){
                //添加小写字母
                chs[i] = (char)(97 + i);
            }else{//27
                //添加大写字母
                // A --- 65
                chs[i] = (char)(65 + i - 26);
            }
        }
        //定义一个字符串类型的变量,用来记录最终的结果
        String result = "";
        //2.随机抽取4次
        //随机抽取数组中的索引
        Random r = new Random();
        for (int i = 0; i &lt; 4; i++) {
            int randomIndex = r.nextInt(chs.length);
            //利用随机索引,获取对应的元素
            //System.out.println(chs[randomIndex]);
            result = result + chs[randomIndex];
        }
        //System.out.println(result);
        //3.随机抽取一个数字0~9
        int number = r.nextInt(10);
        //生成最终的结果
        result = result + number;
        //打印最终结果
        System.out.println(result);
    }
}

练习四:
复制数组需求: 把一个数组中的元素复制到另一个新数组中去。
代码示例:

package com.itheima.test;
public class Test4 {
    public static void main(String[] args) {
        /* 需求:
        把一个数组中的元素复制到另一个新数组中去。*/
        //分析:
        //1.定义一个老数组并存储一些元素
        int[] arr = {1,2,3,4,5};
        //2.定义一个新数组的长度跟老数组一致
        int[] newArr = new int[arr.length];
        //3.遍历老数组,得到老数组中的每一个元素,依次存入到新数组当中
        for (int i = 0; i &lt; arr.length; i++) {
            //i 表示老数组中的索引。新数组中的每一个索引
            //arr[i]  表示老数组中的元素
            newArr[i] = arr[i];
        }
        //4.新数组中已经存满元素了
        for (int i = 0; i &lt; newArr.length; i++) {
            System.out.println(newArr[i]);
        }
    }
}

练习五:
评委打分需求 : 在唱歌比赛中,有6名评委给选手打分,分数范围是[0 - 100]之间的整数。选手的最后得分为:去掉最高分、最低分后的4个评委的平均分,请完成上述过程并计算出选手的得分。
代码示例:

package com.itheima.test;
import java.util.Scanner;
public class Test5 {
    public static void main(String[] args) {
        //在唱歌比赛中,有6名评委给选手打分,分数范围是[0 - 100]之间的整数。
        // 选手的最后得分为:去掉最高分、最低分后的4个评委的平均分,请完成上述过程并计算出选手的得分。
        //分析:
        //1.定义一个数组,用来存储6名评委的打分(0~100)
        int[] scoreArr = getScores();
        for (int i = 0; i &lt; scoreArr.length; i++) {
            System.out.println(scoreArr[i]);
        }
        //2.求出数组中的最大值
        int max = getMax(scoreArr);
        //3.求出数组中的最小值
        int min = getMin(scoreArr);
        //4.求出数组中6个分数的总和
        int sum = getSum(scoreArr);
        //5.(总和 - 最大值 - 最小值 )/4
        int avg =  (sum - max - min)/(scoreArr.length - 2);
        //6.打印结果
        System.out.println("选手的最终得分为:" + avg);
    }
    public static int getSum(int[] scoreArr){
        int sum = 0;
        for (int i = 0; i &lt; scoreArr.length; i++) {
            sum = sum + scoreArr[i];
        }
        return  sum;
    }
    //求数组的最大值
    public static int getMax(int[] scoreArr){
        int max = scoreArr[0];
        for (int i = 1; i &lt; scoreArr.length; i++) {
            if(scoreArr[i] &gt; max){
                max = scoreArr[i];
            }
        }
        return max;
    }
    //求数组的最小值
    public static int getMin(int[] scoreArr){
        int min = scoreArr[0];
        for (int i = 1; i &lt; scoreArr.length; i++) {
            if(scoreArr[i] &lt; min){
                min = scoreArr[i];
            }
        }
        return min;
    }
    //1.我要干嘛?定义一个数组,用来存储6名评委的打分(0~100)
    //2.我需要什么?都不需要
    //3.干完了这件事情,是否需要返回?必须返回
    public static int[] getScores(){
        //定义数组
        int[] scores = new int[6];
        //使用键盘录入的形式,输入分数:0~100
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i &lt; scores.length; ) {
            System.out.println("请输入评委的打分");
            int score = sc.nextInt();//100
            if(score &gt;=0 &amp;&amp; score&lt;= 100){
                scores[i] = score;
                i++;
            }else{
                System.out.println("成绩超出了范围,继续录入,当前的i为:" + i);
            }
        }
        return  scores;
    }
}

练习六:
数字加密需求: 某系统的数字密码(大于0),比如1983,采用加密方式进行传输。规则如下: 先得到每位数,然后每位数都加上5 , 再对10求余,最后将所有数字反转,得到一串新数。
举例: 1 9 8 3
+5 6 14 13 8
%10 6 4 3 8
反转 8 3 4 6
加密后的结果就是:8346
代码示例:

package com.itheima.test;
public class Test6 {
    public static void main(String[] args) {
        /*
        某系统的数字密码(大于0)。比如1983,采用加密方式进行传输,
        规则如下:
            每位数加上5
            再对10求余,
            最后将所有数字反转,
            得到一串新数。
*/
        //分析:
        //1.把整数里面的每一位放到数组当中
        int[] arr = {1, 9, 8, 3};
        //2.加密
        //每位数加上5
        for (int i = 0; i &lt; arr.length; i++) {
            arr[i] = arr[i] + 5;
        }
        //再对10求余,
        for (int i = 0; i &lt; arr.length; i++) {
            arr[i] = arr[i] % 10;
        }
        //将所有数字反转
        for (int i = 0, j = arr.length - 1; i &lt; j; i++, j--) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        //8 3 4 6 --&gt; 8346
        //3.把数组里面的每一个数字进行拼接,变成加密之后的结果
        int number = 0;
        for (int i = 0; i &lt; arr.length; i++) {
            number = number * 10 + arr[i];
        }
        System.out.println(number);
    }
}

练习六扩展:

package com.itheima.test;
public class Test7 {
    public static void main(String[] args) {
        //需求:
        //把整数上的每一位都添加到数组当中
        //反向推导
        //1.计算出数组的长度
        int number = 12345;
        //定义一个变量临时记录number的值,就是为了第三步的时候再次使用
        int temp = number;
        //定义一个变量进行统计
        int count = 0;
        while(number != 0){
            //每一次循环就去掉右边的一个数字
            number = number / 10;
            //去掉一位计数器就自增一次。
            count++;
        }
        //2.定义数组
        //动态初始化
        int[] arr = new int[count];
        //3.把整数上的每一位都添加到数组当中
        int index = arr.length -1;
        while(temp != 0){//12345
            //获取temp里面的每一位数组
            int ge = temp % 10;
            //再去掉右边的那位数字
            temp = temp / 10;
            //把当前获取到的个位添加到数组当中
            arr[index] = ge;
            index--;
        }
        //验证结果  1  2  3  4 5
        for (int i = 0; i &lt; arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

练习七:数字解密把上一题加密之后的数据进行解密
代码示例:

package com.itheima.test;
public class Test8 {
    public static void main(String[] args) {
        /*某系统的数字密码(大于0)。比如1983,采用加密方式进行传输,
        规则如下:
            每位数加上5
            再对10求余,
            最后将所有数字反转,
            得到一串新数。
            按照以上规则进行解密:
            比如1983加密之后变成8346,解密之后变成1983
        */
        //1.定义数组记录解密之后的结果
        int[] arr = {8, 3, 4, 6};
        //2.反转
        for (int i = 0, j = arr.length - 1; i &lt; j; i++, j--) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        //3.由于加密是通过对10取余的方式进行获取的
        //所以在解密的时候就需要判断,0~4之间+10  5~9数字不变
        for (int i = 0; i &lt; arr.length; i++) {
            if (arr[i] &gt;= 0 &amp;&amp; arr[i] &lt;= 4) {
                arr[i] = arr[i] + 10;
            }
        }
        //4.每一位减5
        for (int i = 0; i &lt; arr.length; i++) {
            arr[i] = arr[i] - 5;
        }
        //5.获取数组里面的每一位数字拼接成最终的结果
        int number = 0;
        for (int i = 0; i &lt; arr.length; i++) {
            number = number * 10 + arr[i];
        }
        System.out.println(number);
    }
}

练习八:抽奖需求: 一个大V直播抽奖,奖品是现金红包,分别有{2, 588 , 888, 1000, 10000}五个奖金。请使用代码模拟抽奖,打印出每个奖项,奖项的出现顺序要随机且不重复。打印效果如下:(随机顺序,不一定是下面的顺序)888元的奖金被抽出
588元的奖金被抽出
10000元的奖金被抽出
1000元的奖金被抽出
2元的奖金被抽出
解法一:

package com.itheima.test;
import java.util.Random;
public class Test9 {
    public static void main(String[] args) {
        /* 需求:
        一个大V直播抽奖,奖品是现金红包,分别有{2, 588 , 888, 1000, 10000}五个奖金。
        请使用代码模拟抽奖,打印出每个奖项,奖项的出现顺序要随机且不重复。
        打印效果如下:(随机顺序,不一定是下面的顺序)
            888元的奖金被抽出
            588元的奖金被抽出
            10000元的奖金被抽出
            1000元的奖金被抽出
            2元的奖金被抽出
        */
        //分析:
        //1.定义数组表示奖池
        int[] arr = {2, 588, 888, 1000, 10000};
        //2.定义新数组用于存储抽奖的结果
        int[] newArr = new int[arr.length];
        //3.抽奖
        Random r = new Random();
        //因为有5个奖项,所以这里要循环5次
        for (int i = 0; i &lt; 5; ) {
            //获取随机索引
            int randomIndex = r.nextInt(arr.length);
            //获取奖项
            int prize = arr[randomIndex];
            //判断当前的奖项是否存在,如果存在则重新抽取,如果不存在,就表示是有效奖项
            boolean flag = contains(newArr, prize);
            if(!flag){
                //把当前抽取到的奖项添加到newArr当中
                newArr[i] = prize;
                //添加完毕之后,移动索引
                i++;
            }
        }
        //4.遍历newArr
        for (int i = 0; i &lt; newArr.length; i++) {
            System.out.println(newArr[i]);
        }
    }
    //判断prize在数组当中是否存在
    //存在:true
    //不存在:false
    public static boolean contains(int[] arr,int prize){
        for (int i = 0; i &lt; arr.length; i++) {
            if(arr[i] == prize){
                return true;
            }
        }
        return false;
    }
}

解法二:

package com.itheima.test;
import java.util.Random;
public class Test10 {
    public static void main(String[] args) {
       /* 需求:
        一个大V直播抽奖,奖品是现金红包,分别有{2, 588 , 888, 1000, 10000}五个奖金。
        请使用代码模拟抽奖,打印出每个奖项,奖项的出现顺序要随机且不重复。
        打印效果如下:(随机顺序,不一定是下面的顺序)
            888元的奖金被抽出
            588元的奖金被抽出
            10000元的奖金被抽出
            1000元的奖金被抽出
            2元的奖金被抽出
        */
        //1.把奖池里面的所有奖项打乱顺序
        int[] arr = {2, 588, 888, 1000, 10000};
        Random r = new Random();
        for (int i = 0; i &lt; arr.length; i++) {
            //获取随机索引
            int randomIndex = r.nextInt(arr.length);
            //拿着i跟随机索引randomIndex上的值进行交换
            int temp = arr[i];
            arr[i] = arr[randomIndex];
            arr[randomIndex] = temp;
        }
        //2.遍历奖池,从0索引开始获取每一个奖项
        for (int i = 0; i &lt; arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

练习九:双色球
代码示例:

package com.itheima.test;
import java.util.Random;
import java.util.Scanner;
public class Test11 {
    public static void main(String[] args) {
        //1.生成中奖号码
        int[] arr = createNumber(); // 123456  7
        System.out.println("=======================");
        for (int i = 0; i &lt; arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println("=======================");
        //2.用户输入彩票号码(红球 + 蓝球)//654321
        int[] userInputArr = userInputNumber();
        //3.判断用户的中奖情况
        //红球 蓝球
        int redCount = 0;
        int blueCount = 0;
        //判断红球
        for (int i = 0; i &lt; userInputArr.length - 1; i++) {
            int redNumber = userInputArr[i];
            for (int j = 0; j &lt; arr.length - 1; j++) {
                if(redNumber == arr[j]){
                    redCount++;
                    //如果找到了,那么后面的数字就没有必要继续比较了
                    //跳出内循环,继续判断下一个红球号码是否中奖
                    break;
                }
            }
        }
        //判断蓝球
        int blueNumber = userInputArr[userInputArr.length-1];
        if(blueNumber == arr[arr.length - 1]){
            blueCount++;
        }
        //根据红球的个数以及蓝球的个数来判断中奖情况
        if(redCount == 6 &amp;&amp; blueCount == 1){
            System.out.println("恭喜你,中奖1000万");
        }else if(redCount == 6 &amp;&amp; blueCount == 0){
            System.out.println("恭喜你,中奖500万");
        }else if(redCount == 5 &amp;&amp; blueCount == 1){
            System.out.println("恭喜你,中奖3000");
        }else if((redCount == 5 &amp;&amp; blueCount == 0) ||  (redCount == 4 &amp;&amp; blueCount == 1)){
            System.out.println("恭喜你,中奖200");
        }else if((redCount == 4 &amp;&amp; blueCount == 0) ||  (redCount == 3 &amp;&amp; blueCount == 1)){
            System.out.println("恭喜你,中奖10");
        }else if((redCount == 2 &amp;&amp; blueCount == 1) ||  (redCount == 1 &amp;&amp; blueCount == 1)|| (redCount == 0 &amp;&amp; blueCount == 1)){
            System.out.println("恭喜你,中奖5");
        }else{
            System.out.println("谢谢参与,谢谢惠顾");
        }
    }
    public static int[] userInputNumber() {
        //1.创建数组用于添加用户购买的彩票号码
        //6个红球 1个蓝球 数组长度:7
        int[] arr = new int[7];
        //2.利用键盘录入让用输入
        Scanner sc = new Scanner(System.in);
        //让用户输入红球号码
        for (int i = 0; i &lt; 6; ) {
            System.out.println("请输入第" + (i + 1) + "个红球号码");
            int redNumber = sc.nextInt();
            //redNumber  在1~33  唯一不重复
            if (redNumber &gt;= 1 &amp;&amp; redNumber &lt;= 33) {
                boolean flag = contains(arr, redNumber);
                if (!flag) {
                    //不存在
                    //有效的,可以添加到数组当中
                    arr[i] = redNumber;
                    i++;
                } else {
                    //存在
                    System.out.println("当前红球号码已经存在,请重新输入");
                }
            } else {
                System.out.println("当前红球号码超出范围");
            }
        }
        //让用户输入篮球号码
        System.out.println("请输入篮球号码");
        //1~16
        while (true) {
            int blueNumber = sc.nextInt();
            if (blueNumber &gt;= 1 &amp;&amp; blueNumber &lt;= 16) {
                arr[arr.length - 1] = blueNumber;
                break;
            } else {
                System.out.println("当前篮球号码超出范围");
            }
        }
        return arr;
    }
    public static int[] createNumber() {
        //1.创建数组用于添加中奖号码
        //6个红球 1个蓝球 数组长度:7
        int[] arr = new int[7];
        //2.随机生成号码并添加到数组当中
        //红球:不能重复的  1 2 3 4 5 6
        //蓝球:可以跟红球号码重复 5
        //生成红球号码并添加到数组当中
        Random r = new Random();
        for (int i = 0; i &lt; 6; ) {
            //获取红球号码
            int redNumber = r.nextInt(33) + 1;
            boolean flag = contains(arr, redNumber);
            if (!flag) {
                //把红球号码添加到数组当中
                arr[i] = redNumber;
                i++;
            }
        }
        //生成蓝球号码并添加到数组当中
        int blueNumber = r.nextInt(16) + 1;
        arr[arr.length - 1] = blueNumber;
        return arr;
    }
    //用于判断数组在数组中是否存在
    public static boolean contains(int[] arr, int number) {
        for (int i = 0; i &lt; arr.length; i++) {
            if (arr[i] == number) {
                return true;
            }
        }
        return false;
    }
}

面向对象

面向对象——介绍

面向对象——类和对象

1.类和对象的理解
对象:真实存在的具体东西
类:是对象共同特征的描述
注意:在Java中,必须设计类,才能获得对象
2.类的定义
类的组成是由属性和行为两部分组成
属性:在类中通过成员变量来体现(类中方法外的变量)行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
类的定义步骤:
①定义类
②编写类的成员变量
③编写类的成员方法

public class 类名 { 	
// 成员变量 	变量1的数据类型 变量1; 	变量2的数据类型 变量2; 	… 	
// 成员方法 	方法1; 	方法2;	 
} 

3. 对象的使用
创建对象的格式:

类名 对象名 = new 类名();

调用成员的格式:

对象名.成员变量//代表属性,一般是名词
对象名.成员方法();//代表行为,一般是动词

4.定义类的补充的注意事项

  • 用来描述一类事物的类,专业叫做:javabean类。在javabean类中,是不写main方法的。
  • 在以前,编写main方法的类,叫做测试类。我们可以在测试类中创建javabean类的对象并进行赋值调用
  • 类名首字母建议大写
  • 一个Java文件中是可以定义多个class类的,且只有一个public修饰的类名必须称为代码文件名。实际开发中建议还是一个文件定义一个class类
  • 成员变量的完整格式是:修饰符 数据类型 变量名称=初始化值;一般无需指定初始化值,存在默认值。
    在这里插入图片描述

面向对象——封装

1 封装思想
封装概述:是面向对象三大特征之一(封装,继承,多态)对象代表什么,就得封装对应的数据,并提供数据对应的行为封装代码实现 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问 成员变量private,提供对应的getXxx()/setXxx()方法
2 private关键字

  • private是一个修饰符,可以用来修饰成员(成员变量,成员方法)
  • 被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰

面向对象——就近原则和this关键字

this关键字
this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量

public class Student { 
private String name; 
private int age; 
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 show() { 
   System.out.println(name + "," + age);
    } 
    } 

this的作用
区分成员变量和局部变量
就近原则

System.out.println(age);
System.out.println(this.age);

面向对象——构造方法

1 构造方法概述
构造方法是一种特殊的方法
作用:
创建对象 Student stu = new Student();
格式:public class 类名{ 修饰符 类名( 参数 ) { }}
功能:主要是完成对象数据的初始化
特点:

  1. 方法名与类名相同,大小写也要一致
  2. 没有返回值类型,连void都没有
  3. 没有具体的返回值(不能由return带回结果数据)

执行时机:

  1. 创建对象的时候由虚拟机调用,给变量初始化,不能手动调用构造方法(构造方法的作用)
  2. 每创建一次对象,就会调用一次构造方法

2 构造方法的注意事项

  • 构造方法的创建
  1. 无参构造方法:初始化对象的时候,成员变量的数据均采用默认值
  2. 有参构造方法:在初始化对象的时候,同时为对象进行赋值
  • 构造方法的重载
    如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
  • 推荐的使用方式
    无论是否使用,都手工书写无参数构造方法
    重要功能!可以使用带参构造,为成员变量进行初始化

面向对象——标准的Javabean类

1.标准类制作
① 类名需要见名知意
② 成员变量使用private修饰
③ 提供至少两个构造方法
无参构造方法带全部参数的构造方法
④ get和set方法
提供每一个成员变量对应的setXxx()/getXxx()
⑤ 如果还有其他行为,也需要写上
2.拓展
快捷键:
alt+insert
alt+Fn+insert
插件:
PTG 1秒生成标准Javabean
在这里插入图片描述

面向对象——三种情况的对象内存图

1.Java内存分配介绍

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

2. 对象内存图

2.1 单个对象内存图

Stuednt s=new Student();
  1. 加载class文件
  2. 申明局部变量
  3. 在堆内存中开辟一个空间
  4. 默认初始化
  5. 显示初始化
  6. 构造方法初始化
  7. 将堆内存中的地址赋值给左边的局部变量

成员变量使用过程
成员方法调用过程
在这里插入图片描述

2.2 多个对象内存图
成员变量使用过程
成员方法调用过程
在这里插入图片描述
在这里插入图片描述

总结:多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域中,成员方法多个对象共用的一份

面向对象——基本数据类型和引用数据类型

数据类型分类
基本数据类型:
整数类型、浮点数类型、布尔类型、字符类型
引用类型:
除了基本类型的都为引用类型
基本数据类型内存图
基本数据类型:数据值是存储在自已的空间中
特点:赋值给其他变量,也是赋的真实值
在这里插入图片描述
引用数据类型内存图
引用数据类型:数据值是存储在其他空间中,自已空间中存储的是地址值
特点:赋值给其他变量,赋的地址值
在这里插入图片描述

面向对象——this的内存原理

this作用:区分局部变量和成员变量
this本质:所在的方法调用者的地址值
在这里插入图片描述

面向对象——成员和局部

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

  • 类中位置不同:
    成员变量(类中方法外)
    局部变量(方法内部或方法声明上)
  • 初始化值不同:
    成员变量(有默认初始化值)
    局部变量(没有默认初始化值,必须先定义,赋值才能使用)
  • 内存中位置不同:
    成员变量(堆内存)
    局部变量(栈内存)
  • 生命周期不同:
    成员变量(随着对象的存在而存在,随着对象的消失而消失)
    局部变量(随着方法的调用而存在,醉着方法的调用完毕而消失)
  • 作用域:
    成员变量(整个类中有效)
    局部变量(当前方法中有效)

面向对象综合训练

面向对象综合训练——文字版格斗游戏

练习一:文字版格斗游戏

需求:
 格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人物的时候(new对象的时候),这些信息就应该被确定下来。
举例:
 程序运行之后结果为:
 姓名为:乔峰 血量为:100
 姓名为:鸠摩智 血量为:100
 乔峰举起拳头打了鸠摩智一下,造成了XX点伤害,鸠摩智还剩下XXX点血。
 鸠摩智举起拳头打了鸠摩智一下,造成了XX点伤害,乔峰还剩下XXX点血。
 乔峰举起拳头打了鸠摩智一下,造成了XX点伤害,鸠摩智还剩下XXX点血。
 鸠摩智举起拳头打了鸠摩智一下,造成了XX点伤害,乔峰还剩下XXX点血。
 乔峰K.O.了鸠摩智

拓展:

/*两部分参数
第一部分参数:要输出的内容%s(占位)
第二部分参数:填充的数据
*/
System.out.printf("hello%s","Tom")//helloTom
System.out.printf("%shello%s","Jony","Tom")//JonyhelloTom

代码示例:

import javafx.scene.control.RadioMenuItem;

import java.util.Random;

public class Role {
    private String name;
    private int blood;
    private char gender;
    private String face;
    //容颜:
    String[] boyfaces= {"风流俊雅","气宇轩昂","相貌英俊","五官端正","相貌平平","一塌糊涂","面目狰狞"};
    String[] girlfaces ={"美奂绝伦","沉鱼落雁","婷婷玉立","身材娇好","相貌平平","相貌简 陋","惨不忍睹"};
       // attack 攻击描述:
    String[] attacks_desc={
                "%s 使出了一招【背心钉】,转到对方的身后,一掌向%s 背心的灵台穴拍去。",
                "%s 使出了一招【游空探爪】,飞起身形自半空中变掌为抓锁向%s。",
                "%s 大喝一声,身形下伏,一招【劈雷坠地】,捶向%s 双腿。",
                "%s 运气于掌,一瞬间掌心变得血红,一式【掌心雷】,推向%s。",
                "%s 阴手翻起阳手跟进,一招【没遮拦】,结结实实的捶向%s。",
                "%s 上步抢身,招中套招,一招【劈挂连环】,连环攻向%s。"
        };
      //  injured 受伤描述:
    String[] injureds_desc= {
                "结果%s 退了半步,毫发无损",
                "结果给%s 造成一处瘀伤",
                "结果一击命中,%s 痛得弯下腰",
                "结果%s 痛苦地闷哼了一声,显然受了点内伤",
                "结果%s 摇摇晃晃,一跤摔倒在地",
                "结果%s 脸色一下变得惨白,连退了好几步",
                "结果『轰』的一声,%s 口中鲜血狂喷而出",
                "结果%s 一声惨叫,像滩软泥般塌了下去"
        };

    public Role() {
    }

    public Role(String name, int blood, char gender) {
        this.name = name;
        this.blood = blood;
        this.gender = gender;
        setFace(gender);
    }



    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public int getBlood() {
        return blood;
    }


    public void setBlood(int blood) {
        this.blood = blood;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }


    public String getFace() {
        return face;
    }


    public void setFace(char gender) {
        Random r=new Random();
        if(gender=='男'){
            int index =r.nextInt(boyfaces.length);
            this.face=boyfaces[index];
        }else if(gender=='女'){
            int index =r.nextInt(girlfaces.length);
            this.face=girlfaces[index];
        }else{
            this.face = "面目狰狞";

        }

    }

    public void attack(Role role){
        //atttack Effection
        Random r=new Random();
        int index=r.nextInt(attacks_desc.length);
        String KungFu=attacks_desc[index];
        System.out.printf(KungFu,this.getName(),role.getName());
        System.out.println();



        //
      //  Random r=new Random();
        int hurt=r.nextInt(20)+1;
        int remainBoold= role.getBlood()-hurt;
        remainBoold=remainBoold<0?0:remainBoold;
        role.setBlood(remainBoold);
        System.out.println(this.getName()+"举起拳头,打了"+role.getName()+"一下,"+"造成了"+hurt+"点伤害,鸠摩僧还剩下"+remainBoold+"点血");
        if(remainBoold>90){
            System.out.printf(injureds_desc[0],role.getName());
       }else if(remainBoold>80&&remainBoold<=90){
            System.out.printf(injureds_desc[1],role.getName());
        }else if(remainBoold>70&&remainBoold<=80){
            System.out.printf(injureds_desc[2],role.getName());
        }else if(remainBoold>60&&remainBoold<=70){
            System.out.printf(injureds_desc[3],role.getName());
        }else if(remainBoold>40&&remainBoold<=60){
            System.out.printf(injureds_desc[4],role.getName());
        }else if(remainBoold>20&&remainBoold<=40){
            System.out.printf(injureds_desc[5],role.getName());
        }else if(remainBoold>10&&remainBoold<=20){
            System.out.printf(injureds_desc[6],role.getName());
        }else{
            System.out.printf(injureds_desc[7],role.getName());
        }
        System.out.println();

    }
    public void showRoleInfo(){
        System.out.println("姓名为"+getName());
        System.out.println("血量为"+getBlood());
        System.out.println("性别为"+getGender());
        System.out.println("长相为"+getFace());

    }

}
public class GameTest {
    public static void main(String[] args) {
        Role r1=new Role("乔峰",20,'男');
        Role r2=new Role("鸠摩智",20,'女');
        r1.showRoleInfo();
        r2.showRoleInfo();
        while(true){
            r1.attack(r2);
            if(r2.getBlood()==0){
                System.out.println(r1.getName()+"K.O了"+r2.getName());
                break;
            }
            r2.attack(r1);
            if(r1.getBlood()==0){
                System.out.println(r2.getName()+"K.O了"+r1.getName());
                break;
            }
        }
    }
}

面向对象综合训练——两个对象数组练习

练习三:对象数组(商品)
需求:
定义数组存储3个商品对象。
商品的属性:商品的id,名字,价格,库存。
创建三个商品对象,并把商品对象存入到数组当中。

public class test {
    public static void main(String[] args) {
        Goods[] arr =new Goods[3];
        Goods g1=new Goods("001","华为P40",5999.0,100);
        Goods g2=new Goods("002","保温杯",227.0,50);
        Goods g3=new Goods("003","枸杞",12.7,70);
        arr[0]=g1;
        arr[1]=g2;
        arr[2]=g3;
        for(int i=0;i<arr.length;i++){
            Goods goods=arr[i];
            System.out.println(goods.getId()+","+goods.getName()+","+goods.getPrice()+","+goods.getCount());
        }
    }
}
public class Goods {
    private String id;
    private String name;
    private  double price;
    private int count;

    public Goods() {
    }

    public Goods(String id, String name, double price, int count) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.count = count;
    }

    /**
     * 获取
     * @return id
     */
    public String getId() {
        return id;
    }

    /**
     * 设置
     * @param id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return price
     */
    public double getPrice() {
        return price;
    }

    /**
     * 设置
     * @param price
     */
    public void setPrice(double price) {
        this.price = price;
    }

    /**
     * 获取
     * @return count
     */
    public int getCount() {
        return count;
    }

    /**
     * 设置
     * @param count
     */
    public void setCount(int count) {
        this.count = count;
    }

    public String toString() {
        return "Goods{id = " + id + ", name = " + name + ", price = " + price + ", count = " + count + "}";
    }
}


练习四:对象数组(汽车)
需求:
定义数组存储3部汽车对象。
汽车的属性:品牌,价格,颜色。
创建三个汽车对象,数据通过键盘录入而来,并把数据存入到数组当中。

import java.util.Scanner;

public class CarTest {
    public static void main(String[] args) {
        Car[] arr=new Car[3];
        Scanner sc=new Scanner(System.in);
        for(int i=0;i<arr.length;i++){
            Car c=new Car();
            System.out.println("请输入品牌");
            String brand= sc.next();
            c.setBrand(brand);
            System.out.println("请输入价格");
            int price=sc.nextInt();
            c.setPrice(price);
            System.out.println("请输入颜色");
            String color=sc.next();
            c.setColor(color);

            arr[i]=c;
        }
        for(int i=0;i<arr.length;i++){
            Car car=arr[i];
            System.out.println(car.getBrand()+","+car.getColor()+","+car.getPrice());
        }

    }}
public class Car {
    private String brand;
    private int price;
    private  String color;

    public Car() {
    }

    public Car(String brand, int price, String color) {
        this.brand = brand;
        this.price = price;
        this.color = color;
    }

    /**
     * 获取
     * @return brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * 设置
     * @param brand
     */
    public void setBrand(String brand) {
        this.brand = brand;
    }

    /**
     * 获取
     * @return price
     */
    public int getPrice() {
        return price;
    }

    /**
     * 设置
     * @param price
     */
    public void setPrice(int price) {
        this.price = price;
    }

    /**
     * 获取
     * @return color
     */
    public String getColor() {
        return color;
    }

    /**
     * 设置
     * @param color
     */
    public void setColor(String color) {
        this.color = color;
    }

    public String toString() {
        return "Car{brand = " + brand + ", price = " + price + ", color = " + color + "}";
    }
}

面向对象综合训练——对象数组判断和统计练习

练习五:对象数组(手机)
需求 :
定义数组存储3部手机对象。
手机的属性:品牌,价格,颜色。
要求,计算出三部手机的平均价格

public class PhoneTest {
    public static void main(String[] args) {
        Phone[]arr=new Phone[3];
        Phone p1=new Phone("xiaomi",1999,"white");
        Phone p2=new Phone("honor",2999,"balck");
        Phone p3=new Phone("APPLE",3999,"red");
        arr[0]=p1;
        arr[1]=p2;
        arr[2]=p3;

        int sum=0;
        for(int i=0;i< arr.length;i++){
            Phone phone=arr[i];
            sum=sum+phone.getPrice();
        }
        double avg2=sum*1.0/ arr.length;
        System.out.println(avg2);

    }}
public class Phone {
    private String brand;
    private int price;
    private String color;

    public Phone() {
    }

    public Phone(String brand, int price, String color) {
        this.brand = brand;
        this.price = price;
        this.color = color;
    }

    /**
     * 获取
     * @return brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * 设置
     * @param brand
     */
    public void setBrand(String brand) {
        this.brand = brand;
    }

    /**
     * 获取
     * @return price
     */
    public int getPrice() {
        return price;
    }

    /**
     * 设置
     * @param price
     */
    public void setPrice(int price) {
        this.price = price;
    }

    /**
     * 获取
     * @return color
     */
    public String getColor() {
        return color;
    }

    /**
     * 设置
     * @param color
     */
    public void setColor(String color) {
        this.color = color;
    }

    public String toString() {
        return "Phone{brand = " + brand + ", price = " + price + ", color = " + color + "}";
    }
}

练习六:对象数组(女朋友)
需求:
定义数组存储4个女朋友的对象
女朋友的属性:姓名、年龄、性别、爱好
要求1:计算出四女朋友的平均年龄
要求2:统计年龄比平均值低的女朋友有几个?并把她们的所有信息打印出来。

public class GirlFriendTest {
    public static void main(String[] args) {
        GirlFreind[]arr=new GirlFreind[4];
        GirlFreind gf1=new GirlFreind("zs",16,"beautiful","play game");
        GirlFreind gf2=new GirlFreind("zs",19,"beautiful","play game");
        GirlFreind gf3=new GirlFreind("zs",50,"beautiful","play game");
        GirlFreind gf4=new GirlFreind("zs",19,"beautiful","play game");
        arr[0]=gf1;
        arr[1]=gf2;
        arr[2]=gf3;
        arr[3]=gf4;
        int sum=0;
        for(int i=0;i< arr.length;i++){
            GirlFreind gf=arr[i];
            sum=sum+gf.getAge();
        }
        int count=0;
        int avg=sum/ arr.length;
        for(int i=0;i< arr.length;i++){
            GirlFreind gf=arr[i];
            if(gf.getAge()<avg){
                count++;
                System.out.println(gf.getName()+","+gf.getAge()+","+gf.getGender()+","+gf.getHobby());
            }
        }
        System.out.println(count+"个");
    }
}
public class GirlFreind {
    private String name;
    private int age;
    private String gender;
    private String hobby;

    public GirlFreind() {
    }

    public GirlFreind(String name, int age, String gender, String hobby) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.hobby = hobby;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }

    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    /**
     * 获取
     * @return hobby
     */
    public String getHobby() {
        return hobby;
    }

    /**
     * 设置
     * @param hobby
     */
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String toString() {
        return "GirlFreind{name = " + name + ", age = " + age + ", gender = " + gender + ", hobby = " + hobby + "}";
    }
}

面向对象综合训练——复杂对象数组练习:添加和遍历、删除和修改

练习七:复杂的对象数组操作
定义一个长度为3的数组,数组存储1~3名学生对象作为初始数据,学生对象的学号,姓名各不相同。
学生的属性:学号,姓名,年龄。
要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一性判断。
要求2:添加完毕之后,遍历所有学生信息。
要求3:通过id删除学生信息
如果存在,则删除,如果不存在,则提示删除失败。
要求4:删除完毕之后,遍历所有学生信息。
要求5:查询数组id为“heima002”的学生,如果存在,则将他的年龄+1岁

public class Test {
    public static void main(String[] args) {
        Student[]arr=new Student[3];
        Student stu1=new Student(1,"zhangsan",23);
        Student stu2=new Student(2,"zhang",24);
        Student stu3=new Student(3,"san",25 );

        arr[0]=stu1;
        arr[1]=stu2;
        arr[2]=stu3;
        Student stu4=new Student(4,"xiaohong", 26);
        boolean flag=contains(arr, stu4.getId());
        if (flag){
            System.out.println("当前id存在,请修改id");
        }else{
            int count=getCount(arr);
            if(count== arr.length){

                Student[] newArr=createNewArr(arr);
                newArr[count]=stu4;
                printArr(newArr);
            }else{
                arr[count]=stu4;
                printArr(arr);
            }
        }
        int index=getIndex(arr,2);
        if(index>=0){
            arr[index]=null;
            //修改
//            Student stu=arr[index];
//            int newAge=stu.getAge()+1;
//            stu.setAge(newAge);
        }else{
            System.out.println("删除失败");

//            System.out.println("修改失败");
            }
        System.out.println(index);



    }
    public static int getIndex(Student[]arr,int id){
        for(int i=0;i< arr.length;i++){
            Student stu=arr[i];
            if(stu!=null){
                int sid= stu.getId();
                if(sid==id){
                    return i;
                }
            }
        }
        return -1;

    }
    public static  void printArr(Student[] arr){
        for(int i=0;i<arr.length;i++){
            Student stu=arr[i];
            if(stu!=null){
                System.out.println(stu.getId()+","+stu.getName()+","+ stu.getAge());
            }
        }
    }
    public static Student[] createNewArr(Student[] arr){
        Student[] newArr=new Student[arr.length+1];
        for(int i=0;i< arr.length;i++){
            newArr[i]=arr[i];
        }
        return newArr;
    }
    public static int getCount(Student[] arr){
        int count=0;
        for(int i=0;i<arr.length;i++){
            if(arr[i]!=null){
                count++;
            }
        }
        return count;
    }
    public static boolean contains(Student arr[],int id){
        for(int i=0;i< arr.length;i++){
            Student stu=arr[i];
            if(stu!=null){
                int sid= stu.getId();
                if(sid==id){
                    return true;
                }
            }
            int sid=stu.getId();
            if(sid==id){
                return true;
            }
        }
        return false;
    }
    //
}
public class Student {
    private int id;
    private String name;
    private int age;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return id
     */
    public int getId() {
        return id;
    }

    /**
     * 设置
     * @param id
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }


}

字符串

字符串——API文档

1.API概述
什么是API
API (Application Programming Interface) :应用程序编程接口
java中的API
指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。
API帮助文档
帮助开发人员工号的使用API和查询API的一个工具
2.如何使用API帮助文档
打开帮助文档–找到索引选项卡中的输入框–在输入框中输入Random–看类在哪个包下–看类的描述–看构造方法–看成员方法

字符串——String概述

1.String类概述
String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。String 类在 java.lang 包下,所以使用的时候不需要导包!
2.String类的特点
字符串不可变,它们的值在创建后不能被更改
虽然 String 的值是不可变的,但是它们可以被共享
字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )

字符串——String构造方法代码实现和内存分析

1.String类的构造方法
常用的构造方法
方法名 说明
public String() 创建一个空白字符串对象,不含有任何内容
public String(String original)根据传入的字符串,创建字符串对象
public String(char[] chs)根据字符数组的内容,来创建字符串对象
public String(byte[] bys)根据字节数组的内容,来创建字符串对象
String s = “abc”;直接赋值的方式创建字符串对象,内容就是abc

public class StringDemo1 {
    public static void main(String[] args) {
//       1.直接赋值的方式获取一个字符串对象
        String s1="abc";
        System.out.println(s1);
//      2.使用new的方式获取一个字符串对象
//        空参构造:可以获取一个空白的字符串对象
        String s2=new String();
        System.out.println("@"+s2+"!");
//        传递一个字符串,根据传递的字符串内容再创造一个新的字符串对象
        String s3=new String("abc");
        System.out.println(s3);
//        传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
//        需求:我要修改字符串的内容
//        abc——>{'a','b','c'}——>{Q','b','c'}——>"Qbc"
        char []chs={'a','b','c','d'};
      String s4=new String(chs);
//      传递一个字节数组,跟几次字节数组的内容再创建一个新的字符串对象
//        应用场景:以后网络当中传输的数据其实就是字节信息
//        我们一般要把字节信息进行转换,转成字符串,此时就是要用这个构造了
        byte[] bytes={97,98,99,100};
        String s5=new String(bytes);
        System.out.println(s5);


    }
}

2.创建字符串对象两种方式的区别
通过构造方法创建
通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同
直接赋值方式创建
以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护
3.Java的内存模型
当使用双引号直接赋值时,系统会检查该字符串在串池是否存在。不存在就创建新的,存在就直接复用;new String是存储在堆里的。
在这里插入图片描述
在这里插入图片描述

字符串——字符串比较

1.==号的作用
比较基本数据类型:比较的是具体的值
比较引用数据类型:比较的是对象地址值
2.equals方法的作用

  • boolean equals方法(要比较的字符串) 完全是一样的结果才是true 否则为false
  • boolean equalsIgnoreCase(要比较的字符串)忽略大小写的比较

public boolean equals(String s)比较两个字符串内容是否相同、区分大小写
示例代码

public class StringDemo02 {
    public static void main(String[] args) {
        //构造方法的方式得到对象
        char[] chs = {'a', 'b', 'c'};
        String s1 = new String(chs);
        String s2 = new String(chs);
        //直接赋值的方式得到对象
        String s3 = "abc";
        String s4 = "abc";
        //比较字符串对象地址是否相同
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s3 == s4);
        System.out.println("--------");
        //比较字符串内容是否相同
        System.out.println(s1.equals(s2));
        System.out.println(s1.equals(s3));
        System.out.println(s3.equals(s4));
    }
}

字符串——用户登录

1.案例需求
已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示
2.代码实现

public class Test1登录案例 {
    public static void main(String[] args) {
        //1.定义两个变量用来记录正确的用户名和密码
        String rightUsername = "itheima";
        String rightPassword = "1234qwer";
        //2.键盘录入用户名和密码
        //ctrl + alt + T 选择包裹方式
        for (int i = 0; i < 3; i++) {//0 1 2
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名");
            String username = sc.next();
            System.out.println("请输入密码");
            String password = sc.next();
            //3.判断比较
            if (username.equals(rightUsername) && password.equals(rightPassword)) {
                System.out.println("登录成功");
                //如果正确,循环结束
                break;
            } else {
                //最后一次机会
                if(i == 2){
                    System.out.println("账户" + username + "被锁定,请联系黑马程序员官方小姐姐:XXXXXXX");
                }else{
                    //不是最后一次机会
                    System.out.println("用户名或密码错误,登录失败,还剩下" + (2 - i) + "次机会");//2 1 0
                }
            }
        }
    }
}

字符串——遍历字符串和统计字符

遍历字符串
1.案例需求
键盘录入一个字符串,使用程序实现在控制台遍历该字符串
2.直接遍历字符串

public class Test2字符串直接遍历 {
    public static void main(String[] args) {
        //两个方法:
        //charAt():会根据索引获取对应的字符
        //length(): 会返回字符串的长度
        //1.键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串");
        String str = sc.next();
        System.out.println(str);
        //2.遍历
        for (int i = 0; i < str.length(); i++) {
            //i 依次表示字符串的每一个索引
            //索引的范围:0 ~  长度-1
            //根据索引获取字符串里面的每一个字符
            //ctrl + alt + V 自动生成左边的接受变量
            char c = str.charAt(i);
            System.out.println(c);
        }
    }
}

统计字符次数案例
1案例需求
键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)
2代码实现

public class Test4统计个数 {
    public static void main(String[] args) {
        //键盘录入一个字符串,统计大写,小写,数字出现的次数
        //1.键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        String str = sc.next();
        //2.统计 --- 计数器count
        //此时我要统计的有3样东西,所以要定义3个计数器分别进行统计
        int bigCount = 0;
        int smallCount = 0;
        int numberCount = 0;
        //得到这个字符串里面每一个字符
        for (int i = 0; i < str.length(); i++) {
            //i 表示字符串中的索引
            //c 表示字符串中的每一个字符
            char c = str.charAt(i);
            //对c进行判断
            if (c >= 'a' && c <= 'z') {
                smallCount++;
            }else if(c >= 'A' && c <= 'Z'){
                bigCount++;
            }else if(c >= '0' && c <= '9'){
                numberCount++;
            }
        }
        //3.当循环结束之后,三个变量记录的就是对应的个数
        System.out.println("大写字符有:" + bigCount + "个");
        System.out.println("小写字符有:" + smallCount + "个");
        System.out.println("数字字符有:" + numberCount + "个");
    }
}

字符串——字符串反转和拼接

字符串拼接案例
1案例需求
定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
并在控制台输出结果。例如,数组为 int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]
2代码实现

public class Test5数组拼接成字符串 {
    public static void main(String[] args) {
        //定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
        //并在控制台输出结果。例如,数组为 int[] arr = {1,2,3};
        //执行方法后的输出结果为:[1, 2, 3]
        int[] arr = {1, 2, 3, 4, 5};
        String str = arrToString(arr);
        System.out.println(str);
    }
    //作用:把一个数组变成字符串
    public static String arrToString(int[] arr) {
        String s = "";
        //拼接左括号
        s = s + "["; //此时是拿着长度为0的字符串,跟[进行拼接,产生一个新的字符串。
        //把新的字符串再赋值给s,此时变量s记录的就是新的字符串"["的地址值
        //下面我想得到数组里面的每一个元素并进行拼接
        //那么就需要遍历数组,得到每一个元素才行
        for (int i = 0; i < arr.length; i++) {
            //假设第一次循环:i = 0 获取的就是0索引上的元素
            //在拼接的时候:"[" + 1 + ", " 拼接完毕之后产生一个新的字符串 "[1, "
            //第二次循环:i = 1 获取的就是1索引上的元素
            //在拼接的时候: 此时s就是第一次循环结束后拼接完毕的结果:"[1, "
            //在拼接的时候:"[1, " + 2 + ", " 拼接完毕之后产生一个新的字符串 "[1, 2, "
            //...
           if(i == arr.length - 1){
               //如果是最后一个元素,那么不需要拼接逗号空格
               s = s + arr[i];
           }else{
               //如果不是最后一个元素,需要拼接元素和逗号空格
               s = s + arr[i] + ", ";
           }
        }
        //等循环结束之后,再拼接最后一个右括号
        s = s + "]";
        return s;
    }
    //用来遍历数组
    public static void printArr(int[] arr) {
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                System.out.print(arr[i]);
            } else {
                System.out.print(arr[i] + ", ");
            }
        }
        System.out.println("]");
        //[1, 2, 3, 4, 5]
        //我们现在要知道,这个最终结果是怎么来的?
        //从到右依次打印得来的。
    }
}

字符串反转案例
1.案例需求
定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果
例如,键盘录入 abc,输出结果 cba
2.代码实现

public class Test6反转字符串 {
    public static void main(String[] args) {
        /*定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果
        例如,键盘录入 abc,输出结果 cba*/
        //1.定义一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        String str = sc.next();
        //2.定义一个方法,反转字符串
        //abc  --->  cba
        //可以把字符串倒着遍历,再拼接
        String result = reverse(str);
        System.out.println(result);
    }
    //注释:方法的作用就是反转字符串
    //把传递进来的字符串进行反转
    public static String reverse(String str){//abc
        //核心思想:倒着遍历并进行拼接就可以了
        //fori :正着遍历  forr:倒着遍历
        String s = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            //i 依次表示字符串里面的每一个索引(倒着的)
            //我们就可以拿到里面的每一个字符并拼接
            s = s + str.charAt(i);
        }
        //把倒着拼接之后的结果返回即可
        return s;
    }
}

字符串——金额转换

1.案例需求
把2135变成:零佰零拾零万贰仟壹佰叁拾伍元
把789变成:零佰零拾零万零仟柒佰捌拾玖元
2.代码实现

package com.itheima.stringdemo;
import java.util.Scanner;
public class StringDemo9 {
    public static void main(String[] args) {
        //1.键盘录入一个金额
        Scanner sc = new Scanner(System.in);
        int money;
        while (true) {
            System.out.println("请录入一个金额");
            money = sc.nextInt();
            if (money >= 0 && money <= 9999999) {
                break;
            } else {
                System.out.println("金额无效");
            }
        }
        //定义一个变量用来表示钱的大写
        String moneyStr = "";
        //2.得到money里面的每一位数字,再转成中文
        while (true) {//2135
            //从右往左获取数据,因为右侧是数据的个位
            int ge = money % 10;
            String capitalNumber = getCapitalNumber(ge);
            //把转换之后的大写拼接到moneyStr当中
            moneyStr = capitalNumber + moneyStr;
            //第一次循环 : "伍" + "" = "伍"
            //第二次循环 : "叁" + "伍" = "叁伍"
            //去掉刚刚获取的数据
            money = money / 10;
            //如果数字上的每一位全部获取到了,那么money记录的就是0,此时循环结束
            if (money == 0) {
                break;
            }
        }
        //3.在前面补0,补齐7位
        int count = 7 - moneyStr.length();
        for (int i = 0; i < count; i++) {
            moneyStr = "零" + moneyStr;
        }
        System.out.println(moneyStr);//零零零贰壹叁伍
        //4.插入单位
        //定义一个数组表示单位
        String[] arr = {"佰","拾","万","仟","佰","拾","元"};
        //               零    零   零   贰   壹   叁   伍
        //遍历moneyStr,依次得到 零    零   零   贰   壹   叁   伍
        //然后把arr的单位插入进去
        String result = "";
        for (int i = 0; i < moneyStr.length(); i++) {
            char c = moneyStr.charAt(i);
            //把大写数字和单位拼接到result当中
            result = result + c + arr[i];
        }
        //5.打印最终结果
        System.out.println(result);
    }
    //定义一个方法把数字变成大写的中文
    //1 -- 壹
    public static String getCapitalNumber(int number) {
        //定义数组,让数字跟大写的中文产生一个对应关系
        String[] arr = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        //返回结果
        return arr[number];
    }
}

字符串——手机号屏蔽、身份证信息查看、游戏敏感词屏蔽

手机号屏蔽
需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:131****9468
代码实现:

public class Test8手机号屏蔽 {
    public static void main(String[] args) {
        /*以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
        最终效果为:131****9468*/
        //1.键盘录入一个手机号码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入手机号码");
        String phoneNumber = sc.next();//13112349408
        //2.截取手机号码中的前三位
        String star = phoneNumber.substring(0, 3);
        //3.截取手机号码中的最后四位
        //此时我用substring方法,是用1个参数的,还是两个参数的?1个参数的会更好
        //因为现在我要截取到最后,所以建议使用1个参数的。
        String end = phoneNumber.substring(7);
        //4.拼接
        String result = star + "****" + end;
        System.out.println(result);
    }
}

敏感词替换
需求1:键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换

public class Test9敏感词替换 {
    public static void main(String[] args) {
        //1.定义一个变量表示骂人的话
        String talk = "后裔你玩什么啊,TMD";
        //2.把这句话中的敏感词进行替换
        String result = talk.replace("TMD", "***");
        //3.打印
        System.out.println(talk);
        System.out.println(result);
    }
}

需求2:如果要替换的敏感词比较多怎么办?

public class Test10多个敏感词替换 {
    public static void main(String[] args) {
        //实际开发中,敏感词会有很多很多
        //1.先键盘录入要说的话
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要说的话");
        String talk = sc.next();//后裔你玩什么啊,TMD,GDX,ctmd,ZZ
        //2.定义一个数组用来存多个敏感词
        String[] arr = {"TMD","GDX","ctmd","ZZ","lj","FW","nt"};
        //3.把说的话中所有的敏感词都替换为***
        for (int i = 0; i < arr.length; i++) {
            //i 索引
            //arr[i] 元素 --- 敏感词
            talk = talk.replace(arr[i],"***");
        }
        //4.打印结果
        System.out.println(talk);//后裔你玩什么啊,***,***,***,***
    }
}

身份证信息查看
1.知识点:

  • String substring(int beginIndex,int endindex)截取;注意点这个是包头不包尾,包左不包右,只有返回值才是截取的小串
  • String substring(int beginIndex)截取到末尾

2.案例描述:

身份证的每一位都是有固定的含义:
1、2位:省份
3、4位:城市
5、6位:区县
7-14位:出生年、月、日
15、16位:所在地派出所
17位:性别(奇数男性,偶数女性)
18位:个人信息码(随机产生)
要求打印内容方式如下:
人物信息为:
出生年月日:XXXX年X月X日
性别为:男/女

package com.itheima.stringdemo;
public class StringDemo11 {
    public static void main(String[] args) {
        //1.定义一个字符串记录身份证号码
        String id = "321281202001011234";
        //2.获取出生年月日
        String year = id.substring(6, 10);
        String month = id.substring(10, 12);
        String day = id.substring(12, 14);
        System.out.println("人物信息为:");
        System.out.println("出生年月日:" + year + "年" + month + "月" + day + "日");
        //3.获取性别
        char gender = id.charAt(16);//'3'  ---> 3
        //利用ASCII码表进行转换
        //'0' --->  48
        //'1' --->  49
        //'2' --->  50
        //'3' --->  51
        //'4' --->  52
        //'5' --->  53
        //'6' --->  54
        //'7' --->  55
        //'8' --->  56
        //'9' --->  57
       int num = gender - 48;
        if(num % 2 == 0){
            System.out.println("性别为:女");
        }else{
            System.out.println("性别为:男");
        }
    }
}

字符串——StringBuiler的基本操作

1.概述
StringBuilder 可以看成是一个容器,创建之后里面的内容是可变的。
当我们在拼接字符串和反转字符串的时候会使用到
2.StringBuilder知识点
2.1StringBuilder 构造方法

方法名说明
public StringBuilder()创建一个空白可变字符串对象,不含任何内容
public StringBuilder(String str)根据字符串的内容,来创建可变字符串对象

2.2StringBuilder常用方法

方法名说明
public StringBuilder append(任意类型)添加数据,并返回对象本身
public StringBuilder reverse()反转容器中的内容
public int length()返回长度(字符出现的个数)
public String toString()通过toString()就可以实现把StringBuilder转换为String

3.基本使用

public class StringBuilderDemo3 {
    public static void main(String[] args) {
        //1.创建对象
        StringBuilder sb = new StringBuilder("abc");
        //2.添加元素
        /*sb.append(1);
        sb.append(2.3);
        sb.append(true);*/
        //反转
        sb.reverse();
        //获取长度
        int len = sb.length();
        System.out.println(len);
        //打印
        //普及:
        //因为StringBuilder是Java已经写好的类
        //java在底层对他做了一些特殊处理。
        //打印对象不是地址值而是属性值。
        System.out.println(sb);
    }
}

4.链式编程
定义:当我们在调用一个方法的时候,不需要变量接受他的结果,可以继续调用其他方法

public class StringBuilderDemo4 {
    public static void main(String[] args) {
        //1.创建对象
        StringBuilder sb = new StringBuilder();
        //2.添加字符串
        sb.append("aaa").append("bbb").append("ccc").append("ddd");
        System.out.println(sb);//aaabbbcccddd
        //3.再把StringBuilder变回字符串
        String str = sb.toString();
        System.out.println(str);//aaabbbcccddd
    }
}

练习1:对称字符串
需求:
键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
对称字符串:123321、111
非对称字符串:123123
代码示例:

public class StringBuilderDemo6 {
    //使用StringBuilder的场景:
    //1.字符串的拼接
    //2.字符串的反转
    public static void main(String[] args) {
        //1.键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串");
        String str = sc.next();
        //2.反转键盘录入的字符串
        String result = new StringBuilder().append(str).reverse().toString();
        //3.比较
        if(str.equals(result)){
            System.out.println("当前字符串是对称字符串");
        }else{
            System.out.println("当前字符串不是对称字符串");
        }
    }
}

练习2:拼接字符串
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回。
调用该方法,并在控制台输出结果。
例如:数组为int[] arr = {1,2,3};
执行方法后的输出结果为:[1, 2, 3]
代码示例:

package com.itheima.stringbuilderdemo;
public class StringBuilderDemo7 {
    public static void main(String[] args) {
        //1.定义数组
        int[] arr = {1,2,3};
        //2.调用方法把数组变成字符串
        String str = arrToString(arr);
        System.out.println(str);
    }
    public static String arrToString(int[] arr){
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < arr.length; i++) {
            if(i == arr.length - 1){
                sb.append(arr[i]);
            }else{
                sb.append(arr[i]).append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}

字符串——Stringjoiner

1.定义
StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。
作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。
JDK8出现的
2.StringJoiner的构造方法

方法名说明
public StringJoiner(间隔符号)创建一个StringJoiner对象,直到拼接时的间隔符号
public StringJoiner(间隔符号、开始符号、结束符号)创建一个StringJoiner对象,直到拼接时的间隔符号、开始符号、结束符号
public StringJoiner add添加数据、并且返回对象本身
public int length()返回长度(字符出现个数)
public String toString()返回一个字符串(该字符串就是拼接后的结果)

基本使用:

//1.创建一个对象,并指定中间的间隔符号
StringJoiner sj = new StringJoiner("---");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
//3.打印结果
System.out.println(sj);//aaa---bbb---ccc
//1.创建对象
StringJoiner sj = new StringJoiner(", ","[","]");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
int len = sj.length();
System.out.println(len);//15
//3.打印
System.out.println(sj);//[aaa, bbb, ccc]
String str = sj.toString();
System.out.println(str);//[aaa, bbb, ccc]

总结

  • String:表示字符串的类,定义了很多操作字符串的方法
  • StringBuilder:一个可变的操作字符串的容器,可以高效的拼接字符串,还可以将容器里面的内容反转
  • StringJoiner:JDK8出现的一个可变的操作字符串的容器,可以高效,方便的拼接字符串,在拼接的时候,可以指定间隔符号,开始符号,结束符号。

拓展
快捷键 ctrl+B 查看源码
arr.for i快速生成

字符串——字符串相关的底层原理

字符串存储的内存原理

  1. String s = “abc”;直接赋值
    特点:
    此时字符串abc是存在字符串常量池中的。
    先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。
    所以,直接赋值的方式,代码简单,而且节约内存。
  2. new出来的字符串
    看到new关键字,一定是在堆里面开辟了一个小空间。

例子:

String s1 = new String(“abc”);
String s2 = “abc”;

s1记录的是new出来的,在堆里面的地址值。
s2是直接赋值的,所以记录的是字符串常量池中的地址值。
==号比较的到底是什么?

  1. 如果比较的是基本数据类型:比的是具体的数值是否相等。
  2. 如果比较的是引用数据类型:比的是地址值是否相等。

结论:==只能用于比较基本数据类型。不能比较引用数据类型。

字符串拼接的底层原理

  1. 如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果,会复用串池中的字符串。
  2. 如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存

结论:如果字符串变量拼接,不要直接+,在底层会创建多个对象浪费时间,浪费性能
StringBuilder提高效率原理图
所有的要破解的孽徒都会忘StringBuilder中放,不会创建很多无用的空间,节约内存。
StrigBuilder源码分析

  1. 默认创建一个长度为16的字节数组
  2. 添加的内推小于16,直接存
  3. 添加的内容大于16会扩容(原来容量*2+2)
  4. 如果扩容之后还不够,以实际长度为准

字符串——罗马数字的两种写法

在这里插入图片描述

import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str;
        while (true) {
            System.out.println("请输入一个字符串");
            str = sc.next();
            boolean flag = checkStr(str);
            if (flag) {
                break;
            } else {
                System.out.println("当前字符串不符合规则,请重新输入");
                continue;
            }
        }
        StringBuilder sb=new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            int number=c-48;
            String s=changeLuoMa(number);
            sb.append(s);

        }
        System.out.println(sb);

    }
    public  static String changeLuoMa(int number){
        String[] arr={"","I","II","III","IV","V","VI","VII","VIII","IX"};
        return arr[number];
    }
    public static boolean checkStr(String str){
        if(str.length()>9){
            return false;
        }
        for(int i=0;i<str.length();i++){
            char c=str.charAt(i);
            if(c<'0'||c>'9'){
                return false;
            }
        }
        return true;
    }
}

字符串——调整字符串内容并且比较

在这里插入图片描述
第一种解法:用subString进行截取,把左边的字符截取出来拼接到右边去

import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {

        String strA = "abcde";
        String strB = "ceab";
        //String rotate=rotate(strA);
        boolean result=check(strA,strB);
        System.out.println(result);

    }
    public static boolean check(String strA,String strB){
        for (int i=0;i<strA.length();i++){
            strA=rotate(strA);
            if(strA.equals(strB)){
                return true;
            }
        }
        return false;
    }

    public static String rotate(String str){
        char first=str.charAt(0);
        String end=str.substring(1);
        return end+first;
    }

}

第二种:可以把字符串线边仓一个字符数组。然后调整字符数组里的数据,把字符数组变成字符串

import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {

        String strA = "abcde";
        String strB = "abcde";
        //String rotate=rotate(strA);
        boolean result=check(strA,strB);
        System.out.println(result);

    }
    public static boolean check(String strA,String strB){
        for (int i=0;i<strA.length();i++){
            strA=rotate(strA);
            if(strA.equals(strB)){
                return true;
            }
        }
        return false;
    }

    public static String rotate(String str){
//        char first=str.charAt(0);
//        String end=str.substring(1);
//        return end+first;
        char[]arr=str.toCharArray();
        char fist=arr[0];
        for (int i=1;i< arr.length;i++){
            arr[i-1]=arr[i];
        }
        arr[arr.length-1]=fist;
        String result=new String(arr);
        return result;
    }

}

ArrayList

集合和数组的优势对比:
1.长度可变
2.添加数据的时候不需要考虑索引,默认将数据添加到末尾
ArrayList类概述
1.什么是集合
提供一种存储空间可变的存储模型,存储的数据容量可以发生改变
2.ArrayList集合的特点

  • 长度可以变化,只能存储引用数据类型。
    泛型的使用
  • 用于约束集合中存储元素的数据类型
import java.util.ArrayList;
public class ArrayListDemo1 {
    public static void main(String[] args) {
        //1.创建集合的对象
        //泛型:限定集合中存储数据的类型
        //ArrayList<String> list = new ArrayList<String>();
        //JDK7:
        //此时我们创建的是ArrayList的对象,而ArrayList是java已经写好的一个类
        //这个类在底层做了一些处理
        //打印对象不是地址值,而是集合中存储数据内容
        //在展示的时候会拿[]把所有的数据进行包裹
        ArrayList<String> list = new ArrayList<>();
        System.out.println(list);
    }
}

ArrayList成员方法

方法名说明
boolean add(E e)添加元素,返回值表示是否成功添加
boolean remove(E e)删除指定元素,返回值表示是否成功删除
E remove(int index)删除指定索引元素,返回被删除元素
E set(int index,E e)修改指定索引元素,返回原来的元素
E get(int index)获取指定索引元素
int size()集合的长度,也就是集合中元素的个数
package com.itheima.listdemo;


import java.util.ArrayList;

/*
    boolean add(E e)        添加

    boolean remove(E e)     删除
    E remove(int index)

    E set(int index,E e)    修改

    E get(int index)        查询
    int size()              获取长度

 */
public class ArrayListDemo2 {
    public static void main(String[] args) {

        //1.创建一个集合
        ArrayList<String> list = new ArrayList<>();

        //2.添加元素
        list.add("aaa");
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        

        //3.删除元素
      /*  boolean result1 = list.remove("aaa");
        System.out.println(result1);

        boolean result2 = list.remove("ddd");
        System.out.println(result2);

        String str = list.remove(2);
        System.out.println(str);*/


        //修改元素
        /*String result = list.set(1, "ddd");
        System.out.println(result);*/

        //查询元素
       /* String s = list.get(0);
        System.out.println(s);*/

        //遍历
        for (int i = 0; i < list.size(); i++) {
            //i 索引
            //list.get(i) 元素
            String str = list.get(i);
            System.out.println(str);
        }



    }
}

ArrayList——集合的基本使用

1.2 ArrayList类常用方法
1.2.1 构造方法
方法名 说明
public ArrayList() 创建一个空的集合对象
1.2.2 成员方法
方法名 说明
public boolean add(要添加的元素) 将指定的元素追加到此集合的末尾
public boolean remove(要删除的元素) 删除指定元素,返回值表示是否删除成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数
1.2.3 示例代码

public class ArrayListDemo02 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> array = new ArrayList<String>();
        //添加元素
        array.add("hello");
        array.add("world");
        array.add("java");
        //public boolean remove(Object o):删除指定的元素,返回删除是否成功
        //        System.out.println(array.remove("world"));
        //        System.out.println(array.remove("javaee"));
        //public E remove(int index):删除指定索引处的元素,返回被删除的元素
        //        System.out.println(array.remove(1));
        //IndexOutOfBoundsException
        //        System.out.println(array.remove(3));
        //public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
        //        System.out.println(array.set(1,"javaee"));
        //IndexOutOfBoundsException
        //        System.out.println(array.set(3,"javaee"));
        //public E get(int index):返回指定索引处的元素
        //        System.out.println(array.get(0));
        //        System.out.println(array.get(1));
        //        System.out.println(array.get(2));
        //System.out.println(array.get(3)); //?????? 自己测试
        //public int size():返回集合中的元素的个数
        System.out.println(array.size());
        //输出集合
        System.out.println("array:" + array);
    }
}

ArrayList——添加字符串和整数并且遍历

集合的遍历方式
1.案例需求
创建一个存储字符串的集合,存储3个字符串元素,使用程序实现在控制台遍历该集合,格式[元素1,元素2,元素3]
2.代码实现

public class ArrayListDemo3 {
    public static void main(String[] args) {
        //1.创建集合对象
        ArrayList<String> list = new ArrayList<>();
        //2.添加元素
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        //3.遍历
        //快捷键: list.fori 正向遍历
        //list.forr 倒着遍历
        System.out.print("[");
        for (int i = 0; i < list.size(); i++) {
            //i 依次表示集合里面的每一个索引
            if(i == list.size() - 1){
                //最大索引
                System.out.print(list.get(i));
            }else{
                //非最大索引
                System.out.print(list.get(i) + ", ");
            }
        }
        System.out.print("]");
    }
}

添加数字并遍历
1.案例需求
定义一个集合,添加数字,并进行遍历,比那里格式[元素1,元素2,元素3]
2.基本数据类型对应的包装类

byteByte
shortShort
chartCharacter
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean

3.代码实现

package com.itheima.test;

import java.util.ArrayList;

public class Test2 {
    public static void main(String[] args) {
        //1.创建集合
        ArrayList<Integer> list = new ArrayList<>();

        //2.添加元素
        //jdk5以后 int Integer 之间是可以互相转化的
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

        //3.遍历集合
        System.out.print("[");
        for (int i = 0; i < list.size(); i++) {
            if(i == list.size() - 1){
                System.out.print(list.get(i));
            }else{
                System.out.print(list.get(i) + ", ");
            }
        }
        System.out.println("]");
    }
}

ArrayList——添加学生对象并且遍历

1.4.1 案例需求
创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合
1.4.2 代码实现

package com.itheima.test;

import java.util.ArrayList;
import java.util.Scanner;

public class Test5 {
    public static void main(String[] args) {
        //1.创建集合
        ArrayList<Student> list = new ArrayList<>();
        //长度为0
        //2.键盘录入学生的信息并添加到集合当中
       
        Student s = new Student();
        for (int i = 0; i < 3; i++) {
         Scanner sc = new Scanner(System.in); 
            System.out.println("请输入学生的姓名");
            String name = sc.next();
            System.out.println("请输入学生的年龄");
            int age = sc.nextInt();

            //把name和age赋值给学生对象
            s.setName(name);
            s.setAge(age);

            //把学生对象添加到集合当中
            list.add(s);
        }
        //3.遍历
        for (int i = 0; i < list.size(); i++) {
            //i 索引 list.get(i) 元素/学生对象
            Student stu = list.get(i);
            System.out.println(stu.getName() + ", " + stu.getAge());
        }
    }
}

package com.itheima.test;

public class Student {
    //1.私有化成员变量
    //2.空参构造方法
    //3.带全部参数的构造方法
    //4.get/set方法

    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


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

ArrayList——查找用户是否存在

快捷键:ctrl+p 提示
1.5 查找用户的索引
需求:
1,main方法中定义一个集合,存入三个用户对象。
用户属性为:id,username,password
2,要求:定义一个方法,根据id查找对应的学生信息。
如果存在,返回索引
如果不存在,返回-1
代码示例:

public class ArrayListDemo6 {
    public static void main(String[] args) {
        /*需求:
        1,main方法中定义一个集合,存入三个用户对象。
        用户属性为:id,username,password
        2,要求:定义一个方法,根据id查找对应的学生信息。
        如果存在,返回索引
        如果不存在,返回-1*/
        //1.创建集合对象
        ArrayList<User> list = new ArrayList<>();
        //2.创建用户对象
        User u1 = new User("heima001", "zhangsan", "123456");
        User u2 = new User("heima002", "lisi", "1234");
        User u3 = new User("heima003", "wangwu", "1234qwer");
        //3.把用户对象添加到集合当中
        list.add(u1);
        list.add(u2);
        list.add(u3);
        //4.调用方法,通过id获取对应的索引
        int index = getIndex(list, "heima001");
        System.out.println(index);
    }
    //1.我要干嘛?  根据id查找对应的学生信息
    //2.我干这件事情需要什么才能完成?   集合 id
    //3.方法的调用处是否需要继续使用方法的结果?
    //要用必须返回,不要用可以返回也可以不返回
    //明确说明需要有返回值 int
    public static int getIndex(ArrayList<User> list, String id) {
        //遍历集合得到每一个元素
        for (int i = 0; i < list.size(); i++) {
            User u = list.get(i);
            String uid = u.getId();
            if(uid.equals(id)){
                return i;
            }
        }
        //因为只有当集合里面所有的元素都比较完了,才能断定id是不存在的。
        return -1;
    }
}

1.6 判断用户的是否存在

public class ArrayListDemo5 {
    public static void main(String[] args) {
       /* 需求:
        1,main方法中定义一个集合,存入三个用户对象。
        用户属性为:id,username,password
        2,要求:定义一个方法,根据id查找对应的学生信息。
        如果存在,返回true
        如果不存在,返回false*/
        //1.定义集合
        ArrayList<User> list = new ArrayList<>();
        //2.创建对象
        User u1 = new User("heima001","zhangsan","123456");
        User u2 = new User("heima002","lisi","12345678");
        User u3 = new User("heima003","wangwu","1234qwer");
        //3.把用户对象添加到集合当中
        list.add(u1);
        list.add(u2);
        list.add(u3);
        //4.调用方法,查询id是否存在
        boolean result = contains(list, "heima001");
        System.out.println(result);
    }
    //定义在测试类中的方法需要加static
    //1.我要干嘛? 我要根据id查询学生是否存在
    //2.我干这件事情,需要什么才能完成? 集合 id
    //3.方法的调用处是否需要使用方法的结果?
    //如果要用,必须返回,如果不用,可以返回也可以不返回
    //但是本题明确说明需要返回
    public static boolean contains(ArrayList<User> list, String id){
        //循环遍历集合,得到集合里面的每一个元素
        //再进行判断
        for (int i = 0; i < list.size(); i++) {
            //i 索引  list.get(i); 元素
            User u = list.get(i);
            //判断id是否存在,我是拿着谁跟谁比较
            //需要把用户对象里面的id拿出来再进行比较。
            String uid = u.getId();
            if(id.equals(uid)){
                return true;//return 关键字:作用就是结束方法。
            }
        }
        //只有当集合里面所有的元素全部比较完毕才能认为是不存在的。
        return false;
    }
}

ArrayList——返回多个数据

在这里插入图片描述

package com.itheima.test;


/*
需求:
        定义Javabean类:Phone
        Phone属性:品牌,价格。
        main方法中定义一个集合,存入三个手机对象。
        分别为:小米,1000。苹果,8000。锤子 2999。
        定义一个方法,将价格低于3000的手机信息返回。
*/

import java.util.ArrayList;

public class  Test8 {
    public static void main(String[] args) {

        //1.创建集合对象
        ArrayList<Phone> list = new ArrayList<>();

        //2.创建手机的对象
        Phone p1 = new Phone("小米",1000);
        Phone p2 = new Phone("苹果",8000);
        Phone p3 = new Phone("锤子",2999);

        //3.添加数据
        list.add(p1);
        list.add(p2);
        list.add(p3);

        //4.调用方法
        ArrayList<Phone> phoneInfoList = getPhoneInfo(list);

        //5.遍历集合
        for (int i = 0; i < phoneInfoList.size(); i++) {
            Phone phone = phoneInfoList.get(i);
            System.out.println(phone.getBrand() + ", " + phone.getPrice());
        }

    }


    //1.我要干嘛? 查询手机信息
    //2.我干这件事情,需要什么才能完成?  集合
    //3.我干完了,方法的调用处是否需要继续使用结果?  返回

    //技巧:
    //如果我们要返回多个数据,可以把这些数据先放到一个容器当中,再把容器返回
    //集合 数组
    public static ArrayList<Phone> getPhoneInfo(ArrayList<Phone> list){
        //定义一个集合用于存储价格低于3000的手机对象
        ArrayList<Phone> resultList = new ArrayList<>();
        //遍历集合
        for (int i = 0; i < list.size(); i++) {
            Phone p = list.get(i);
            int price = p.getPrice();
            //如果当前手机的价格低于3000,那么就把手机对象添加到resultList中
            if(price < 3000){
                resultList.add(p);
            }
        }
        //返回resultList
        return resultList;
    }
}
package com.itheima.test;

public class Phone {
    //Phone属性:品牌,价格。
    private String brand;
    private int price;

    public Phone() {
    }


    public Phone(String brand, int price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

学生管理系统

学生管理系统实现步骤

  • 案例需求

    ​ 针对目前我们的所学内容,完成一个综合案例:学生管理系统。该系统主要功能如下:

    ​ 添加学生:通过键盘录入学生信息,添加到集合中

    ​ 删除学生:通过键盘录入要删除学生的学号,将该学生对象从集合中删除

    ​ 修改学生:通过键盘录入要修改学生的学号,将该学生对象其他信息进行修改

    ​ 查看学生:将集合中的学生对象信息进行展示

    ​ 退出系统:结束程序

  • 实现步骤

    1. 定义学生类,包含以下成员变量

      ​ private String sid // 学生id

      ​ private String name // 学生姓名

      ​ private String age // 学生年龄

      ​ private String address // 学生所在地

    2. 学生管理系统主界面的搭建步骤

      2.1 用输出语句完成主界面的编写
      2.2 用Scanner实现键盘输入
      2.3 用switch语句完成选择的功能
      2.4 用循环完成功能结束后再次回到主界面

    3. 学生管理系统的添加学生功能实现步骤

      3.1 定义一个方法,接收ArrayList集合
      3.2 方法内完成添加学生的功能
      ​ ①键盘录入学生信息
      ​ ②根据录入的信息创建学生对象
      ​ ③将学生对象添加到集合中
      ​ ④提示添加成功信息
      3.3 在添加学生的选项里调用添加学生的方法

    4. 学生管理系统的查看学生功能实现步骤

      4.1 定义一个方法,接收ArrayList集合
      4.2 方法内遍历集合,将学生信息进行输出
      4.3 在查看所有学生选项里调用查看学生方法

    5. 学生管理系统的删除学生功能实现步骤

      5.1 定义一个方法,接收ArrayList集合
      5.2 方法中接收要删除学生的学号
      5.3 遍历集合,获取每个学生对象
      5.4 使用学生对象的学号和录入的要删除的学号进行比较,如果相同,则将当前学生对象从集合中删除
      5.5 在删除学生选项里调用删除学生的方法

    6. 学生管理系统的修改学生功能实现步骤

      6.1 定义一个方法,接收ArrayList集合
      6.2 方法中接收要修改学生的学号
      6.3 通过键盘录入学生对象所需的信息,并创建对象
      6.4 遍历集合,获取每一个学生对象。并和录入的修改学生学号进行比较.如果相同,则使用新学生对象替换当前学生对象
      6.5 在修改学生选项里调用修改学生的方法

    7. 退出系统

      使用System.exit(0);退出JVM

学生管理系统升级——完整代码实现

package com.itheima.studentsystem;

public class Student {
    private String id;
    private String name;
    private int age;
    private String address;

 	//下面是空参,有参,get和set方法
}

package com.itheima.studentsystem;

import java.util.ArrayList;
import java.util.Scanner;

public class StudentSystem {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        loop:
        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("请输入您的选择:");
            Scanner sc = new Scanner(System.in);
            String choose = sc.next();
            switch (choose) {
                case "1" -> addStudent(list);
                case "2" -> deleteStudent(list);
                case "3" -> updateStudent(list);
                case "4" -> queryStudent(list);
                case "5" -> {
                    System.out.println("退出");
                    //break loop;
                    System.exit(0);//停止虚拟机运行
                }
                default -> System.out.println("没有这个选项");
            }
        }
    }

    //添加学生
    public static void addStudent(ArrayList<Student> list) {
        //利用空参构造先创建学生对象
        Student s = new Student();

        Scanner sc = new Scanner(System.in);
        String id = null;
        while (true) {
            System.out.println("请输入学生的id");
            id = sc.next();
            boolean flag = contains(list, id);
            if(flag){
                //表示id已经存在,需要重新录入
                System.out.println("id已经存在,请重新录入");
            }else{
                //表示id不存在,表示可以使用
                s.setId(id);
                break;
            }
        }

        System.out.println("请输入学生的姓名");
        String name = sc.next();
        s.setName(name);

        System.out.println("请输入学生的年龄");
        int age = sc.nextInt();
        s.setAge(age);

        System.out.println("请输入学生的家庭住址");
        String address = sc.next();
        s.setAddress(address);


        //把学生对象添加到集合当中
        list.add(s);

        //提示一下用户
        System.out.println("学生信息添加成功");
    }

    //删除学生
    public static void deleteStudent(ArrayList<Student> list) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要删除的id");
        String id = sc.next();
        //查询id在集合中的索引
        int index = getIndex(list, id);
        //对index进行判断
        //如果-1,就表示不存在,结束方法,回到初始菜单
        if(index >= 0){
            //如果大于等于0的,表示存在,直接删除
            list.remove(index);
            System.out.println("id为:" + id + "的学生删除成功");
        }else{
            System.out.println("id不存在,删除失败");
        }
    }

    //修改学生
    public static void updateStudent(ArrayList<Student> list) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要修改学生的id");
        String id = sc.next();

        int index = getIndex(list, id);

        if(index == -1){
            System.out.println("要修改的id" + id + "不存在,请重新输入");
            return;
        }

        //当代码执行到这里,表示什么?表示当前id是存在的。
        //获取要修改的学生对象
        Student stu = list.get(index);

        //输入其他的信息并修改
        System.out.println("请输入要修改的学生姓名");
        String newName = sc.next();
        stu.setName(newName);

        System.out.println("请输入要修改的学生年龄");
        int newAge = sc.nextInt();
        stu.setAge(newAge);

        System.out.println("请输入要修改的学生家庭住址");
        String newAddress = sc.next();
        stu.setAddress(newAddress);

        System.out.println("学生信息修改成功");


    }


    //查询学生
    public static void queryStudent(ArrayList<Student> list) {
        if (list.size() == 0) {
            System.out.println("当前无学生信息,请添加后再查询");
            //结束方法
            return;
        }

        //打印表头信息
        System.out.println("id\t\t姓名\t年龄\t家庭住址");
        //当代码执行到这里,表示集合中是有数据的
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t" + stu.getAddress());
        }
    }


    //判断id在集合中是否存在
    public static boolean contains(ArrayList<Student> list, String id) {
        //循环遍历集合得到里面的每一个学生对象
        /*for (int i = 0; i < list.size(); i++) {
            //拿到学生对象后,获取id并进行判断
            Student stu = list.get(i);
            String sid = stu.getId();
            if(sid.equals(id)){
                //存在,true
                return true;
            }
        }
        // 不存在false
        return false;*/
       return getIndex(list,id) >= 0;
    }

    //通过id获取索引的方法
    public static int getIndex(ArrayList<Student> list, String id){
        //遍历集合
        for (int i = 0; i < list.size(); i++) {
            //得到每一个学生对象
            Student stu = list.get(i);
            //得到每一个学生对象的id
            String sid = stu.getId();
            //拿着集合中的学生id跟要查询的id进行比较
            if(sid.equals(id)){
                //如果一样,那么就返回索引
                return i;
            }
        }
        //当循环结束之后还没有找到,就表示不存在,返回-1.
        return -1;
    }
}

面向对象进阶

第一章 复习回顾

1.1 如何定义类

类的定义格式如下:

修饰符 class 类名 {
    // 1.成员变量(属性)
    // 2.成员方法 (行为) 
    // 3.构造方法 (初始化类的对象数据的)
}

例如:

public class Student {
    // 1.成员变量
    public String name ;
    public char sex ; // '男'  '女'
    public int age;
}

1.2 如何通过类创建对象

类名 对象名称 = new 类名();

例如:

Student stu = new Student();

1.3 封装

1.3.1 封装的步骤

1.使用 private 关键字来修饰成员变量。

2.使用public修饰getter和setter方法。

1.3.2 封装的步骤实现
  1. private修饰成员变量
public class Student {
    private String name;
    private int age;
}
  1. public修饰getter和setter方法
public class Student {
    private String name;
    private int age;

    public void setName(String n) {
      	name = n;
    }

    public String getName() {
      	return name;
    }

    public void setAge(int a) {
        if (a > 0 && a <200) {
            age = a;
        } else {
            System.out.println("年龄非法!");
        }
    }

    public int getAge() {
      	return age;
    }
}

1.4 构造方法

1.4.1 构造方法的作用

在创建对象的时候,给成员变量进行初始化。

初始化即赋值的意思。

1.4.2 构造方法的格式

修饰符 类名(形参列表) {
    // 构造体代码,执行代码
}

1.4.3 构造方法的应用

首先定义一个学生类,代码如下:

public class Student {
    // 1.成员变量
    public String name;
    public int age;

    // 2.构造方法
    public Student() {
		System.out.println("无参数构造方法被调用")}
}

接下来通过调用构造方法得到两个学生对象。

public class CreateStu02 {
    public static void main(String[] args) {
        // 创建一个学生对象
        // 类名 变量名称 = new 类名();
        Student s1 = new Student();
        // 使用对象访问成员变量,赋值
        s1.name = "张三";
        s1.age = 20 ;

        // 使用对象访问成员变量 输出值
        System.out.println(s1.name);
        System.out.println(s1.age); 

        Student s2 = new Student();
        // 使用对象访问成员变量 赋值
        s2.name = "李四";
        s2.age = 18 ;
        System.out.println(s2.name);
        System.out.println(s2.age);
    }
}

1.5 this关键字的作用

1.5.1 this关键字的作用

this代表所在类的当前对象的引用(地址值),即代表当前对象。

1.5.2 this关键字的应用

1.5.2.1 用于普通的gettter与setter方法

this出现在实例方法中,谁调用这个方法(哪个对象调用这个方法),this就代表谁(this就代表哪个对象)。

public class Student {
    private String name;
    private int age;

    public void setName(String name) {
      	this.name = name;
    }

    public String getName() {
      	return name;
    }

    public void setAge(int age) {
        if (age > 0 && age < 200) {
            this.age = age;
        } else {
            System.out.println("年龄非法!");
        }
    }

    public int getAge() {
      	return age;
    }
}
1.5.2.2 用于构造方法中

this出现在构造方法中,代表构造方法正在初始化的那个对象。

public class Student {
    private String name;
    private int age;
    
    // 无参数构造方法
    public Student() {} 
    
    // 有参数构造方法
    public Student(String name,int age) {
    	this.name = name;
    	this.age = age; 
    }
}

面向对象进阶——static

快捷键:
滚轮或者alt+鼠标不动 修改多行
ctrl+alt+l 格式化代码
1.staitc定义
含义:staic表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
(1)静态变量(类变量):被static修饰的成员变量

  • 格式:修饰符 static 数据类型 变量名 = 初始值;
  • 特点:
    被该类所有的对象共享
    不属于对象、属于类
    随着类的加载而加载,优先于对象存在
  • 调用方式:
    类名调用(推荐)类名.静态方法
    对象名调用

(2)静态方法:被static修饰的成员方法,叫做静态方法
多用在测试类和工具类中
Javabean类中很少用
调用方式:
类名调用(推荐)对象.实例方法
对象名调用

2.static内存图
静态变量优先于对象加载,非静态受变量控制。
在这里插入图片描述
在这里插入图片描述
备注:可以被共享的属性可以定义为静态属性

3.static应用:编写工具类
工具类:帮助我们做一些事情的,但不是描述任何事物的类
区别:
javabean类:用来描述一类事物的类,比如Dog, Cat等
测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口
注意:
1.类名间名知意
2.私有化构造方法
3.方法定义为静态

4.staitic注意事项
因为静态方法没有this关键字所以不能调用非静态的。
a、静态方法只能访问静态变量和静态方法
b、非静态方法可以访问静态变量或者静态方法,也可以访问非静态变量和非静态成员方法
c、静态方法中没有关键字static

总结
1.当 static 修饰成员变量或者成员方法时,该变量称为静态变量,该方法称为静态方法。该类的每个对象都共享同一个类的静态变量和静态方法。任何对象都可以更改该静态变量的值或者访问静态方法。但是不推荐这种方式去访问。因为静态变量或者静态方法直接通过类名访问即可,完全没有必要用对象去访问。

2.无static修饰的成员变量或者成员方法,称为实例变量,实例方法,实例变量和实例方法必须创建类的对象,然后通过对象来访问。

3.static修饰的成员属于类,会存储在静态区,是随着类的加载而加载的,且只加载一次,所以只有一份,节省内存。存储于一块固定的内存区域(静态区),所以,可以直接被类名调用。它优先于对象存在,所以,可以被所有对象共享。

4.无static修饰的成员,是属于对象,对象有多少个,他们就会出现多少份。所以必须由对象调用。

package com.itheima.a03staticdemo3;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //1.创建一个集合用来存储学生对象
        ArrayList<Student> list = new ArrayList<>();

        //2.创建3个学生对象
        Student stu1 = new Student("zhangsan",23,"男");
        Student stu2 = new Student("lisi",24,"女");
        Student stu3 = new Student("wangwu",25,"男");


        //3把学生对象添加到集合当中
        list.add(stu1);
        list.add(stu2);
        list.add(stu3);

        //4.调用工具类中的方法
        int maxAgeStudent = StudentUtil.getMaxAgeStudent(list);

        System.out.println(maxAgeStudent);
    }
}
package com.itheima.a03staticdemo3;

import java.util.ArrayList;

public class StudentUtil {

    private StudentUtil(){}

    //静态方法
    public static int getMaxAgeStudent(ArrayList<Student> list){
        //1.定义一个参照物
        int max = list.get(0).getAge();

        //2.循环遍历集合
        for (int i = 1; i < list.size(); i++) {
            //i 索引  list.get(i)元素/学生对象  我们还需要getAge获取到年龄之后再进行比较
            int tempAge = list.get(i).getAge();
            if(tempAge > max){
                max = tempAge;
            }
        }

        //3.直接返回max
        return max;
    }
}
package com.itheima.a03staticdemo3;

public class Student {
    private String name;
    private int age;
    private String gender;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

面向对象进阶——继承

1.继承的含义
继承描述的是事物之间的所属关系,这种关系是:is-a 的关系。例如,兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。

继承:就是子类继承父类的属性行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

1)什么时候用继承?
当类与类之间,存在相同的内容,并且满足子类是父类的一种,就可以考虑使用继承来优化代码
2) Java的继承特点:
a、面向对象的三大特性:封装、继承、多态(封装:对象那个代表什么就封装对应的数据,并且提供数据的对应行为。)
b、Java支持单继承不支持多继承,但支持多层继承即a继承b,b继承c;每一个类都直接或者间接的继承Object
c、子类的继承范围

构造方法非私有 不能私有 不能
成员变量非私有 能私有 能
成员方法非私有 能私有 不能

备注:虚方法表:非private、非static、非final

2.继承的格式
通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {
	...
}

class 子类 extends 父类 {
	...
}

需要注意:Java是单继承的,一个类只能继承一个直接父类,跟现实世界很像,但是Java中的子类是更加强大的。子类不能继承父类的构造方法。值得注意的是子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已,可以通过getter/setter方法访问父类的private成员变量。

3.继承的意义
继承是类与类之间产生子父的关系,子类直接使用,减少代码冗余,提高代码的复用性,子类在父类的基础上增加功能
4.继承结构中的语法特点
(1)继承中成员变量的特点
1.继承中成员变量的访问特点:就近原则
在局部位置找–>本类成员位置–>父类位置逐级往上
2.如果出现重名的成员变量怎么办?

Syetem.out.println(name);从局部 位置开始往上找
Syetem.out.println(this.name);从本类成员变量位置开始往上找
Syetem.out.println(super.name);从父类位置开始往上找

(2)方法重写
1.父类的方法不能满足子类的需求时,子类将方法重写
2.书写的格式:在继承体系中,子类出现了和父类一模一样的方法声明,我们将这个子类这个方法为重写的方法(改写方法体)
3.@override重写注解
a、@override是放在重写后的方法上,校验子类重写时语法是否正确。
b、加上注解后如果有红色波浪线,表示语法错误
c、建议重写方法都加上@override注解,代码安全,优雅。
4.方法重写的注意事项和要求
a、重写方法的名称,形参列表必须与父类中的一致
b、子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)
c、子类重写父类方法时,返回值类型子类必须小于等于父类
d、建议:重写的方法尽量和父类一致
e、只有被添加到虚方法表中的方法才能被重写
(3)继承中:构造方法的访问特点
a、特点:
父类中的构造方法不会被子类继承
子类中所有的构造方法默认先访问父类中的无参构造,再执行自已。
b、为什么?
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
子类在初始化的时候,有可能会使用父类中的数据,如果父类没有完成初始化,子类将无法使用父类中的数据。
c、怎么调用父类的构造方法的?
子类构造方法的第一行语句默认都是:super(),不写也存在,且必须时第一行
5.总结:
继承中构造方法的访问特点:
子类不能继承父类的构造方法,但是可以通过super调用
子类构造方法的第一行,有一个默认的super();
默认先访问父类中的无参构造方法,再执行自已
如果想要方法文父类有无参构造,必须手动书写
(4)this、super使用总结
this:理解为变量、表示的当前方法调用者的地址值
super:代表父类的存储空间

关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量 访问成员本类成员变量this.成员方法{…} 访问本类成员方法this.{…} 访问本类构造方法
supersuper.成员变量 访问父类成员变量this.成员方法{…} 访问本类成员方法super.{…} 范围内父类构造方法
package com.itheima.a10oopextendsdemo10;

public class Cook extends Employee{

    public Cook() {
    }

    public Cook(String id, String name, double salary) {
        super(id, name, salary);
    }


    @Override
    public void work() {
        System.out.println("厨师正在炒菜");
    }
}

package com.itheima.a10oopextendsdemo10;

public class Employee {
    //1.类名见名知意
    //2.所有的成员变量都需要私有
    //3.构造方法(空参  带全部参数的构造)
    //4.get/set

    private String id;
    private String name;
    private double salary;

    public Employee() {
    }

    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    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 double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    //工作
    public void work(){
        System.out.println("员工在工作");
    }

    //吃饭
    public void eat(){
        System.out.println("吃米饭");
    }
}

package com.itheima.a10oopextendsdemo10;

public class Manager extends Employee{

    private double bouns;

    //空参构造
    public Manager() {
    }

    //带全部参数的构造
    //父类 + 子类
    public Manager(String id, String name, double salary, double bouns) {
        super(id, name, salary);
        this.bouns = bouns;
    }


    public double getBouns() {
        return bouns;
    }

    public void setBouns(double bouns) {
        this.bouns = bouns;
    }

    @Override
    public void work() {
        System.out.println("管理其他人");
    }
}

package com.itheima.a10oopextendsdemo10;

public class Test {
    public static void main(String[] args) {
        //创建对象并赋值调用
        Manager m = new Manager("heima001","张三",15000,8000);
        System.out.println(m.getId() + ", " + m.getName() +
                ", " + m.getSalary() + ", " + m.getBouns());
        m.work();
        m.eat();



        Cook c = new Cook();
        c.setId("heima002");
        c.setName("李四");
        c.setSalary(8000);
        System.out.println(c.getId() + ", " + c.getName() + ", " + c.getSalary());
        c.work();
        c.eat();
    }
}

面向对象进阶——多态

什么是多态
同类型对象表现的不同形态
多态的表现形式

父类类型 对象名称=子类对象;

多态的前提
有继承/实现关系
有父类引用指向子类对象Fu f=new Zi()
有方法重写
案例:
老师学生注册信息
思路:
1.Person父类:定义属性 创建get/set方法 ,show(){}
2.Teacher类:继承父类,重写show()
3.Student类:继承父类,重写show()
4.测试类:public static void register(Person p){
p.show()}创建对象 Person s=new Student(),s.setXX(),s.register()

多态的好处
使用父类型作为单数,可以接收所有的子类对象,体现多态的扩展性和便利
多态调用成员的特点
)成员变量调用:编译看左边,运行看左边
)成员方法调用:编译看左边,运行看右边

Fu f = new Zi()//编译看左边的父类中有没有name这个属性,没有就报错
//在实际运行的时候,把父类name属性的值打印出来
System.out.println(f.name);
//编译看左边的父类中有没有show这个方法,没有就报错
//在实际运行的时候,运行的是子类中的show方法
f.show();

多态的优势弊端
1.多态的优势:
在多态的形态下,右边的对象可以实现解耦合,便于拓展和维护,

父类类型 变量名 = new 子类/实现类构造器;
变量名.方法名();

定义方法的时候,使用父类型作为参数,可以接受所有的子类对象,体现多态的拓展性和便利

方法中,使用父类型作为参数,可以接受所有的子类对象
2.多态的弊端:
能使用子类特有的功能
3.应用数据类型的类型转换,有几种方式?自动类型转换,强制类转换

  • 向上转型(自动转换):多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。
    使用格式:
父类类型  变量名 = new 子类类型();
如:Animal a = new Cat();

原因是:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。

  • 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
    一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
    使用格式:
子类类型 变量名 = (子类类型) 父类变量名;:Aniaml a = new Cat();
   Cat c =(Cat) a;  

4.强制类型转换能解决什么问题?
a、可以转换成真正的子类类型,从而调用子类独有的功能
b、转换类型与真实对象类型不一致会报错
c、转换的时候用instanceof关键字进行判断
d、前面在运行对象,后面强制类型转换会报错

instanceof关键字
例子:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat

        // 向下转型  
        Dog d = (Dog)a;       
        d.watchHouse();        // 调用的是 Dog 的 watchHouse 【运行报错】
    }  
}
/*这段代码可以通过编译,但是运行时,却报出了 `ClassCastException` ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。*/

为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

变量名 instanceof 数据类型 
如果变量属于该数据类型或者其子类类型,返回true。
如果变量不属于该数据类型或者其子类类型,返回false

上面例子解决方法

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat

        // 向下转型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 调用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 调用的是 Dog 的 watchHouse
        }
    }  
}

instanceof新特性
JDK14的时候提出了新特性,把判断和强转合并成了一行

//新特性
//先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if(a instanceof Dog d){
    d.lookHome();
}else if(a instanceof Cat c){
    c.catchMouse();
}else{
    System.out.println("没有这个类型,无法转换");
}

综合练习

需求:根据需求完成代码:
	1.定义狗类
		属性:
			年龄,颜色
		行为:
			eat(String something)(something表示吃的东西)
			看家lookHome方法(无参数)
2.定义猫类
	属性:
		年龄,颜色
	行为:
		eat(String something)方法(something表示吃的东西)
		逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
	属性:
		姓名,年龄
	行为:
		keepPet(Dog dog,String something)方法
			功能:喂养宠物狗,something表示喂养的东西
	行为:
		keepPet(Cat cat,String something)方法
			功能:喂养宠物猫,something表示喂养的东西
	生成空参有参构造,set和get方法  
4.定义测试类(完成以下打印效果):
	keepPet(Dog dog,String somethind)方法打印内容如下:
		年龄为30岁的老王养了一只黑颜色的2岁的狗
		2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
	keepPet(Cat cat,String somethind)方法打印内容如下:
		年龄为25岁的老李养了一只灰颜色的3岁的猫
		3岁的灰颜色的猫眯着眼睛侧着头吃鱼
5.思考:		
	1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
	2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
//动物类(父类)
public class Animal {
    private int age;
    private String color;


    public Animal() {
    }

    public Animal(int age, String color) {
        this.age = age;
        this.color = color;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void eat(String something){
        System.out.println("动物在吃" + something);
    }
}

//猫类(子类)
public class Cat extends Animal {

    public Cat() {
    }

    public Cat(int age, String color) {
        super(age, color);
    }

    @Override
    public void eat(String something) {
        System.out.println(getAge() + "岁的" + getColor() + "颜色的猫眯着眼睛侧着头吃" + something);
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }

}

//狗类(子类)
public class Dog extends Animal {
    public Dog() {
    }

    public Dog(int age, String color) {
        super(age, color);
    }

    //行为
    //eat(String something)(something表示吃的东西)
    //看家lookHome方法(无参数)
    @Override
    public void eat(String something) {
        System.out.println(getAge() + "岁的" + getColor() + "颜色的狗两只前腿死死的抱住" + something + "猛吃");
    }

    public void lookHome(){
        System.out.println("狗在看家");
    }
}


//饲养员类
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 void keepPet(Dog dog, String something) {
        System.out.println("年龄为" + age + "岁的" + name + "养了一只" + dog.getColor() + "颜色的" + dog.getAge() + "岁的狗");
        dog.eat(something);
    }

    //饲养猫
    public void keepPet(Cat cat, String something) {
        System.out.println("年龄为" + age + "岁的" + name + "养了一只" + cat.getColor() + "颜色的" + cat.getAge() + "岁的猫");
        cat.eat(something);
    }*/


    //想要一个方法,能接收所有的动物,包括猫,包括狗
    //方法的形参:可以写这些类的父类 Animal
    public void keepPet(Animal a, String something) {
        if(a instanceof Dog d){
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的狗");
            d.eat(something);
        }else if(a instanceof Cat c){
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + c.getColor() + "颜色的" + c.getAge() + "岁的猫");
            c.eat(something);
        }else{
            System.out.println("没有这种动物");
        }
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        //创建对象并调用方法
       /* Person p1 = new Person("老王",30);
        Dog d = new Dog(2,"黑");
        p1.keepPet(d,"骨头");


        Person p2 = new Person("老李",25);
        Cat c = new Cat(3,"灰");
        p2.keepPet(c,"鱼");*/


        //创建饲养员的对象
        Person p = new Person("老王",30);
        Dog d = new Dog(2,"黑");
        Cat c = new Cat(3,"灰");
        p.keepPet(d,"骨头");
        p.keepPet(c,"鱼");

    }
}

面向对象进阶——包和final

2.1 包

​ 包在操作系统中其实就是一个文件夹。包是用来分门别类的管理技术,不同的技术类放在不同的包下,方便管理和维护。

包名的命名规范

路径名.路径名.xxx.xxx
// 例如:com.itheima.oa
  • 包名一般是公司域名的倒写。例如:黑马是www.itheima.com,包名就可以定义成com.itheima.技术名称。
  • 包名必须用”.“连接。
  • 包名的每个路径名必须是一个合法的标识符,而且不能是Java的关键字。

2.2 导包

什么时候需要导包?

​ 情况一:在使用Java中提供的非核心包中的类时

​ 情况二:使用自己写的其他包中的类时

什么时候不需要导包?

​ 情况一:在使用Java核心包(java.lang)中的类时

​ 情况二:在使用自己写的同一个包中的类时

2.3 使用不同包下的相同类怎么办?

假设demo1和demo2中都有一个Student该如何使用?

代码示例:

//使用全类名的形式即可。
//全类名:包名 + 类名
//拷贝全类名的快捷键:选中类名crtl + shift + alt + c 或者用鼠标点copy,再点击copy Reference
com.itheima.homework.demo1.Student s1 = new com.itheima.homework.demo1.Student();
com.itheima.homework.demo2.Student s2 = new com.itheima.homework.demo2.Student();

4.1 概述

​ 学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。

如果有一个方法我不想别人去改写里面内容,该怎么办呢?

Java提供了final 关键字,表示修饰的内容不可变。

  • final: 不可改变,最终的含义。可以用于修饰类、方法和变量。
    • 类:被修饰的类,不能被继承。
    • 方法:被修饰的方法,不能被重写。
    • 变量:被修饰的变量,有且仅能被赋值一次。

4.2 使用方式

4.2.1 修饰类

final修饰的类,不能被继承。

格式如下:

final class 类名 {
}

代码:

final class Fu {
}
// class Zi extends Fu {} // 报错,不能继承final的类

查询API发现像 public final class Stringpublic final class Mathpublic final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

4.2.2 修饰方法

final修饰的方法,不能被重写。
格式如下:

修饰符 final 返回值类型 方法名(参数列表){
    //方法体
}

代码:

class Fu2 {
	final public void show1() {
		System.out.println("Fu2 show1");
	}
	public void show2() {
		System.out.println("Fu2 show2");
	}
}

class Zi2 extends Fu2 {
//	@Override
//	public void show1() {
//		System.out.println("Zi2 show1");
//	}
	@Override
	public void show2() {
		System.out.println("Zi2 show2");
	}
}

4.2.3 修饰变量-局部变量

  1. 局部变量——基本类型
    基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:
public class FinalDemo1 {
    public static void main(String[] args) {
        // 声明变量,使用final修饰
        final int a;
        // 第一次赋值 
        a = 10;
        // 第二次赋值
        a = 20; // 报错,不可重新赋值

        // 声明变量,直接赋值,使用final修饰
        final int b = 10;
        // 第二次赋值
        b = 20; // 报错,不可重新赋值
    }
}

思考,下面两种写法,哪种可以通过编译?

写法1:

final int c = 0;
for (int i = 0; i < 10; i++) {
    c = i;
    System.out.println(c);
}

写法2:

for (int i = 0; i < 10; i++) {
    final int c = i;
    System.out.println(c);
}

根据 final 的定义,写法1报错!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量c。这也是大家需要注意的地方。

4.2.4 修饰变量-成员变量

成员变量涉及到初始化的问题,初始化方式有显示初始化和构造方法初始化,只能选择其中一个:

  • 显示初始化(在定义成员变量的时候立马赋值)(常用);
public class Student {
    final int num = 10;
}
  • 构造方法初始化(在构造方法中赋值一次)(不常用,了解即可)。

    注意:每个构造方法中都要赋值一次!

public class Student {
    final int num = 10;
    final int num2;

    public Student() {
        this.num2 = 20;
//     this.num2 = 20;
    }
    
     public Student(String name) {
        this.num2 = 20;
//     this.num2 = 20;
    }
}

被final修饰的常量名称,一般都有书写规范,所有字母都大写

面向对象进阶——权限修饰符和代码块

3.1 权限修饰符

​ 在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,我们之前已经学习过了public 和 private,接下来我们研究一下protected和默认修饰符的作用。

  • public:公共的,所有地方都可以访问。

  • protected:本类 ,本包,其他包中的子类都可以访问。

  • 默认(没有修饰符):本类 ,本包可以访问。

    注意:默认是空着不写,不是default

  • private:私有的,当前类可以访问。
    public > protected > 默认 > private

3.2 不同权限的访问能力

publicprotected默认private
同一类中
同一包中的类
不同包的子类
不同包中的无关类

可见,public具有最大权限。private则是最小权限。

编写代码时,如果没有特殊的考虑,建议这样使用权限:

  • 成员变量使用private ,隐藏细节。
  • 构造方法使用 public ,方便创建对象。
  • 成员方法使用public ,方便调用方法。

小贴士:不加权限修饰符,就是默认权限

面向对象进阶——抽象类和抽象方法

Java三大特性:封装,继承,多态
1.抽象方法
含义:将共性的行为(方法)抽取父类之后。由于每一个子类执行的内容不是一样的,所以在父类中不能确定具体的方法体,该方法就可以被定义为抽象方法。
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。

  • 抽象方法 : 没有方法体的方法。
  • 抽象类:包含抽象方法的类。
  • 抽象类的特征:
    有得:抽象类得到了拥有抽象方法的能力。
    有失:抽象类失去了创建对象的能力。
    其他成员(构造方法,实例方法,静态方法等)抽象类都是具备的

2.抽象类和抽象方法的定义格式
抽象类定义格式

public abstarct 返回值类型 方法名(参数列表);

抽象方法的定义格式

public abstarct class 类名{}

3.抽象类和抽思想那个方法的注意事项
1)抽象类相当于给了框架去给具体类使用。抽象类存在的意义是为了被子类继承。
2)抽象类创建构造方法的作用是给当创建子类对象时候给子类赋值,即直接调用抽象类里的实例方法get/set()
3)继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。
4)抽象类和抽象方法的注意事项
a、抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
b、抽象中不一定有抽象方法、有抽象方法的类一定是抽象类。未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
c、抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。子类的构造方法中,有默认的super(),需要访问父类构造方法。
d、抽象类的子类必须重写抽象父类中所有的抽象方法,否则子类也必须定义成抽象类,编译无法通过而报错。
4.脑图规划抽象类例子
在这里插入图片描述

5.抽象类和抽象方法的意义
在这里插入图片描述
6.重新认识main方法

public clasHelloWorld{
public static void mian(String[] args){
System.out.println("Hello")
}

public: 被JVM调用,访问权限足够大
static:被JVM调用,不用创建对象,直接类名访问,因为static是静态的,所以测试类其他方法也需要静态
void:被JVM调用,不需要给JVM返回值
main:一个通用的名称,虽然不是关键字,但可以被JVM识别
String[]args:以前用于接收键盘录入的数据,现在没用

面向对象进阶——接口

1.接口
1)接口代表规则,是行为的抽象,想要让哪个类拥有一个行为就让这个类实现对应的接口
2)当一个方法的参数是接口的时候,可以传递接所有实现的类的对象,这种方式成为接口多态

2.接口应用
不在乎搬家的对象,可以完成搬家这个行为就可以
接口定义

//接口的定义格式:
interface 接口名称{
    // 抽象方法
}

// 接口的声明:interface
// 接口名称:首字母大写,满足“驼峰模式”

实体类

public void 搬家(接口名称 c){
}

3.与抽象类的异同
1)抽象类对类的抽象
2)接口对行为的抽象
在这里插入图片描述

4.接口的定义和使用
1)接口的关键案子interface定义

public interface 接口名{}

2)接口不能实例化
3)接口和类之间是实现关系,通过implement关键字表示

/**接口的实现:
    在Java中接口是被实现的,实现接口的类称为实现类。
    实现类的格式:*/
class 类名 implements 接口1,接口2,接口3...{

}

4)接口的子类(实现类)
要么重写接口中的所有方法
要么是抽象类
5)注意事项
注意1:接口和类的实现关系,可以单实现,也可以多实现

public class 类名 implements 接口名1,接口名2{}

注意2:实现类还可以继承一个类的同时实现多个接口。

public class 类名 extends 父类 implements 接口名1,接口名2{}

类实现接口的要求和意义:1. 必须重写实现的全部接口中所有抽象方法。2. 如果一个类实现了接口,但是没有重写完全部接口的全部抽象方法,这个类也必须定义成抽象类。3. 意义:接口体现的是一种规范,接口对实现类是一种强制性的约束,要么全部完成接口申明的功能,要么自己也定义成抽象类。这正是一种强制性的规范。

5.接口中成员特点
1)成员变量
只能是常量
默认修饰符public static final
2)构造方法
没有
3)成员方法
只能是抽象方法
默认修饰符public abstract
6.接口和类之间的关系
1)类和类的关系
继承关系,只能单继承,不能多继承,但是可以多层继承
2)类是接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
3)接口和接口的关系
继承关系,可以单继承也可以多继承
7.例子分析
在这里插入图片描述
8.JDK接口的演变

在JDK7,包括JDK7之前,接口中的只有包含:抽象方法和常量,其中接口中的抽象方法默认会自动加上public abstract修饰; 在接口中定义的成员变量默认会加上: public static final修饰。也就是说在接口中定义的成员变量实际上是一个常量。这里是使用public static final修饰后,变量值就不可被修改,并且是静态化的变量可以直接用接口名访问,所以也叫常量。常量必须要给初始值。常量命名规范建议字母全部大写,多个单词用下划线连接。

JDK7以前:接口只能定义抽象方法
**JDK8的新特性:**接口中可以有方法体的方法
JDK9的新特性:接口中可以定义私有的方法
JDK8以后接口中新增加的方法
1)允许在接口中定义默认的方法,需要使用关键字default修饰
作用:解决接口升级的问题
2)接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表){}
范例:public default void show(){}
3)接口中默认方法的注意事项
默认方法不是抽象方法,所以不强制被重写,但如果被重写,重写要去掉default关键字
public可以省略,default不能省略
如果实现多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法重写

JDK9的新增的方法
接口中私有的方法的定义格式
格式1 private 返回值类型 方法名(参数列表){}
范例1: private void show(){}
格式2: private satic 返回值类型 方法名(参数列表){}
范例2:private static void method(){}

interface Inter{
public default void start(){
System.out.println("statrt rountime working..")
log();
}
public default void end(){
System.out.println("end rountine working..");
log();
}
}
public default void log(){
System.out.println("logging")
}
```java
此方法只为Inter接口提供服务,不需要外类访问

```java
private void log(){
System.out.println("logging");

9.适配器设计模型
(1)设计模式:是一套反复使用,被多数人知晓的,经过分类编目的,代码设计经验的总结,使用设计模式是为了可重复的代码,让代码更容易被他人理解,保证代码的可靠性,程序的复用性
(2)适配器设计模式:解决接口中和实现类之间的矛盾问题
3).总结
1)当一个接口的抽象方法过多,但是我只要使用其中的一部分的使用就可以用适配器模型
2)书写步骤:
编写中间类XXXAdapter 实现对应接口
对接口的抽象方法进行空实现
让真正了解实现类继承中间类,并且重写需要的方法
为了避免其他类创建适配器类的对象,中间适配类用abstract进行修饰。
如图
在这里插入图片描述

面向对象进阶——初始内部类

3.1 概述

3.1.1 什么是内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。可以把内部类理解成寄生,外部类理解成宿主。

3.1.2 什么时候使用内部类

一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用

  1. 人里面有一颗心脏。
  2. 汽车内部有一个发动机。
  3. 为了实现更好的封装性。

内部类的访问特点:

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象

3.2 内部类的分类

按定义的位置来分

  1. 成员内部内,类定义在了成员位置 (类中方法外称为成员位置,无static修饰的内部类)
  2. 静态内部类,类定义在了成员位置 (类中方法外称为成员位置,有static修饰的内部类)
  3. 局部内部类,类定义在方法内
  4. 匿名内部类,没有名字的内部类,可以在方法中,也可以在类中方法外。

面向对象进阶——成员内部类

3.3 成员内部类

成员内部类特点

  • 无static修饰的内部类,属于外部类对象的。
  • 宿主:外部类对象。

内部类的使用格式

 外部类.内部类。 // 访问内部类的类型都是用 外部类.内部类

获取成员内部类对象的两种方式

方式一:外部直接创建成员内部类的对象

外部类.内部类 变量 = new 外部类().new 内部类();

方式二:在外部类中定义一个方法提供内部类的对象

案例演示

方式一:
public class Test {
    public static void main(String[] args) {
        //  宿主:外部类对象。
       // Outer out = new Outer();
        // 创建内部类对象。
        Outer.Inner oi = new Outer().new Inner();
        oi.method();
    }
}

class Outer {
    // 成员内部类,属于外部类对象的。
    // 拓展:成员内部类不能定义静态成员。
    public class Inner{
        // 这里面的东西与类是完全一样的。
        public void method(){
            System.out.println("内部类中的方法被调用了");
        }
    }
}


方式二:
public class Outer {
    String name;
    private class Inner{
        static int a = 10;
    }
    public Inner getInstance(){
        return new Inner();
    }
}

public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        System.out.println(o.getInstance());


    }
}

3.4 成员内部类的细节

编写成员内部类的注意点:

  1. 成员内部类可以被一些修饰符所修饰,比如: private,默认,protected,public,static等
  2. 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
  3. 创建内部类对象时,对象中有一个隐含的Outer.this记录外部类对象的地址值。(请参见3.6节的内存图)

详解:

​ 内部类被private修饰,外界无法直接获取内部类的对象,只能通过3.3节中的方式二获取内部类的对象

​ 被其他权限修饰符修饰的内部类一般用3.3节中的方式一直接获取内部类的对象

​ 内部类被static修饰是成员内部类中的特殊情况,叫做静态内部类下面单独学习。

​ 内部类如果想要访问外部类的成员变量,外部类的变量必须用final修饰,JDK8以前必须手动写final,JDK8之后不需要手动写,JDK默认加上。

3.5 成员内部类面试题

请在?地方向上相应代码,以达到输出的内容

注意:内部类访问外部类对象的格式是:外部类名.this

public class Test {
    public static void main(String[] args) {
        Outer.inner oi = new Outer().new inner();
        oi.method();
    }
}

class Outer {	// 外部类
    private int a = 30;

    // 在成员位置定义一个类
    class inner {
        private int a = 20;

        public void method() {
            int a = 10;
            System.out.println(???);	// 10   答案:a
            System.out.println(???);	// 20	答案:this.a
            System.out.println(???);	// 30	答案:Outer.this.a
        }
    }
}

3.6 成员内部类内存图

在这里插入图片描述

面向对象进阶——静态内部类和局部内部类

3.7 静态内部类

静态内部类特点

  • 静态内部类是一种特殊的成员内部类。
  • 有static修饰,属于外部类本身的。
  • 总结:静态内部类与其他类的用法完全一样。只是访问的时候需要加上外部类.内部类。
  • 拓展1:静态内部类可以直接访问外部类的静态成员。
  • 拓展2:静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。
  • 拓展3:静态内部类中没有银行的Outer.this。

内部类的使用格式

外部类.内部类。

静态内部类对象的创建格式

外部类.内部类  变量 = new  外部类.内部类构造器;

调用方法的格式:

  • 调用非静态方法的格式:先创建对象,用对象调用
  • 调用静态方法的格式:外部类名.内部类名.方法名();

案例演示

// 外部类:Outer01
class Outer01{
    private static  String sc_name = "黑马程序";
    // 内部类: Inner01
    public static class Inner01{
        // 这里面的东西与类是完全一样的。
        private String name;
        public Inner01(String name) {
            this.name = name;
        }
        public void showName(){
            System.out.println(this.name);
            // 拓展:静态内部类可以直接访问外部类的静态成员。
            System.out.println(sc_name);
        }
    }
}

public class InnerClassDemo01 {
    public static void main(String[] args) {
        // 创建静态内部类对象。
        // 外部类.内部类  变量 = new  外部类.内部类构造器;
        Outer01.Inner01 in  = new Outer01.Inner01("张三");
        in.showName();
    }
}

3.8 局部内部类

  • 局部内部类 :定义在方法中的类。

定义格式:

class 外部类名 {
	数据类型 变量名;
	
	修饰符 返回值类型 方法名(参数列表) {
		// …
		class 内部类 {
			// 成员变量
			// 成员方法
		}
	}
}

面向对象进阶——匿名内部类

拓展:反编译 Dos窗口输入javap

3.9.1 概述

匿名内部类 :是内部类的简化写法。他是一个隐含了名字的内部类。开发中,最常用到的内部类就是匿名内部类了。

3.9.2 格式

new 类名或者接口名() {
     重写方法;
};

包含了:

  • 继承或者实现关系

  • 方法重写

  • 创建对象

所以从语法上来讲,这个整体其实是匿名内部类对象

3.9.2 什么时候用到匿名内部类

实际上,如果我们希望定义一个只要使用一次的类,就可考虑使用匿名内部类。匿名内部类的本质作用

是为了简化代码

之前我们使用接口时,似乎得做如下几步操作:

  1. 定义子类
  2. 重写接口中的方法
  3. 创建子类对象
  4. 调用重写后的方法
interface Swim {
    public abstract void swimming();
}

// 1. 定义接口的实现类
class Student implements Swim {
    // 2. 重写抽象方法
    @Override
    public void swimming() {
        System.out.println("狗刨式...");
    }
}

public class Test {
    public static void main(String[] args) {
        // 3. 创建实现类对象
        Student s = new Student();
        // 4. 调用方法
        s.swimming();
    }
}

我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。

3.9.3 匿名内部类前提和格式

匿名内部类必须继承一个父类或者实现一个父接口

匿名内部类格式

new 父类名或者接口名(){
    // 方法重写
    @Override 
    public void method() {
        // 执行语句
    }
};

3.9.4 使用方式

以接口为例,匿名内部类的使用,代码如下:

interface Swim {
    public abstract void swimming();
}

public class Demo07 {
    public static void main(String[] args) {
        // 使用匿名内部类
		new Swim() {
			@Override
			public void swimming() {
				System.out.println("自由泳...");
			}
		}.swimming();

        // 接口 变量 = new 实现类(); // 多态,走子类的重写方法
        Swim s2 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("蛙泳...");
            }
        };

        s2.swimming();
        s2.swimming();
    }
}

3.9.5 匿名内部类的特点

  1. 定义一个没有名字的内部类
  2. 这个类实现了父类,或者父类接口
  3. 匿名内部类会创建这个没有名字的类的对象

3.9.6 匿名内部类的使用场景

通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:

interface Swim {
    public abstract void swimming();
}

public class Demo07 {
    public static void main(String[] args) {
        // 普通方式传入对象
        // 创建实现类对象
        Student s = new Student();
        
        goSwimming(s);
        // 匿名内部类使用场景:作为方法参数传递
        Swim s3 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("蝶泳...");
            }
        };
        // 传入匿名内部类
        goSwimming(s3);

        // 完美方案: 一步到位
        goSwimming(new Swim() {
            public void swimming() {
                System.out.println("大学生, 蛙泳...");
            }
        });

        goSwimming(new Swim() {
            public void swimming() {
                System.out.println("小学生, 自由泳...");
            }
        });
    }

    // 定义一个方法,模拟请一些人去游泳
    public static void goSwimming(Swim s) {
        s.swimming();
    }
}

阶段项目

GUI 图形化项目,包含AWT包和Swing包
组件认识:
JFrame 最外层的窗体
JMenuBar 最上层的菜单
JLable 管理文字和图片的容器

常用API

常见算法

lambda表达式

经典算法题

集合进阶

1.16阶段项目

1.17常用API

1.18算法

1.19集合进阶

1.20阶段项目

1.21不可变集合详解

1.23Stream流

1.24方法引用

1.25异常

1.26File

1.27IO流

1.28多线程

1.29网络编程

1.30反射

1.31动态代理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奶茶精Gaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值