当前位置:   article > 正文

Java基础_java的来历

java的来历

1.Java介绍

1.1Java的起源与演变

1.1.1Java起源

 20世纪90年代,单片式计算机系统诞生,单片式计算机系统不仅廉价,而且功能强大,使用它可以大幅度提升消费性电子产品的智能化程度
 SUN公司为了抢占市场先机,在1991年成立了一个由詹姆斯·高斯林(James Gosling)领导,名为“Green”项目小组,目的是开发一种能够在各种消费性电子产品上运行的程序架构
 那么使用何种编程语言来设计,是项目小组头疼的事。当时C++较为有优势的,项目小组首先考虑的是采用它来编写程序,但C++过于复杂和庞大,再加上由于消费电子产品所采用的嵌入式处理器芯片的种类繁杂,需要让编写的程序跨平台运行,假如用C++编写的话对程序的跨平台运行不友好
 最后项目小组决定:既不用C++编写,也不开发全新的编程语言,而是对C++进行改造:去除了C++复杂的指针和内存管理,并结合嵌入式系统的实时性要求,最终在1992年,他们开发了一种名为“Oak”的面向对象语言
当他们在向硬件生产商进行演示的时候,硬件生产商对此并不感冒,OaK语言因为缺乏硬件的支持而无法进入市场,从而被搁置一旁
 1994年,项目小组看到了浏览器在未来的发展前景,于是决定将OaK应用于万维网。1995年,他们用OaK语言研发了一种能将小程序嵌入到网页中执行的技术——Applet,由于Applet不仅能嵌入网页,还可随同网页在网络上进行传输,这让无数的程序员看到了OaK这门语言,与此同时,OaK正式更名为Java。从此,Java在互联网的推动下火了

1.1.2Java演变

  • 1991年 Green项目,开发语言最初命名为Oak (橡树)

  • 1994年,开发组意识到Oak 非常适合于互联网

  • 1996年,发布JDK1.0,约8.3万个网页应用Java技术来制作

  • 1997年,发布JDK 1.1,JavaOne会议召开,创当时全球同类会议规模之最

  • 1998年,发布JDK 1.2,同年发布企业平台J2EE

  • 1999年,Java分成J2SE、J2EE和J2ME,JSP/Servlet技术诞生

  • 2004年,发布里程碑式版本:JDK1.5,为突出此版本的重要性,更名为JDK 5.0

  • 2005年,J2SE -> JavaSE,J2EE -> JavaEE,J2ME -> JavaME

  • 2009年,Oracle公司收购SUN,交易价格74亿美元

  • 2011年,发布JDK 7.0

  • 2014年,发布JDK 8.0,是继JDK 5.0以来变化最大的版本

  • 2017年,发布JDK 9.0,最大限度实现模块化

  • 2018年3月,发布JDK 10.0,版本号也称为18.3

  • 2018年9月,发布JDK 11.0,版本号也称为18.9

1.2Java体系与特点

1.2.1Java体系

Java SE: Java Platform,Standard Edition
标准版: 各应用平台的基础,桌面开发和低端商务应用的解决方案

Java EE: Java Platform,Enterprise Edition
企业版: 以企业为环境而开发应用程序的解决方案

Java ME : Java Platform, Micro Edition
微型版: 致力于消费产品 和嵌入式设备的最佳解决方案

1.2.2Java的特性

一种纯面向对象的编程语言

一种与平台无关(跨平台)的语言。(它提供了在不同平台下运行的解释环境)

一种健壮的语言,吸收了C/C++语言的优点

有较高的安全性(自动回收垃圾,强制类型检查,取消指针)

1.3Java跨平台原理

在这里插入图片描述

1.3.1java技术的两种核心机制

Java虚拟机(Java Virtual Machine) JVM

垃圾回收器(Garbage Collection) GC
在这里插入图片描述

1.3.2 Java虚拟机 (JVM)

在这里插入图片描述
JVM可以理解成一个可运行Java字节码的虚拟计算机系统

  • 它有一个解释器组件,可以实现Java字节码和计算机操作系统之间的通信

  • 对于不同的运行平台,有不同 的JVM

JVM屏蔽了底层运行平台的差别,实现了“一次编译,随处运行”

1.3.3 垃圾回收器(GC)

不再使用的内存空间应当进行回收-垃圾回收

在C/C++等语言中,由程序员负责回收无用内存

Java语言消除了程序员回收无用内存空间的责任

JVM提供了一个系统线程 , 用于跟踪存储空间的分配情况 , 检查并释放那些可以被释放的存储空间

垃圾回收器在Java程序运行过程中自动启用,程序员无法精确控制和干预

1.3.4JDK、JRE、JVM

  • JDK:Java开发工具包
    JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE,所以安装了JDK,就不用在单独安装JRE了。其中的开发工具包括:编译工具(javac.exe) 打包工具(jar.exe)等

  • JRE:Java运行时环境
    包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可

  • JVM:Java虚拟机

三者的关系如下
在这里插入图片描述

1.3.5 JDK版本选择

一般企业开发推荐JDK8和JDK11,Java的未来版本属于JDK17

2.环境搭建

2.1常用DOS命令

  • dir : 列出当前目录下的文件以及文件夹
  • cls: 清除屏幕
  • md : 创建目录
  • rd : 删除目录
  • cd : 进入指定目录
  • cd… : 退回到上一级目录
  • cd: 退回到根目录
  • del : 删除文件
  • exit : 退出 dos 命令行
  • echo: 打印内容

注:常用快捷键

  • tab:自动补全
  • ← →:移动光标
  • ↑ ↓:调阅历史操作命令
  • Delete和Backspace:删除字符

2.2 Java安装

2.2.1安装JDK

推荐JDK8以及以上的版本,更推荐选择JDK8或JDK11的版本

2.2.2配置环境变量

在此电脑-属性-高级系统设置-环境变量中进行配置

红线部分为jdk的安装根目录
在这里插入图片描述

红线部分为命令的寻址目录
在这里插入图片描述

3.Java程序开发步骤

在这里插入图片描述

  • 将Java代码编写到扩展名为.java的文件中
  • 使用javac命令对该java文件进行编译
  • 使用java命令对生成的class文件进行运行

注: 编写的源代码/程序的文件的后缀.java
在这里插入图片描述

4.Java的命名规范

命名规范参考Java开发手册(嵩山版)

Java对包、类、方法、参数和变量等要素命名时使用的字符序列称为标识符

命名规范: 软性建议

标识符命名习惯:见名知意

类名规范: 首字母大写,后面每个单词首字母大写(大驼峰式)

方法名规范: 首字母小写,后面每个单词首字母大写(小驼峰式)

变量名规范: 首字母小写,后面每个单词首字母大写。
包名规范:全都小写

在这里插入图片描述

5.Java转义符号

在这里插入图片描述
实战案例:
\n
在这里插入图片描述
\r
在这里插入图片描述
\t
在这里插入图片描述
\
在这里插入图片描述
\ ’
在这里插入图片描述
\ "
在这里插入图片描述
注:在字符串中加上\符号,那么字符串中的转义字符将不被处理,如下
在这里插入图片描述
运行结果如下
在这里插入图片描述

6.Java注释

Java程序有三种注释方式

6.1单行注释

格式: // 开头,行末结束
// 用于对单行代码的说明

6.2多行注释

格式: / * 开头,* / 结束
中间行的*号不是必须,只是为了格式整齐

6.3文档注释

格式: 以 /** 开始,以 */ 结束

文档注释负责描述类、接口、方法、构造器、成员属性,可以被JDK提供的工具 javadoc 所解析,自动生成一套以网页文件形式体现该程序说明文档的注释

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

注: 文档注释必须写在类、接口、方法、构造器、成员字段前面,写在其他位置无效

7.Java的关键字

在这里插入图片描述
在这里插入图片描述

8.Java的变量

在java中未知数叫变量,未知数可能是整数,也可能是小数,java是强类型语言,要求未知数前面一定要有具体的类型(整数、小数等),因为,这些未知数也是占内存的

8.1变量的声明

  • 必须包含 类型、变量名
    在这里插入图片描述
  • 变量没有声明 ,不能直接使用
    如下,没有声明变量y就使用,会报错
    在这里插入图片描述
  • 不能重复声明(定义)变量
    如下,重复声明了一个变量,报错提示显示:duplicate local variable w,即本地变量w重复
    在这里插入图片描述
    在这里插入图片描述

8.2变量的初始化

8.2.1先声明,后初始化

在这里插入图片描述

8.2.2声明变量的同时直接初始化

在这里插入图片描述
注:
1.没初始化的变量不能被使用(打印)
如下,声明了一个整型变量myMath,但是没有初始化,报错提示没初始化
在这里插入图片描述
初始化变量myMath后,没有报错
在这里插入图片描述

2.如下,先声明并初始化一个整型变量b,而后再赋值,变量b的值是后来再赋的值
在这里插入图片描述

8.3变量的访问

从内存中取出变量,就算访问
在这里插入图片描述
注: 先声明并初始化变量后才能访问(使用)变量

8.4不同类型不能直接赋值

给整型变量b赋值为小数,报错提示类型不匹配
在这里插入图片描述

如下,声明了一个整型变量,赋值为小数,报错
在这里插入图片描述
赋值改为整数,没有报错
在这里插入图片描述

9.进制

在这里插入图片描述

  • 八进制:以0开头
  • 十六进制:以0x或0X开头
  • 二进制:以0b或0B开头

实战案例
在这里插入图片描述
运行结果如下
在这里插入图片描述

9.1二进制

计算机中的数据都以二进制数字保存

二进制:逢二进一,即只有0、1两个值
如:十进制的10在计算机内保存为二进制的1010

计算机中信息的存储单位

位(Bit): 表示一个二进制数码0或1,是计算机存储处理信息的最基本的单位

字节(Byte): 一个字节由8个位组成,第一位是符号位,0表示正,1表示负,它表示作为一个完整处理单位的8个二进制数码

字: 32位计算机:1字=32位=4字节;64位计算机:1字=64位=8字节

补充:二进制转十进制

8421法, 若是多位二进制数字,则依据2的次方依次向上叠加,二进制数字中有0则不进行计算,有1则找1对应的数字进行相加即可

在这里插入图片描述

9.2十六进制

二进制表示法太冗长,所以在程序中一般喜欢用十六进制

十六进制:基数为十六,逢十六进一。它用abcdef表示从0-9之上的值

Java中十六进制数据要以0x或0X开头,如:0x23D

十六进制转换成二进制只需将每个十六进制数字替换为相对应的四个二进制位即可
在这里插入图片描述

9.3八进制

八进制:基数为八

Java中八进制数据要以0开头。如:0123

八进制转换成二进制:只需将每个八进制数字替换为相对应的三个二进制位即可

现在的计算机系统很少用八进制的了
在这里插入图片描述

10.数据类型

在这里插入图片描述

10.1基本数据类型

java的基本数据类型共8种,如下
在这里插入图片描述

10.1.1整型

1.整数数字默认是int类型(即直接量是int),若要声明long类型的,需要在变量的值后面添加L后缀(不区分大小写),也可以省略(省略的时候暗含类型转换)

如下图,声明并初始化了一个变量b,不加l后缀出现报错,报错提示变量的值超出范围
在这里插入图片描述

添加L后缀后,报错取消
在这里插入图片描述

2.整数做除法,结果还是整数,并且不能四舍五入
在这里插入图片描述

3.0不能作为除数,否则运行时会报错
在这里插入图片描述

4.存的数过大,可能溢出,也可能报错,例子如下

报错

Integer.MAX_VALUE是整数类型中int的最大值,为2147483647
在这里插入图片描述

编译时报错,报错提示显示int类型的值超出范围,因为整数默认是int类型,但是int类型最大值为2147483647,这里超出了,所以报错在这里插入图片描述

在long类型变量后面加上L后缀,报错取消
在这里插入图片描述

溢出

编译和运行都不报错,因为存的数过大,溢出了
在这里插入图片描述
运行后结果
在这里插入图片描述

5.初始化int类型的变量时也可以如下这样写

int x = 1,y = 2,z = 3;
  • 1

10.1.2浮点型

1.有小数点的数字默认是double类型(即直接量是double),如果要声明一个float类型的变量,需要在变量值的后面添加f后缀(不区分大小写)

如下图,声明并初始化一个变量f2,不加后缀f出现报错,报错提示类型不匹配
在这里插入图片描述

添加后缀f后,报错取消
在这里插入图片描述

2.double类型可以使用科学计数法来赋值
例如,3.14e2、3.14E2表示3.14 * 10的2次方
在这里插入图片描述
结果为
在这里插入图片描述

3.浮点数是可以存整数的,因为浮点型比整型存储空间大
在这里插入图片描述

4.浮点数做除法,结果是浮点数
在这里插入图片描述
在这里插入图片描述

5.double声明并初始化一个0.开头的小数时,可以将0省略
在这里插入图片描述
如下,运行结果还是0.3
在这里插入图片描述
6.浮点数会丢失精度在这里插入图片描述

10.1.3字符型

1.语法格式:char a = 'x';
字符型的值必须使用单引号引起来,且只能存一个字符
在这里插入图片描述
如下,存两个字符,报错,报错提示Invalid character constant,即无效的字符常量
在这里插入图片描述
2.char其实是一个无符号整数,这个整数和字符进行对应,如下

  • 97:a
  • 65:A
  • 48:0

在这里插入图片描述
3.字符集
ascii码:处理英文字母等少量的字符
iso8859-1:不处理中文
gbk、gb2312…:支持中文
unicode字符集:
存储的方式:utf-8 utf-16

注:乱码,就是因为字符集不一致
比如说数字121,在新华字典中代表“中”,在英汉字典中代表“我”,此时就会造成乱码

4.char的赋值方式如下

  • char a = ‘中’;
    在这里插入图片描述

  • char b = 97;
    在这里插入图片描述

  • char c = ‘\u535A’;
    \u表示unicode值
    在这里插入图片描述
    5.如下图,在控制台打印并不是ab,因为char的底层是整数,a对应97,b对应98,两个变量相加就是两数相加
    在这里插入图片描述
    若想在控制台打印ab,可以使用字符串拼接的方式
    在这里插入图片描述

10.1.4布尔型

1.boolean类型就两个值

  • true
  • false

2.结果是布尔的都是布尔表达式,true和false也是布尔表达式

3.实战案例
在这里插入图片描述

10.2基本数据类型转换

数据类型按容量大小排序如下
在这里插入图片描述

10.2.1强制类型转换

当一个存储空间大的类型转到存储空间小的类型时,正常是不让转的,但是java提供了一个强制类型转换的方式,格式如下

  • (要转成的类型)变量名

强制转换,可能数据会不正确
在这里插入图片描述

10.2.2自动类型转换

容量小的数据类型会自动转换为容量大的数据类型
在这里插入图片描述

10.2.3补充

  • 有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算

  • byte,short,char之间不会相互转换,他们三者在计算时会先转换为int类型
    如下图,计算两个byte类型相加并把结果赋给一个byte类型的值时报错,报错提示类型不匹配
    在这里插入图片描述
    强制转换类型后,报错取消
    在这里插入图片描述
    也可以不给运算结果赋值,直接在控制台打印,此时运算后的结果默认是int类型
    在这里插入图片描述

  • boolean类型不能与其它数据类型运算

  • 当把任何基本数据类型的值和字符串(String)进行连接运算时(+),基本数据类型的值将自动转化为字符串(String)类型,也就是说当+号用在字符串和其他变量中间,就变成了拼接操作
    实战案例
    1.练习1在这里插入图片描述
    2.练习2,如下图,此时在控制台输出123,因为字符串和任何数据类型拼接都会变成字符串,首先,字符串1和整型2拼接后变为字符串12,字符串12又和整型3进行拼接,变为字符串123
    在这里插入图片描述
    3.练习3在这里插入图片描述
    4.练习4在这里插入图片描述

11.运算符

操作符优先级
表达式的运算按照运算符的优先顺序从高到低进行,同级运算符从左到右进行

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

11.1算术运算符

在这里插入图片描述

11.1.1自增

在这里插入图片描述

注:特殊
1.如下图这样赋值时(红线处),若++在后面,则先赋值再自增;若++在前面,则先自增再赋值
在这里插入图片描述

2.如下图,若直接打印i++,则i为10,在Java中,通过直接使用System.out.println(i++);的语句进行打印时,结果会先打印i的当前值,然后再对i进行自增操作

请注意,打印的结果取决于该语句的执行时机和上下文,假设i是一个初始值为0的整数变量,并且该语句被执行一次,打印的结果将是0,而不是1,这是因为i++是一个后缀自增操作符,在表达式中使用时,它会先返回i的当前值,然后再对i进行自增操作,因此,在打印时,在自增之前,i的值仍然为0

如果对表达式中++i进行打印,它将返回自增后的值,例如,System.out.println(++i);在执行后打印的结果将是1,因为++i是一个前缀自增操作符,它会先对i进行自增操作,然后再返回自增后的值进行打印

综上所述,直接打印i++的结果将是操作之前的值,而打印++i的结果将是操作之后的值

3.若把自增自减作为判断条件,则变量的值也会改变

在这里插入图片描述
运行结果如下
在这里插入图片描述

11.1.2自减

在这里插入图片描述
注:特殊
如下图这样赋值时(红线处),若–在后面,则先赋值再自减;若–在前面,则先自减再赋值
在这里插入图片描述
注:
1.自增和自减都是这样,若++在前,先做自增再做别的运算;若++在后,先做别的运算再自增

11.1.3实战案例

最后进行赋值操作
在这里插入图片描述

11.1.4取余

在这里插入图片描述

11.2关系运算符

在Java中,“==” 是一个用于比较两个值是否相等的运算符,它可以用于比较数值、字符、布尔值以及对象引用的相等性, 当被比较的两个值相等时,表达式返回 true;当它们不相等时,表达式返回 false

在Java中,“!=” 是一个用于比较两个值是否不相等的运算符,它可以用于比较数值、字符、布尔值以及对象引用的不等性, 当被比较的两个值不相等时,表达式返回 true;当它们相等时,表达式返回 false
在这里插入图片描述
关系运算符,是有结果的,结果是boolean类型的

11.2.1实战案例

1.练习1,==在这里插入图片描述

2.练习2,==在这里插入图片描述

补充
在这里插入图片描述

11.3逻辑运算符

&&(并且) ||(或) !(非)
关系运算符 可以理解为一个条件,如果有多个条件, 就需要用逻辑运算符来进行连接

11.3.1实战案例

1.练习1,&&,||在这里插入图片描述

2.练习2,||在这里插入图片描述

3.练习3,!在这里插入图片描述

11.4位运算符

位运算即先拆分成二进制,然后按位做运算

  • &与运算: 若都是1结果是1,否则是0

  • |或运算: 若都是0则为0,有一个是1就是1

  • ^异或: 相同为0,不同为1

  • >>: 转换成二进制右移 通常/2
    右移原理同左移

  • <<: 转换成二进制左移 通常*2
    左移就在后面补0,左移几位就乘以2的几次方,如下
    在这里插入图片描述

  • >>>: 无符号右移,不管是正是负左侧(高位)都补0
    在这里插入图片描述

  • 短路与、或
    如果是逻辑运算符,以boolean表达式1 && boolean表达式2为例,如果表达式1是false,java不会走表达式2,因为不论表达式2是true还是false,整体结果都是false,所以java会选择短路操作,如果是位运算,没有这个说法,两个表达式都会执行
    在这里插入图片描述
    在这里插入图片描述

11.5赋值运算符

在这里插入图片描述

11.5.1实战案例

1.练习1,+=在这里插入图片描述

2.练习2,字符串拼接在这里插入图片描述
3.练习3,+=,在下图这段代码中,变量 b2 的数据类型仍然是 byte,虽然在计算 b2 += 3; 这行代码时,会将右侧的表达式 b2 + 3 中的 3 隐式转换为 int 类型,但最终结果会被自动转回 byte 类型,然后再赋值给 b2

Java会进行这种隐式的类型转换是为了确保代码的兼容性和安全性。在对 b2 += 3; 进行计算时,首先将 b2 的值 2 加上 3,得到结果 5。然后,将 5 转换回 byte 类型,并将结果 5 赋值给 b2

因此,尽管在计算过程中会涉及 int 类型,但 b2 的数据类型仍然是 byte
在这里插入图片描述
注:若是如下图这样赋值则需要强制转换
在这里插入图片描述

11.6三目运算符

11.6.1 格式

boolean表达式?值1:值2(两个值类型一样)

解释: 如果布尔表达式为true,三目运算的值就是值1,否则是值2

11.6.2实战案例

1.练习1,若大于10岁结果是1,否则是0在这里插入图片描述
2.练习2,判断输入的数据,若是1就显示男生,否则显示女生
左边的值是什么类型,右边就要用相应类型去承接,如下,左边"男生女生"是字符串类型,所以右边需要用字符串类型去承接

在这里插入图片描述3.练习3,判断学生的成绩,90以上为A,60-90为B,否则为C
三目是可以嵌套的,如下在这里插入图片描述

12.分支

12.1if分支

if是分组的,每一组if会选择一个条件进入

12.1.1一个分支

格式:

if(boolean表达式){
    //如果boolean表达式为true,就进入该代码块
}else{
    //如果boolean表达式为false,就进入该代码块
{
  • 1
  • 2
  • 3
  • 4
  • 5

实战案例: 判断年龄是否到8岁,若到了8岁,就不能看动画片
在这里插入图片描述

12.2.1多个分支

格式:

if(boolean表达式){
  		//如果boolea表达式为true 就进入该代码块
  	}else if(boolean表达式){
  		...
  	}else if(boolean表达式){
  		...
  	}else if(boolean表达式){
  		...
  	}else{
  		//如果boolea表达式为false 就进入该代码块
  	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

实战案例: 判断职务
在这里插入图片描述

12.3.1分支嵌套

格式:

if(boolean表达式){
//如果boolea表达式为true 就进入该代码块
   if(boolean表达式){
      ...
   }else if(boolean表达式){
            ...
   }else{
         ...
   }
}else{
//如果boolea表达式为false 就进入该代码块
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

实战案例:
开放:到月底了,若手里还有500元以上,出去吃烧烤;若有100元以上,吃小吃部;若50-100,吃泡面;不到50,喝风
隔离:有100以上,点外卖;若50-100,吃泡面;不到50,喝风

		System.out.println("请输入状态:");
		String s1 = s.next();	
		System.out.println("请输入余额:");
		int i1 = s.nextInt();
		
		if(s1.equals("开放")){
			if(i1 > 500){
				System.out.println("吃烧烤喽");
			}else if(i1 >= 100 && i1 <= 500){
				System.out.println("勉强吃小吃部吧");
			}
		}else if(s1.equals("隔离")){
			if(i1 > 100){
				System.out.println("被隔离,点外卖吧");
			}
		}else if(s1.equals("没钱")){
			if(i1 >= 50 && i1 <= 100){
				System.out.println("吃康师傅红烧牛肉面");
			}else if(i1 < 50){
				System.out.println("别吃了哥们儿,喝西北风吧");
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

12.2.Switch分支

12.2.1格式

switch(变量){
  case1:
  	[break;]
  case2:
  	[break;]
  ....
  default://如果前面的case都不满足,会进入default,相当于else
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

12.2.2实战案例

1.练习1,判断季节

String season = "4";
		switch(season){
		case "春":
			System.out.println("好");
			break;
		case "夏":
			System.out.println("真好");
			break;
		case "秋":
			System.out.println("特别好");
			break;
		case "冬":
			System.out.println("冬天东北有暖气,nice");
			break;
			default:
				System.out.println("打错了");
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行后结果如下
在这里插入图片描述

2.练习2,判断状态,若是工作日则上课,否则休息

int week = 7;
		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;
			default:
				System.out.println("休息");
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

运行后结果如下
在这里插入图片描述
注:
1.从满足条件的case进入,一直向后执行,遇到第一个break退出,如果一直没有break的话则不会退出,default中的代码也会执行
2.季节、红绿灯、星期等这些不常改变的,非范围的会使用 switch这种方式

简化代码(case 0:case 1:)如下

switch(week){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
			System.out.println("上课");
			break;
		case 6: case 7://可以像上面case12345一样竖着写,也可以这样横着写
			System.out.println("休息");
			break;
			default:
				System.out.println("打错了");
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.练习3,牛奶返利:伊利,蒙牛返5%;安慕希,金典,纯真:20%;完达山,古城:30%

		Scanner s = new Scanner(System.in);
		System.out.println("请输入想查询返利的牛奶:");
		String milk = s.next();
		
		switch (milk){
		case "伊利": case "蒙牛":
			System.out.println("返利5%");
			break;
		case "安慕希": case "金典": case "纯甄":
			System.out.println("返利20%");
			break;
		case "完达山": case "古城":
			System.out.println("返利30%");
			break;
			default:
				System.out.println("输入有误,请重新输入");
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行后结果如下
在这里插入图片描述

4.练习4,判断成绩等级,60以上为等级A,否则为等级B

//练习四:60分以上等级为A,否则为B
		System.out.println("请输入您的成绩:");
		int score = s.nextInt();
		switch(score/60){
		case 1:
			System.out.println("您的成绩为:A");
			break;
		case 0:
			System.out.println("您的成绩为:B");
			break;
			default:
				System.out.println("您的输入有误");
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注:
1.switch中的变量也可以做一些特殊的处理,如:
switch(score/60){case 0:case 1:}这种
2.switch接收的变量有类型限制:
byte、short、char、int、String、枚举
3. 值1值2是变量的值

13.Scanner

Scanner是一个辅助工具,Scanner是一个扫描器,会扫描在控制台(Console) 中输入的数据

13.1实战案例

13.1.1练习1,基本Scanner练习,创建一个扫描仪

在这里插入图片描述

13.1.2练习2,有两个数a和b,若a能被b整除,或者a和b的和大于1000,则输出a,否则输出b

在这里插入图片描述

13.1.3.练习3,开放:到月底了,若手里还有500元以上,出去吃烧烤;若有100元以上,吃小吃部;若50-100,吃泡面;不到50,喝风;隔离:有100以上,点外卖;若50-100,吃泡面;不到50,喝风

		System.out.println("请输入状态:");
		String s1 = s.next();	
		System.out.println("请输入余额:");
		int i1 = s.nextInt();
		
		if(s1.equals("开放")){
			if(i1 > 500){
				System.out.println("吃烧烤喽");
			}else if(i1 >= 100 && i1 <= 500){
				System.out.println("勉强吃小吃部吧");
			}
		}else if(s1.equals("隔离")){
			if(i1 > 100){
				System.out.println("被隔离,点外卖吧");
			}
		}else if(s1.equals("没钱")){
			if(i1 >= 50 && i1 <= 100){
				System.out.println("吃康师傅红烧牛肉面");
			}else if(i1 < 50){
				System.out.println("别吃了哥们儿,喝西北风吧");
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

运行结果如下
在这里插入图片描述
注:
1.nextInt接受int类型,同理,.nextDouble接受double类型
2.输入中文时,尽量将光标移到下面
3.多次测试,可能程序还没有执行完,就进行下一次测试了,会忘记关闭程序,注意定期关闭一下

14.循环

循环体:我们负责写一遍,jvm帮我们执行10遍

14.1while循环

14.1.1格式

while(boolean表达式){
		//循环体
}
  • 1
  • 2
  • 3
while(age < 8){//循环条件
			System.out.println("可以看动画片");//循环体
			age++;//条件变化
		}
  • 1
  • 2
  • 3
  • 4

1、判断 boolean表达式,如果为true,就执行循环体
2、判断 boolean表达式,如果为true,就执行循环体

n、判断 boolean表达式,如果为false,就不执行循环体

14.1.2实战案例

14.1.2.1练习1,循环中的计数的变量,常被拿来使用
//我今年n岁了,可以看动画片
		while(age < 10){
			System.out.println("我今年"+age+"岁了,可以看动画片");
			age++;//计数
		}
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果如下
在这里插入图片描述

14.1.2.2练习2,死循环,break,continue
死循环
  while(true){
  
  }
  • 1
  • 2
  • 3
  • 4

break用于退出循环,break常和if一起使用

while(true){
			if(age < 10){
				System.out.println("我今年"+age+"岁了,可以看动画片");
			}else{
				break;//退出循环
			}
			age++;
		}
		System.out.println(age);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果如下
在这里插入图片描述
注:当break只能跳出内层循环,跳不出外层循环时,可以使用如下几种方法
1.判断一下是怎么从内层循环跳出来的,到了外层再判断一下
2.在外层循环加一个标志,如下

nn:while(){
      while(){
          break nn;
       }
} 
  • 1
  • 2
  • 3
  • 4
  • 5

3.打标志位

原理同方法1

boolean flag = true;
//如果条件改变,flag变为false
if(flag == false){
   break;
}
  • 1
  • 2
  • 3
  • 4
  • 5

打标志位实例

Scanner s = new Scanner(System.in);
		System.out.println("欢迎光临本商店");
		int sum = 0;
		boolean flag = true;//标志位
		while(true){
			//输入价格
			System.out.println("请输入商品价格:");
			int price = s.nextInt();
			//输入数量
			System.out.println("请输入商品数量:");
			int num = s.nextInt();
			//共计,继续(1),结算(2),其他键报错
			sum += price*num;
			System.out.println("此次消费共计"+sum+"元,继续购买请按1,结算请按2");
			//判断按键
			int key;
			while(true){
				key = s.nextInt();
				if(key == 1){
					break;
				}else if(key == 2){
					//直接结算
					flag = false;
					break;
				}else{
					//按错,提示
					System.out.println("输入错误,继续购买请按1,结算请按2");
				}			
			}
			if(flag == false){
				System.out.println("此次消费共计"+sum+"元,欢迎再次光临");
				break;
			}
			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

运行结果如下

在这里插入图片描述

continue用于跳出某一次循环

for(int i = 1;i <= 5;i++){
			if(i == 3){
				continue;//跳出本次循环
			}
			System.out.println(i);
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果如下
在这里插入图片描述

14.1.2.3练习3,输入银行密码无次数限制
Scanner s = new Scanner(System.in);
		System.out.println("您好,请输入密码:");
		int i1 = s.nextInt();
		
		
		while(true){
			if(i1 != 128){//!=比较两个值是否不相等
				System.out.println("您好,密码输入错误,请重新输入");
				i1 = s.nextInt();
			}else if(i1 == 128){
				System.out.println("您好,欢迎来到本银行");
				break;
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

输入银行密码,有次数限制

Scanner s = new Scanner(System.in);
		System.out.println("请输入您的密码:");
		int i = s.nextInt();
		int time = 1;
		//假设正确密码为815,共三次输入密码的机会
		
		while(time <= 3){
			if(i == 815){
				System.out.println("密码正确,欢迎来到本银行办理业务");
				break;
			}else{
				if(time == 3){
					System.out.println("输入的密码有误,您的次数已用尽,您的银行账户被暂时锁定");
					break;
				}
				System.out.println("输入的密码有误,请重新输入:");
				time++;
				i = s.nextInt();
			}
			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
14.1.2.4练习4,盖一栋楼需要1亿元,有10亿,要盖12栋,盖了一栋还剩9亿,盖了第二栋栋还剩8亿…钱没了,不盖了或者盖完了竣工
		int l = 0;
		int m = 5;
		int n = 5;
		
		while(l <= 9){
			l++;
			System.out.println("盖了"+l+"栋楼,还剩"+(m-l)+"亿");
			if(l == n){
				System.out.println("盖完了,竣工");
				break;
			}
			if((m-l) == 0){
				System.out.println("没钱了,不能盖楼");
				break;
			}
			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
14.1.2.5练习5,超市收银,题目梗概如下
欢迎光临
   请输入商品价格
   5
   请输入商品数量
   2
   共消费10元,继续购买请按1,结算请按2,退出请按3
   1
   请输入商品价格
   6 
   请输入商品数量
   1
   共消费16元,继续购买请按1,结算请按2
   2
   您此次共消费16元,请付款,欢迎下次光临
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Scanner s = new Scanner(System.in);
		System.out.println("欢迎光临本超市");
		int sum = 0;
		while (true) {
			System.out.println("购买请按1,结算请按2,退出请按3");
			int key = s.nextInt();
			if (key == 1) {
				// 购买
				System.out.println("请输入商品价格");
				int p = s.nextInt();
				System.out.println("请输入商品数量");
				int n = s.nextInt();
				sum += p * n;
			} else if (key == 2) {
				// 结算
				System.out.println("您此次共消费" + sum + "元,请付款,欢迎下次光临");
				break;
			} else if (key == 3) {
				// 退出
				System.out.println("欢迎下次光临");
				break;
			} else {
				// 输入有误,重新输入
				System.out.println("输入有误,请重新输入");
			}

		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果如下
在这里插入图片描述

14.2do while循环

14.2.1格式

do{
  	循环体
  	}while(boolean表达式);
  • 1
  • 2
  • 3

14.2.2实战案例

public static void main(String[] args) {
		int age = 3;
		do{
			System.out.println("看动漫喽");
			age++;
		}while(age < 7);

	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

14.3for循环

14.3.1格式

for(初始化某变量(1);循环条件(2);变量变化(3)){
  		循环体(4)
  	}
  • 1
  • 2
  • 3

运行顺序为:1…2…4…3…243…243…
注:
1.循环中的i通常是用来计数的,一直在变
2.循环体中的代码,常常利用i的变化
3.若初始化的变量在循环条件中,则这个变量只能活到循环结束,下一次循环还能使用相同的变量,如下

在这里插入图片描述
两次循环中用了同一个变量i1,并不报错,运行结果如下
在这里插入图片描述

14.3.2实战案例

14.3.2.1练习1,累加求和(1+2+3+…+100 = 5050)

做累加操作时用+=,涉及到累加的变量要放在for循环的外面

int sum = 1;
		 for(int i = 2;i <= 100;i++){
		 sum += i;//也可以写sum = sum + i;
		 }
		 System.out.println(sum);
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果如下
在这里插入图片描述

14.3.2.2练习2,输出13579

关于奇偶数的表示,2i-1、2i+1、 i%2!=0、i%2==1等等。修改循环中的步长:i++:步长为1;i=i+2:步长为2

for(int i1 = 1;i1 < 10;i1+=2){
		 System.out.println(i1);
		 }
  • 1
  • 2
  • 3

运行结果如下
在这里插入图片描述

14.3.2.3练习3,计算奇偶数的个数,题目梗概如下
请输入一个正整数,-1退出
  4
请输入一个正整数,-1退出
  5
请输入一个正整数,-1退出
  -1
 
您一共输入了 4个偶数,3个奇数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
Scanner s = new Scanner(System.in);
		int o = 0;//偶数
		int j = 0;//奇数
		while(true){
			System.out.println("请输入一个正整数,-1退出 ");
			int num = s.nextInt();
			if(num == -1){
				//退出
				System.out.println("您已退出");
				break;
			}else if(num % 2 == 0){
				//偶数
				System.out.println("偶数");
				o++;
			}else if(num % 2 != 0){
				//奇数
				System.out.println("奇数");
				j++;
			}
		}
		System.out.println("您一共输入了"+o+"个偶数,"+j+"个奇数");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行结果如下
在这里插入图片描述

注:正式开发中,通常把判断代码放下面

14.3.3练习for循环

14.3.3.1练习1,打印星星(********),一个一个打印

注:System.out.println();会换行;System.out.print();不换行

for(int i = 1;i < 10;i++){
			System.out.print("*");
		}
  • 1
  • 2
  • 3

运行结果如下
在这里插入图片描述

14.3.3.2练习2,打印多行星星

当需要处理又有行又有列这样的数据时,通常使用双层循环,也叫嵌套循环,其中,外层循环负责行,内层循环负责列

for(int i1 = 1;i1 <=3;i1++){
			//循环体,这里负责打印一行
			for(int i = 1;i <= 8;i++){
				System.out.print("*");
			}
			System.out.println();//用来换行
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果如下
在这里插入图片描述

14.3.3.3练习3,用星星打印直角三角形
for(int i1 = 1;i1 <= 5;i1++){
			//循环体,这里负责打印一行
			for(int i = 1;i <= i1;i++){//找规律,第一行一列,第二行二列
				System.out.print("*");
			}
			System.out.println();//用来换行			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果如下
在这里插入图片描述

14.3.3.4练习4,九九乘法表
for(int i = 1;i <= 9;i++){//9行
			for(int j = 1;j <= i;j++){//9列
				System.out.print(j+"*"+i+"="+(j*i)+"\t");
			}
			System.out.println();
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果如下
在这里插入图片描述

15.随机数

Math.random()可以随机出 一个 [0,1)的小数,包括0,但不包括1

15.1实战案例

15.1.1练习1,生成100以内的随机数

int i1 = (int)(Math.random()*100);//[0,100)
		System.out.println(i1);
  • 1
  • 2

或者

double r = Math.random();//[0,1)
		int i = (int)(r*100);//[0,100)
		System.out.println(i);
  • 1
  • 2
  • 3

15.1.2练习2,生成4以内的随机数

练习2.1,生成4以内的随机整数

int i2 = (int)(Math.random()*4);//[0,4)
		System.out.println(i2);
  • 1
  • 2

练习2.2,生成4以内的随机小数

double d1 = Math.random()*4;
		System.out.println(d1);
  • 1
  • 2

15.1.3练习3,生成5~8之间的随机数

(思路:把范围[5,8)-5,也就是生成[0,3)之间的随机数)

int i3 = (int)((Math.random()*3)+5);
		System.out.println(i3);
  • 1
  • 2

15.1.4练习4,随机加法

Scanner s = new Scanner(System.in);
		System.out.println("请输入想要练习的题数:");
		int num = s.nextInt();
		for(int i = 1;i <= num;i++){
			int i4 = (int)(Math.random()*100);
			int i5 = (int)(Math.random()*100);
			System.out.println(i4+"+"+i5);
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

15.1.5练习5,随机加减法,使加法和减法出现的概率相同

Scanner s = new Scanner(System.in);
		System.out.println("请输入想要练习的题数:");
		int num = s.nextInt();
		for(int i = 1;i <= num;i++){
			int j = (int)(Math.random()*2);//可能是0,可能是1
			int i4 = (int)(Math.random()*100);
			int i5 = (int)(Math.random()*100);
			if(j == 0){
				System.out.println(i4+"+"+i5);
			}else if(j == 1){
				System.out.println(i4+"-"+i5);
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行结果如下
在这里插入图片描述

16.综合练习

16.1水仙花数

16.1.1第一版

一个三位数,如153,1的三次方+5的三次方+3的三次方=1+125+27=153,这个数就叫水仙花数,123就不是水仙花数,找出100~999中哪些是水仙花数

int i1 = 0;//个位
		int i2 = 0;//十位
		int i3 = 1;//百位
		//从100开始判断,到999结束
		for(int i = 100;i <= 999;i++){
			//把三位数中的个十百位取出来
			i1 = i%10;
			i2 = i/10%10;
			i3 = i/100;
			//判断一个数个位的三次方+十位的三次方+百位的三次方的和是否等于这个数
			if(i1*i1*i1 + i2*i2*i2 + i3*i3*i3 == i){
				//水仙花数
				System.out.println(i);
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

16.2小球反弹

一个球从100米高处落下,每次落地后反弹回原来高度的一半,再落下…求在第10次落地时,共经过多少米?第10次反弹了多高?

double sum = 100;//第一次落地不参与循环,所以初始值为100
		double height = 100;//反弹的高度
		for(int i = 1;i <= 9;i++){
			sum += height;//第i+1次落地
		    height /= 2;
		}
		System.out.println(sum);
		System.out.println(height/2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

16.3超市收银

超市收银,继续购买请按1,结算请按2,按其他键弹出错误提示

Scanner s = new Scanner(System.in);
		System.out.println("欢迎光临本商店");
		int sum = 0;
		while(true){
			//输入价格
			System.out.println("请输入商品价格:");
			int price = s.nextInt();
			//输入数量
			System.out.println("请输入商品数量:");
			int num = s.nextInt();
			//共计,继续(1),结算(2),其他键报错
			sum += price*num;
			System.out.println("此次消费共计"+sum+"元,继续购买请按1,结算请按2");
			//判断按键
			int key;
			while(true){
				key = s.nextInt();
				if(key == 1){
					break;
				}else if(key == 2){
					//直接结算
					break;
				}else{
					//按错,提示
					System.out.println("输入错误,继续购买请按1,结算请按2");
				}
			}
			if(key == 2){
				System.out.println("此次消费共计"+sum+"元,欢迎再次光临");
				break;
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

16.4猜数字大小

Scanner s = new Scanner(System.in);
		int i = (int)(Math.random()*100);
		int time = 0;
		while(true){
			System.out.println("请输入您要猜的数字:");
			time++;
			int num = s.nextInt();
			if(num > i){
				//大了
				System.out.println("大了");				
			}else if(num < i){
				//小了
				System.out.println("小了");
			}else{
				//猜对
				System.out.println("恭喜您猜中了");
				System.out.println("您一共猜了"+time+"次");
				break;
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

运行结果如下
在这里插入图片描述

17.数组

17.1格式

int[] a = {};
  • 1

存在数组中的数据取出的方式为:数组名[索引/下标]

int[] a = {1,3,5,7,9};//一个数组
		System.out.println(a[4]);//9
  • 1
  • 2

若想修改数组中的数据,需先取出再重新赋值

int[] a = {1,3,5,7,9};
		System.out.println(a[4]);//9
		a[4] = 2;
		System.out.println(a[4]);//2
  • 1
  • 2
  • 3
  • 4

17.2数组的声明和初始化

17.2.1初始化方式一

动态的初始化数组

int[] b = new int[5];//创建了一个长度为5的数组
  • 1

17.2.2初始化方式二

静态的初始化数组

int[] c = new int[]{1,2,3};
  • 1

注:此时不要在int的中括号中写长度

17.2.3初始化方式三

方式二可以简写为,但不是什么时候都可以这样写,只能在声明的同时直接初始化的情况下才能使用,这种也是静态的初始化数组

int[] d = {1,2,2,4};
  • 1

17.2.4初始化方式四(不推荐)

int arr[] = new int[4];
  • 1

注:
1.若数据量小可以使用静态初始化方式;若数据量大可以使用动态初始化方式
2.数组什么类型都可以
3.如果我们不给数组中的元素赋值 ,数组中的元素,会有默认值:整型默认值是0;char的默认值是\u0000;浮点数的默认值是0.0;boolean的默认值是false,非基本数据类型 默认值为:null

17.3数组的长度

int[] arr2 = {32,4,6,7,8,1};
System.out.println("数组的长度为:"+arr2.length);
  • 1
  • 2

在这里插入图片描述
注:数组中最后一个元素

int[] arr2 = {32,4,6,7,8,1};
System.out.println("数组最后一个元素为:"+arr2[arr2.length-1]);
  • 1
  • 2

在这里插入图片描述
注:
1.数组中元素的类型必须相同
2.数组通常和for循环合用也就是遍历,当for循环时,利用长度可以知道需要循环多少次

17.4实战案例

17.4.1练习1,创建一个长度为10的整数数组并给数组中的元素赋值,2,4,6,8,10…

遍历数组,i通常从0开始,正好和数组的下标一致,arr[i]是一个常用代码,遍历的条件不再是i<10,而是i<arr.length

int[] arr = new int[10];
		for(int i = 0;i <arr.length; i++){
			arr[i] = i*2+2;
		}
  • 1
  • 2
  • 3
  • 4

运行结果如下
在这里插入图片描述

17.4.2练习2,用for循环,将练习1中数组的元素输出出来

for(int i = 0;i < arr.length;i++){
			System.out.print(arr[i]+"\t");
		}
  • 1
  • 2
  • 3

运行结果如下
在这里插入图片描述

17.4.3练习3,创建一个长度为10的整数数组,并赋100以内的随机值

int[] arr1 = new int[10];
		for(int i = 0;i < arr1.length;i++){
			arr1[i] = (int)(Math.random()*100);
		}
		System.out.println(Arrays.toString(arr1));
  • 1
  • 2
  • 3
  • 4
  • 5

17.4.4练习4,创建一个长度为10的数组,里面存10以内的随机数,求该数组中所有元素的和(别在创建数组的过程中运算)

int[] arr3 = new int[10];
		for(int i = 0;i < arr3.length;i++){
			arr3[i] = (int)(Math.random()*10);
		}
		System.out.println(Arrays.toString(arr3));
		int sum = 0;
		for(int i = 0;i < arr3.length;i++){
			sum += arr3[i];
		}
		//arr3[0]+arr3[1]+arr3[2]+   +arr3[arr3.length-1]
		System.out.println(sum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果如下
在这里插入图片描述

17.4.5练习5,统计字符串中英文字母的个数,数字的个数,其他字符的个数

String str = "sfgsdfs364可大可";
		char[] arr = str.toCharArray();
		System.out.println(Arrays.toString(arr));
		int e = 0;
		int n = 0;
		int q = 0;	
		for(int i = 0;i < arr.length;i++){
		    if((arr[i]<=90 && arr[i]>=65) || (arr[i]<=122 && arr[i]>=97)){  //(arr[i]<='z' && arr[i]>='a')
		    	e++;
		    }else if(arr[i]>=48 && arr[i]<=57){
		    	n++;
		    }else{
		    	q++;
		    }
		}
		System.out.println("英文有"+e+"个,数字有"+n+"个,其他字符有"+q+"个");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行结果如下
在这里插入图片描述

17.4.6练习6,把一个数组中的两个数进行调换

注:小套路

//两个数调换为--a=8,b=5
		int a = 5;
		int b = 8;
		int c = a;
		a = b;
		b = c;
		System.out.println("a="+a+",b="+b);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果如下
在这里插入图片描述

        int[] arr = {5,8};
//		int[] arr1 = {0,0};
//		arr1[0] = arr[0];
//		arr[0] = arr[1];
//		arr[1] = arr1[0];
		int temp = arr[0];
		arr[0] = arr[1];
		arr[1] = temp;
		System.out.println(Arrays.toString(arr));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果如下
在这里插入图片描述

17.4.7练习7,买了n瓶饮料,统计有几瓶脉动

String[] arr = {"雪碧","脉动","可乐","脉动","脉动","脉动"};
		int m = 0;
		for(int i = 0;i<arr.length;i++){
			if(arr[i].equals("脉动")){
				m++;
			}
		}
		System.out.println("您买的饮料中共有"+m+"瓶脉动");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

17.4.8练习8,一个数组中存了10名学生的成绩,算一下班级的最高分,比第一名成绩差10分的为优秀,比第一名成绩少10-30分的为及格,否则不及格

算一下班级的最高分(求数组中最大的值)

int[] score = new int[10];
		for(int i = 0;i<score.length;i++){
			score[i] = (int)(Math.random()*100);
		}
		System.out.println(Arrays.toString(score));
		int max = 0;
		for(int j = 0;j < score.length;j++){
			if(score[j] > max){
				max = score[j];
			}
		}
		System.out.println("最高分为:"+max);
		int a = 0;
		int b = 0;
		int c = 0;
		for(int j = 0;j < score.length;j++){
			if(max - score[j] <= 10){
				a++;
			}else if((max - score[j] <= 30) && (max - score[j] > 10)){
				b++;
			}else{
				c++;
			}
		}
		System.out.println("优秀的学生为"+a+",及格的学生为"+b+",不及格的学生为"+c);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

运行结果如下
在这里插入图片描述

17.5排序

17.5.1冒泡排序

在这里插入图片描述

int[] arr = new int[5];
		for(int i = 0;i < arr.length;i++){
			arr[i] = (int)(Math.random()*10);
		}
		System.out.println(Arrays.toString(arr));
		for(int i = 0;i < arr.length-1;i++){
			//?轮
			for(int j = 0;j < arr.length-1;j++){
				//比较
				if(arr[j] > arr[j+1]){
					//交换
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
		System.out.println(Arrays.toString(arr));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果如下
在这里插入图片描述

17.5.2冒泡排序优化(减少无效排序)

public static void main(String[] args) {
		int[] arr = new int[5];		
		for(int i = 0;i < arr.length;i++){
			arr[i] = (int)(Math.random()*10);
		}
		System.out.println(Arrays.toString(arr));
		for(int i = 0;i < arr.length-1;i++){
			//?轮
			boolean flag = true;//标志位
			for(int j = 0;j < arr.length-1-i;j++){
				//比较			
				if(arr[j] > arr[j+1]){
					//交换
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
					flag = false;
				}				
			}
			if(flag == true){
				//这轮一个也没换
				break;
			}
			System.out.println(Arrays.toString(arr));
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

运行结果如下
在这里插入图片描述

17.6数组的内存管理

栈和堆,栈没有堆大,栈中放的是数组的名字,数组中的数据在堆中存着,并会有一个地址,也就是说,数组需要将数据存在堆中,而数组变量本身需要引用堆中的数据,这种数据类型叫引用类型,假设有一个数组int[] arr,arr可以叫做变量也可以叫做引用
在这里插入图片描述

int[] arr = new int[4];//写new就是在堆中开辟一块空间 ,假设地址为:0x3f
		arr[2] = 5;// 给0x3f地址中的第2的元素赋值
		int[] arr1 = arr;//arr1中存的就是0x3f\
		arr1[1] = 8;//这里看起来修改的是arr1数组,但其实在堆中,改的还是0x3f对应的数据
		System.out.println(arr[1]);
  • 1
  • 2
  • 3
  • 4
  • 5

18.方法

把一段公共的代码封装起来就叫方法,方法通常是提供功能的,和main方法并列,注意别写在main里面,方法写完必须在main中进行调用,因为main是java程序的入口

public static void main(String[] args) {
		yeonJun();
		sunYshu();
	}
	
	public static void yeonJun(){
		System.out.println("love u yeonjun");
	}

	
	public static void sunYshu(){
		System.out.println("i love sys");
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行结果如下
在这里插入图片描述

18.1方法的定义(声明)

修饰符(public static)  void(返回值)  方法名(形式参数列表:形参){
        方法体;
}
  • 1
  • 2
  • 3

注:代码要写在方法中

18.1.1返回值

如果一个方法写了返回值,就必须返回一个数据,并且返回数据的类型需要和返回值的类型相同(截止目前),如下

  • 返回数据的类型和返回值的类型相同,不报错
    在这里插入图片描述
  • 返回数据的类型和返回值的类型不相同,报错,报错原因是double类型不能转为int类型,即大类型不能转为小类型,除非强制转换
    在这里插入图片描述
  • 返回数据的类型和返回值的类型不是一定不能相同,需要视情况而定,如下图
    在这里插入图片描述

方法的返回值可以使用变量来接收(若没有返回值则不能接收,否则会报错),变量类型需要和方法的返回值类型对应上,如下

public static void main(String[] args) {
         int[] x = array(5);//array(5)表示调用了array方法,并传入5作为参数
         System.out.println(x);
}

public static int[] array(int a){
		int[] arr = new int[a];
		for(int i =0;i < arr.length;i++){
			arr[i] = (int)(Math.random()*100);
		}
		return arr;//返回一个int类型的数组
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

一个方法有返回值,也可以直接输出这个方法,如下

System.out.println(Arrays.toString(array(5)));
  • 1

注:return是用来结束一个方法的,如果该方法有返回值,就必须写return;如果该方法是void,可以不写return,看需求,如下

//测试void方法也可以写return,作用是结束该方法
public static void main(String[] args) {
		cd(5);
	}
	public static void cd(int age){
		if(age < 10){
			return;
		}
		System.out.println("我已经长大了");
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

运行结果如下
在这里插入图片描述
此时控制台不会有任何打印,因为age小于10,所以代码运行到if中执行完return后会结束该方法,所以不会继续执行下面的代码

18.2方法的调用

  	方法名(实际参数列表:实参);
  • 1

注:方法体中定义的变量,还可以写在方法名后面的括号中(形参),写在括号中,本来是没有值的,但是在main中调用该方法时,会将值传过来(实参)

18.3实战案例

18.3.1练习1,求圆的面积,用户调用该方法,提供给方法圆的半径,该方法会计算出圆的面积

public static void main(String[] args) {
		plus(2,4);
		mj(4.0);
		meIntroduce("yeonjun",23);
}
public static void mj(double r){
		double i = 3.14*r*r;
		System.out.println("圆的面积为:"+i);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果如下
在这里插入图片描述

18.3.2练习2,写一个方法进行自我介绍,用户需要传入姓名,年龄,打印出我叫xxx,今年xxx岁

public static void main(String[] args) {
		plus(2,4);
		mj(4.0);
		meIntroduce("yeonjun",23);
}
public static void meIntroduce(String s,int i){
		System.out.println("我叫"+s+",今年"+i+"岁");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

18.3.3练习3,肯德基周四打折,题目梗概如下

若今天周四,学生吃饭会打折,不管是否排队都会去;若今天不是周四,学生可能去吃也可能不去取决于排队的人数,若多于5人就不吃了
若不是学生,若人数多于5人就不吃了
写个方法判断来的顾客会不会吃饭,比如输出:今天周三,是学生,排队5人,不吃
  • 1
  • 2
  • 3
public static void main(String[] args) {
		eat("周三","学生",2);
}
public static void eat(String day,String person,int num){
		if(day.equals("周四") && person.equals("学生")){
			//一定会去
			System.out.println("去吃");
		}else if(num > 5){
			//不去
			System.out.println("不去吃");
		}else{
			//会去
			System.out.println("去吃");
		}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

运行结果如下
在这里插入图片描述

18.3.4练习4,写一个方法,该方法会帮我们创建一个整数数组,并且会帮我们赋随机值,调用时只需提供要创建的数组的长度

public static void main(String[] args) {
System.out.println(Arrays.toString(array(3)));
}
public static int[] array(int a){
		int[] arr = new int[a];
		for(int i =0;i < arr.length;i++){
			arr[i] = (int)(Math.random()*100);
		}
		return arr;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

运行结果如下
在这里插入图片描述

18.3.5练习5,写一个方法,传入两个整数,哪个数大,就返回哪个数

public static void main(String[] args) {
System.out.println(compareNum(23,4));
}
public static int compareNum(int a,int b){
		if(a > b){
			//返回a
			return a;
		}else{
			//返回b
			return b;
		}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

运行结果如下
在这里插入图片描述
注:java会发现如果不符合条件,就不会执行if代码段,那么代码中相当于没有写return,此时如果返回值不是void,那么就会报错,报错提示没有返回数据,但实际上我们真返回了,就要考虑没有返回全这种情况,如下
在这里插入图片描述
写全后报错消失
在这里插入图片描述

18.3.6练习6,用方法写一个小计算器,传入两个数还有要进行的操作,方法会执行这个操作并将结果返回

public static void main(String[] args) {
		System.out.println(calc(4,2,"&"));
	}
	public static int calc(int a,int b,String c){
		if(c.equals("+")){
			return a+b;
		}else if(c.equals("-")){
			return a-b;
		}else if(c.equals("*")){
			return a*b;
		}else{
			return (a/b);
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

运行结果如下
在这里插入图片描述

18.4方法的内存管理

方法是放在栈中的,先调用的方法放在最下面,后调用的方法放在最上面,每一个方法在被调用时,jvm都会给它分配一块空间,这一块空间叫做栈帧,每个方法执行完成后会被销毁,java也会将这块空间(即栈帧)销毁

在这里插入图片描述

假设main方法中定义了一个int a变量,某方法中也定义了一个int a变量,那么这两个方法中的变量并不会冲突,所以不会报错,如下图
在这里插入图片描述
两个方法,被调用时,会形成两个栈帧,如果是传参或者返回值,也不要求名字一定相同,如下图
在这里插入图片描述
在这里插入图片描述

18.5递归

方法自己调用自己叫做递归,容易造成栈溢出错误(StackOverflowError),所以递归需要有一个出口

套路:当我计算0-100的和时,找一个人(1)计算前99个数,我再用前99个数的和加100;人(1)找了一个人(2)计算前98个数,人(1)再用前98个数加99;人(2)找了一个人(3)计算前97个数,人(2)再用前97个数加98…,当计算这种类型的题时可以用递归

18.5.1实战案例

18.5.1.1用递归做累加求和
public static void main(String[] args) {
		System.out.println(test1(100));
}
	public static int test1(int num){//num可以帮我们计算0~num的和
		if(num == 1){
			return 1;//递归的出口
		}
		return test1(num-1)+num;//返回0~num的和
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
18.5.1.2斐波那契数列(1 1 2 3 5 8 13 21 34 55 89),前两个数是1,后面的数是前两个数的和,用递归求数列中的第7个数
/**
	 * test方法帮我们计算第n个数是多少
	 * n是数列中的第几个数
	 * 返回第n位的值是多少
	 */
public static void main(String[] args) {		
		System.out.println(test(8));
}
public static int test(int n){
		if(n == 1 || n == 2){
			//出口
			return 1;
		}
		return test(n-2) + test(n-1);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

注:在一个方法中修改数组,即使这个方法有返回值但没有接收,这个数组也已经改变了,如下

public class Demo05 {
	public static void main(String[] args) {
        int[] array = {1, 2, 3};
        modifyArray(array);
        System.out.println(Arrays.toString(array)); // 输出:[2, 4, 6]
    }
    
    public static int[] modifyArray(int[] arr) {
        // 在这个方法内部对数组进行修改
        for (int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }
        
        // 返回修改后的数组,但没有接收返回值
        return arr;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

19.综合练习

19.1生成一副扑克牌并洗牌

对于数组,可以对数组的下标进行随机操作

public class Demo02_扑克牌 {
	public static void main(String[] args) {
		String[] color = {"方块","梅花","黑桃","红桃"};
		String[] num = {"A ","2 ","3 ","4 ","5 ","6 ","7 ","8 ","9 ","10 ","J ","Q ","K "};	
		String[] s = new String[54];//准备一个装扑克的数组
		int count = 0;
		//给装扑克的数组赋值
		for (int i = 0; i < color.length; i++) {
			for (int j = 0; j < num.length; j++) {
				s[count] = color[i] + num[j];
				count++;
			}
		}
		s[52] = "小王";
		s[53] = "大王";
		System.out.println(Arrays.toString(s));
		
		wash(s);
		System.out.println(Arrays.toString(s));
	}
	
	/*
	 * 洗牌的方法
	 */
	public static void wash(String[] s){
		//随机生成两个下标,让这两个位置互换一下
		//套路:对于数组可以让数组的下标进行随机操作
		for (int i = 0; i < 20; i++) {
			int i1 = (int)(Math.random()*54);
			int i2 = (int)(Math.random()*54);
			System.out.println(i1+" "+i2);
			//互换
			String temp = s[i1]; 
			s[i1] = s[i2];
			s[i2] = temp;
		}		
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

运行结果如下
在这里插入图片描述

用方法写

public static void main(String[] args) {
		String[] color = {"♥️","♣","♠","♦"};
		String[] type = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
		
		//生成扑克牌
		System.out.println(Arrays.toString(creatPoker(color,type)));
//		String[] pokerArr = creatPoker(color,type);
//		System.out.println(Arrays.toString(pokerArr));
		
		
		//洗牌
		System.out.println(Arrays.toString(shuffle(creatPoker(color,type))));//这样写报错?因为没有返回值,所以不能接
//		shuffle(pokerArr);
//		System.out.println(Arrays.toString(pokerArr));
	}
	
	//生成扑克牌
	public static String[] creatPoker(String[] color,String[] type){		
		String[] poker = new String[54];
		int count = 0;
		for (int i = 0; i < color.length; i++) {
			for (int j = 0; j < type.length; j++) {
				poker[count] = color[i] + type[j];
				count++;
			}
		}
		//System.out.println(count);此时count为52
		poker[52] = "小王";
		poker[53] = "大王";
		return poker;
	}
	
	//洗牌
	public static String[] shuffle(String[] arr){
		for (int i = 0; i < 20; i++) {
			//定义两个随机下标
			int i1 = (int)(Math.random()*54);
			int i2 = (int)(Math.random()*54);
			System.out.println(i1+"\t"+i2);
			//交换两个下标中的数
			String temp = arr[i1];
			arr[i1] = arr[i2];
			arr[i2] = temp;
		}
		return arr;
		//System.out.println(Arrays.toString(arr));
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

19.2二进制转十进制

public static void main(String[] args) {
		System.out.println(binToDec("101011"));
	}
	
	//1 0 1 0 1 1 1
	//Math.pow(a,b);-->a的b次方
	public static int binToDec(String s){
		char[] arr = s.toCharArray();
		int sum = 0;
		for(int i = 0;i < arr.length;i++){
			if(arr[i] == '1'){
				sum += Math.pow(2,arr.length-1-i);
			}
		}
		return sum;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行结果如下
在这里插入图片描述

20.面向对象

面向对象有三大特性:继承、封装、多态
1.package包
(1)需要写在第一行
(2)同一个package下不能有重复的类名
(3)类的全限定名:包+类名,如sys.day11.Demo02

2.使用某个类,如果本包下有,默认就是使用本包下的,如果本包下没有,需要导入,但是也不一定非要导包,可以使用类的全限定名来处理,只不过导包可以简化我们代码的写法,如下

使用本包下有的类
在这里插入图片描述

使用别的包的类—导包
在这里插入图片描述
使用别的包的类—写类的全限定名
在这里插入图片描述

3.如果碰巧出现同时使用不同包下的同名的两个类,我们可以导一个包,另一个类,使用类的全限定名

4.java默认帮我们导入java.lang这个包下的类

5.静态导包—访问控制符
public(公共的)、default(默认的)(啥也不写,如void testDefault(){}就是一个默认方法)、private(私有的)、protected(受保护的),作用范围为private<default<protected<public

在这里插入图片描述
注:private_get_set
成员变量基本上都是private修饰,方法基本上都是public修饰,前提得是非设计类的代码想要访问private修饰的成员变量,可以用getset方法,如下

private String brand;
	private int wheelNum;
	private int peopleNum;
	
	
	public String getBrand(){
		//获取品牌
		return brand;
	}
	
	public void setBrand(String brand){
		//设置(修改)品牌
		this.brand = brand;
	}
	
	
	public int getWheelNum(){
		//获取轮子数
		return wheelNum;
	}
	
	public void setWheelNum(int wheelNum){
		//设置(修改)轮子数
		this.wheelNum = wheelNum;
	}
	
	
	public int getPeopleNum(){
		//获取核载人数
		return peopleNum;
	}
	
	public void setPeopleNum(int peopleNum){
		//设置(修改)核载人数
		this.peopleNum = peopleNum;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

在这里插入图片描述

java允许我们自定义类型,如下

public class Dog {
	String name;
	String gender;
	int age;
	String color;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上方代码是一个自己定义的Dog类型

使用数据

public static void main(String[] args) {
		Dog wangwang = new Dog();//创建一个变量
		wangwang.name = "果果";//通过.的方式来操作里面的数据
		wangwang.gender = "母";
		wangwang.age = 2;
		wangwang.color = "白色";

	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

20.1类(类型)

抽象的,对某一类实物的描述,概念上的内容

20.1.1创建一个类,格式如下

修饰符 class 类名{
     //属性(成员变量)


     //方法
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

20.1.2想使用类需要创建对象(也叫实例)

Dog wangwang = new Dog();
  • 1

20.1.3访问对象中的属性,用"."来访问

wangwang.name = "果果";
  • 1

20.1.4一个.java文件中可以定义多个类,但只能有一个public修饰的类,类名和.java文件名相同的类需要用public去修饰

在这里插入图片描述

20.1.5对象的属性是有默认值的

int、short、byte、long的默认值为0;double的默认值为0.0;boolean的默认值为false;char的默认值为\u0000;引用类型的默认值为null

Dog ww3 = new Dog();
		System.out.println(ww3.age);//0
		System.out.println(ww3.color);//null
		System.out.println(ww3.gender);//null
  • 1
  • 2
  • 3
  • 4

运行结果如下
在这里插入图片描述

20.1.6调用方法

变量名(对象).方法();

box.rightMove();
  • 1

20.1.7方法重载(overload)

同一个类中,可以有多个方法名字相同,但是参数列表和个数、顺序和类型不能相同,否则会报错,因为java找方法按方法名和参数列表找,跟返回值无关(System.out.println();就是方法重载)
在这里插入图片描述

20.1.8引用类型的变量也叫引用

20.1.9java中实例就是对象,是某个类的一个对象,类只是一个抽象的东西,对象才是实在的东西,所以叫实例,我们可以把new出来的对象叫做实例,说白了就是这个new出来的“东西”,叫它对象也可以,叫它实例也可以,对象和实例在这个角度上来讲是等价的

20.2对象的内存管理

在这里插入图片描述
当new一个新对象时,一定会在堆中开辟一块新空间,并且这个空间中有对象的默认属性值,这块新空间有一个地址,其他的对象也可以指向这个地址

20.3构造方法

20.3.1当new一个新对象时,会做两件事,在堆中开辟一块儿空间;调用构造方法(写了实参就调用有参构造;没写实参就调用无参构造),如下

Dog d1 = new Dog();
  • 1

20.3.2构造方法的方法名需要是类名,没有返回值,但是不可以写void

#无参的构造方法
public Dog(){

}
  • 1
  • 2
  • 3
  • 4

20.3.3构造方法只在new对象的时候使用,平时是"."不出来的,构造方法通常是给成员变量进行初始化的

有参的构造方法

	public Dog(String n,int a,String c,String g){
		name = n;
		age = a;
		color = c;
		gender = g;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建对象的同时直接初始化

		Dog d3 = new Dog("苹果",2,"白","女");
		d3.info();
  • 1
  • 2

20.3.4构造方法是可以重载的,java默认送一个构造方法,但是如果自己写了构造方法它就不送了,解决方案:调用自己写的构造方法或者新写一个无参的构造方法

//有参的构造方法
	public Dog(String n,int a,String c,String g){
		name = n;
		age = a;
		color = c;
		gender = g;
}
	
//无参的构造方法
	public Dog(){
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

注:
1.自己写的类,如果写了有参构造,一定要配一个无参构造
2.一个类如果有成员变量,可以加构造方法来对成员变量进行初始化

20.4this

20.4.1.this是一个对象,谁调用,this就是谁

//有参的构造方法
	public Dog(String name,int age,String color,String gender){
		this.name = name;
		this.age = age;
		this.color = color;
		this.gender = gender;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

20.4.2.在构造方法中调用另一个构造方法用this,调用构造方法必须写在第一行,构造方法只能由构造方法来调用,普通方法调用不了

调用格式:this(实参列表);

//有参的构造方法
	public Dog(String n,int a,String c,String g){
		name = n;
		age = a;
		color = c;
		gender = g;
}
	
//无参的构造方法
	public Dog(){
		this("嘎嘎",3,"白","女");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

注:若想让成员变量有自定义的默认值,则可以在无参的构造方法中调用有参的构造方法;也可以在无参的构造方法中直接赋值,如下

没调用之前运行结果如下
在这里插入图片描述

调用之后运行结果如下
1.调用有参的构造方法赋自定义的默认值
在这里插入图片描述
在这里插入图片描述
2.直接给变量赋默认值
在这里插入图片描述
在这里插入图片描述

20.5空指针异常

普通方法(即没有static的方法)和成员变量需要由对象来调用,如果是null在调用普通方法或是成员变量(属性)会造成空指针异常(NullPointerException),如果arr数组为null,则使用arr[i]也会出现空指针异常

如下图,此时d和p之间没有形成关联,所以Person类中dog的值为空(null),所以在调用方法时会造成空指针异常,空指针异常会提示第几行出错(如下图黄色部分),所以若出现这种情况就找".“,因为大概率是”."前面的东西出错
在这里插入图片描述

在这里插入图片描述

20.6值传递

Java中参数的传递就是值传递,若是基本类型,传的就是值;若是引用类型,传的是地址(一个引用类型只能存一个地址),因为引用类型中存的就是地址

20.7成员变量和局部变量

20.7.1局部变量

1.定义在方法中
2.生命周期:方法调用时产生,方法结束时销毁
3.默认不被初始化

20.7.2成员变量

1.定义在类内,方法外
2.生命周期:对象被创建时产生,对象被垃圾回收时销毁(即没有东西指着的时候销毁)
3.默认会被初始化

20.8实战案例

20.8.1人和狗

题目梗概如下

/*
 * 有一个Dog类
 * 	属性:name、age
 * 	方法: 吃 nn在吃 肉
 * 有一个Person类
 * 	属性:name、Dog、四只狗
 * 	方法:
 * 		喂狗吃饭、给狗改名、换个狗、喂四只狗吃饭,给数组中的狗改名
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

自己创建的类

public class Dog {
	String name;
	int age;

	public Dog() {

	}

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

	public Dog(String name) {
		this.name = name;
	}

	public void eat(String food) {
		// 传什么吃什么
		System.out.println(name + "在吃" + food);

	}
}

class Person {
	String name;
	Dog dog;
	Dog[] d = new Dog[4];

	public void dogEat(String f) {
		// 喂狗吃饭
		dog.eat(f);
		
		for (int i = 0; i < d.length; i++) {
			d[i].eat(f);
		}
	}

	

	public void changeName(String name) {
		// 给狗改名
		dog.name = name;
		System.out.println(dog.name);
		
	}
	
	public void changeDogsName(String name,int index){
		//给数组中的狗改名
		this.d[index].name = name;
	}
	
	public void changeDog(Dog dog){
		//换狗
		this.dog = dog;
	}
	

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

测试类

public static void main(String[] args) {
		Dog d = new Dog("苹果",2);
		//Dog d1 = new Dog("钻钻");
		Person p = new Person();
		p.dog = d;
		//p.dog = d1;
		
		p.d[0] = new Dog("苹果");
		p.d[1] = new Dog("兰博");
		p.d[2] = new Dog("钻石");
		p.d[3] = new Dog("黄金");
		
		p.dogEat("猪肝");
		System.out.println("-------------");
//		p.dogEat("鸡腿");
//		p.changeName("兰博");
//		p.dogEat("鸡腿");
		
		//Person p1 = new Person();
		p.dogEat("磨牙棒");
		System.out.println("------------");
		p.changeDog(new Dog("果果"));
		p.dogEat("肉");
		System.out.println("--------------");
		p.changeDogsName("兰兰", 2);
		p.dogEat("饺子");
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果如下
在这里插入图片描述

20.8.2读书管理

题目梗概如下
在这里插入图片描述

自己创建的类

ublic class HomeWork_Student {
	// 学生类
	String name;// 张三,李四
	String cardType;// A卡,B卡

	//无参的构造方法
	public HomeWork_Student() {

	}

	//有参的构造方法
	public HomeWork_Student(String name,String cardType) {
		this.name = name;
		this.cardType = cardType;
	}
}

class bookRoot {
	// 图书管理员类
	
	HomeWork_Student student;

	// 借书方法:通过传入不同的卡,借出不同的书
	// 传A卡,借封神榜;传B卡,借java编程思想
	public void borrowBook(HomeWork_Student student) {
			if (student.cardType.equals("A")) {
				System.out.println(student.name+"学生,手里的卡是"+student.cardType+"卡,可以借到封神榜");
			} else {
				System.out.println(student.name+"学生,手里的卡是"+student.cardType+"卡,可以借到java编程思想");
			}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

测试类

public class HomeWork_读书管理测试 {
	public static void main(String[] args) {
		HomeWork_Student stu = new HomeWork_Student("yeonjun","A");
		bookRoot br = new bookRoot();
		br.student = stu;
		br.borrowBook(stu);
		System.out.println(stu.name);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果如下
在这里插入图片描述

20.8.3创建一个电脑并让它开机

题目梗概如下

/*
 * CPU类
 *   属性:品牌,型号
 *   方法:开机-->   intel酷睿i9正在开机
 * Disk类:
 *   属性:品牌,容量
 *   方法:开机-->   希捷 2T 硬盘正在开机
 * 电脑类
 *   属性:CPU Disk
 *   方法:开机-->   如:
 *                   intel酷睿i9正在开机
 *                   希捷 2T 硬盘正在开机
 * 测试类:
 *    创建一个电脑并让它开机
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

自己创建的类

public class Computer {
	//属性
	CPU cpu;//CPU也是一个类型
	Disk disk;
	
	//开机的方法
	public void powerUp(){
		cpu.powerUp();//CPU开机
		disk.powerUp();//硬盘开机
	}
	
}

class CPU{
	//属性
	String cpuBrand;//cpu品牌:intel
	String type;//cpu型号:酷睿i9
	
	
	//有参的构造方法
	public CPU(String cpuBrand,String type){
		this.cpuBrand = cpuBrand;
		this.type = type;
		
	}
	
	//无参的构造方法
	public CPU(){
		
	}
	
	//开机方法
	public void powerUp(){
		System.out.println(cpuBrand+type+"正在开机");
	}
}

class Disk{
	//属性
	String diskBrand;//disk(硬盘)品牌:希捷
	String cap;//disk容量:2T
	
	//有参的构造方法
	public Disk(String diskBrand,String cap){
		this.diskBrand = diskBrand;
		this.cap = cap;
	}
	
	//无参的构造方法
	public Disk(){
		
	}
	
	//开机方法
	public void powerUp(){
		System.out.println(diskBrand+cap+"正在开机");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

测试类

public class ComputerTest {
	public static void main(String[] args) {
		Computer c1 = new Computer();
		c1.cpu = new CPU("intel","酷睿i9");//左侧是CPU类型,右侧需要是CPU类型的对象
		c1.disk = new Disk("希捷","2T");
		c1.powerUp();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果如下
在这里插入图片描述

20.8.4俄罗斯方块

让T左移,打印T的场地

Box类

public class Box {
	// 属性
	int line;// 行
	int list;// 列

	//构造方法,如果用户调用无参的构造方法,默认是(5,5)
	public Box(){
//		this.line = 5;
//		this.list = 5;
		this(5,5);
	}
	
	public Box(int line,int list){
		this.line = line;
		this.list = list;
	}
	
	
	// 方法
	public void leftMove() {  //左移
		list--;
	}

	public void rightMove() {  //右移
		list++;
	}

	public void downMove() {  //下移
		line++;
	}

	public void printInfo() {
		System.out.println("(" + line + "," + list + ")");
	}
	
	
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

T类

public class T {
	//属性,boxes数组中有四个小盒子
	Box[] boxes = new Box[4];
	
	//方法	
	public T(){
		//无参的构造方法
	}
	
	public T(int line,int list){
		//有参的构造方法
		boxes[0] = new Box(line,list);
		boxes[1] = new Box(line,list+1);
		boxes[2] = new Box(line,list+2);
		boxes[3] = new Box(line+1,list+1);
	}
	
	public void moveLeft(){
		//左移,想让T左移,那么T中的每个小盒子都要左移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].leftMove();
		}		
	}
	
	public void moveRight(){
		//右移,想让T右移,那么T中的每个小盒子都要右移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].rightMove();
		}		
	}
	
	public void moveDown(){
		//下移,想让T下移,那么T中的每个小盒子都要下移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].downMove();
		}		
	}
	
	public void info(){
		//打印信息,打印每一个小盒子的坐标信息
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].printInfo();
		}		
	}
	
	public void area(){
		//打印T的场地
		for (int i = 0; i < 10; i++) {//行
			
			for (int j = 0; j < 10; j++) {//列
				//打印一个星星
//				if (i == 5 && j == 5) {
//					System.out.print("*  ");
//				}else{
//					System.out.print("-  ");
//				}
				boolean flag = false;//标志
				for (int q = 0; q < boxes.length; q++) {
					if(i == boxes[q].line && j == boxes[q].list){
						System.out.print("*  ");	
						flag = true;
						//break;   //在此题中break有没有均可
					}
				}
				
				if(flag == false){
					System.out.print("-  ");
				}								
			}
			System.out.println(i);
		}
		for (int i = 0; i < 10; i++) {
			System.out.print(i+"  ");
		}
		
	}
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

测试类

public class TTest {
	public static void main(String[] args) {
		T t = new T(5,5);
		//t.info();
//		t.moveLeft();
//		System.out.println("-------------");
//		t.info();
		t.area();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

运行结果如下
在这里插入图片描述

面向对象版

public class Block {
	// 父类,公共部分
	Box[] boxes = new Box[4];

	public void moveLeft() {
		// 左移,想让T左移,那么T中的每个小盒子都要左移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].leftMove();
		}
	}

	public void moveRight() {
		// 右移,想让T右移,那么T中的每个小盒子都要右移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].rightMove();
		}
	}

	public void moveDown() {
		// 下移,想让T下移,那么T中的每个小盒子都要下移
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].downMove();
		}
	}

	public void info() {
		// 打印信息,打印每一个小盒子的坐标信息
		for (int i = 0; i < boxes.length; i++) {
			boxes[i].printInfo();
		}
	}
}

class T extends Block {
	public T() {
		// 无参的构造方法
	}

	public T(int line, int list) {
		// 有参的构造方法
		boxes[0] = new Box(line, list);
		boxes[1] = new Box(line, list + 1);
		boxes[2] = new Box(line, list + 2);
		boxes[3] = new Box(line + 1, list + 1);
	}
}

class L extends Block {
	public L() {

	}

	public L(int line, int list) {
		boxes[0] = new Box(line, list);
		boxes[1] = new Box(line + 1, list);
		boxes[2] = new Box(line + 2, list);
		boxes[3] = new Box(line + 2, list + 1);
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

20.8.5桌子,桌腿

题目梗概如下
在这里插入图片描述

public class HomeWork_Table {
	public static void main(String[] args) {
		Table t = new Table("白色");
//		t.getTls()[0] = new TableLeg("白色");
//		t.getTls()[1] = new TableLeg("白色");
//		t.getTls()[2] = new TableLeg("白色");
//		t.getTls()[3] = new TableLeg("白色");
		t.infoLegs();
		System.out.println("---------------");
		t.changeLegsColor("黑色");
		t.infoLegs();
		System.out.println("-----------------");
		t.changeLeg(2, new TableLeg("蓝色"));
		t.infoLegs();
		
		
	}
}


class TableLeg{
	private String color;
	
	public TableLeg(){
		
	}
	
	public TableLeg(String color){
		this.color = color;
	}
	
	public String getColor(){
		return color;
	}
	
	public void setColor(String color){
		this.color = color;
	}
	
	public void changeColor(String color){
		//改一个桌腿的颜色
		this.setColor(color);
	}

	public void info(){
		System.out.println("桌腿的颜色为:"+color);
	}
	
	
}

class Table{
	private TableLeg[] tls = new TableLeg[4];
	

	public Table(){
		
	}
	
	
	public Table(String color) {
		super();
		for (int i = 0; i < tls.length; i++) {
			tls[i] = new TableLeg(color);
		}
	}

	public TableLeg[] getTls(){
		return tls;
	}
	
	public void setTls(TableLeg[] tls){
		this.tls = tls;
	}
	
	
	public void changeLegsColor(String color){
		//给桌腿们改色
		for (int i = 0; i < tls.length; i++) {
			tls[i].changeColor(color);
		}
	}
	
	public void changeLeg(int index,TableLeg tl){
		//换第几个桌腿?
		tls[index] = tl;
	}

	public void infoLegs(){
		for (int i = 0; i < tls.length; i++) {
			tls[i].info();
		}
	}
	
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

运行结果如下
在这里插入图片描述

注:
1.如果手里有引用类型,可以直接使用它,如可以使用它自带的方法
2.测试类是带程序入口(main方法)的类
3.基本类型赋值,直接赋值就可以;引用类型赋值,需要赋对象(在堆里找一个符合条件的对象):
(1)如果有现成的对象可以直接赋值
(2)如果没有现成的对象就new一个

21.二维数组

21.1创建二维数组的方式

21.1.1方式1

int[][] arr = new int[3][4];
  • 1

上面这句话让java帮我们创建了四个数组,一个大数组,还有三个一维小数组,其中大数组的长度为3,小数组们的长度为4,大数组中存的是三个小数组的地址,也就是说java会为我们创建一个长度为3的二维数组,三个长度为4的一维数组,并给一维数组赋默认值

21.1.2方式2

int[][] arr = new int[3][];
  • 1

上面这句话让java为我们创建一个长度为3的二维数组,并给这个二维数组中的元素们赋值为null(因为引用类型的变量默认值为null),使用时,需要给这些元素创建指定长度的数组,否则直接使用会报空指针异常

21.1.3方式3 二维数组的静态初始化

        //int[] ss = new int[]{1,2,3};这是一维数组的静态初始化方式
		int[][] arr02 = new int[][]{{1,3},{2,3},{1,2,3}};//可以这样写
		int[][] arr03 = {{1,3},{2,3},{1,2,3}};//也可以简写为这样
  • 1
  • 2
  • 3

21.2数组下标越界异常

数组下标越界异常指的是在访问数组元素时,使用了超出数组有效下标范围的索引,例如,数组长度为N,而使用了小于0或大于等于N的索引值

例如java.lang.ArrayIndexOutOfBoundsException: 2,2代表java在帮我们跑arr[2]的时候出现了越界

21.3实战案例

21.3.1练习1,给二维数组赋值:100以内的随机数

int[][] arr = new int[2][3];
		
		for (int i = 0; i < arr.length; i++) { //arr.length表示二维数组的长度
			for (int j = 0; j < arr[i].length; j++) {
			//arr[i].length表示二维数组中每一个一维数组的长度
				arr[i][j] = (int)(Math.random()*100);
			}
		}
		System.out.println(Arrays.deepToString(arr)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

21.3.2练习2,二维数组的第二种赋值方式

int[][] arr1 = new int[3][];
		arr1[0] = new int[4];
		arr1[1] = new int[2];
		
		for (int i = 0; i < arr1.length; i++) {
			if(arr1[i] != null){
				for (int j = 0; j < arr1[i].length; j++) {
					arr1[i][j] = (int)(Math.random()*100);
				}
			}
			
		}
		//下面是打印二维数组的方式
		System.out.println(Arrays.deepToString(arr1));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

21.3.3练习3,求二维数组中所有元素的和

int[][] arr = new int[2][3];
		int sum = 0;
		for (int i = 0; i < arr.length; i++) { //arr.length为二维数组的长度
			for (int j = 0; j < arr[i].length; j++) {
				arr[i][j] = (int)(Math.random()*100);
				sum = sum + arr[i][j];
			}
		}
		System.out.println(Arrays.deepToString(arr));
		System.out.println(sum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

22.方法区

方法区存的是类信息,它有一个特点,就是东西就一份,类信息就像一个说明书,比如说,当new对象的时候,堆里面知道这个对象有什么成员属性,靠的就是这个说明书;或者又比如说,当调用方法的时候在会在栈中生成一个栈帧,java知道生成多大栈帧,靠的也是这个类信息,类信息既没有值也不会运行

23.继承

继承使用关键字extends,子类想要使用父类的代码,需要使用关键字extends,格式如下

class Dog extends Animal{
	//Dog为子类,Animal为父类
}
  • 1
  • 2
  • 3

23.1父类

父类中存的是公共部分的代码,具有公共部分的类,我们叫它父类、基类、超类

23.2子类

子类也叫子类、派生类、扩展类,子类可以用父类的代码,子类也可以有自己的方法,如下

23.2.1用父类的代码

public class Demo02_继承 {
	public static void main(String[] args) {
		Dog d = new Dog();
		d.name = "果果";
		d.age = 2;
		d.eat();
	}
}
class Animal{
	//父类
	String name;
	int age;
	
	
	public void eat(){
		System.out.println(name+age+"岁了,在吃零食");
	}
}

class Dog extends Animal{
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

运行结果如下
在这里插入图片描述

23.2.2有自己的方法

public class Demo02_继承 {
	public static void main(String[] args) {
		Dog d = new Dog();
		d.name = "果果";
		d.age = 2;
		d.eat();
		d.eatMore();
	}
}

class Animal{
	//父类
	String name;
	int age;
	
	
	public void eat(){
		System.out.println(name+age+"岁了,在吃零食");
	}
}

class Dog extends Animal{
	public void eatMore(){
		System.out.println("吃磨牙棒");
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果如下
在这里插入图片描述
注:
1.java中子类的构造方法默认会去调用父类的无参构造,如果父类没有无参构造函数,子类必须显示调用父类的其他构造函数,否则将报错
2.java送构造:给类送无参构造;给子类的构造方法中送一句话super();
3.子类调用父类的构造方法super();
4.java是单继承,一个子类只能继承一个父类
5.子类重写父类方法,访问控制符可以变大或相等,即父类如果是protected,子类可以是public或protected
6.返回值类型可以更改,但更改的返回值类型(子)跟原返回值类型(父)需要是继承关系,子类重写父类方法,返回值类型,可以是父类方法返回值类型的子类
7.子类对象不能在自己的方法内部直接访问父类的私有属性和私有方法,可以通过public修饰的getset方法来间接访问

23.3方法重写

如果子类想自己实现某些方法,不想用父类提供的,就可以重写,父类的方法,这样在调用的时候,就会直接调用子类自己重写的那个方法,如下

public class Demo02_继承 {
	public static void main(String[] args) {
		Cat c = new Cat();
		c.name = "钻钻";
		c.age = 3;
		c.eat();
	}
}

class Animal{
	//父类
	String name;
	int age;
	
	
	public void eat(){
		System.out.println(name+age+"岁了,在吃零食");
	}
}

class Cat extends Animal{
	//重写父类的方法
	@Override
	public void eat(){
		System.out.println("吃猫粮");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果如下
在这里插入图片描述

方法重写需要注意以下几点:
1.方法名、参数列表需要相同
2.返回值类型小于等于父类
3.修饰符大于等于父类
4.抛出的异常小于等于父类
5.重写的方法,方法上面可以用@Override注解
(1)当某个方法上面添加了@Override注解,代表当前方法是重写方法
(2)如果该方法写错了,有这个注解会报错,所以该注解,起到了一个检查的作用
父类方法
在这里插入图片描述

子类重写方法
在这里插入图片描述
如上,重写方法名和父类方法名不一致,所以报错
6.如果子类重写父类的方法,还想继续使用父类原方法的内容,需要加一个关键字super ,类似于this,如下

public class Demo02_继承 {
	public static void main(String[] args) {
		Cat c = new Cat();
		c.name = "钻钻";
		c.age = 3;
		c.eat();
	}
}

class Animal{
	//父类
	String name;
	int age;
	
	
	public void eat(){
		System.out.println(name+age+"岁了,在吃零食");
	}
}

class Cat extends Animal{
	//重写父类的方法
	@Override
	public void eat(){
	    super.eat();//调用父类的eat方法
		System.out.println("吃猫粮");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

运行结果如下
在这里插入图片描述

24.static

24.1static介绍

24.1.1static表示静态的、类级别的,有static修饰的成员变量(属性)或方法不需要对象的存在,就可以使用,存在方法区中,就一份

24.1.2调用的方式:类名.static变量;类名.static方法,

24.1.3成员变量想要调用需要有对象,因为成员变量存在对象中,静态变量是类级别的,不需要对象,存在方法区中,静态的成员变量比普通的成员变量活的久,非static方法需要由对象.非static方法去调用,static方法用类名/对象都可以调用但是推荐使用类名调用

24.1.4如果调用同一个类中main方法下面有static的方法,直接写方法名()即可,如下

在这里插入图片描述
如果在main方法中调用别的类中有static的方法,则需要用类名.方法名的方式,如下
在这里插入图片描述
在这里插入图片描述

24.1.5static修饰的方法中,不能有this、super这两个关键字

24.1.6非static方法需要由对象来调用,非static方法也不是不能在main中调用,只是不能直接调用, 我们可以new完对象再调用

24.2static应用

24.2.1工具类

如果某些方法不需要对象的存在就可以使用它的功能,那么这个方法就可以设置为static方法

工具类是static的一个应用,工具类本身不需要成员变量,也不需要有对象,通常内部的方法都是static的,比如说Math、Arrays都是工具类

24.2.2工厂类

场景:假设华为笔记本厂商把设计资料都给我们了,咱们自己想创建一个笔记本也费劲,我们希望创建笔记本对象这件事,让厂商来做,我们只负责传入一些必需的参数

工厂类中的方法通常是static修饰

设计模式:23种,其中有一种叫工厂模式,还有一种叫单例模式,如下

24.2.2.1单例模式
/*单例模式
 * 要求定义一个类,该类只能创建一个对象
 *   分析:
 *   1.需要将构造方法变为私有,用户就不能直接new对象了
 *   2.发现一个都不能new了
 *   3.写一个public的方法,相当于关了门,开了扇窗户
 *   4.又发现自己写的方法外面调用不了
 *   5.将该方法修改为静态方法,这样不用对象也能调用了
 *   6.窗户开大了,所有人都可以通过这个方法 创建新对象
 * 	 7.给方法中添加了if判断
 * 		如果已经存在一个对象,就返回该对象
 * 		否则创建一个新对象,并返回
 * 	 8.我们需要找一个变量来存这个唯一的对象
 * 		使用了private static Dog dog;这种方式
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

懒汉式
保证不了唯一的对象,因为dog = new Dog();,new Dog()是需要时间的,在这个时间中如果有别的人也来调用创建对象这个方法,就会创建出两个对象,所以对象会不唯一

class Dog{
	private static Dog dog = null;  //这东西在方法区,需要写static因为"创建对象()"是类级别的
	
	private Dog(){
		//私有的构造方法
	}
	
	public static Dog 创建对象(){
		if(dog == null){  //判断唯一的对象是否已经创建
			dog = new Dog();  //还没创建,新new一个,并先存到dog这个静态变量中
			return dog;  //并返回给用户
		}else{  //如果静态变量dog中已经有对象了
			return dog;  // 直接返回已有的对象
		}
		
		//也可以如下这样写
//		if(dog == null){
//			dog = new Dog();
//		}
//		return dog;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

饿汉式
能保证只有一个对象

class Cat{
	private static Cat c = new Cat();//免去了先创建的烦恼,但是有问题类似于开机自启动
	
	private Cat(){
		
	}
	
	public static Cat getCat(){
		return c;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

测试

在这里插入图片描述

25.代码块

25.1构造代码块

在类内方法外,在构造方法之前执行,可用于通用的初始化操作,每次调用构造方法都会执行

25.2局部代码块

在方法内,可以缩小变量的作用域,即变量出了局部代码块后就不能用了,如下
在这里插入图片描述

25.3静态代码块

在类内方法外,用static修饰,在调用静态方法或静态变量时会触发静态代码块,通常是类加载时,在构造代码块之前执行,静态代码块只被加载一次,通常是给static变量进行初始化操作的(进行静态初始化操作的),不能初始化普通的成员变量,静态代码块中的变量出了大括号之后就不能用了

25.4代码块执行顺序

public static void main(String[] args) {
		B b = new B();
	}
}

class A{
	{
		System.out.println("3...我是A类的构造代码块..");
	}
	static{
		System.out.println("1...我是A类的静态代码块..");
	}
	public A(){
		System.out.println("4...我是A类的构造方法..");
	}
}
class B extends A{
	{
		System.out.println("5...我是B类的构造代码块..");
	}
	static{
		System.out.println("2...我是B类的静态代码块..");
	}
	public B(){
		System.out.println("6...我是B类的构造方法..");
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

26.final

26.1用final修饰的成员变量只能赋一次值,只有三个位置可以进行赋值:声明的同时直接赋值;在构造方法中赋值;在构造代码块中赋值

26.2用final修饰的局部变量只能赋一次值,可以在声明的同时直接赋值,也可以先声明后赋值

26.3final修饰方法,该方法不能被重写

26.4final修饰类,该类不能被继承

26.5final常和static一起用,叫做常量,约定俗成是大写,如:MY_AGE

26.6常量类,如xxxConstants,类中会有多个static final修饰的数据,这种数据通常是不改变的,项目中通用,在Java中,定义常量时必须给其赋一个初始值

在这里插入图片描述
注:如上图,定义的常量写在方法外

26.7final修饰引用类型,引用类型中存的是地址,这个地址不可以改,但是该地址对应的 实例对象中的成员变量是可以改的,如下

final D d = new D();
		d.name = "nn";
		System.out.println(d.name);
		d.name = "bb";
		System.out.println(d.name);
		
		// d = new D();//这种修改不可以
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

27.Object

Object是所有类的父类,也叫顶级父类
注:基本数据类型和object是没有关系的,基本数据类型的包装类的父类则是object

27.1toString()

Object中有toString方法,子类通常会重写父类的toString()方法,可以利用IDE(eclipse、idea等开发工具)自动生成重写的toString方法,调用时toString方法可以省略不写,如syso(dog)和syso(dog.toString())结果是一样的,都能输出成员变量的信息

27.2equals

场景:
财务处创建一个学生对象 ,身份证号是123456789
教务处理创建一个学生对象 ,身份证号是123456789
在堆中一定不是同一个对象
但在业务中,这两个学生,就应该是同一个学生
但==就比地址,所以有时不方便

== 恒等
1.对于基本数据类型, == 就直接判断是否相等
2.对于引用数据类型, == 在判断两个对象的地址是否相同

Object的equals方法是用 == 进行判断是否相等的,通常业务需求不能用恒等来判断,所以通常子类需要重写父类的equals方法,equals要求相对严格(也就是说重写equals方法必须要写下面这三条):如果两个对象恒等(即p1==p2结果为true),那么equals也相等;如果一个对象和null进行比较,结果需要返回false;如果一个对象和另一个对象类型不同,需要返回false,接下来,就可以写我们自己的比较规则了,如:我们要求Pig必须name和age都相同,才算相等,具体如下

@Override
	public boolean equals(Object obj) {
		if (this == obj)  //如果恒等返回true
			return true;
		if (obj == null)  //因为调用方不可能是空,否则会报空指针
			return false;
		if (getClass() != obj.getClass())  //判断类型是否相同
			return false;
		Pig other = (Pig) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

之前,只要是同一个对象,这个地址值是相同的,现在两个nn不是同一个对象,但让我们人为的判断了相等(重写equals判断的),如果不改hashCode,别人会看到两个nn equals相等,但hashcode不同,所以我们在重写equals的同时,也会重写hashcode这个方法,该方法用来保证如果两个对象(p1、p2) equals相等,那么它们通过hashcode方法算出来的值一定相同

@Override
	public int hashCode() {//com.easthome.day01.Dog@0x66(0x66其实不是地址,只是一个数值)
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

27.3包装类

八个基本数据类型不是对象,所以java提供了 包装类 ,每个基本数据类型都有自己的包装类,如下

/*
 * int -- Integer
 * byte -- Byte
 * short -- Short
 * double -- Double
 * float -- Float
 * long -- Long
 * boolean -- Boolean
 * char -- Character
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

27.3.1Integer包装类

27.3.1.1自动拆封箱

1.自动封箱

int i1 = 2;
		//下面这是赋值操作,类型需要匹配,但是java自动的将右侧的int类型封到了一个Integer对象中然后进行了赋值操作
Integer i2 = i1;//自动封箱
  • 1
  • 2
  • 3

2.自动拆箱

int i1 = 2;
		//下面这是赋值操作,类型需要匹配,但是java自动的将右侧的int类型封到了一个Integer对象中
Integer i2 = i1;//自动封箱
i1 = i2;//自动拆箱,不需要手动进行转换
  • 1
  • 2
  • 3
  • 4
27.3.1.2Integer自带的方法

1.int类型的最大值

System.out.println("----------------Integer自带的方法-----------");
		System.out.println("int类型的最大值:"+Integer.MAX_VALUE);
  • 1
  • 2

2.将字符串转为整数Integer.valueOf();(常用)

返回值是Integer类型

Integer i3 = Integer.valueOf("123");
System.out.println("字符串转为了整数:"+i3);
  • 1
  • 2

自动封箱的原理,其实是java在底层帮我们调用了Integer.valueOf(5);

i3 = Integer.valueOf(5);  //传入一个int类型的5,会返回一个Integer类型的5
  • 1

如下,用int类型去接也不会出错,因为自动拆箱了
在这里插入图片描述

注:NumberFormatException(数字格式化出错)

如下图这样打代码会报错,报错是因为字符串里装数字能按数字的形式去处理,装别的就处理不了了,所以叫数字格式化出错
在这里插入图片描述
在这里插入图片描述
3.int类型共多少位(Integer.SIZE)

System.out.println("int类型共多少位:"+Integer.SIZE);//32位
  • 1

4.int类型的字节数(Integer.BYTES)

System.out.println("int类型的字节数:"+Integer.BYTES);//4字节
  • 1

5.将字符串转为整数Integer.parseInt()

返回值是int类型

int i4 = Integer.parseInt("123");//双引号中也不能写英文字母否则会报错NumberFormatException
System.out.println(i4);
  • 1
  • 2

6.将一个Integer类型转为一个int类型intValue(),返回值是int类型

i3 = Integer.valueOf(5);  //传入一个int类型的5,会返回一个Integer类型的5
System.out.println(i3); 
int i7 = i3.intValue();
  • 1
  • 2
  • 3

自动拆箱的原理,其实是java在底层帮我们调用了i3.intValue();

注:valueOf和parseInt()的区别
两者都是把字符串转为整数,只不过返回的类型不同,看自己需要

27.3.1.3常量池(面试题)
Integer i8 = -128;
Integer i9 = -128;
System.out.println(i8 == i9);//true
  • 1
  • 2
  • 3

解释:在方法区中有一个位置叫做常量池,存着-128~127之间的所有整数,给i8和i9赋值时会先去常量池里找,若在常量池里找到了,并且两个数还相同那么结果就为true,因为地址都是常量池,所以相同,此时,即使Integer是一个类,也是不需要new对象这种操作的;但是若超过了常量池的范围(-128-127),就需要new对象,地址不同,所以结果是false

28.抽象类

场景如下

一个圆类
  属性:半径
  方法:求面积
长方形
  属性:长宽
  方法:求面积
提取一个公共的父类,写一个测试类
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

28.1抽象类需要有abstract来修饰,如下

abstract class Father{

}
  • 1
  • 2
  • 3

28.2抽象类不让new

28.3还是继承,只不过父类中可能会有抽象的方法

28.4java允许我们写半成品方法,半成品方法也叫抽象方法,没有方法体,但需添加abstract关键字,代表抽象的,如下

public abstract double area();  //半成品的方法,也叫抽象方法,没有方法体
  • 1

28.5抽象类中可以写非抽象方法,一个类中有抽象方法那么这个类必须要用abstract修饰,但是一个抽象类不一定要有抽象方法

28.6子类继承一个抽象的父类会将抽象方法也继承下来,处理方式如下

28.6.1不重写,代表该子类中也有抽象方法,那么就需要使用abstract来修饰这个子类

abstract class Father{
	
	public abstract double area();  //半成品的方法,也叫抽象方法,没有方法体
}

abstract class Square extends Father{
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

28.6.2重写父类的抽象方法

abstract class Father{
	
	public abstract double area();  //半成品的方法,也叫抽象方法,没有方法体
}

class Square extends Father{
	public double area(){
		return 0;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注:重写父类的抽象方法时不能写abstract关键字

28.7abstract不能和final一起用;abstract不能作用在private方法上,因为子类不能重写父类的private方法;abstract不能作用在static方法上,因为子类不能重写父类的static方法

28.8抽象类可以有构造方法

28.9父类数组可以装子类类型的元素,如下

public class Demo03_抽象类 {
	public static void main(String[] args) {
		Cir c = new Cir(6);
		//System.out.println(c.area());
		
		Cir c1 = new Cir(2);
		Cir c2 = new Cir(4);
		Rec r1 = new Rec(2,5);
		Rec r2 = new Rec(1,5);
		//父类数组装子类元素
		Father[] arr = {c,c1,c2,r1,r2};
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i].area());
		}
	}
}

abstract class Father{
	
	public abstract double area();  //半成品的方法,也叫抽象方法,没有方法体
}



class Cir extends Father{
	int ridius;  //半径
	
	public Cir() {
		super();
	}

	public Cir(int ridius) {
		super();
		this.ridius = ridius;
	}

	public double area(){
		return 3.14*ridius*ridius;
	}
}


class Rec extends Father{
	double length;  //长
	double width;   //宽
	
	public Rec() {
		super();
	}

	public Rec(double length, double width) {
		super();
		this.length = length;
		this.width = width;
	}

	public double area(){
		return length*width;		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

运行结果如下
在这里插入图片描述

29.接口

注:接口和接口之间用继承

29.1jdk8之前的接口

29.1.1接口依然是子父类的关系,关键字是interface,之前的子父类叫继承,但如果是接口,叫“实现”,关键字是implements,如:Fox类实现了Animal接口,其中Fox类我们会叫它子类或实现类

interface Animal {

}
class Fox implements Animal {
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

29.1.2抽象类可以有抽象方法也可以有非抽象方法;接口全是抽象方法,不能有非抽象方法(也就是我们平时写的普通方法),接口中的方法默认是public abstract修饰的,public abstract可省略

interface Animal {
	void test();
}
  • 1
  • 2
  • 3

29.1.3java中的继承是单继承,java中的接口是多实现

interface Animal {
	
}

interface A {
	
}

class Fox implements Animal, A {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

29.1.4接口也不能new

29.1.5接口中都是常量,并可以省略public static final

在这里插入图片描述

29.1.6子类会实现父类接口的抽象方法,所以子类需要重写父类的抽象方法

interface Animal {
	void test();
}

interface A {
	
}

class Fox implements Animal, A {
	public void test() {

	}

	

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

29.2jdk8接口

29.2.1jdk8接口中,接口中可以写完整的普通方法了,只是需要加上default关键字

interface C{
	public default void eat(){
		System.out.println("ccc");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5

29.2.2jdk8还允许写静态方法,但是需要用接口名去调用,不能用子类对象去调用

29.2.3子类如果想调用父类的default方法,不能直接写super.父类的default方法,需要写父接口名.super.父类的default方法

interface C{
	public default void eat(){
		System.out.println("ccc");
	}
}

class C1 implements C{
	public void eat(){
		C.super.eat();
		System.out.println("111");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

29.2.4如果子类实现的多个父类中有相同的default方法,子类需要重写这个default方法,否则java在执行子类对象.default方法时会混淆,不知到要找哪个default方法,因为两个父类都有

public class Demo05_jdk8接口 {
	public static void main(String[] args) {
		C1 cc = new C1();
		cc.eat();
	}
}
interface C{
	public default void eat(){
		System.out.println("ccc");
	}
}
interface E{
	public default void eat(){
		System.out.println("ddd");
	}
}

class C1 implements C,E{
	public void eat(){
		C.super.eat();
		E.super.eat();
		System.out.println("111");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

运行结果如下
在这里插入图片描述

30.多态

30.1多态是多种形态的意思

30.2java允许将子类直接赋给父类,子类可以直接赋值给父类的引用(变量)

public static void main(String[] args) {
		Student y1 = new YJS();
}

//父类学生
abstract class Student{

}

//子类研究生
class YJS extends Student{
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

30.3一个类型的引用(比如说Student类型的变量y1和k1)在指向不同实例时会有不同的实现,同样的对象被不同的类型(各种父类或它本身)引用时,功能会不一样("."出的东西不一样)

30.4静态编译和动态绑定

30.4.1静态编译

此时代码并没有运行,编译期能"."出什么取决于等号左边是什么类型(即父类是什么类型)

30.4.2动态绑定

代码运行期间再确定应该调用哪个方法,"."调用的时候能出现什么结果取决于等号右边是什么类型(即子类是什么类型)

总结:能"."出来什么方法归左边管,能具体调用什么方法,运行出什么结果归右边管

30.4.3实战案例

public class Demo01_多态 {
	public static void main(String[] args) {
		Student y1 = new YJS();
		y1.study();
		System.out.println("-------------------");
		Student k1 = new KDB();
		BGB k2 = new KDB();
		YJY k3 = new KDB();
		k1.study();
		k1.outPractice();
		k2.meet();
		k3.mark();
		System.out.println("---------------");
	}

abstract class Student{
	String name;  //姓名
	int age;  //年龄
	int num;  //学号
	
	//抽象方法学习
	public abstract void study();  
	
	//出操
	public void outPractice(){
		System.out.println("在出操");
	}
}

//子类研究生
class YJS extends Student{
	
	//重写父类的study方法
	public void study(){
		System.out.println("研究生在学习");
	}
}

//子类科代表
class KDB extends Student implements BGB,YJY{
	
	//重写父类的study方法
	public void study(){
		System.out.println("科代表在学习");
	}
	
	//重写接口的meet方法
	public void meet(){
		System.out.println("科代表在开会");
	}
	
	//重写接口的mark方法
	public void mark(){
		System.out.println("科代表在阅卷");
	}
	
}

//接口班干部
interface BGB{
	
	//抽象方法开会
	void meet();  
}

//接口阅卷员
interface YJY{
	
	//抽象方法阅卷
	void mark();  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

运行结果如下
在这里插入图片描述

30.5向上造型(向上转型)

子类可以向上转型为父类,如Student y1 = new YJS();

30.6父类转子类需要强制转换

为什么需要强制转换:

不强转会报错,因为java认为貌似可以转,但又有风险(比如说ClassCastException(类型转换异常)),所以需要我们强制转换,如果我们确定没有风险(转了没问题),或者不怕丢东西,就可以强转

风险是什么:

因为父类可以指向不同的子类实例对象,由于向上转型,不会出错,但强转时, 如果Cat强转成了Dog就会出问题

编译期父类可以强转成子类,但可能会出错:ClassCastException(类型转换异常),如下

把父类s1的引用强制转换成子类YJS类

Student s1 = new KDB();
YJS y2 = (YJS)s1;
  • 1
  • 2

运行结果如下
在这里插入图片描述
总结:父类想强制转换成子类,父类指向的对象(实例)和子类必须是同一个类型,否则运行时会出错(ClassCastException(类型转换异常)),但编译期还没有报错提示

注:
如下这种不可以,会出错,如果想字符串转整数,还是需要Integer.valueOf或Integer.parseInt

String str = "dfv";
int a = (int)str;
  • 1
  • 2

30.6.1instanceof

  • 用于测试它左边对象指向的实例是不是它右边的类型,返回boolean的数据类型
  • instanceof左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false
    注:类的实例包含本身的实例,以及所有直接或间接子类的实例
  • instanceof左边与右边必须是同种类或存在继承关系,否则会编译错误
  • 左边的对象实例不能是基础数据类型
  • null用instanceof跟任何类型比较时都是false
  • instanceof一般用于对象类型强制转换

s instanceof KDB这句话的意思是:s指向的对象是不是KDB类型,如下代码进行判断,如果是KDB类型就进行强制转换

public static void main(String[] args) {
      	Student s1 = new KDB();
		KDB k4 = (KDB)s1;
		test1(s1);
}

public static void test1(Student s){
		if (s instanceof KDB) {
			System.out.println("s是科代表");
			KDB k5 = (KDB)s;
		}else{
			System.out.println("s不是科代表");
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

运行结果如下
在这里插入图片描述

30.7实战案例

30.7.1灯泡练习

/*
 * 红灯泡类
 * 	方法:开灯()-->发红光
 * 绿灯泡类
 * 	方法:开灯()-->发绿光
 * 灯泡类:
 * 	
 * 台灯类:
 * 	成员变量:灯泡
 * 	方法:点灯()-->
 * 测试类:
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

sys.day14.Demo02_灯泡练习

31.内部类

31.1非静态内部类

31.1.1创建内部类,首先要有外部类的对象,创建的方式如下(内部类如果是私有的,调不到)

Outer.Inner inner = new Outer().new Inner();	
  • 1

31.1.2内部类想使用外部类直接用就可以,因为内部类中埋了一个外部类的指针Outer.this,这个指针可以省略

class Outer{
	String outerName;
	public void testOuter(){
		System.out.println("外部类的方法");
	}

	private class Inner{
		String innerName;
		public void testInner(){
			System.out.println("内部类的方法");
			//内部类使用外部类
			System.out.println(outerName);
			testOuter();
		}
		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

31.1.3当然内部类自己也有自己的this指针

class Outer{
	String nameOuter="outer";
	public void testOuter(){
		System.out.println("外部类的方法..."+nameOuter);
	}
	private class Inner{
		private String nameInner = "inner";
		public void testInner(){
			System.out.println("内部类的方法..."+this.nameInner);
			//内部类想用 外部类
			System.out.println(Outer.this.nameOuter);

		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

31.1.4外部类想使用内部类需要先创建内部类对象

class Outer{
	String outerName;
	public void testOuter(){
		System.out.println("外部类的方法");
		//外部类想使用内部类需要先创建内部类对象
		Inner inner = new Inner();
		System.out.println(inner.innerName);
		inner.testInner();
	}
	private class Inner{
		String innerName;
		public void testInner(){
			System.out.println("内部类的方法");
		}
		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

31.1.5非静态内部类中,不可以有static修饰的变量或方法

31.2静态内部类

31.2.1静态内部类是static修饰的,不要求一定存在外部类的对象,因为它是类级别

class Outer01{
	static String nameOuter;
	public static void testOuter01(){
		System.out.println("外部类的静态方法...");
	}
	
	//静态内部类
	static class Inner01{
		public void testInner01(){
			System.out.println("haha");
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

31.2.2创建的方式

//下面代码需要Outer01.Inner01不是private的
		Outer01.Inner01 inner = new Outer01.Inner01();//创建静态内部类的实例
  • 1
  • 2

31.2.3访问静态内部类的方法

Outer01.Inner01.testInner02();就可以直接访问静态内部类的static方法

inner.testInner01();
Outer01.Inner01.testInner02();
  • 1
  • 2

31.2.4静态内部类中埋的不是Outer01.this,而是Outer01(可省略),所以在静态内部类中可以直接访问外部类的static方法或变量

class Outer01{
	static String nameOuter;
	public static void testOuter01(){
		System.out.println("外部类的静态方法...");
	}
	
	static class Inner01{
		public void testInner01(){
			System.out.println("haha");
		}
		public static void testInner02(){
			System.out.println("静态内部类的 静态方法");
			Outer01.testOuter01();//静态内部类中埋的不是Outer01.this,而是Outer01
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

31.2.5外部类如果想访问静态内部类的静态资源 ,需要用"Inner01."来进行操作;如果想要访问非静态资源需要创建对象

class Outer01{
	static String nameOuter;
	public static void testOuter01(){
		System.out.println("外部类的静态方法...");
		Inner01.testInner03();
		Outer01.Inner01 inner = new Outer01.Inner01();
		inner.testInner01();
	}
	
	static class Inner01{
		public void testInner01(){
			System.out.println("haha");
		}
		public static void testInner03(){
			System.out.println("静态内部类的一个静态方法..");
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

31.2.6应用场景–单例饿汉式

31.3局部内部类

31.3.1定义在方法中

public class Demo06_局部内部类 {
	public static void main(String[] args) {
		class A{
			public void test1(){
				System.out.println("玩");
			}
		}
		A a = new A();
		a.test1();
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

31.3.2匿名内部类

31.3.2.1介绍

介绍如下

如果需要一个子类,但主要是需要子类实现某方法
并且,这个子类用一次就不用了,感觉对方想要的根本就不是子类而是一个方法,但java不支持直接用方法(方法一定得写到类中),所以我们不得以为这个方法建了一个类
java允许我们使用匿名类来完成上面的需求,匿名类可以理解为只想要方法,对类名没要求
  • 1
  • 2
  • 3
public class Demo07_匿名内部类 {
	public static void main(String[] args) {
		Animal a1 = new Dog();
		a1.run();
		Animal a2 = new Cat();
		a2.run();
		
		//匿名内部类
		Animal a3 = new Animal(){
			@Override
			public void run(){
				System.out.println("懒得创建类,你不就想让我跑步吗\n我跑给你看得了,别让我创建类了");
			}
		};
		a3.run();
		
		Animal a4 = new Animal(){
			@Override
			public void run() {
				System.out.println("又让我跑。。。。");
			}			
		};
		a4.run();
	}
}

interface Animal{
	void run();
}

class Dog implements Animal{
	public void run(){
		System.out.println("小狗在跑步");
	}
}

class Cat implements Animal{
	public void run(){
		System.out.println("小猫在跑步");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
31.3.2.2匿名内部类简化写法(lambda表达式)

lambda表达式要求:父类是接口,只能有一个待实现的方法(也就是函数式接口)

  • 格式:类型 变量名 = (参数列表)->{方法体};, 即(参数列表)->{方法体};就是一个对象
Animal a2 = (String food)->{System.out.println("在吃"+food);};
a2.eat("小零食");
  • 1
  • 2
31.3.2.3注解

如果一个接口只有一个待实现的方法,那么java有一个注解可以帮我们看着这个接口,如果接口中不止一个方法,就会报错,这样的接口叫做函数式接口,如下

@FunctionalInterface
interface Plus{
	int test1(int a,int b);
}
  • 1
  • 2
  • 3
  • 4

@FunctionalInterface:函数式接口(只有一个待实现的方法),也就是说如果一个接口是函数式接口,写匿名内部类时就可以简化为lambda表达式

31.3.2.4继续简化

1.形参列表中的参数类型可以省略
2.如果参数列表中只有一个参数,参数列表的小括号可以省略
3.如果方法没有返回值且方法体中只有一条语句:方法体的大括号可以省略
4.如果方法有返回值并且方法体中只有一条语句:大括号和return都可以省略;要么都不省,要么都省掉

总结
创建一个对象,类型是一个接口(该接口中只有一个待实现的方法)

  • 新建一个实现类
  • 使用匿名内部类
  • lambda表达式:Animal a1 = ()->{};

32.枚举

枚举也可以看成是一种类,它有固定的几个对象,不像别的类想生成几个对象就可以生成几个对象

32.1枚举关键字enum

public class Demo02_枚举 {
	public static void main(String[] args) {
		System.out.println(Season.FALL);
	}
}
enum Season{
	SPRING,SUMMER,FALL,WINTER;//这个就是我们定义的对象(实例),其实他们是常量,所以可以用类名.直接调用,这些实例必须写在第一行
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

32.2枚举一般和switch一起用

public class Demo02_枚举 {
	public static void main(String[] args) {
		test1(Season.WINTER);
	}
	
	public static void test1(Season s){
		switch(s){
			case SPRING:
				System.out.println("春天");
				break;
			case SUMMER:
				System.out.println("夏天");
				break;
			case FALL:
				System.out.println("秋天");
				break;
			case WINTER:
				System.out.println("冬天");
				break;
		}
	}
}


enum Season{
	SPRING,SUMMER,FALL,WINTER;//这个就是我么定义的对象(实例),其实他们是常量,所以可以用类名.直接调用,这些实例必须写在第一行
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果如下
在这里插入图片描述

32.3values()可以获取枚举的所有实例并存在数组中

在这里插入图片描述

32.4valueOf()可以获取枚举中的某一个实例并返回

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/1002786
推荐阅读
相关标签
  

闽ICP备14008679号