Java基础知识笔记(一)


初识Java


Java背景知识

  • Java是美国sun公司(Stanford University  Network)在1995年推出的一门计算机高级编程语言。
  • Java早期称为Oak(橡树),后期改名为Java。
  • Java之父:詹姆斯.高斯林(James Gosling)。
  • 2009年 sun公司被Oracle公司(甲骨文公司)收购。

sun公司在1995年年初步发布了Java语言,sun公司直接把Java放到互联网上,免费给大家使用。甚至连源代码也不保密,也放在互联网上向所有人公开。

有了Java语言后,浏览器的功能被扩大了,Java程序可以直接在浏览器里运行,可以直接与远程服务器交互:用Java语言编程,可以在互联网上像传送电子邮件一样方便地传送程序文件!

1995年,sun虽然推出了Java,但这只是一种语言,如果想开发复杂地应用程序,必须要有一个强大地开发类库。因此,sun在1996年年年初发布了JDK1.0.这个版本包括两个部分:运行环境(即JRE)和开发环境(JDK)。运行环境包括核心API、集成API、用户界面API、发布技术、Java虚拟机(JVM)5个部分;开发环境包括:编译Java程序的编译器(即javac命令)。

接着,sun在1997年2月18日发布了JDK1.1。JDK1.1增加了JIT(即时编译)编译器。JIT和传统的编译器不同,传统的编译器是编译一条,运行完后将其扔掉;而JIT会将经常用到的指令保存在内存中,当下次调用时就不需要重新编译了,通过这种方式让JDK在效率上有了很大提升。

1998年12月,sun发布了Java历史上最重要的JDK版本:JDK1.2,伴随JDK1.2一同发布的还有JSP/Servlet、EJB等规范,并将Java分成了J2EE、J2SE、J2ME三个版本。

J2ME:主要用于控制移动设备和信息家电等有限存储设备。

J2SE:整个Java技术的核心和基础,它是J2ME和J2EE编程的基础。

J2EE:Java技术中应用最广泛的部分,J2EE提供了企业应用开发相关的完整解决方案。

不仅如此,JDK1.2还把它的API分成了三大类:核心API、可选API、特殊API。

核心API:由sun公司制定的基本的API,所有的Java平台都应该提供。这就是平常所说的Java核心类库。

可选API:这就是sun公司为JDK提供的扩充API,这些API因平台的不同而不同。

特殊API:用于满足特殊要求的API,如用于JCA和JCE的第三方加密类库。

Java技术体系(Java有哪些技术平台)

1.

技术体系:Java SE(Java Standard Edition):标准版

说明:Java技术的核心和基础

2.

技术体系:Java EE(Java Enterprise Edition):企业版

说明:企业级应用开发的一套解决方案

3.

技术体系:Java ME(Java Micro Edition):小型版

说明:针对移动设备应用的解决方案


JDK的选择安装和下载


搭建Java开发环境

  • Java的开发环境叫JDK(Java Development Kit:Java开发者工具包),必须安装JDK才能使用Java。是sun提供的一套用于开发Java应用程序的开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。

JRE

JRE,Java运行时环境,它的全称是Java Runtime Environment,因此也被称为JRE,他是运行Java程序的必需条件。

一般而言,如果运行Java程序,可以安装JRE,无须安装JDK。

简单来说,JRE包含JVM。JVM是运行Java程序的核心虚拟机,而运行Java程序不仅需要核心虚拟机,还需要其他的类加载器、字节码校验器以及大量的基础类库。JRE除了包含JVM之外,还包含运行Java程序的其他环境支持。

注:

如果需要开发Java程序,则应该选择安装JDK;当然,安装了JDK之后,就包含了JRE,也是可以运行Java程序。但如果只是运行Java程序,则需要在计算机上安装JRE,仅安装了JVM是不够的。实际上,Oracle网站上提供的就是JRE的下载,并不是单独JVM的下载。

JDK的发展史

1996年JDK(1.0)

1998年JDK(1.2)

2000年JDK(1.3)

.......

2004年JDK-5

2009年JDK(Orale收购sun)

......

2014年JDK-8 LTS(LTS:long-term support 长期支持版)

......

(企业更在意稳定性 JDK8)

如何获取JDK

百度输入Oracle

进入官网

点击products

Java 

Java downloads

Java 17

Windows

如何安装JDK

  • 傻瓜式安装,直接下一步...(注意1:安装路径中不要包含中文和空格)(注意2:所有的开发工具最好安装到统一目录)

先找到下载文件 点击下一步 更改路径 路径不包含中文和空格

如何验证JDK是否成功 

  • 看Java、javac是否可用
  • 看Java、javac的版本好是否无问题

1. 打开命令行窗口

按下Win+R,在运行输入框中输入cmd,敲回车

2. 看Java、Javac是否可用

输入Java 或 输入javac

3. 验证版本号是否正确

输入Java -version 或 输入Javac -version

如何卸载JDK

找到控制面板

程序

卸载程序

找到JDK 

右击卸载确定

前置知识:了解JDK中的Java、Javac的基本作用

java --> jdk ...... ---> bin 

说明:将来我们写好的Java程序都是高级语言,计算机底层是硬件 不能识别这些语言,必须先通过Javac编译工具进行翻译,然后再通过Java执行工具才可以驱动机器干活。

  • java.exe 执行工具
  • javac.exe 编译工具

安装JDK 组件了解

Development Tools、Source Code

Development Tools

Development Tools:这是JDK的核心,包括编译Java程序必需的命令工具。实际上,这个选项里面已经包含了运行Java程序的JRE,这个JRE会安装在JDK安装目录的子目录里,这也是无须安装公共JRE的原因。

公共JRE是一个独立的JRE系统,会单独安装在系统的其他路径下。公共JRE会向IE浏览器和系统中注册Java运行时环境。通过这种方式,系统 中任何应用程序都可以使用公共JRE。由于现在在网页上执行Applet的机会越来越少,而且完全可以选择使用JDK目录下的JRE来运行Java程序,因此没有太大必要安装公共JRE。

Source Code

安装这个选项将会安装Java所有核心类库 的源代码。

JDK安装路径下的文件路径

bin、db、include、jre、lib、javafx-src、src.zip、README和LICENSE等说明性文档。

bin

bin:该路径下存放了JDK的各种工具命令,常用的javac、Java等命令就放在该路径下。

db

db:该路径是安装Java DB的路径。

include

include:一些平台特定的头文件。

jre

jre:该路径下安装的就是运行Java程序所需的JRE环境。

lib

lib:该路径下存放的是JDK工具命令的实际执行程序。

javafx-src

javafx-src:该压缩文件里存放的就是Java FX 所有核心类库的源代码。

src.zip

src.zip:该压缩文件里存放的是Java所有核心类库的源代码。


掌握DOS窗口常见命令的使用


补充几个命令行窗口的常用命令

  • 切换至D盘 输入 D:
  • 切换至E盘 输入 E:
  • 查看当前目录下的文件信息 输入dir
  • 进入单级目录 eg:进入单级目录饼干呢 输入cd 饼干呢(tab键可以往后补全)
  • 进入多级目录  输入 cd D:\itheima\JavaSE(目录路径可以找到文件全部复制 粘贴到命令行窗口)
  • 回退到上一级目录 输入cd.. 
  • 回退到盘符根目录 输入 cd /
  • 清屏 输入 cls
  • 创建目录 eg:创建 team1 输入 md team1
  • 删除目录 eg:删除te1 首先 先进入目录下,输入 rm te1


Java程序运行机制


高级语言的运行机制

计算机高级语言按程序的执行方式可以分为编译型和解释型两种。

编译型语言

编译型语言是指使用专门的编译器,针对特定平台(操作系统)将某种高级语言源代码一次性“翻译”成可以被该平台硬件执行的机器码(包括机器指令和操作数),并包装成该平台所能识别的可执行性程序的格式,这个转换过程称为编译(Compile)。编译生成的可执行性程序可以脱离开发环境,在特定的平台上独立运行。

有些程序编译结束后,还可能需要对其他编译好的目标代码进行链接,即组装两个以上的目标代码模块生成最终的可执行程序,通过这种方式实现低层次的代码复用。

因为编译型语言是一次性地编译成机器码,所以可以脱离开发环境独立运行,而且通常运行效率较高;但因为编译型语言地程序被编译成特定平台上地机器码,因此编译生成地可执行性程序通常无法移植到其他平台上运行;如果需要移植,则必须将源代码复制到特定平台上,针对特定平台进行修改,至少也需要采用特定平台上地编译器重新编译。

现有的 C、C++、Objective-C、Pascal等高级语言都属于编译型语言。

解释型语言

解释型语言是指使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行的语言。解释型语言通常不会进行整体性的编译和链接处理,解释型语言相当于把编译型语言中的编译和解释过程混合到一起同时完成。

可以认为:每次执行解释型语言的程序都需要进行一次编译,因此解释型语言的程序运行效率通常较低,而且不能脱离解释器独立运行。但解释型语言有一个优势:跨平台比较容易,只需要提供特定平台的解释器即可,每个特定平台上的解释器负责将源程序解释成特定平台的机器指令即可。解释型语言可以方便地实现源程序级的移植,但这是以牺牲程序执行效率为代价的。·

现有的 Ruby、Python等语言属于解释型语言。

伪编译型语言

Visual Basic,它属于半编译型语言,并不是真正的编译型语言。

Java程序的运行机制

Java语言比较特殊,由Java语言编写的程序需要经过编译步骤,但这个编译步骤并不会生成特定平台的机器码,而是生成一种与平台无关的字节码(也就是 * . class文件)。这种字节码不是可执行性的,必须使用Java解释器来解释执行。因此可以认为:Java语言既是编译型语言,也是解释型语言。或者说,Java语言既不是纯粹的编译型语言,也不是纯粹的解释型语言。Java程序的执行过程必须经过先编译、后解释两个步骤。

JVM

Java语言里负责解释执行字节码文件的是Java虚拟机,即JVM(Java Virtual Machine)。JVM是可运行Java字节码文件的虚拟计算机。所有平台上的JVM向编译器提供相同的编程接口,而编译器只需要面向虚拟机,生成虚拟机能理解的代码,然后由虚拟机来解释执行。在一些虚拟机的实现中,还会将虚拟机代码转换成特定系统的机器码执行,从而提高执行效率。

当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码不面向任何具体平台,只面向JVM。不同平台上的JVM都是不同的,但它们都提供了相同的接口。JVM是Java程序跨平台的关键部分,只要为不同平台实现了相应的虚拟机,编译后的安居啊字节码就可以在该平台上运行。显然,相同的字节码程序需要在不同的平台上运行,这几乎是“不可能的”,只有通过中间的转换器才可以实现,JVM就是这个转换器。

JVM是一个抽象的计算机,和实际的计算机一样,它具有指令集并使用不同不存储区域。它负责执行指令,还管理数据、内存和寄存器。

JVM的统一标准

Oracle公司制定的Java虚拟机规范在技术上规定了JVM的统一标准,具体定义了JVM的如下细节:

1.指令集

2.寄存器

3.类文件的格式

4.栈

5.垃圾回收堆

6.存储区

Oracle公司制定这些规范的目的是为了提供统一的标准,最终实现Java程序的平台无关性。


开发HelloWorld程序


 Java程序开发的三步骤

  • 开发Java程序,需要三个步骤:编写代码,编译代码,运行代码
  • 编写代码 HelloWorld.java(源代码源文件)---> 编译代码 使用javac编译 HelloWorld.class(字节码文件)---> 运行代码 使用Java运行

注意事项:

  • 第一个Java程序建议使用记事本书写
  • 建议代码文件名全英文,首字母大写,满足驼峰模式,源代码文件的后缀必须是  . java 
  • Java程序严格区分大小写

编写代码

  • 1. 新建文件

  • 2. 在记事本中编写代码

第一个程序的代码如下:

public class HelloWorld{
    public static void main (String[] args){
        System.out.println("Hello World");
    }
}

注意:文件名称必须与代码中的类名称一致。

  • 保存文件:ctrl + s

编译代码、运行代码

  • 1.编译:javac文件名.java

范例:javac HelloWorld.java

  • 2. 运行 :java 类名

范例:Java HelloWorld


Java基础知识了解


  1. public 表示公开的。
  2. class 表示定义一个类,是关键字,后面跟着类名
  3. HelloWorld 表示一个类名。
  4. public class HelloWorld 表示定义一个公开的类,起名为HelloWorld。
  5.  public static void main (String[] args)   Java程序的入口方法,程序将从这里开始执行。
  6. System.out.println("Hello World");    向控制台打印一条语句。输出语句 Hello World
  7. Java程序严格区分大小写
  8. 每一行执行语句必须以分号(英文)结束
  9. 一个源文件中可以声明多个class,编译后,会生成一个或多个字节码文件。每一个字节码文件对应一个Java类,并且字节码文件名与类名相同
  10. 一个源文件中可以声明多个类,但是最多只能有一个类使用public进行声明,且要求声明public的类的类名与源文件名相同
     


常见问题解答


HelloWorld案例常见错误

1. Windows 的文件扩展名没有勾选

解决方案:必须勾选文件扩展名,再新建Java文件

2. 代码写对了,但是忘记保存了

3. 文件名和类名不一致

4. 大小写错误,单词拼写错误,存在中文符号,找不到main方法

5. 括号不配对

6. 编译、执行使用不当

### 一个什么错都犯过的程序员,才是真正的程序员!###


Java程序的执行原理、BUG介绍


计算机能认识的机器语言长什么样子?

  • 机器语言:00011100 00110101 ......
  • 计算机底层都是硬件电路,可以通过不通电和通电,表示0、1

注: 可以使用机器语言编程来实现呼吸灯效果

机器语言是由什么组成的

  • 0和1

java程序的执行原理是什么样的?

  • 不管是什么样的高级编程语言,最终都是翻译成计算机底层可以识别的机器语言。

编程语言发展历程

  • 机器语言
  • 汇编语言
  • 高级语言

 为什么学习高级编程语言?

  • 更简单:使用接近人类自己的语言书写,翻译器再将其翻译成计算机能理解的机器指令。

BUG

  • 原意是臭虫或者虫子,现在用来指代再电脑系统或者程序中隐藏的一些问题或者漏洞。
  • BUG的创始人:格蕾丝.赫伯

JDK的组成、跨平台原理


JDK的组成

  • JVM(java Virtual Machine):Java虚拟机,真正运行Java程序的地方。
  • 核心类库:Java自己写好的程序,给程序员自己写的程序调用的。
  • JRE(Java Runtime Environment):Java的运行环境
  • JDK(Java Development Kit):Java开发工具包(包括上面所有)。

JRE组成:JVM + 核心类库

JDK组成:JVM + 核心类库 + 开发工具(Java Javac  ......)

JDK组成:JRE + 开发工具(Java Javac ......)

java的跨平台、工作原理

  • 一次编译,处处可用。
  • 我们程序只需要开发一次,就可以在各种安装了JVM的系统平台上运行。


Path、JAVA_HOME环境变量配置


Path环境变量

  • path环境变量用于记住程序路径,方便在命令行窗口的任意目录启动程序

编译和运行Java程序必须经过两个步骤

1.将源文件编译成字节码。

2.解释执行平台无关的字节码程序。

使用命令行窗口打开qq程序

1. 打开命令行模式 cmd

2. 找到qq程序路径

3.  path环境变量位置 配置qq程序path

此电脑 右键 属性  高级系统设置  高级  环境变量   ...的用户变量中path  双击 新建 复制qq程序路径  点击确定 点击确定 

4.用命令行模式打开qq程序

打开新的命令行窗口 输入qq (在命令行窗口的任意一个路径都可打开qq程序)

为Java、javac配置path的注意事项

  • 目前较新的JDK安装时会自动配置java、javac程序的路径到path环境变量中去,因此,Java、javac可以直接使用
  • 注意:以前的老版本的JDK在安装的时没用自动配置Path环境变量的,此时必需要自己配置path环境变量。
  • 建议还是自己配置一下 “path”、“JAVA_HOME”

自行配置Java、javac的path环境变量

1. 找到Java程序 和 Javac程序的路径 复制路径

jdk ......   bin  

2. 打开path环境变量

此电脑 右击 属性 高级系统设置 高级  环境变量  

(注:配置在 .....的用户变量中的path 和 配置在系统变量中的path 二者均可行)

(注:配置在 ......的用户变量中的path 只针对当前登录的系统用户有效,不影响其他登录的用户)

(在配置之前建议把之前自动配置的C:\ProgramData\Oracle\Java\javapath删除,用自己配的)

2.  配置Java、javac的path环境变量 

此电脑 右击 属性 高级系统设置 高级  环境变量  

...的用户变量下  双击path 新建 复制 Java程序 和 Javac程序的路径 点击确定 

重新配置了环境变量以后,必须检测是否配置成功

打开命令行窗口,输入javac -version 及 java -version 分别看版本提示

配置Java _home 环境变量 

JAVA_HOME :告诉操作系统JDK安装在哪个位置(将来其他技术要通过这个环境变量找JDK)。

注意:较新版本的JDK只是配置了Path,没用自动配置JAVA_HOME。

多学一招: 推荐:Path %JAVA_HOME%\bin

1. 找到jdk的位置 复制路径

2. 找到环境变量

此电脑 右击 属性 高级系统设置 高级  环境变量  

3. 新建JAVA_HOME

4. Path %JAVA_HOME%\bin

...的用户变量下 双击path 新建 输入 %JAVA_HOME%\bin


IntelliJ IDEA开发工具概述


之前的开发工具存在一些问题

  • 文本编辑工具:记事本、NotePad++、EditPlus、sublime...编写代码时没用错误提醒、没有智能代码提示、需要自己进行编译、执行,功能不够强大。

集成开发环境(IDE,Integrated Development Environment)

  • 把代码编写,编译,执行等多种功能综合到一起的开发工具,可以进行代码智能提示,错误提醒,项目管理等等。
  • 常见的Java IDE工具有:Eclipse、MyEclipse、IntelliJ IDEA、Jbuilder 、NetBeans等。

IntelliJ IDEA简介

  • IntelliJ IDEA一般简称 IDEA,在代码错误提醒,智能代码补全等多方面表现的都非常优秀,是进行Java开发时,很多企业首选的开发工具。

IDEA的下载、安装

1. 百度搜索 IntelliJ IDEA---> 进入官网 ---> Windows ---> ULtimate(旗舰版)、 Community(社区版)(社区版功能比旗舰版功能少,旗舰版要付费) --->DownLoad

(不建议使用最新版本IDEA)

2. 找到应用 双击 

3. next 更改路径 next

4. 根据情况点击启动图标 next

5. next

6. 

7. 

8. 根据自身情况而定

IDEA程序的卸载

找到控制面板 程序 卸载程序 找到IntelliJ IDEA 右键 卸载 是 勾选 


IDEA开发HelloWorld程序


IDEA管理Java程序的结构

  • project(项目、工程)
  • module(模块)
  • package(包)
  • class(类)

新建工程

1.

2. 

3. 

4. 

5.

创建模块

1.

2.

3.

新建包

1.

2. 包名 按下回车

编写Java程序

1.

2. 取类名 按下回车

3.编写代码

package com.liu.hello;

public class HelloWorld {
    //输入main直接回车
    public static void main(String[] args) {
        //输入sout 直接回车
        System.out.println("Hello World");
    }
}

4. 运行代码

运行结果

使用idea开发第一个Java程序的步骤 总结

  1. 创建工程 new project(空工程)
  2. 创建模块 new Module
  3. 创建包 new Package
  4. 创建类
  5. 编写代码、并启动

使用idea开发Java程序的步骤

  • project ---> module ---> package ---> class
  • project中可以创建多个module
  • module中可以创建多个package
  • package中可以创建多个class

创建的关键字

  • new project/module/package/class

idea中的Java程序是自动编译和执行的,编译后的class文件在工程路径下的一个 out 文件里。


IDEA的配置、快捷键设置


设置IDEA的主题

file ---> settings ---> appearance & Behavior ---> appearance ---> theme ---> intelliJ Light ---> ok

---> apply

设置字体颜色

file ---> settings ---> editor ---> font ---> size ---> ok ---> apply 

设置代码的背景颜色

例如 

file ---> settings ---> editor ---> color scheme ---> general ---> text ---> default text ---> background ---> ok ---> apply 

IDEA 常用快捷键

  • 组合几个键一起按下来完成某件事,可以提高开发效率。

补充 快捷键:

选中部分代码 CTRL + ATL + T  :给部分代码 添加循环操作

重新建包演示一下

package com.liu.speedkey;

public class SpeedKeyDemo {
    //输入main直接回车
    public static void main(String[] args) {
        //输入sout 直接回车
        System.out.println("Hello World");
        //直接输入 "Hello World".sout 直接回车
        System.out.println("Hello World"); //此行 按下CTRL+D
        //CTRL + D 复制当前行数据到下一行
        System.out.println("Hello World");
        System.out.println("Hello World");
        System.out.println("Hello World");
        // CTRL + Y 删除所在行,建议 CTRL + X
        // CTRL + X 剪切键 也可删除行
        // CTRL + Z 撤销操作

        //CTRL + ALT + L 格式化代码
        // ALT + SHIFT + 上箭头 , ALT + SHIFT + 下箭头   上下移动当前代码
        // CTRL + / , CTRL + SHIFT + /  对代码进行注释

    }
}


IDEA的其他操作


删除文件

修改类名称

修改模块

导入模块(方法一 ,不建议)

找到导入模块的文件路径,复制路径

打开IDEA ,file ,new , module from existing sources...  , 

导入模块(方法二 ,建议)

(此方法导入的模块会一直在,不会从IDEA的工程中丢失)

找到要导入的模块,复制工程,粘贴到IDEA要使用的工程固定目录下,再使用方法一,进行拷贝

 复制路径

打开IDEA ,file ,new , module from existing sources...  , 

导入模块(方法三 )

(新建工程)

找到模块 , 复制路径

打开IDEA , 粘贴 , 欧克

删除模块(了解)

(只删除了IDEA中的功能模块,并没有彻底删除模块,需要打开电脑中的目录文件)

(彻底删除了)

打开工程

关闭工程

将类分页打开(即同一个界面打开两个类)

生成get set方法

产生构造器

 idea自动导包

重写构造器


阶段总结:Java概述、快速入门、IDEA使用


Java快速入门、IDEA开发工具的使用

1. Java的概述

  • Java事sun公司1995年推出,2009年被Oracle收购
  • Java的爸爸:詹姆斯 . 高斯林
  • Java是一门高级编程语言,语言风格接近人类的自然语言,写程序简单易懂
  • Java的流行度高,商业占用度很高
  • 很重要的特性:可移植性
  • Java能干什么?什么都可以干,但是最被市场认可的是企业级开发:京东、淘宝这样的互联网系统
  • Java的技术体系:JavaSE  标准版:java技术的核心和基础

                                    JavaEE  企业版:大型互联网企业级解决方案,充分被市场认可

                                    JavaME  小型版:移动应用的解决方案,没有被市场认可

2. Java的产品

  • jdk  Java的开发工具包,必须安装它才可以使用Java
  • 去Oracle官网下载,安装时不要放在空格和中文路径
  • 我们用的是JDK 17,企业中可用JDK 8
  • LTS:长期支持版:JDK 8 11、、17
  • JDK中要用的2个重要的程序:Javac  编译程序 

                Java  执行程序

  • JDK安装后要验证是否安装成功:打开命令行窗口 Win + R -->cmd 回车 

                 输入Java Javac Java-version..看提示有没有问题

补充知识:常用命令行命令 cls 清理屏幕

             cd

             dir

             切盘:盘符

3. 开发一个Java的入门程序:Hello World

(1)、编写代码 

  • 建议全英文名称,首字母大写 后跟一定是Java结尾
  • 代码写啥 

public class HelloWorld{
    public static void main (String[] args){
        System.out.println("Hello World");
    }
}

(2)、编译代码

  • javac HelloWorld.java---> 产生class文件: HelloWorld.class

(3)、执行代码 

  • java HelloWorld  --->输出 HelloWorld

4. Java程序的执行原理

  • Java程序最终会翻译,解释成计算机能识别的机器语言:000111...这样的形式驱动机器干活
  • BUG 代表程序出现问题或者漏洞的意思

     DEBUG 解决问题的意思

5. path环境变量,JAVA_HOME

  • path的作用:记住程序的路径,方便在命令行窗口的任意目录驱动程序
  • 新版本的JDK安装的时候会自动配置javac和Java程序的路径到path环境变量中去,所以,javac和Java可以在命令行窗口中直接使用了吧
  • 重点注意:老版本的JDK安装的时候是不会自动配置javac和Java程序的路径到path环境变量中去

6. 开发工具 IntelliJ IDEA

  • 集成开发工具(IDEA工具) 工程结构话管理项目,有错误提醒,有代码智能补全...
  • IDEA去官网下载安装:傻瓜式安装

IDEA开发第一个Java程序 (1)、必须创建工程project

            (2)、必须创建模块module 

            (3)、创建一个包 

 


Java基础语法:注释详解


编写程序时总是需要为程序添加一些注释,用以说明 某段代码地作用,或者说明某个类地用途、某个方法地功能,以及该方法的参数和返回值的数据类型及4意义等。

除此之外,添加注释也是调试程序的一个重要方法。如果觉得某段代码可能有问题,可以先把这段代码注释起来,让编译器忽略这段代码,再次编译、运行,如果程序可以正常执行,则可以说明错误就是由这段代码引起的,这样就缩小了错误所在的范围,有利于排错;如果依然出现相同的错误,则可以说明错误不是由这段代码引起的,同样也缩小了错误的范围。

什么是注释

注释是写在程序中对代码进行解释说明的文字,方便自己和其他人查看,以便理解程序的

注释有哪些

单行注释、多行注释、文档注释

单行注释

// 注释内容,只能写一行

单行注释就是在程序中注释一行代码,在Java语言中,将双斜线( // )放在需要注释的内容之前就可以了。

多行注释

/*

注释内容1

注释内容2

*/

多行注释是指一次性地将多行代码注释掉,在Java语言中,使用( “ /* ” 和 “ * / ”)将程序中需要注释地内容包含起来,“ /* ” 表示注释开始,而“ */ ”表示注释结束。

文档注释

文档注释:文档注释的内容是可以提取到一个程序说明文档中去的

开发一个大型软件时,需要定义成千上万的类,而且需要很多人参与开发,每个人都会开发一些类,并在类里定义一些方法、成员变量提供给其他人使用,但其他人怎么知道如何使用这些类和方法呢?这时候就需要提供一份说明文档,用于说明每个类、每个方法的用途。当其他人使用一个类或者一个方法时,他无须关心这个类或方法的具体实现,他只要知道这个类或方法的功能即可,然后使用这个类或方法来实现具体的目的,也就是通过调用应用程序接口(API)来编程。API文档就是用以说明这些应用程序接口的文档。对于Java语言而言,API文档通过详细说明 每个类、每个方法的功能及用法等。

文档注释以斜线后紧跟两个星号(/**)开始,以星号后紧跟一个斜线(*/)结束,中间部分都是文档注释,会被提取到API文档中。

/**

注释内容

注释内容

*/

package com.liu.note;

/**
 * 文档注释
 * 调频
 * 同频
 * 忠诚
 * 唯一
 * 礼物
 */
public class NoteDemo {
    public static void main(String[] args) {
        //单行注释
        //以下是一个打印语句,是往控制台输出内容的
        System.out.println("我开始学习Java程序,happy!");
        //多行注释
        /*
        开心最重要
        你开心就好
         */
        System.out.println("玫瑰");
        System.out.println("玫瑰花");
    }
}

注释的特点

  • 注释不影响程序的执行的
  • javac命令进行编译,产生 . class 文件
  • 写注释是一个利人利己的好习惯

快捷键进行注释

  • ctrl + /     单行注释(对当前行进行注释)
  • ctrl + shift + /      对选中的代码进行多行注释


Java基础语法:字面量详解


字面量

  • 计算机是用来处理数据的,字面量就是告诉程序员:数据在程序中的书写格式

常用数据

package com.liu.literal;

public class LiteralDemo {
    public static void main(String[] args) {
        //目标:掌握常见数据在程序中的书写格式

        //1、整数
        System.out.println(500);

        //2. 小数
        System.out.println(99.5);

        //3. 字符:必须要用单引号围起来,有且只能有一个字符
        System.out.println('a');
        System.out.println('0');
        System.out.println('中');
        //错误写法 中国为字符串 非字符 System.out.println('中国');

        //4. 空字符
        System.out.println(' ');
        //错误写法 单引号里面要有东西 不能什么都不写 System.out.println('');

        //5. 特色字符
        // \n 代表的是换行的意思
        // \t 代表的是一个tab
        System.out.println('\n');//这行代码在执行的时候会换两行
        // \n 代表换行,println代表换行
        System.out.println('饼');
        System.out.println('\n');
        System.out.println('干');
        System.out.println('\t');

        //6. 字符串:必须用双引号围起来,里面的内容其实可以随意
        System.out.println("我爱吃水果");
        System.out.println("我爱吃饼干");
        System.out.println("");
        System.out.println(" ");

        //7. 布尔值:true false
        System.out.println(true);
        System.out.println(false);


    }
}


Java基础语法:变量详解


什么是变量

  • 变量是用来记住程序要处理的数据的

变量的定义格式

  • 数据类型 变量名称 =  数据 ;   int age = 18 ;
  • 数据类型:限制盒子中只能存储某种数据形式:例如:int(整数类型)、double(小数类型)
  • 变量名称:首字母建议小写,有意义
  • = 赋值

为什么要使用变量

  • 使用变量既要处理数据,编写的代码更灵活,管理代码更方便。

变量在计算机中的执行原理

  • 变量就是内存中的一块区域,可以理解成一个盒子,用来装一个数据的!

变量有啥特点

  • 变量中装的数据是可以被替换的

变量有啥应用场景

  • 写程序对数据进行处理就很方便了

package com.liu.variable;

public class VariableDemo1 {
    public static void main(String[] args) {
        //目标:认识变量,掌握使用变量的好处,变量的特点,应用场景

        // 1. 定义一个整型变量记住一个整数
        //数据类型 变量名 = 数据 ;
        // 注意:=在Java中是赋值的意思,从右往左看
        //把18这个数据赋值给左边的变量age装起来
        int age = 18;
        System.out.println(age);

        //2.记住一个人的成绩
        double score = 99.5;
        System.out.println(score);

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

        //3. 使用变量的好处: 便于扩展和维护
        int number =  666;
        System.out.println(number);
        System.out.println(number);
        System.out.println(number);

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

        //4.变量的特点:里面装的数据可以被替换
        int age2 = 20;
        System.out.println(age2);

        age2 = 19; //赋值:从右边往左边执行
        System.out.println(age2);

        age2 = age2 + 1;
        System.out.println(age2);

        //5. 需求:钱包有9.5元,收到了10元红包,有发出去了5元红包,请输出各阶段钱包的情况
        double money = 9.5;
        System.out.println(money);

        //收红包10元
        money = money + 10;
        System.out.println(money);

        //发出去5元
        money = money - 5;
        System.out.println(money);

    }
}


Java基础语法:变量使用时的注意事项


使用变量时有哪些注意点?

  • 变量要先声明,才能使用
  • 什么类型的变量,只能存储什么类型的数据(变量声明后,不要存储其他类型数据)
  • 变量存在访问范围,同一个范围内,多个变量的名字不能一样
  • 变量定义时可以不给赋初始值;但是在使用时,变量里必须有值
  • 变量的有效范围是从 定义 开始到 } 截止,且在同一个范围内部不能定义2个同名变量
package com.liu.variable;

public class VariableDemo2 {
    public static void main(String[] args) {
        //目标:搞清楚使用变量的几点注意事项
        //1. 变量要先声明才能使用
        int age = 18;
        System.out.println(age);

        //2. 变量是什么类型,就应该用来装什么类型的数据,否则报错
//        age = 9.8;

        //3.变量是从定义开始到 “ } ” 截止的范围内有效,且同一个范围内,定义的多个变量,它们的名称不能一样
        {
            int a = 19;
            System.out.println(a);
        }
//        System.out.println(a);
        System.out.println(age);

        //4. 变量定义的时候可以不赋初始值,但在使用时,变量里必须有值,否则报错
        int number;
        number = 500;
        System.out.println(number);


    }
}


常见的 javac  标记


常见的 javac  标记

@author:指定Java程序的作者

@version:指定源文件的版本

@deprecated:不推荐使用方法

@param:方法的参数说明信息

@return:方法的返回值说明信息

@see:“参见”,用于指定交叉参考的内容

@exception:抛出异常的类型

@throws:抛出的异常,和@exception同义


分隔符


Java语言里面的分号(;)、花括号({})、方括号(【】)、圆括号(())、空格、圆点( .)都具有特殊的分隔作用,因此被统称为分隔符。

分号

Java语言采用分号(;)作为语句的分隔,因此每个Java语句必须使用分号作为结尾。Java程序允许一行书写多个语句,每个语句之间以分号隔开即可,一个语句也可以跨多行,只要在最后结束的地方使用分号结束即可。

花括号

花括号的作用就是定义一个代码块,一个代码块指的就是 “{” 和 “}” 所包含的一段代码,代码块在逻辑上是一个整体。对Java语言而言,类定义部分必须放在一个代码块里,方法体部分也必须放在一个代码块里。除此之外,条件语句中的条件执行体和循环语句中的循环体通常也放在代码块了。

花括号一般是成对出现的,有一个 “{” 则必然有一个 “}”,反之亦然。

方括号

方括号的主要作用是用于访问数组元素,方括号通常紧跟数组变量名,而方括号里指定希望访问的数组元素的索引。

圆括号

圆括号是一个功能非常丰富的分隔符:定义方法是必须使用圆括号来包含所有的形参声明,调用方法时也必须使用圆括号来传入实参值;不仅如此,圆括号还可以将表达式中某个部分括成一个整体,保证这个部分优先计算;除此之外,圆括号还可以作为强制类型转换的运算符。

空格

Java语言使用空格分隔一条语句的不同部分。Java 语言时一门格式自由语言,所以空格几乎可以出现在Java程序的任何地方,也可以出现任意多个空格,但不要使用空格把一个变量名隔开成两个,这将导致程序出错。

Java语言中的空格包含空格符(Space)、制表符(Tab)和回车(Enter)等。

除此之外,Java源程序还会使用空格来合理缩进Java代码,从而提高更好的可读性。

圆点

圆点(.)通常作为类/对象和它的成员(包括成员变量、方法和内部类)之间的分隔符,表面调用某个类或某个实例的指定成员。


Java基础语法:关键字、标识符


关键字

  • Java语言自己用到的一些词,有特殊作用的,我们称之为关键字,如:public、class、int、double...
  • 当定义标识符时,不要让标识符和关键字相同,否则将引起错误。即标识符不能用关键字命名。
  • Java中的所有关键字都是小写的,TRUE、FALSE、NULL都不是关键字。
  • 注意:关键字是Java用了的,我们就不能用来作为:类名、变量名,否则会报错!
  • goto和const 这两个关键字也被称为保留字。

标识符

  • 标识符就是名字,我们写程序时会起一些名字,如类名、变量名等等都是标识符
  • 标识符就是用于给程序中的变量、类、方法命名的符号

标识符的要求

  • 基本组成:由数字、字母、下划线(_)和美元符($)等组成
  • 强制要求:不能意数字开头、不能用关键字和保留字作为名字,但可以包含关键字和保留字、不能包含空格、且是区分大小写的
  • 只能包含美元符($),不能包含@、#等其他特殊字符。
  • 标识符必须以字母、下划线(_)、美元符($)开头,后面可以跟任意数目的字母、数字、下划线(_)和美元符($)。此处的字母并不局限于26个英文字母 ,而且可以包含中文字符、日文字符等。
  • 正确的命名 :bj   b2   $2   中国    _2b   ak47   Class   HelloWorld 
  • 错误的命名 :2b  class   #liu 

标识符的建议规范

  • 变量名称:满足标识符规则,同时建议用英文、有意义、首字母小写,满足“驼峰模式”,例如:int studyNumber = 500 ;
  • 类名称:满足标识符规则,建议全英文、有意义、首字母大写,满足“驼峰模式”,例如:Hello World,Student


Java语法:变量里的数据在计算机中的存储原理


数据在计算机底层都是怎么存储的?

  • 都是采用二进制:使用0、1,按照逢2进1的规则表示数据来存储。

如何快速的算出一个数据的二进制形式?

  • 除二取余法

二进制

  • 只有0、1,按照逢2进1的方式表示数据:

十进制转二进制的算法

  • 除二取余法

计算机中表示数据的最小单位

  • 计算机表示数据的最小单元:一个字节(byte,简称B,是使用8个二进制位组成的)(8位一组)
  • 字节中的每个二进制位就称为位(bit,简称b),1B = 8b


Java语法:字符,图片,声音的存储说明


字符在计算机中是如何存储的呢?

  • ASCII编码表:即美国信息交换标准码,规定了现代英语、数字字符和其他西欧字符对应的数字编号。
  • 字符 'A' 对应的数字是65
  • 字符 'a' 对应的数字是97
  • 字符 '0' 对应的数字是48

package com.liu.variable;

public class ASCIIDemo1 {
    public static void main(String[] args) {
        //目标:掌握ASCII编码表的编码特点
        System.out.println('a'+10); //97+10=107
        System.out.println('A'+10); //65+10=75
        System.out.println('0'+10); //48+10=58

    }
}

图片和音频等文件的数据是怎么存储的啊?

  • 也是采用二进制进行存储的

图片数据 - 彩色图

  • 图片就是无数个像素点组成的
  • 每个像素点的数据:用0 ~ 255 * 255 * 255 表示其颜色

声音数据


Java语法:二进制、八进制、十六进制


Java中整数值有4种表示方法:十进制、二进制、八进制和十六进制,其中二进制的整数以0b或0B开头;八进制的整数以0开头;十六进制的整数以0x或者0X开头,其中10~15分别以a~f(此处的a~f不区分大小写)来表示。

在某些时候,程序需要直接使用二进制整数,二进制整数更“真实”,更能表达整数在内存中的存在形式。不仅如此,有些程序(尤其在开发一些游戏时)使用二进制整数会更便捷。

所有数字在计算机底层都是以二进制形式存在的,原码是直接将一个数值转算成二进制数。但计算机以补码的形式保存所有的整数。补码的计算规则:正数的补码和原码完全相同,负数的补码是其反码加1;反码是对原码按位取反,只是最高位(符号位)保持不变。

十进制转二进制的算法

  • 十进制数转二进制数:除二取余法

二进制转十进制数

  • 8421法

八进制、十六进制介绍

  • 为了便于观察和表示二进制,推出了八进制和十六进制。
  • 每3位二进制作为一个单元,最小数是0,最大数是7,共8个数字,这就是八进制(421)

  • 每4位二进制作为一个单元,最小数是0,最大数是15,共16个数字,依次用:0~9 ABCDEF 代表就是十六进制(8421)

  • 注意:Java程序中支持书写二进制、八进制、十六进制的数据,分别需要以0B或者0b、0、0X或者0x开头。
package com.liu.variable;

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


        //二进制、八进制、十六进制在程序中的写法
        int a1 = 0B01100001;
        System.out.println(a1);

        int a2 = 0141; //0开头的数据当成八进制看待!
        System.out.println(a2);

        int a3 = 0XFA;//0X开头的数据是十六进制
        System.out.println(a3);
    }
}

计算机的数据单位

  • 计算机表示数据的最小组成单元是:字节,1B = 8b
  • 在B的基础上,计算机发展出了KB、MB、GB、TB...这些数据单位。
  • 1B=8b
  • 1 KB = 1024 B
  • 1MB = 1024KB
  • 1GB=1024MB
  • 1TB=1024GB


Java语法:数据类型


数据类型的分类

  1. 基本数据类型(Primitive Type)
  2. 引用数据类型(Reference Type)

基本数据类型

  • 4大类8种
  • 基本类型包括 boolean类型 和 数值类型
  • 数值类型包括 整数类型 和 浮点类型
  • 整数类型包括 byte、short 、int、long、char(字符类型)
  • 浮点类型包括 float、double

byte:一个byte类型整数在内存里占8位

short:一个short类型整数在内存里占16位

int:一个int类型整数在内存里占32位

long:一个long类型整数在内存里占64位

int是最常用的整数类型,因此在通常情况下,直接给出一个整数值默认就是int类型。除此之外,有如下两种情形必须指出:1.如果直接将一个较小的整数值(在byte或short类型的表数范围内)赋给一个byte或short变量,系统会自动把这个整数值当成byte或者short类型来处理。2. 如果使用一个巨大的整数值(超出了int类型的表数范围)时,Java不会自动把这个数值当成long类型类处理。如果希望系统把一个整数值当成long类型来处理,应在这个整数值后增加英文字母l或者L作为后缀。通常推荐使用L,因为英文字母l'很容易跟数字1混淆。

Java的浮点类型有两种:float和double。Java的浮点类型有固定的表数范围和字段长度,字段长度和表数范围与机器无关。Java的浮点数遵循IEEE 754标准,采用二进制数据的科学计数法来表示浮点数,对于float型数值,第1位是符号位,接下来8位表示指数,再接下开的23位表示尾数;对于double类型数值,第1位也是符号位,接下来的11位表示指数,再接下的52位表示尾数。

double类型代表双精度浮点数,float类型代表单精度浮点数。一个double类型的数值占8字节、64位,一个float类型的数值占4字节 、32位。

Java语言的浮点类型默认是double类型,如果希望Java把一个浮点类型值当成float类型处理,应该在这个浮点类型值后紧跟f或F。例如5.12代表一个double类型的值,占64位的内存空间;5.12f或者5.12F才表示一个float类型的值,占32位的内存空间。

布尔型只有一个boolean类型,用于表示逻辑上的“真”或“假”。在Java语言中,boolean类型的数值只能是true或false,不能用0或者非0来代表。其他基本数据类型的值也不能转换成boolean类型。

Java规范并没有强制指定boolean类型的变量所占用的内存空间虽然boolean类型的变量或者值只要1位即可保存,但由于大部分计算机在分配内存时允许分配的最小内存单元式字节(8位),因此bit大部分时候实际上占用8位。

package com.liu.variable;

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

        //掌握常见的基本数据类型的使用
        //1. byte short int long
        byte a = 127;//-128~127
//    byte a2 = 128;//越界了

        short s = 13244;
//    short s1 = 93244; //越界了

        int i = 422424;// 默认

        //注意:随便写一个整型字面量默认是int类型的
        // 424242444444虽然没有超过long的范围,但是超过了本身int类型的范围
        //如果希望随便写一个整型自变量默认是long类型的,需要在后面加上L/l
//    long lg = 424242444444; 错误写法
        long lg = 424242444444L;

        //2. float double
        //注意:随便写个小数字面量,默认是double,如果希望小数是float,后面加上F/f
        float f = 3.14F;

        double d = 56.45;

        //3. char 字符型
        char ch = 'a';
        char ch2 = '中';

        //4. boolean
        boolean flag = true;
        boolean flag2 = false;

        //拓展一种引用数据类型,后面要用
        //String 称之为字符串类型,定义的变量可以用于记住一个字符串数据。
        String name = "张三";
        System.out.println(name);

    }
}

字符型

字符型通常用于表示单个的字符,字符型值必须使用单引号(‘)括起来。Java语言使用16位的Unicode字符集作为编码方式,而Unicode被设计成支持世界上所有书面语言的字符,包括中文字符因此Java程序支持各种语言字符。

字符型值有如下三种表现形式:1. 直接通过单个字符来指定字符型值,例如:’A‘、’9‘和’0‘等 ; 2. 通过转义字符表示特殊字符型值,例如’\n‘、'\t'等 ; 3.直接使用Unicode值来表示字符型值,格式是’\uXXXX‘,其中XXXX代表一个十六进制的整数。

\b 退格符

\n 换行符

\t 制表符

\“ 双引号

\' 单引号

\\ 反斜杠

char类型的变量、值完全可以参与加、减、乘、除等数学运算,也可以比较大小——实际上都是用该字符对应的编码参与运算。

引用数据类型

  • String
  • Java没有提供表示字符串的基本数据类型,而是通过String类来表示字符串,由于字符串由多个字符组成,因此字符串要使用双引号括起来。
  • 引用类型包括类、接口和数组类型,还有一种特殊的null类型。所谓引用数据类型就是对一个对象的引用,对象包括实例和数组两种。实际上,引用类型变量就是一个指针,只是Java语言里不再使用指针这个说法。
  • 空类型(null type)就是null值的类型,这种类型没有名称。因为null类型没有名称,所以不可能声明一个null类型的变量或者转换到null类型。空引用(null)就是null类型变量唯一的值。空引用(null)是null类型变量唯一的值。空引用(null)可以转换为任何引用类型。
  • 在实际开发中,程序员可以忽略null类型,假定null只是引用类型的一个特殊直接量。

随便写的整数、小数字面量,他们默认什么类型?

  • 23,默认是int类型,加上L/l就是long类型的数据了
  • 23.8,默认是double类型,加上F/f就是float类型了


Java语法:自动类型转换


什么是自动类型转换,为什么要进行自动类型转换?

  • 类型范围小的变量,可以直接赋值给类型范围大的变量。 byte ---->int 
  • 存在不同类型的变量赋值给其他类型的变量

自动类型转换在计算机的执行原理

自动类型转换的其他形式

package com.liu.type;

public class TypeConversionDemo1 {
    public static void main(String[] args) {
       //目标:理解自动类型转换机制
       byte a = 12;
       int b = a;//发生了自动类型转换
        System.out.println(a);
        System.out.println(b);

        int c = 100;
        double d = c;//发生了自动类型转换
        System.out.println(d);

        char ch = 'a';//a=97 ---> 00000000 01100001
        int i = ch;//发生了自动类型转换 00000000 00000000 00000000 01100001

    }
}


Java语法:表达式的自动类型转换


表达式的自动类型转换

  • 在表达式中,小范围类型的变量,会自动转换成表达式中较大范围的类型,再参与运算。

注意事项

  • 表达式的最终结果类型由表达式中的最高类型决定。
  • 在表达式中,byte、short、char是直接转换成int类型参与运算的。
package com.liu.type;

public class TypeConversionDemo2 {
    public static void main(String[] args) {
        //目标:掌握表达式的自动类型转换规则
        byte a = 10;
        int b = 20;
        int c = 30;
        long rs =a + b + c ;
        System.out.println(rs);

        double rs2 = a + b +1.0;
        System.out.println(rs2);

        byte i = 10;
        short j = 30;
        int rs3 = i + j;
        System.out.println(rs3);
        
        //面试笔试题
        byte b1 = 110;
        byte b2 = 80;
        int  b3 = b1 + b2 ;
        System.out.println(b3);

    }
}


Java语法:强制类型转换


默认情况下,强制类型转换: 

  • 类型范围大的数据或者变量,直接赋值给类型范围小的变量,会报错。

强制类型转换

  • 强行将其类型范围大的变量、数据赋值给类型范围小的变量
  • 数据类型 变量2 = (数据类型)变量1、数据

强制类型转换在计算机中的执行原理

 注意事项

  • 强制类型转换可能造成数据(丢失)溢出
  • 浮点型强转成整型,直接丢掉小数部分,保留整数部分返回

package com.liu.type;

public class TypeConversionDemo3 {
    public static void main(String[] args) {
        //目标:掌握强制类型转换
        int a = 20;
        byte b = (byte) a;//alt + 回车键
        System.out.println(a);
        System.out.println(b);

        int i = 1500;
        byte j = (byte) i;
        System.out.println(j);

        double d = 99.5;
        int n = (int) d; //强制类型转换
        System.out.println(n); //丢掉小数部分,保留整数部分


    }
}


Java语法:算术运算符、+符号做连接符


基本的算术运算符

“ + ” 符号可以做连接符的

  • “ + ” 符号与字符串运算的时候是用作连接符的,其结果依然是一个字符串

独门秘籍:

  • 能算则算,不能算就在一起。(计算机很聪明)
package com.liu.operator;

public class OperatorDemo {
    public static void main(String[] args) {
        //目标:掌握基本的算术运算符的使用
        int a = 10;
        int b = 2;
        System.out.println(a + b);
        System.out.println(a - b);
        System.out.println(a * b);
        System.out.println(a / b);
        System.out.println(5 / 2);//2.5 --->2
        System.out.println(5.0 / 2);//2.5
        int i = 5;
        int j = 2;
        System.out.println(i / j);//2
        System.out.println(1.0 * i / j);//2.5

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

        System.out.println("------------------------------------");
        
        //目标:掌握使用+符号做连接符的情况
        int a2 = 5;
        System.out.println("abc" + a2);//abc5
        System.out.println(a2 + 5);//10
        System.out.println("liu" + a2 + 'a');//liu5a
        System.out.println(a2 + 'a' + "liu");//5+97=102 //102liu
    }
}

算术运算符有哪些?

  • +   -   *   /   %

/ 需要注意什么,为什么?

  • 如果两个整数做除法,其结果一定是整数,因为最高类型是整数

+ 除了做基本数学运算,还有哪些功能?

  • 与字符串+运算时会当成连接符,其结果还是字符串
  • 识别技巧:能算则算,不能算就在一起。(计算机很聪明)


Java语法:自增、自减运算符


自增自减运算符

 注意:

  • ++  -- 只能操作变量,不能操作字面量。

自增自减的使用注意事项

  • ++ 、--  如果不是单独使用(如在表达式中或者同时有其他操作),放在变量前后会存在明显的区别
  1. 放在变量的前面,先对变量进行+1、-1,再拿变量的值进行运算
  2. 放在变量的后面,先拿变量的值进行运算,再对变量的值进行+1、-1

package com.liu.operator;

public class OperatorDemo2 {
    public static void main(String[] args) {
        //目标:掌握自增自减运算符的使用
        int a = 10;
        a ++; //a = a + 1
        System.out.println(a);

        a--;
        System.out.println(a);//a=11-1

   //自增自减只能操作变量,不能操作字面量。
//        2++;
//        System.out.println(2++);

        System.out.println("---------------------------------------------");
        
        int i = 10;
        int rs = ++i;//先加后用
        System.out.println(rs);
        System.out.println(i);
        
        int j = 10;
        int rs2 = j++;//先用后加
        System.out.println(rs2);
        System.out.println(j);
    }
}


Java语法:自增自减(拓展案例)


package com.liu.operator;

public class OperatorDemo2 {
    public static void main(String[] args) {
//拓展
        int m =5;
        int n = 3;
        int result = ++m - --m + m-- - ++n + n-- +3;
        //++m=6 m=6
        //--m=5 m=5
        //m--=5 m=4
        //++n=4 n=4
        //n--=4 n=3
        //6-5+5-4+4+3=9
        System.out.println(result); //9
        System.out.println(m); //4
        System.out.println(n); //3
    }
}


java语法:赋值运算符


基本赋值运算符

  • 就是 “ = ”,从右边往左边看
  • int a = 10 ; //先看 “ = " 右边,把数据10赋值给左边的变量a存储

扩展赋值运算符

注意

  • 扩展的赋值运算符隐含了强制类型转换。
  • += 可以实现数据的累加,把别人的数据加给自己。
package com.liu.operator;

public class OperatorDemo3 {
    public static void main(String[] args) {
        //目标:掌握扩展赋值运算符的使用
        // +=
        // 需求:收红包
        double a = 9.5;
        double b = 520;
        //a =(double)(a + b);
        a +=b;
        System.out.println(a);

        //需求:发红包
        double i = 600;
        double j = 520;
        //i = (double)(i - j);
        i -= j;
        System.out.println(i);

        int m = 10;
        int n = 10;
        m *= n; //等价形式 m = (int)(m*n)
        System.out.println(m);
        m /= n; //等价形式 m = (int)(m/n)
        System.out.println(m);
        m %= n; //等价形式 m = (int)(m%n)
        System.out.println(m);

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

        byte x = 10;
        byte y = 30;
        //x = x + y;//编译报错
//        x = (byte) (x+y); 正确代码
        x +=y; //等价形式  x = (byte) (x+y);
        System.out.println(x);
    }
}


Java语法:关系运算符


关系运算符

  • 判断数据是否满足条件,最终会返回一个判断的结果,这个结果是布尔类型的值:true 或者 false。

注意:

  • 在Java中判断是否相等一定是 ” == “ ,千万不要把 ” == “ 误写成 ” = “
package com.liu.operator;

public class OperatorDemo4 {
    public static void main(String[] args) {
        //目标:掌握关系运算符的基本使用
        int a = 10;
        int b = 5;
        boolean rs = a > b ;
        System.out.println(rs);

        System.out.println(a >= b);//要么a大于b,要么a=b
        System.out.println(2 >= 2);//true
        System.out.println(a < b);
        System.out.println(a <= b);//false
        System.out.println(2 <= 2);//true
        System.out.println(a == b);//false
        System.out.println(5 == 5);//true
        System.out.println(a = b );//5 //注意了 判断是否相等一定用==,=是用来赋值的
        System.out.println(a != b);//true
        System.out.println(10!=10);//false
    }
}


Java语法:逻辑运算符


逻辑运算符

  • 把多个条件放在一起运算,最终返回布尔类型的值:true、false.

注意:

  • 在Java中,” & “、” | “:无论左边是 false 还是 true,右边都要执行。
  • 由于 &&、|| 运算效率更高、在开发过程中用的更多

package com.liu.operator;

public class OperatorDemo5 {
    public static void main(String[] args) {
        //目标:掌握逻辑运算符的使用
        //需求:要求手机必须满足尺寸大于等于6.95,且内存必须大于等于8
        double size = 6.8;
        int storage = 16;
        //1. & 前后的条件的结果必须都是true,结果才是true
        boolean rs = size >= 6.95 & storage >= 8;
        System.out.println(rs);//false

        //需求:要求手机要么满足尺寸大于等于6.95,要么内存必须大于等于8
        //2. | 只要多个条件中有一个是true,结果就是true
        boolean rs2 = size >= 6.95 | storage >= 8;
        System.out.println(rs2);//true

        // 3. ! 取反的意思
        System.out.println(!true); //false
        System.out.println(!false); //true
        System.out.println(!(2>1)); //false

        //4. ^ 前后的条件结果相同时返回false,不同时返回true
        System.out.println(true ^ true);//false
        System.out.println(false ^ false);//false
        System.out.println(true ^ false);//true
        System.out.println(false ^ true);//true

        //5. 左边为false,右边不执行
        int i = 10;
        int j = 20;
        System.out.println( i > 100 && ++j > 99);
        System.out.println(j);

        //6. || 左边为true,右边就不执行
        int m = 10;
        int n = 30;
        System.out.println(m > 3 || ++n > 40);
        System.out.println(n);
    }
}


Java语法:三元运算符、运算符优先级


三元运算符介绍

  • 格式:条件表达式 ?值1 :值2 ;
  • 执行流程:首先计算关系表达式的值,如果值为true,返回值1,如果为false,返回值2 

运算符优先级

  • 在表示式中,哪个运算符先执行后执行是要看优先级的,例如 ” *、/ “ 的优先级高于 ” +、- “

package com.liu.operator;

public class OperatorDemo6 {
    public static void main(String[] args) {
        //目标:掌握三元运算符的基本使用
        double score = 98.5;
        String rs = score >= 60 ? "成绩及格":"成绩不及格";
        System.out.println(rs);

        //需求:找出2个整数中的较大值,并输出
        int a = 99;
        int b = 67;
        int max =  a > b ? a : b;
        System.out.println(max);

        //需求:找3个整数中的较大值
        int i = 10;
        int j = 45;
        int k = 34;

        //找到2个整数中的最大值
        int temp = i > j ? i :j;
        //找出temp与k中的较大值
        int max2 = temp > k ? temp : k;
        System.out.println(max2);//45

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

        System.out.println(10 > 3 || 10>3 && 10<3);//true
        System.out.println((10 > 3 || 10>3) && 10<3);//false

    }
}


Java语法:API介绍、Scanner:录入用户键盘输入的数据


需求:

  • 请在程序中,提示用户通过键盘输入自己的姓名、年龄,并能在程序中收到这些数据,怎么解觉?答:Java已经写好了实现程序,我们调用即可!

API(Application Programming Interface:应用程序编程接口)

  • Java写好的程序,咱们程序员可以直接拿来调用。
  • Java为自己写好的程序提供了相应的程序使用说明书(API文档)。

API文档在哪可以找到?

  1. 打开百度 
  2. 输入Oracle官网
  3. 找到products 点击
  4. 找到Java 点击
  5. 点击 Download Java
  6. 点击 JDK17
  7. 点击 Documentation Download (文档下载)
  8. 找到Download 有个jdk版本文档的下载链接 点击下载
  9. 同意勾选 点击下载

为什么要需学习查看API文档的方法?

API是Java提供的基本编程接口,当使用Java语言进行编程时,不可能把所有的Java类、所有方法全部记下来,当编程遇到一个不确定的地方时,必须通过API文档来查看某个类、某个方法的功能和用法。因此,掌握查看API文档的方法时学习Java的一个最基本的技能。读者可以尝试查阅API文档的String类来掌握String类的用法。

使用Scanner接收用户键盘输入的数据,需要三个步骤:

  1. 导包:告诉程序去JDK的那个包中找扫描器技术
  2. 抄代码:代表得到键盘扫描器对象(东西)
  3. 抄代码:等待接收用户输入数据

注意:

  • System、String在JDK中的 java.lang 包下。
  • lang包不需要我们导包,是默认的包。
package com.liu.scanner;
import java.util.Scanner;
public class ScannerDemo1 {
    public static void main(String[] args) {
        //1. 导包:一般不需要我们自己做,idea工具会自动帮助我们导包的
        //2. 抄写代码:得到一个键盘扫描器对象(东西)
        Scanner sc = new Scanner(System.in);
        //3. 开始调用sc的功能,来接收用户键盘输入的数据
        System.out.println("请您输入您的年龄");
        int age = sc.nextInt();//执行到这,会开始等待用户输入一个整数,直到用户按下回车键,才会拿到数据。
        System.out.println("您的年龄是:"+ age);

        System.out.println("请输入您的名字:");
        String name = sc.next();//执行到这,会开始等待用户输入一个字符串,直到用户按下回车键,才会拿到数据。
        System.out.println(name +"欢迎您进入系统~~~");


    }
}


阶段总结:类型转换、运算符、案例知识(键盘录入技术)


类型转换

  1. 原因:开发中会存在不同类型的变量或者数据赋值给其他类型的变量,也存在不同类型的数据一起运算,其结果类型要确定下来。
  2. 自动类型转换的原理:小范围类型的变量可以直接赋值给大范围类型的变量。
  3. 自动类型转换的范围信息:
  4. 自动类型转换的形式:byte a =20 ; int b = a ;
  5. 自动类型转换注意:char ch = ' a ' ;  int code = ch (注意这种形式是可以的)
  6. 表达式的自动类型转 含义:在表示式中,小范围类型的变量会自动提升成大范围运算
  7. 表达式的自动类型转换 结论:表达式的最终结果数据类型是由表达式中的最高数据类型决定的,最高数类型是什么,其结果数据类型就是什么
  8. 表达式的自动类型转换 注意:byte 、short、char在表达式中,是直接提升成 int 运算的
  9. 表达式的自动类型转换 面试笔试:
  10. 强制类型转换 含义:大范围类型的变量或者数据不能直接赋值给小范围类型的变量,否则报错!必须进行强制类型转换才可以。
  11. 强制类型转换 格式:数据类型 变量 = (数据类型)其他类型的变量/数据
  12. 强制类型转换 注意:强制类型转换可能出现数据丢失,int a = 1500;byte b = (byte) a;
  13. 强制类型转换 注意:浮点类型的变量或者数据强制转换成整型,保留整数部分返回的,小数部分直接不要了 double a = 99.5 ;  int i = (int) a ; // i =99

运算符(基本运算符、自增自减、赋值、关系、逻辑)

  1. 基本算术运算符 常见的: + - * / %
  2. 基本运算符 注意: / 两个整数相除的结果一定是整数 例:10/3=3 , 1.0*10/3=3.333...
  3. +符号做连接符 场景:+符号与字符一起运算时,充当连接符,连接后的结果还是一个字符串。
  4. +符号做连接符 识别技巧:能算则算,不能算大家连在一起。
  5. 自增自减运算符:++对变量进行+1操作 ,  --对变量进行-1操作。
  6. 自增自减运算符 注意事项:只能操作变量,不能操作字面量。例如:a++;//没毛病的  2++;//没有这种形式,报错  ; ++ --单独使用,放在变量前后,没有区别 例如:a++;++a ; ++  --如果不是单独使用,放在变量前后有明显区别,在变量前面:先+1,-1再使用变量,在变量后面:先使用变量,再对变量+1 -1
  7. 赋值运算符 := ,+= ,-= ,*= ,/= , %=
  8. 赋值运算符的应用:a +=b;等价于 a=(a的类型)(a+b)
  9. 赋值运算符的用处:适合做数据的累加操作 int a = 10; int b = 5;a += b; 自带强制转换 byte b1 = 2;byte b2 = 3;byte b3 =(byte)(b1+b2);---->b1 +=b ;
  10. 关系运算符:==  !=  >  >=  <  <=
  11. 关系运算符 判断是否满足条件,返回true 和 false 例如:int age =19;System.out.println(age >=18);等价于 boolean rs =age >= 18; System.out.println(rs);
  12. 逻辑运算符 :&  &&   |   ||   !  ^
  13. 逻辑运算符 与:&(逻辑与):且的意思,必须前后都是true,结果才是true, &&(短路与):且的意思,必须前后都是true,结果才是true,&与&& 的区别:&&如果发现前面是false,后面不执行,直接返回结果,性能较好,用的更多。
  14. 逻辑运算符 或: |(逻辑或):或的意思,只要前后有一个true,结果就一定是true,||(短路与):或的意思,只要前后有一个true,结果就一定是true,|(逻辑或)和 ||(短路与)的区别:||如果发现前面是true,后面不执行,直接返回结果,性能较好一点,用的更多一点。
  15. 逻辑运算符 取反 :!(取反)!false = true    !true = false
  16. 逻辑运算符 异或 :^(异或)  前后一样返回false,前后不一样返回true

运算符(三元运算符 )

  • 三元运算符是做分支选择的,关键是格式,条件表达式?值1 :值2

运算符(运算符优先级)

运算符存在谁先谁后执行的情况:()优先级最高 , * / 高于 + -  , &&优先级高于 || 

案例知识:键盘录入技术

  1. Java自己提供好的程序给程序员调用的
  2. API文档:应用程序编程接口,技术说明书,告诉我们该怎么使用Java程序
  3. 键盘录入技术:(1)、导包(自动导):import java.util.Scanner。(2)、创建一个扫描器对象:Scanner sc = new Scanner(System.in); (3)、等待接收用户的数据:int age = src.nextInt();  (4)、等待接收用的数据:String name = sc.next();


流程控制:分支结构:if、switch、switch穿透性


Java提供了两种常见的分支控制结构:if语句和switch语句,其中if语句使用布尔表达式或布尔值作为分支条件来进行分支控制;而switch语句则用于对多个整型值进行匹配,从而实现分支控制。

 if分支

  • 根据条件(真或假)来决定执行某段代码

if分支有三种形式

放在if之后括号里的只能是一个逻辑表达式,即这个表达式的返回值只能是

true或者false。

后面的花括号括起来的多行代码被称为代码块,一个代码块通常被当成一个整体来执行(除非运行过程中遇到return、break、continue等关键字,或者遇到了异常),因此这个代码块也被称为条件执行体。

如果if()、else if()和else后的代码块只有一行语句时,则可以省略花括号,因为单行语句本身就是一个整体,无须用花括号来把它们定义成一个整体。

对于任何的 if else语句,表面上看起来else后没有任何条件,或者else if后只有一个条件——但这不是真相:因为else的含义是“否则”——else本身就是一个条件!这也是把if、else后代码块统称为条件执行体的原因,else的隐含条件是对前面条件取反 。

package com.liu.branch;

public class IfDemo1 {
    public static void main(String[] args) {
        //目标:需要掌握if分支三种形式的用法和执行流程

        //需求1:测量用户体温,发现体温高于37度就报警
        double t = 36.9;
        if (t>37){
            System.out.println("这个人的温度异常,把他赶紧带着~");
        }
        //需求2 :发红包,你的钱包余额是99元,现在要发出90元
        //如果钱够,触发发红包的动作,如果钱不够,提升余额不足
        double money = 99;
        if (money>=90){
            System.out.println("发红包成功了~");
        }else {
            System.out.println("余额不足~");
        }
        //需求3:某个公司有一个绩效系统,根据员工的打分输出对应的绩效级别,
        // 【0,60)D,【60,80)C,【80,90)B,【90,100】A
        int score = 78;
        if (score >=0 && score < 60){
            System.out.println("您的绩效级别是:D");
        }else if(score >=60 && score < 80){
            System.out.println("您的绩效级别是:c");
        }else if(score >=80 && score < 90){
            System.out.println("您的绩效级别是:B");
        }else if(score >=90 && score <= 100){
            System.out.println("您的绩效级别是:A");
        }else {
            System.out.println("您录入的分数有毛病~");
        }
    }
}

if的第一种形式

if的第二种形式

if的第三种形式

if使用的几个常见问题

  • if(条件){}, ()后不跟 “;” 否则{}种的代码将不受if控制了
  • 如果if语句的{}中只有一行代码的情况,{}可以省略不写(但是不推荐省略)。

switch分支

  • 是通过比较值来决定执行哪条分支。

switch语句由一个控制表达式和多个case标签组成,和if语句不同的是,switch语句后面的控制表达式的数据类型只能是byte、short、chat、int四种整数类型枚举类型和java.lang.String类型(从Java7才允许),不能是boolean类型。

switch语句往往需要在case标签后紧跟一个代码块,case标签作为这个代码块的标识

switch分支的执行流程

  1. 先执行表达式的值,再拿着这个值去与case后的值进行匹配
  2. 与哪个case后的值匹配为true,就执行哪个case块的代码,遇到break就跳出switch分支
  3. 如果全部case后的值与之匹配都是false,则执行default块的代码。

switch分支的导学案例:电子备忘录

  • 周一:埋头苦干,解决bug;周二、;请求大牛程序员帮忙;周三:今晚啤酒 、龙虾、小烧烤
    周四:主动帮助新来的女程序解决bug;周五:今晚吃鸡;周六:与王婆介绍的小芳相亲
    周日:郁郁寡欢、准备上班
package com.liu.branch;

public class SwitchDemo2 {
    public static void main(String[] args) {
        //目标:掌握switch的写法,理解其执行流程

        //switch分支的导学案例:电子备忘录
        //周一:埋头苦干,解决bug;周二、;请求大牛程序员帮忙;周三:今晚啤酒 、龙虾、小烧烤
        //周四:主动帮助新来的女程序解决bug;周五:今晚吃鸡;周六:与王婆介绍的小芳相亲
        //周日:郁郁寡欢、准备上班
        String week = "周三";
        switch (week){
            case "周一":
                System.out.println("埋头苦干,解决bug");
                break;
            case "周二":
                System.out.println("请求大牛程序员帮忙");
                break;
            case "周三":
                System.out.println("今晚啤酒 、龙虾、小烧烤");
                break;
            case "周四":
                System.out.println("主动帮助新来的女程序解决bug");
                break;
            case "周五":
                System.out.println("今晚吃鸡烤");
                break;
            case "周六":
                System.out.println("与王婆介绍的小芳相亲");
                break;
            case "周日":
                System.out.println("郁郁寡欢、准备上班");
                break;
            default:
                System.out.println("您输入的星期信息肯定是不存在的~");
        }

    }
}

if、switch的比较,以及各自适合什么业务场景?

  • if在功能上远远强大于switch
  • 当前条件是与一个一个值比较的时候,应该使用if分支
  • 当条件是与一个一个的值比较的时候,switch分支更适合:格式良好,性能较好,代码优雅

使用switch分支的几点注意事项

  1. 表达式类型只能是byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String,不支持double、float、long
  2. case给出的值不允许重复,且只能是字面量,不能是变量
  3. 正常使用switch的时候,不要忘记写break,否则会出现穿透现象
package com.liu.branch;

public class SwitchDemo3 {
    public static void main(String[] args) {
        //目标:搞清楚switch使用时的几点注意事项

        //1. 表达式类型只能是byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String,不支持double、float、long
        int a =10;
        double b = 0.1;
        double b2 = 0.2;
        double c = b+b2;
        System.out.println(c);
        switch (a){

        }
        //2、case给出的值不允许重复,且只能是字面量,不能是变量
        int i = 20;
        switch (i){
            case 20:
                break;
//            case 20:
//                break;
        }

        //3、正常使用switch的时候,不要忘记写break,否则会出现穿透现象
        String week = "周三";
        switch (week){
            case "周一":
                System.out.println("埋头苦干,解决bug");
                break;
            case "周二":
                System.out.println("请求大牛程序员帮忙");
                //break;
            case "周三":
                System.out.println("今晚啤酒 、龙虾、小烧烤");
                //break;
            case "周四":
                System.out.println("主动帮助新来的女程序解决bug");
                break;
            case "周五":
                System.out.println("今晚吃鸡烤");
                break;
            case "周六":
                System.out.println("与王婆介绍的小芳相亲");
                break;
            case "周日":
                System.out.println("郁郁寡欢、准备上班");
                break;
            default:
                System.out.println("您输入的星期信息肯定是不存在的~");
        }

    }
}

switch穿透性在某些情况下可以简化代码

  • 当存在多个case分支的代码相同时,可以把相同的代码放到一个case块中,其他的case块都通过穿透性穿透到该case块执行代码即可,这样可以简化代码。
  • 案例:周一:埋头苦干,解决bug ;周二:请求大牛程序员帮忙 ; 周三:请求大牛程序员帮忙 ; 周四:请求大牛程序员帮忙 ; 周五:自己整理代码;周六:打游戏:周日:打游戏
package com.liu.branch;

public class SwitchDemo4 {
    public static void main(String[] args) {
        //案例:周一:埋头苦干,解决bug ;
        // 周二:请求大牛程序员帮忙 ;周三:请求大牛程序员帮忙 ;周四:请求大牛程序员帮忙 ;
        // 周五:自己整理代码;
        // 周六:打游戏:周日:打游戏
        String week = "周三";
        switch (week){
            case "周一":
                System.out.println("埋头苦干,解决bug");
                break;
            case "周二":
            case "周三":
            case "周四":
                System.out.println("请求大牛程序员帮忙");
                break;
            case "周五":
                System.out.println("自己解决代码");
                break;
            case "周六":
            case "周日":
                System.out.println("打游戏");
                break;
            default:
                System.out.println("您输入的星期信息肯定是不存在的~");
        }

    }
}


流程控制:循环结构:for循环、for循环案例


for循环

  • 控制循环格式

for循环格式

执行流程

package com.liu.loop;

public class ForDemo1 {
    public static void main(String[] args) {
        //目标:需要同学们掌握for循环的书写格式,并理解其执行流程
        //需求:打印三行Hello World
        /*
        流程 :
        首先会执行初始化:int i= 0 ;
        i = 0,判断循环条件 0<3,返回true,计算机会进入到循环中执行输出第一行 Hello World,
        接着执行迭代语句i++, i = 1,判断循环条件 1<3,返回true,计算机会进入到循环中执行输出第一行 Hello World,
        接着执行迭代语句i++, i = 2,判断循环条件 2<3,返回true,计算机会进入到循环中执行输出第一行 Hello World,
        接着执行迭代语句i++, i = 3,判断循环条件 3<3,不成立,返回false,循环立即结束。
         */
        for (int i = 0;i<3;i++) {
            // i = 0 1 2
            System.out.println("Hello World");
        }
            System.out.println("----------------------------------------");

            for (int i = 1; i <=5;i++){
                //i = 1 2 3 4 5
                System.out.println("Hello World 2");
            }
        System.out.println("----------------------------------------");

            for (int i = 1;i <= 10;i += 2){
                //1 3 5 7 9
                System.out.println("Hello World 3");
            }
    }
}

for循环在开发中的常见应用场景

  • 减少代码的重复编写、灵活的控制程序的执行
  • 批量生成数据
package com.liu.loop;

public class ForDemo2 {
    public static void main(String[] args) {
        //目标:掌握使用for批量产生数据
        for (int i = 0; i <= 100; i++) {
            System.out.println(i);
        }
        System.out.println("--------------------------");

        //需求:1-5之和
        // 2. 定义一个变量用于求和
        int sum1 = 0; //0 1 3 6 10 15
        //1.定义一个循环,先产生1-5,这5个数
        for (int i = 1; i <= 5; i++) {
            // i= 1 2 3 4 5
            sum1 += i; //等价 sum = sum + i;
        }
        System.out.println("1-5的数据和:" + sum1);

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

        //需求:1-100之和
        // 2. 定义一个变量用于求和
        int sum2 = 0;
        //1.定义一个循环,先产生1-5,这5个数
        for (int i = 1; i <= 100; i++) {
            sum2 += i; //等价 sum = sum + i;
        }
        System.out.println("1-100的数据和:" + sum2);

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

        //2. 定义一个变量用于求和
        int sum3 = 0;
        //1. 定义一个循环产生1-100之间的奇数
        for (int i = 1;i < 100;i+=2){
            // i 1 3 5 7 ...
            sum3 +=i;
        }
        System.out.println("1-100之间的奇数和:"+sum3);

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

        //2.定义一个变量用于累加数求和
        int sum4 = 0;
        //1. 定义一个循环产生1-100之间的每个奇数
        for (int i = 1;i<=100;i++){
            //i = 1 2 3 4 5 6 ... 99 100
            //2. 使用一个if分支,判断i此时记住的数据是否是奇数,是奇数我们才累加给一个变量
            if (i % 2 == 1){
                //1 3 5 7 9 ...99
                sum4 +=i;
            }
        }
        System.out.println("1-100之间的奇数和:"+sum4);

    }

}






流程控制:循环结构:while循环、珠穆朗玛峰


while循环

package com.liu.loop;

public class WhileDemo3 {
    public static void main(String[] args) {
        //目标:掌握while循环的书写格式,以及理解其执行流程
        //需求:打印多行Hello World
        int i = 0;
        while (i < 5){
            // i= 0 1 2 3 4
            System.out.println("Hello World");
            i ++;
        }
    }
}

while和for有什么区别?什么时候用for,什么时候用while?

  • 功能上是完全一样的,for能解决的,while也能解决,反正亦然。
  • 使用规范:知道循环几次建议:使用for;不知道循环几次建议使用:while

案例:珠穆朗玛峰

需求:世界最高山峰珠穆朗玛峰高度是:8848.86米=8848860毫米,假如我有一张足够大的纸,它的厚度是0.1毫米。请问:该纸张折多少次,可以折成珠穆朗玛峰的高度?

(一开始不知道要循环多少次,则使用while)

分析:(1)定义变量存储珠穆朗玛峰的高度、纸张的高度 ;(2) 使用while循环来控制纸张折叠,循环条件是(纸张厚度<山峰高度);(3)循环每执行一次,就表示纸张折叠一次,并把纸张厚度变为原来两倍;(4) 循环外定义计数变量count,循环每折叠一次纸张,让count变量 +1。

package com.liu.loop;

public class WhileText4 {
    public static void main(String[] args) {
        //目标:使用while循环解决问题,并理解什么情况下使用while、for

        //1.定义一个变量记住珠穆朗玛峰的高度和纸张的高度
        double peakHeight = 8848860;
        double paperThickness = 0.1;
        //3. 定义一个变量count 用于记住纸张折叠了多少次
        int count = 0;
        //2. 定义while循环控制纸张开始折叠
        while (paperThickness<peakHeight){
            //把纸张进行折叠,把纸张的厚度变为原来的2倍
            paperThickness = paperThickness * 2;
            count ++ ;
        }
        System.out.println("需要折叠多少次:"+ count);
        System.out.println("最终纸张的厚度是:"+ paperThickness);
    }
}

package com.liu.loop;

public class WhileText4 {
    public static void main(String[] args) {
        //目标:使用while循环解决问题,并理解什么情况下使用while、for

        //1.定义一个变量记住珠穆朗玛峰的高度和纸张的高度
        double peakHeight = 8848860;
        double paperThickness = 0.1;
        //3. 定义一个变量count 用于记住纸张折叠了多少次
        int count = 0;
        //2. 定义while循环控制纸张开始折叠
       for (;paperThickness<peakHeight;count ++){
            //把纸张进行折叠,把纸张的厚度变为原来的2倍
            paperThickness = paperThickness * 2;
        }
        System.out.println("需要折叠多少次:"+ count);
        System.out.println("最终纸张的厚度是:"+ paperThickness);
    }
}


流程控制:循环结构:do-while


do-while循环

package com.liu.loop;

public class DoWhileDemo5 {
    public static void main(String[] args) {
        //目标:掌握do-while循环的书写格式,执行流程,特点和应用场景
        //需求:打印多行Hello World
        int i = 0;
        do {
            System.out.println("Heool World");
            i ++;
        }while (i  < 3 );

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

        //特点:先执行后判断
        do {
            System.out.println("Hello World 2");
        }while (false);
    }
}

do-while循环的特点:

  • 先执行后判断


三种循环的区别小结


三种循环区别

  • for循环和while循环(先判断后执行);do...while(先执行后判断)
  • for循环和while循环的执行流程是一模一样的,功能上无区别,for能做的 while也能做,反之亦然。
  • 使用规范:如果已知循环次数建议使用for循环,如果不清楚要循环多少次建议使用while循环。
  • 其他区别:for循环中,控制循环的变量只在循环中使用。while循环中,控制循环的变量在循环后还可以继续使用。
package com.liu.loop;

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


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

        for (int j = 0; j<3 ; j++){
            System.out.println("Hello World3");
        }
//        System.out.println(j); j变量只能在循环内使用

        int m = 0;
        while (m<3){
            System.out.println("Hello World");
            m++;
        }
        //m变量在循环后还可以继续使用
        System.out.println(m);//3
    }
}


流程控制:死循环,循环嵌套


死循环

  • 可以一种执行下去的一种循环,如果没有干预不会停下来

死循环的写法

package com.liu.loop;

public class EndLessLoopDemon6 {
    public static void main(String[] args) {
        //目标:掌握死循环的写法

        //1.死循环第一种
//        for (int i = 0; ;i++){
//            System.out.println("Hello World");
//        }

//       //2.死循环第二种
//        while (true){
//            System.out.println("Hello World 2");
//        }

        //3.死循环第三种
        do{
            System.out.println("Hello World 3");
        }while (true);

    }
}

死循环的应用场景

  • 做服务器程序


循环嵌套


循环嵌套

  • 循环中又包含循环
  • 如果把一个循环放在另一个循环体内,那么就可以形成嵌套循环,嵌套混混既可以是for循环嵌套while循环,也可以是while循环嵌套do while循环········即各种类型的循环都可以作为外层循环,也可以作为内层循环。
  • 当程序遇到嵌套循环时,如果外层循环的循环条件被允许,则开始执行外层循环的循环体,而内层循环将被外层循环的循环体来执行——只是内层循环需要反复执行自己的循环体而已。当内层循环的执行结束,且外层循环的循环体执行结束时,则再次计算外层循环的循环条件,决定是否再次开始执行外层循环的循环体。

package com.liu.loop;

public class LoopNestedDemo7 {
    public static void main(String[] args) {
    //目标:循环嵌套的执行流程

    //场景:假如你有对象,你犯错了,你对象罚你说:3天,每天五句我爱你
        //方法一
//        for (int i = 1;i<=3;i ++){
//            // i = 1 2 3
//            System.out.println("我爱你:" + i);
//            System.out.println("我爱你:" + i);
//            System.out.println("我爱你:" + i);
//            System.out.println("我爱你:" + i);
//            System.out.println("我爱你:" + i);
//            System.out.println("--------------------------------");
//
//        }

        //方法二
        for (int i = 1;i<=3;i ++){
           // i = 1 2 3
            for (int j = 1;j<=5;j++){
                System.out.println("我爱你:" + i);
            }
            System.out.println("我爱你:" + i);
            System.out.println("--------------------------------");
        }

        // 打印三行 ****
        //方法一
        for (int i = 1;i <=3;i++){
            // i = 1 2 3
            System.out.println("****");
        }

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

        // 打印三行 ****
        //方法二
        for (int i = 1;i <=3;i++){
            // i = 1 2 3
            //定义一个循环控制每行打印多少列*
            for (int j = 1;j<=4;j++) {
                System.out.print("*"); // print 不换行
            }
            System.out.println();//换行
        }

    }

}

循环嵌套的特点

  • 外部循环每循环一次,内部循环会全部执行完一轮。


跳转关键字:break、contine


  • Java语言没有提供goto语句来控制程序的跳转,这种做法提高了程序流程控制的可读性,但降低了程序流程控制的灵活性。为了弥补这种不足,Java提供了contine和break来控制循环结构。除此之外,return可以结束整个方法,当然也就结束了一次循环。

跳转关键字

  • break:跳出并结束当前所在循环的执行。
  • continue:用于跳出当前循环的当次执行,直接进入循环的下一次执行。

注意事项

  • break:只能用于结束所在循环,或者结束所在switch分支的执行。
  • continue:只能在循环中进行使用。
package com.liu.loop;

public class BreakAndContinueDemo8 {
    public static void main(String[] args) {
        //目标:掌握break和continue的作用
        //1. break :跳出并结束当前所在循环的执行
        //场景:假如你又有对象了,你犯错了,你对象罚你说:5句我爱你
        //说到第三句的时候心软了,让你别再说了。
        for (int i = 1;i<=5;i++){
            System.out.println("我爱你:"+i);
            if (i==3){
                //说明已经说完了第三句了,心软了。
                break;//跳出并结束当前所在循环的执行
            }
        }

        //2、continue:跳出当前循环的当次执行,直接进入循环的下一次执行
        //场景:假如你有对象,你犯错了,你对象罚你洗碗5天。
        //第三天的时候,你表现很好,第三天不用洗碗,但是很快不解,第四天还是要继续的
        for (int i = 1;i<=5;i++){
            if(i==3){
                //已经到了第三天,第三天不用洗的。
                continue;
            }
            System.out.println("洗碗:"+i);

        }
    }
}

  • break用于完全结束一个循环,跳出循环体,不管事哪种循环,一旦在循环体中遇到break,系统将完全结束该循环,开始执行循环之后的代码。
  • break语句不仅可以结束其所在的循环,还可以直接结束其外层循环。
  • continue只是忽略本次循环剩下语句,接着开始下一次循环,并不会终止循环。
  • break则是完全终止循环本身。


流程控制:随机数Random、Random案例


Random

  • 作用:生成随机数

得到0~9的随机数的实现步骤

注意:

  • nextInt(n) 功能 只能生成:0 至 n-1 之间的随机数,不包含n。

package com.liu.random;

import java.util.Random;

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

    //目标:掌握使用random生成随机数的步骤
    //1、导包
    //2、创建一个random的对象,用于生成一个随机数
    Random r = new Random();
    //3、调用Random提供的功能,nextInt得到随机数
        for (int i = 1;i<=20;i++) {
            int data = r.nextInt(10);//0~9
            System.out.println(data);
        }

    }
}

Random生成指定区间随机数

例如:要生成 1-10 之间的随机数,程序怎么实现?

技巧:减加法

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

        //生成 1-10 之间的随机数
        // 1-10 =》 -1 =》 (0-9)+1
        for (int i = 1;i<=20;i++) {
            int data2 = r.nextInt(10);
            System.out.println(data2);
        }

        System.out.println("--------------------------------------");
        
        // 3-17 =》 -3 =》(0-14)+3
        for (int i =1;i<=20;i++) {
            int data3 = r.nextInt(15)+3;
            System.out.println(data3);
        }

如何生成 65 - 91 之间的随机数?

  • 65 - 91 ==》 -65 ==》 (0 - 26)+65
  • int number = r .  nextInt(27) + 65 ;

猜数字游戏

  • 需求:随机生成一个 1- 100 之间的数据,提示用户猜测,猜大提示过大,猜小提示过小,直到猜中结束游戏。
  • 分析: 1、先随机生成一个 1- 100 之间的数据 。2、定义一个死循环让用户可以一直猜测。 3、在死循环里,每次都提示用户输入一个猜测的数字,猜大提示过大,猜小提示过小,猜中则结束游戏。
package com.liu.random;

import java.util.Random;
import java.util.Scanner;

public class RandomTest2 {
    public static void main(String[] args) {
        //1、随机产生一个 1- 100 之间的数据,作为中将号码
        Random r = new Random();
        int luckNumber = r.nextInt(100)+1;
        //2、定义一个死循环,让用户不断的猜测数据
        Scanner sc = new Scanner(System.in);
        while (true){
            //提示用户猜测
            System.out.println("请您输入猜测的数据:");
            int guestNumber = sc.nextInt();

            //3、判断用户猜测的数字与幸运号码的大小情况
            if (guestNumber > luckNumber){
                System.out.println("您猜测的数字过大!");
            }else if (guestNumber<luckNumber){
                System.out.println("您猜测的数字过小~");
            }else {
                System.out.println("恭喜您,猜测成功了,可以买单了!");
                break;//结束死循环
            }
        }
    }
}


阶段总结:分支结构、循环结构、跳转关键字:break和continue、随机数Random


程序流程控制

  • 就是控制代码怎么去执行的。
  • 三种结构:顺序结构、分支结构、循环结构
  • 分支结构:if、switch

分支结构

  1. if 的作用:可以判断条件来决定执行哪个分支
  2. if 的格式:
  3. switch 作用:根据表达式的值来进行值匹配选择对应的分支执行
  4. switch 格式:
  5. if 和 switch 的区别:都是做分支操作的;if的功能更强大;如果是值匹配的操作建议用switch,格式清晰,性能较好!
  6. switch 的注意事项:表达式类型只能是byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String,不支持double、float、long ;case给出的值不允许重复,且只能是字面量,不能是变量 ; 正常使用switch的时候,不要忘记写break,否则会出现穿透现象
  7. switch的穿透性的含义:switch中没有写break,遇到了case会一直往下走,直到遇到break才会跳出。
  8. switch的穿透性适合做多个值对应的case块的操作是相同的!可以穿透到一个位置集中处理,这样可以提高开发效率,降低代码重复

循环结构

  1. 循环结构的作用:控制一段代码重复的执行多次
  2. for循环格式:
  3. while循环格式:
  4. do—while循环格式:
  5. do—while突出特点:一定会执行一次循环体语句!再判断循环条件
  6. 循环结构的区别:for和while都是先判断后执行,do—while第一次是先执行然后再判断,for和while在功能上完全一样,流程也是一样的,如果一开始就知道循环几次用for,如果一开始不知道循环用几次用while。
  7. 死循环是一直执行下去:
  8. 死循环的写法:

跳转关键字:break和continue

  1. break:跳出并结束当前所在循环的执行。
  2. continue:用于跳出当前循环的当次执行,直接进入循环的下一次执行。
  3. break:只能用于结束所在循环,或者结束所在switch分支的执行。
  4. continue:只能在循环中进行使用。

案例技术:随机数Random类

  1. 作用:产生一个随机数
  2. 步骤:导包(自动做的:import java.until.Random);创建随机数对象:Random r = new Random(); 开始得到随机数:int data = r.nextInt();//0-9
  3. 生产指定区间的随机数:(1)、减加发:1-10 ==》-1 ==》(0-9)+1 ; int data = r.nextInt(10)+1; (2)、Java其实给了我们一些功能直接就能得到指定区间的随机数:Random r = new Random;//10-30 ;for(int i= 0;i<100;i++){int data = r.nextInt(10,31);System.out.println(data);}


认识数组


数组是什么

  • 数组就是一个容器,用来存储一批同类型的数据。

数组是编程语言中最常见的一种数据结构,可用于存储多个数据,每个数组元素存放一个数据,通常可通过数组元素的索引来访问数组元素,包括为数组元素赋值和取出素组元素得值。Java语言的数组则是具有其特有的特征。

Java的数组要求所有的数组元素具有相同的数据类型。因此,在一个数组中,数组元素的类型是唯一的,即一个数组里只能存储一种数组类型的数据,而不能存储多种数据类型的数据。                                                                                                                                                                               一旦数组的初始化完成,数组在内存中所占的空间将被固定下来,因此数组的长度将不可改变。 即使把某个数组元素的数据清空,但它所占的空间依然被保留,依然属于该数组,数组的长度依然不变。

Java中的数组既可以存储基本类型的数据,也可以存储引用类型的数据,只要所有的数组元素具有相同的类型即可。

值得指出的是,数组也是一种数据类型,它本身是一种引用类型。例如:int是一个基本类型,但int[] (这是定义数组的一种方式) 就是一种引用类型了。                                                                                                                                                                                                                                  int[] 就是一种数据类型,与int类型、String类型类似,一样可以使用该类型来定义变量,也可以使用该类型进行类型转换等。使用 int[] 类型来定义变量、进行类型转换时与使用其他普通类型没有任何区别。  int[] 类型是一种引用类型,创建 int[] 类型的对象也是创建数组,需要使用创建数的语法。       

定义一个int数组类型的变量,变量命为intArr   

int[] intArr;

使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度

intArr = new int[] {5,8,6,20};                                                                                                                                                                                                    

例子

有变量,为什么还用数组?


数组的定义和访问


静态初始化数组

  • 定义数组的时候直接给数组赋值。
  • 初始化时由程序员显示指定每个数组元素的初始值,由系统决定数组长度。

静态初始化数组的格式:

注意:

  • “数组类型【】 数组名” 也可以写成  “数组类型 数组名【】”
  • 什么类型的数组只能存放什么类型的数据
package com.liu.define;

public class ArrayDemo1 {
    public static void main(String[] args) {
        //目标:掌握数组的定义方式一:静态初始化数组

        //1. 数据类型【】 数组名 = new 数据类型【】{元素1,元素2,元素3,······}
        int[] ages = new int[]{12,24,36};
        double[] scores = new double[]{89.8,99.5,59.5,88};

        //2.简化写法
        //数据类型【】 数组名 = {元素1,元素2,元素3,·······}
        int[] ages2 = {12,24,32};
        double[] scores2 = {89.8,99.5,59.5,88};

        //3.数据类型【】 数组名 也可以写成 数据类型 数组名【】
        int[] ages3 = {12,24,36};
        double scores3[] = {89.8,99.5,59.5,88};
        

    }
}

数组在计算机中的基本原理

注意:

  • 数组变量名中存储的是数组在内存中的地址,数组是一种引用数据类型。

数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是定义了一个指针),这个引用变量还未指定任何有效的内存,因此定义数组时不能指定数组的长度。而且由于定义数组只是定义了一个引用变量,并未指向任何有效内存空间,所有还没有内存空间来存储数组元素,因此这个数组也不能使用,只要对数组进行初始化后才能使用。

定义数组时不能指定数组的长度

Java语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋值初始值

不允许 只分配内存空间,而不不赋初始值。一旦为数组的每个数组元素分配了内存空间,每个内存空间里存储的内容就是该数组元素的值,即使这个内存空间存储的内容是空,这个空也是一个值(null)。不管以哪种方式来初始化数组,只要为数组元素分配了内存空间,数组元素就具有了初始值。初始值的获得有两种形式:一种是由系统自动分配;另一种由程序员指定。

package com.liu.define;

public class ArrayDemo1 {
    public static void main(String[] args) {
        //目标:掌握数组的定义方式一:静态初始化数组

        //1. 数据类型【】 数组名 = new 数据类型【】{元素1,元素2,元素3,······}
        int[] ages = new int[]{12,24,36};
        double[] scores = new double[]{89.8,99.5,59.5,88};
        System.out.println(ages);
        System.out.println(scores);

数组的访问

数组最常见的用法就是访问数组元素,包括对数组元素进行赋值和取出数组元素的值。访问数组元素都是通过在数组引用变量后紧跟一个方括号( [ ] ),方括号里是数组元素的索引值,这样就可以访问数组元素了。访问到数组元素后,就可以把一个数组元素当成一个普通变量使用了,包括为该变量赋值和取出该变量的值,这个变量的类型就是定义数组时使用的类型。

Java语言的数组索引是从0开始的,也就是说,第一个数组元素的索引值为0,最后一个数组元素的索引值为长度减1。

如果访问数组元素时指定的索引值小于0,或者大于等于数组的长度,编译程序不会出现任何错误,但运行时出现异常。

  • 数组名【索引】

数组的长度属性:length

数组的最大索引

  • 数组名.length - 1 //前提:元素个数大于0

如果访问数组时,使用的索引超过了最大索引会出什么问题

  • 执行程序时会出现bug,出现一个索引越界的异常提示。

package com.liu.define;

public class ArrayDemo2 {
    public static void main(String[] args) {
        //目标:掌握数组的访问
        int[] arr = {12,24,36};
                    // 0  1   2
        //1.访问数组的全部变量
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        //System.out.println(arr[3]);

        //2. 修改数组中的数据
        arr[0] = 66;
        arr[2] = 100;
        System.out.println(arr[0]);//66
        System.out.println(arr[1]);//24
        System.out.println(arr[2]);//100

        //3. 访问数组元素个数,数组名.length
        System.out.println(arr.length);

        //技巧:获取数据的最大索引
        System.out.println(arr.length-1);

        int[] arr2 ={};
        System.out.println(arr2.length - 1 );


    }
}


数组的遍历


什么是数组遍历:

  • 遍历:就是一个一个数据的访问

为什么要遍历数组?

求和  元素搜索  找最大值、最小值

package com.liu.define;

public class ArrayDemo3 {
    public static void main(String[] args) {
        //目标:掌握数组的遍历
        int[] ages = {12,24,36};
                      //0   1  2

//        System.out.println(ages[0]);
//        System.out.println(ages[1]);
//        System.out.println(ages[2]);

        for (int i = 0;i < ages.length; i ++){ //ages.fori 回车
            // i= 0 1 2
            System.out.println(ages[i]);
        }

    }
}

案例训练

数组遍历求和-求和

需求:某部门5名员工的销售额分别是:16、26、36、6、100,请计算出他们部门的总销售额。

分析:1.把这5个数据拿到程序中去 ===》使用数组 int【】 money = {16,26,36,6,100};  2.遍历数组中的每个数据,然后再外面定义求和变量把他们累加起来。

package com.liu.define;

public class ArrayTest4 {
    public static void main(String[] args) {
        //目标:完成对数组的元素求和
        //1. 定义一个数组存储5名员工的销售额
        int[] money = {16,26,36,6,100};
                        //0  1 2  3  4

        //3.定义一个变量用于累加求和
        int sum = 0 ;

        //2.遍历数组中的每个数据
        for (int i = 0;i < money.length;i++){
            //0  1 2  3  4
            sum += money[i];
        }
        System.out.println("员工的销售总额:" + sum);
    }
}


动态初始化数组


数组的动态初始化

  • 定义数组时先不存入具体的元素值,只确定数组存储的数据类型和数组的长度
  • 初始化时程序员只指定数组长度,由系统为数组元素分配初始值

数组的动态初始化格式:

数据类型【】 数组名 = new 数据类型【长度】;

int[] arr = new int[3];

//后赋值

arr[0] = 10;

System.out.println(arr[0]); //10

温馨提示

  • 静态初始化和动态初始化数组的写法时独立的,不可以混用。

int[] arr = new int[3]{30,40,50}; 错误写法

package com.liu.define;

public class ArrayDemo5 {
    public static void main(String[] args) {
        //目标:掌握定义数组的方式而:动态初始化数组
        //1. 数据类型【】 数组名= new 数据类型【长度】
        int[] ages = new int[3]; //ages = [0,0,0]

        System.out.println(ages[0]);
        System.out.println(ages[1]);
        System.out.println(ages[2]);

        ages[0]=12;
        ages[1]=18;
        ages[2]=32;

        System.out.println(ages[0]);
        System.out.println(ages[1]);
        System.out.println(ages[2]);

//        int[] arr = new int[3]{0,20,50}; 错误写法

    }
}

动态初始化数组元素默认值规则:

char[] chars = new  char[3]; // [0,0,0]
        System.out.println((int)chars[0]); //char是字符类型 打印出来的会是底层的字符 ,因此可以转换成int型
        System.out.println((int)chars[2]);

        double[] score = new double[80];
        System.out.println(score[0]);
        System.out.println(score[79]);

        boolean[] flags = new boolean[100];
        System.out.println(flags[0]);
        System.out.println(flags[99]);

        String[] names = new String[80];
        System.out.println(names[0]);
        System.out.println(names[79]);
        

两种数组定义的方法各自适合什场景?

  • 动态初始化:适合开发不确定具体元素值,只知道元素个数的业务场景。
  • 静态初始化:适合一开始就知道要存入哪些元素值的业务场景。

案例训练

评委打分案例

需求:某歌唱比赛,需要开发一个系统:可以录入6名评委的打分,录入完毕后立即输出平均分做出选手得分。

分析:1. 6名评委的打分是后期录入的,一开始不知道具体的分数,因此定义一个动态初始化的数组存分数。double[] scores = new double[6];  2.遍历数组中的每个位置,每次提示用户录入一个评委的分数,并存入到数组对应的位置。 3.遍历数组中的每个元素进行求和,最终算出平均分打印出来即可。

package com.liu.define;

import java.util.Scanner;

public class ArrayTest6 {
    public static void main(String[] args) {
        //目标:完成评委打分的案例
        //1.定义一个动态初始化的数组 负责后期存储6个评委的打分
        double[] scores = new double[6];

        Scanner sc = new Scanner(System.in);

        //2.遍历数组中的每个位置,录入评委的分数,存入到数组中去
        for (int i = 0;i < scores.length;i++){
            // i = 0 1 2 3 4 5
            System.out.println("请输入当前第"+(i+1)+"个评委的分数:");
            double score = sc.nextDouble();
            scores[i] = score;
        }

        //3.遍历数组中的每个数进行求和
        double sum = 0 ;
        for (int i= 0;i< scores.length;i++){
            sum += scores[i];
        }
        System.out.println("选手最终得分是:"+sum / scores.length);
    }
}


数组在计算机的执行原理


package com.liu.memony;

public class ArrayDemo1 {
    public static void main(String[] args) {
        //目标:掌握普通变量,数组在计算机中的执行原理,Java程序在计算机中的执行过程
        int a = 20;
        System.out.println(a);

        int[] arr = new int[]{11,22,33};
        System.out.println(arr);

        System.out.println(arr[1]);

        arr[0]=44;
        arr[1]=55;
        arr[2]=66;

        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);

    }
}

Java内存分配介绍

数组在计算机中的执行原理

总结:

1、运行一个Java程序,主要看JVM中包含的哪几个部分?

答:方法区、栈内存、堆内存

2、简单说说 int a = 20 ; int [] arr = new int[3] 这两行代码的执行原理?

答:

a是变量,直接放在栈中,a变量中存储的数据就是20这个值

new int[3] 是创建一个数组对象,会在堆内存中开辟区域存储3个整数

arr 是变量,在栈中,arr中存储的是数组对象在堆内存中的地址值

package com.liu.memony;

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

    //目标:认识多个变量面向同一个数组对象的形式,并掌握其注意事项
    int[] arr1 = {11,22,33};

    //把int类型的数组变量arr1赋值给int类型的数组类型变量arr2
    int[] arr2 = arr1;

        System.out.println(arr1);
        System.out.println(arr2);

        arr2[1] = 99;
        System.out.println(arr1[1]);

    }
}

多个变量指向同一个数组

使用数组时常见的一个问题

如果某个数组变量存储的地址是null,那么该变量将不再指向任何数组对象

arr2 = null; //拿到的数组变量中存储的就是null
System.out.println(arr2);

//System.out.println(arr2[0]); //出现报错;空指针异常
//System.out.println(arr2.length); //出现报错,空指针异常

总结:

1、多个数组变量,指向同一个数组对象的原因是什么?需要什么?

答:

多个数组变量中存储的是同一个数组对象的地址

多个变量修改的都是同一个数组对象中的数据

2、如果某个数组变量中存储的null,代表什么意思?需要注意什么?

答:

代码这个数组变量没有指向数组对象

可以输出这个变量,但是不能用这个数组变量去访问数据或者访问数组长度,会报空指针异常:NullPointerException


数组案例:求最大值,反转


求最大值

package com.liu.demo;

public class Test1 {
    public static void main(String[] args) {
        // 目标:掌握数组元素求最值
        //1. 把颜值数据拿到程序中来,用数组装起来
        int[] faceScores = {15,9000,10000,20000,9500,-5};
        //                   0  1     2    3     4    5

        //2.定义一个变量用于最终记住最大值
        int max = faceScores[0];

        //3.从数组的第二个位置开始遍历 i
        for (int i = 0;i<faceScores.length;i++){
            // i = 1 2 3 4 5
            //判断下一个当前遍历的这个数据,是否大于最大值变量max存储的数据,当前遍历的数据需要赋值max
            if (faceScores[i]>max){
                max = faceScores[i];
            }
        }
        System.out.println("最高颜值是:" + max);

    }
}

总结:

求数组中的最大值,我们是如何实现的?

答:

1. 把数据拿到程序中去,用数组装起来

2. 定义一个变量max用于记录最大值,max变量默认存储了第一个元素值作为参照物

3. 从第二个位置开始遍历数组的数据,如果当前元素大于变量存储的数据,则替换变量存储的值为该元素

4. 循环结束后输出max变量即可

数组反转

需求:某个数组有5个数据:10,20,30,40,50,请将这个数组中的数据进行反转

【10,20,30,40,50】 反转后 【50,40,30,20,10】

分析:

数组反转操作实际上就是:依次前后交换数据即可实现。

package com.liu.demo;

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

    //目标:实现数组反转
    //1.准备一个数组
    int[] arr = {10,20,30,40,50};
    //           i            j

    //2. 定义一个循环,设计两个变量,一个在前,一个在后
        for (int i = 0,j = arr.length-1;i < j;i++,j--){
            //arr[i]  arr[j]
            //交换
            //1.定义一个临时变量记住后一处位置的值
            int temp = arr[j];
            //2.把前一个位置的值赋值给后一个位置了
            arr[j] =arr[i];
            //3.把临时变量中记住的后一个位置处的值赋值给前一个位置处
            arr[i] = temp;

        }
            //4.遍历数组中的每个数据,看是否反转成功了
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i] + " ");
            }
    }
}

总结:

1.我们如何完成数组的反转的?

答:

使用for循环,控制让数组的前后位置的元素,依次交换

2. 数组如何实现前后元素交换的?

答:

定义一个临时变量记住后一个位置处的元素值

再把前一个位置处的元素值,赋值给后一个位置处

最后把临时变量记住的后一个位置的值赋值给前一个位置处


Java数组:随机排名,debug


随机排名

需求:某公司开发部5名开发人员,要进行项目进展汇报演讲,现在采取随机排名后进行汇报。请先依次录入5名员工的工号,然后展示出一组随机的排名顺序。

分析:

在程序中录入5名员工的工号存储起来 -----> 使用动态初始化数组的方式

依次遍历数组中的每个数据

每遍历一个数据,都随机一个索引值出来,让当前数据与该索引位置处的数据进行交换。

输出数据中的内容即可

package com.liu.demo;

import java.util.Random;
import java.util.Scanner;

public class Test3 {
    public static void main(String[] args) {
        //目标:完成随机排名
        //1.定义一个动态初始化的数组用于存储5名员工的工号
        int[] codes = new int[5];
        //[0,0,0,0,0]
        // 0 1 2 3 4

        //2.提示用户录入5名用户的工号
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < codes.length; i++) {
            // i = 0 1 2 3 4
            System.out.println("请您输入当前第" + (i + 1) + "员工的工号:");
            int code = sc.nextInt();
            codes[i] = code;
        }

        //3.打乱数组中的元素顺序
        // [12,33,54,26,8]
        //   i    index
        Random r = new Random();
        for (int i = 0; i < codes.length; i++) {
            //code[i]
            //每遍历到一个数据,都随机一个数组索引范围内的值,然后让当前遍历的数据与该索引位置处的值交换
            int index = r.nextInt(codes.length);//0 - 4
            //定义一个临时变量记住index位置的值
            int temp = codes[index];
            //把i位置处的值赋值给index位置处
            codes[index] = codes[i];
            //把index位置处的值赋值给i位置处
            codes[i] = temp;
        }
        //4.遍历数组中的工号输出即可
        for (int i = 0; i < codes.length; i++) {
            System.out.print(codes[i] + " ");
        }
    }

}

随机交换排名的其他使用场景

  • 随机发牌

Debug工具

IDEA自带的断点调试工具,可以控制代码从断点开始一行一行的执行,然后详细观看程序执行的情况。

Debug工具使用方法

第一步 设置断点

第二步 右击选择Debug······

补充:可以看详细的过程、 详细的代码执行过程

总结:


总结:数组


数组

  1. 数组的作用:就是一个数据,用于在程序中存储一批同种类型的数据
  2. 数组的定义 静态初始化 :格式1 数据类型[] 数组名称 = new 数据类型[] {元素1,元素2 ,元素3,······} 
  3. 数组的定义 静态初始化 :格式2 数据类型[] 数组名称 = new 数据类型[] {元素1,元素2, 元素3,······]
  4. 数组的定义 静态初始化  特点:在定义数组的时候同时为数组确定了数据
  5. 数组的定义 静态初始化 使用场景:一旦确定了数据的具体值,我没就用这种方式存储批量数据
  6. 数组的定义 动态初始化 格式:数据类型[] 数组名称 = new 数据类型[长度]
  7. 数组的定义 动态初始化 特点:一开始值确定数组的类型和长度,不确定具体存入的数据值
  8. 数组的定义 动态初始化 使用场景:适合一开始不能确定具体数据的情况,先定数组,后赋值数据进去
  9. 数组的访问 格式 :数组名称[索引]
  10. 数组的访问 取值 :int data = arr[i]
  11. 数组的访问 赋值:arr[i] = 22 
  12. 数组的访问 长度:arr.length[]
  13. 数组的注意事项:什么类型的数组只能存放什么类型的数据; 数据类型[]  变量名称 可以写成 数据类型 变量名称[] ; 数组一旦定义出来,程序执行的过程中,长度、类型就被固定了
  14. 动态初始化数组的元素存在默认值:

数组的遍历

  1. 什么是遍历:一个一个的访问数据
  2. 为什么要遍历:业务开发中都需要用到,统计数据,搜索数
  3. 数组如何遍历:

数组的案例

  • 参见代码

数组的内存图

  • Java的内存分配 :方法区:放Class文件的 ; 栈内存:运行的方法,main方法,定义的变量 ; 堆内存:new出来的对象,都在堆内存中

数组使用的常见问题:

  1. 不要访问超过数组的最大索引,否则出现数组访问越界异常;
  2. 空指针异常问题:int[] arr = null;  

Debug工具的使用

  1. 找问题并解决:断点调试工具
  2. 基本使用步骤:打断点; 右键使用Debug使用; 控制一行一行的往下执行


Java方法:方法概述


方法是类或对象行为特征的抽象,方法是类或对象最重要的组成部分。但从功能上来看,方法完全类似于传统结构化程序设计里的函数。值得指出的是,Java里的方法不能独立存在,所有的方法都必须定义在类里。方法在逻辑上要么属于类,要么属于对象。

在面向对象编程语言里,类才是一等公民,整个系统由一个个的类组成。因此在Java语言里,方法不能独立存在,方法必须属于类或对象。

因此,如果需要定义方法,则只能在类体内定义,不能独立定义一个方法。一旦将一个方法定义在某个类的类体内,如果这个方法使用了static修饰,则这个方法属于这个类,否则这个方法属于这个类的实例。

因此Java里的方法不能独立存在,它必须属于一个类或一个对象,因此方法也不能像函数那样被独立执行,执行方法时必须使用类或对象来作为调用者,即所有方法都必须使用“类 . 方法”或“对象 . 方法”的形式来调用。这里可能产生一个问题:同一个类里不同方法之间相互调用时,不就可以直接调用吗?这里需要指出:同一个类的一个方法调用另外一个方法时,如果被调方法是普通方法,则默认使用this作为调用者;如果被调方法是静态方法,则默认使用类作为调用者。也就是说,表面上看起来某些方法可以被独立执行,大实际上还是使用this或者类作为调用者。
 

方法是什么

  • 方法是一种语法结构,他可以把一段代码封装成一个功能,以便重复调用。

方法的完整格式

package com.liu.define;

public class MethodDemo1 {
    public static void main(String[] args) {
        //目标:掌握定义方法的完整格式,高清楚使用方法的好处
        //需求:假如现在很多程序员都要进行2个整数的求和操作

        //1.李工程师
        int rs = sum(10,20);
        System.out.println(rs);

        //2. 张工程师
        int rs2 = sum(30,20);
        System.out.println(rs2);
    }

    public static int sum(int a,int b){
        int c = a + b;
        return c;
    }
}

示例:

方法如何执行?

  • 方法定义后,必须调用才可以跑起来,调用格式:方法名(···);

方法的调用流程:Debug工具

方法定义时几个注意点

  • 方法的修饰符:暂时都使用 public static 修饰
  • 方法申明了具体的返回值类型,内部必须使用 return 返回对应类型的数据
  • 形参列表可以有多个,甚至可以没有;如果有多个形参,多个形参必须使用 ”,“ 隔开,且不能给初始化值。
  • 方法不能独立定义,方法只能在类体里定义。
  • 从逻辑意义上来看,方法要么属于该类本身,要么属于该类的一个对象。
  • 永远不能独立执行方法,执行方法必须使用类或对象作为调用者。

使用方法的好处?

  • 提高了代码的复用性,提高了开发效率。

  • 让程序的逻辑更清晰


使用static修饰的方法属于这个类本身,使用static修饰的方法既可以使用类作为调用者来调用,也可以使用对象作为调用者来调用。但值得指出的是,因为使用static修饰的方法还是属于这个类的,因此使用该类的任何对象来调用来调用这个方法时将会得到相同的执行结果,这是由于底层依然是使用这些实例所属的类作为调用者。

没有static修饰的方法属于该类的对象,不属于这个类本身。因此没有static修饰的方法只能使用对象作为调用者来调用,不能使用类作为调用者来调用。使用不同对象作为调用者来调用同一个普通方法,可能得到不同的结果。


Java方法:方法定义的其他形式,常见问题


方法的其他形式

方法定义时:需要按照方法解决的实际业务需求,来设计合理的方法形式解决问题。


无参数,无返回值

package com.liu.define;

public class MethodDemo2 {
    public static void main(String[] args) {
        //目标:掌握按照方法解决的实际业务需求不同,设计成合理的方法形式来解决问题
        //需求:打印三行hello world
        printHeoolWorld();

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

        printHeoolWorld();
    }

    /**
     * 无参数,无返回值的方法
     */
    public static void printHeoolWorld(){
        for (int i = 0; i < 3; i++) {
            System.out.println("Hello World");
        }
    }
}

有参数,有返回值

package com.liu.define;

public class MethodDemo2 {
    public static void main(String[] args) {
        //目标:掌握按照方法解决的实际业务需求不同,设计成合理的方法形式来解决问题
        //需求:打印多行hello world
        printHeoolWorld(3);

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

        printHeoolWorld(6);
    }

    /**
     * 有参数,无返回值的方法
     */
    public static void printHeoolWorld(int n){
        for (int i = 0; i < n; i++) {
            System.out.println("Hello World");
        }
    }
}

注意事项

  • 如果方法不需要返回数据,返回值类型必须申明成void(无返回值申明),此时方法内部不可以使用return返回数据。
  • 方法如果不需要接收数据,则不需要定义形参,且调用方法时也不可以传数据给方法了
  • 没有参数,且没有返回值类型(void)申明方法,称为无参数、无返回值的方法,依次类推。

总结:

如果方法不需要接收数据处理,不需要返回数据,应该怎么办?要注意什么

  • 方法不需要接收数据,则形参列表可以不写;方法不需要返回数据,则申明返回值类型为void
  • 方法没有申明返回值类型(void),内部不能使用return返回数据
  • 方法如果没有形参列表,调用的时候则不能传入参数值,否则报错

方法使用时的常见问题:

  • 方法在类中的位置放前放后无所谓,但一个方法不能定义在另一个方法里面
  • 方法的返回值类型写void(无返回申明)时,方法内不能使用return返回数据,如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据
  • return语句的下面,不能编写代码,属于无效的代码,执行不到这儿
  • 方法不调用就不会执行,调用方法时,传给方法的数据,必须严格匹配方法的参数情况
  • 调用有返回值的方法有三种方式:1.可以定义变量接收结果 2. 或者直接输出调用 3. 甚至直接调用;
  • 调用无返回值的方法,只有一种:1. 只直接调用


Java方法:方法的案例


设计方法的技巧,主要关注三方面:

  • 方法是否需要接收数据进行处理?
  • 方法是否需要返回数据?
  • 方法要处理的业务(编程能力)

案例:计算1-n的和

需求:求1-n的和

分析:

1.方法是否需要接收数据进行处理?

需要接收n具体的值,因此形参声明为:int n

2.方法是否需要返回数据?

需要返回1-n的求和结果,因此返回值类型声明为int

3.方法内部的业务:

完成求1-n的和并返回

package com.liu.define;

public class MethodTest4 {
    public static void main(String[] args) {
        //目标:掌握设计方法的技巧
        int rs = add(5);
        System.out.println("1-5的和是:" + rs);

        int rs2 = add(100);
        System.out.println("1-100的求和是:" + rs2);

    }
    public static int add(int n){
        int sum = 0 ;
        for (int i = 1; i < n; i++) {
           // i = 1 2 3 ```` n
            sum +=i;
        }
        return sum;
    }
}

案例:判断一个整数是奇数还是偶数

需求:判断一个整数是奇数还是偶数,并把判断的结果输出来

分析:

1. 方法是否需要接收数据进行处理?

需要接收一个整数来判断,因此形参声明为:int number

2. 方法是否需要返回数据?

方法内部判断完后直接输出结果即可,无需返回,因此返回值类型声明为:void

3. 方法内部的业务:

通过if语句判断number是奇数还是偶数,并输出结果

package com.liu.define;

public class MethodTest4 {
    public static void main(String[] args) {
        //目标:掌握设计方法的技巧
        int rs = add(5);
        System.out.println("1-5的和是:" + rs);

        int rs2 = add(100);
        System.out.println("1-100的求和是:" + rs2);

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

        judge(10);
        judge(7);
    }

    public static void judge(int number){
        if (number % 2 == 0){
            System.out.println(number + "是一个偶数!");
        }else{
            System.out.println(number + "是一个奇数!");
        }
    }

    public static int add(int n){
        int sum = 0 ;
        for (int i = 1; i < n; i++) {
           // i = 1 2 3 ```` n
            sum +=i;
        }
        return sum;
    }
}

总结:

1.定义方法重点关注的是哪几点?

方法是否需要接收数据?也就是是否需要定义形参列表

方法是否需要返回数据?也就是是否需要声明具体的返回值类型

2. 如何设计方法完成1-n的求和?

3. 我没如何设计方法判断一个整数是奇数还是偶数的?


Java方法:方法在计算机中的执行


方法在计算机中的执行原理

  • 方法被调用的时候,是进入到栈内存中运行。

总结:

1.方法的运行区域在哪里?

栈内存

2. 栈有什么特点?方法为什么要在栈中运行自己

先进先出

保证一个方法调用完另一个方法后,可以回来


Java方法:方法参数传递


Java的参数传递机制都是:值传递

  • 所谓值传递:指的是在传输实参给方法的形参的时候,传输的是实参变量中存储的值的副本
  • 实参:在方法内部定义的变量
  • 形参:定义方法时 “(···)” 中所声明的的参数

基本类型的参数传递:

package com.liu.parameter;

public class MethodDemo1 {
    public static void main(String[] args) {
        //目标:理解方法的参数传递机制:值传递
        int a = 10;
        change(a); //change(10);
        System.out.println("main:" + a); //10
    }

    public static void  change(int a){
        System.out.println("change1:" + a); //10
        a= 20;
        System.out.println("change2:" + a); //20
    }
}

引用类型的参数传递

package com.liu.parameter;

public class MethodDemo2 {
    public static void main(String[] args) {
        //目标:理解引用类型的传递机制
        int[] arrs = new  int[]{10,10,30};
        change(arrs);
        System.out.println("main:"+ arrs[1]);
    }
    public  static  void change(int[] arrs){
        System.out.println("方法内1:" + arrs[1]);
        arrs[1] = 222;
        System.out.println("方法内2 :"+ arrs[1]);
    }
}

总结:基本类型和引用类型的参数在传递的时候有什么不同?

  • 都是值传递
  • 基本类型的参数传输传输存储的数据值
  • 引用类型的参数传输存储的地址值


Java方法:参数传递的案例


案例:打印int类型的数组内容

需求:输出一个int类型的数组内容,要求输出格式为:【11,22,33,44,55】

分析:1.方法是否需要接收数据进行处理?需要接收一个ingt类型的数组,因此形参声明为:int[] arr  2. 方法是否需要返回数据?方法内部直接输出数组内容即可,无需返回,因此返回值类型声明为:void   3. 方法内部的业务:遍历数组,并输出相应的内容

package com.liu.parameter;

public class MethodTest3 {
    public static void main(String[] args) {
        //目标:完成打印int类型的数组你内容
        int[] arr = new int[]{10,30,50,70};
        printArray(arr);
    }
    public static void printArray(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("]");
    }
}
package com.liu.parameter;

public class MethodTest3 {
    public static void main(String[] args) {
        //目标:完成打印int类型的数组你内容
        int[] arr = new int[]{10,30,50,70};
        printArray(arr);
    }
    public static void printArray(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.print(i == arr.length-1 ? arr[i]:arr[i] + ",");
        }
        System.out.println("]");
    }
}

package com.liu.parameter;

public class MethodTest3 {
    public static void main(String[] args) {
        //目标:完成打印int类型的数组你内容
        int[] arr = new int[]{10,30,50,70};
        printArray(arr);

        int[] arr2 = null;
        printArray(arr2);

        int[] arr3 ={};
        printArray(arr3);
    }

    public static void printArray(int[] arr){

        if (arr == null) {
            System.out.println(arr);//null
            return;//跳出当前方法
        }

        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.print(i == arr.length-1 ? arr[i]:arr[i] + ",");
        }
        System.out.println("]");
    }
}

案例:比较两个int类型的数组是否一样,返回true或者false

需求:如果两个int类型的数组,元素个数,对应位置的元素内容都是一样的则认为这2个数组是一模一样的

分析:1.方法是否需要接收数据进行处理?需要接收两个int类型的数组,因此,形参声明为:int[] arr1,int[] arr2    2. 方法是否需要返回数据? 方法判断完后需要返回:true、false,因此,返回值类型声明为boolean类型    3.方法内部的业务:判断两个数组内容是否一样。

package com.liu.parameter;

public class MethodTest4 {
    public static void main(String[] args) {
        //目标:完成判断两个类型的数组是否一样
//        int[] arr1 = null;
        int[] arr1 = {10,20,30,40};
        int[] arr2 ={10,20,30};
        System.out.println(equals(arr1,arr2));
    }

    public static boolean equals(int[] arr1,int[] arr2) {
        //1.判断啊arr1和arr2是否都是null
        if (arr1 == null && arr2 == null) {
            return true;//相等的
        }

        //2.判断arr1是null,或者arr2是null
        if (arr1 == null || arr2 == null) {
            return false;//不相等
        }
        //3. 判断2个数组传递长度是否一样,如果长度不一样直接返回false
        if (arr1.length != arr2.length) {
            return false; //不相等
        }

        //4. 两个数组的长度是一样的,接着比较它们的内容是否一样
        //arr1 = [10,20,30]
        //arr2 = [10,20,30]
        for (int i = 0; i < arr1.length; i++) {
            //判断当前位置2个数组的元素是否都一样,不一样直接返回false
            if (arr1[i] != arr2[i]) {
                return false; //不相等
            }
        }
        return true;//两个数组是一样的

    }
}


Java方法:递归方法


方法递归

一个方法体内调用它自身,被称为方法递归。方法递归包含了一种隐式的循环,它会重复执行某段代码,但这个重复执行无须循环控制。


Java方法:方法重载,return关键字


方法重载

  • 一个类中,出现多个方法的名称相同,但是它们的形参列表是不同的,那么这些方法就称为方法重载了。
package com.liu.overload;

public class MethodOverLoadDemo1 {
    public static void main(String[] args) {
        //目标:认识方法重载并掌握其应用场景
        test();
        test(100);

    }
    public static void  test(){
        System.out.println("==test1==");

    }
    public static  void test(int a){
        System.out.println("==test2==" +a);
    }
}

在Java程序中确定一个方法需要三个要素:

  • 调用者,也就是方法的所属者,既可以是类,也可以是对象。
  • 方法名:方法的标识。
  • 形参列表:当调用方法时,系统将会根据传入的实参列表匹配。

方法重载的要求就是两同一不同:

同一个类中方法名相同,参数列表不同。至于方法的其他部分,如方法返回值类型‘修饰符等,与方法重载没有任何关系。

方法重载的注意注意事项:

  • 一个类中,只要一些方法的名称相同、形参列表不同,那么它们就是方法重载了,其它的都不管(如:修饰符,返回值类型是否都无所谓)。
  • 形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。

方法重载的应用场景

  • 开发中我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很专业的

案例导学

开发武器系统,功能需求如下:

1. 可以默认发一枚武器

2. 可以指定地区发射一枚武器

3. 可以指定地区发射多枚武器

package com.liu.overload;

public class MethodTest2 {
    public static void main(String[] args) {
        //目标:掌握方法重载的应用场景
        fire();
        fire("米国",999);
    }

    public static void fire(){
        fire("岛国");
    }

    public static void fire(String country){
       fire(country,1);
    }

    public static void fire(String country,int number){
        System.out.println("发射了" + number + "枚武器给" + country);
    }
}

return关键字在方法中单独使用

  • return:可以用在无返回值的方法中,作用是:立即跳出并结束当前方法的执行

package com.liu.returnDemo;

public class ReturnDemo1 {
    public static void main(String[] args) {
        //目标:掌握return单独使用;
        //return:在无返回值方法中的使用,跳出并立即结束当前方法的执行
        System.out.println("程序开始...");
        chu(10,0);
        System.out.println("程序结束...");
    }

    public static void chu(int a,int b){
        if (b == 0){
            System.out.println("您的数据有问题,不能除0");
            return;//跳出并结束当前方法的执行
        }
        int c = a / b;

    }
}

return:跳出并立即结束所在方法的执行

break:跳出并结束当前所在循环的执行

continue:结束当前所在循环的当次继续,进入下一次执行


总结:方法


  1. 方法的作用:封装一段代码的语法结构,可以被重复调用,以此提高代码的复用性,提高开发效率,让程序逻辑更清晰
  2. 方法的完整定义格式:
  3. 方法的其他定义格式:如果方法中没有结果数据需要返回,返回值类型声明为:void
  4. 方法的调用:必须调用方法,方法才可以跑起来 ; 有返回值类型声明的方法的调用:(1)、赋值调用:定义变量接收方法的结果(2)、输出调用:放在输出语句中调用(3)、直接调用:方法还是会执行的,只是返回的结果我们不要了  ; 无返回值的方法调用:直接调用一下。
  5. 方法的注意事项:如果方法不需要返回数据,返回值类型必须申明成void(无返回值申明),此时方法内部不可以使用return返回数据。  方法如果不需要接收数据,则不需要定义形参,且调用方法时也不可以传数据给方法了。   没有参数,且没有返回值类型(void)申明方法,称为无参数、无返回值的方法,依次类推。
  6. 方法的参数传递机制:值传递  你传输实参给方法的形参,传输的不是实参本身,而是实参中存储的数据的值的一个副本 ; 无论是基本数据类型还是引用数据类型的参数,都是满足值的传递,基本类型的参数传输的是存储的数据,引用类型的参数传输的是存储的地址值。
  7. 方法重载:同一个类中,方法名称相同,形参列表必须不同,才是方法重载。
  8. 方法重载的好处:方法名相同标记是同一个功能,可读性好!形参列表不同,体现功能的差异话,这是专业设计,还可以提高开发效率。
  9. 识别方法重载的技巧:形参列表不同:形参个数,类型,顺序不同。不关心形参变量的名称:(int a, int b) ( int c, int d,int e )。。
  10. return:跳出并立即结束当前方法的执行。


Java案例:买飞机票


需求:

用户购买机票时,机票原价会按照淡季、旺季,头等舱还是经济舱的情况进行相应的优惠,优惠方案如下:5-10月为旺季,头等舱9折,经济舱8.5折11月份到来来年4月为淡季,头等舱7折,经济舱6.5折,请开发程序计算出用当前机票的优惠价。

分析:

1. 方法是否需要接收数据?需要接收机票原件、当前月份、舱位类型; 2. 方法是否需要返回数据?需要返回计算出的机票优惠价; 3. 方法内部:先使用if判断月份是旺季还是淡季,然后使用switch分支判断是头等舱还是经济舱

package com.liu;

public class Test1 {
    public static void main(String[] args) {
        //目标:完成买飞机票的案例
        double price = calculate(1000,8,"经济舱");
        System.out.println("优惠价是:" + price);

    }
    public static double calculate(double price,int month,String type) {
        //1.判断当前月份是淡季还是旺季
        if (month >= 5 && month <= 10) {
            //旺季
            //2. 判断舱位类型
            switch (type) {
                case "头等舱":
                    price *= 0.9;
                    break;
                case "经济舱":
                    price *= 0.85;
                    break;
            }
        } else {
            //淡季
            switch (type) {
                case "头等舱":
                    price *= 0.7;
                    break;
                case "经济舱":
                    price *= 0.65;
                    break;
            }
        }
        return price;
    }
}


总结:

1.遇到需要通过判断数据在哪个区间,来决定执行哪个业务,应该用什么实现?

应该使用 if 分支结构实现

2.遇到需要通过判断数据匹配哪个值,来决定执行哪个业务,应该什么实现?

应该是有switch分支结构实现


Java案例:开发验证码


需求:

开发一个程序,可以生成指定位数的验证码,可以是数字、大小写字母。

分析:

1. 方法是否需要接收数据?需要接收一个整数,控制生成验证码的位数。2. 方法是否需要返回数据?需要返回生成的验证码。3.方法内部的业务:使用for循环依次生成每位随机字符,并使用一个String类的变量把每个字符连接起来,最后返回该变量即可。

package com.liu;

import java.util.Random;

public class Test2 {
    public static void main(String[] args) {
        //目标:完成生成验证码
        System.out.println(createCode(5));
    }
    public static String createCode(int n){
        //1.定义一个for循环用于控制产生多少位随机字符
        Random r = new Random();
        //3.定义一个String类型的变量用于记住产生的每位随机字符
        String code = "";
        for (int i = 1; i <n ; i++) {
            //i = 1 2 3 4 5
            //2. 为每个位置生成一个随机字符,可能是数字,大小写字母。
            //思路:随机一个0 1 2 之间的数字出来,0代表随机一个数字字符,1、2代表随机大写字母、小写字母
           int type = r.nextInt(3);// 0 1 2
            switch (type){
                case 0:
                    //随机一个数字字符
                    //方便字符串拼接
                    code += r.nextInt(10); //0-9  code = code +8
                    break;
                case 1:
                    //随机一个大写字符 A 65   Z 65+25  (0-25)+65
                    char ch1 = (char) (r.nextInt(26)+65);
                    code += ch1;
                    break;
                case 2:
                    //随机一个小写字符 a 97   z 97+25  (0-25)+97
                    char ch2 = (char) (r.nextInt(26)+97);
                    code += ch2;
                    break;

            }

        }
        return code;
    }
}

 总结:

1.定义一个for循环,循环5次

2. 随机生成0 1 2 的数据,依次代表当前要生成的字符是:数字、大写字母、小写字母

3. 把0、1 、2 交给switch生成对应类型的随机字符

4. 在循环外定义一个String类型的变量用来连接生成的随机字符

5. 循环结束后,返回String类型的变量即是生成的随机验证码


Java案例:评委打分


需求:

在唱歌比赛中,可能有多名评委要给选手打分,分数是【0-100】之间的整数。选手最后得分为:去掉最高分、最低分后剩余分数的平均分,请编写程序能够录入多名评委的分数,并算出选手的最终得分

分析:

1、方法是否需要接收数据进行处理?需要接收评委的人数 2、方法是否需要返回数据?需要返回计算出的选手最终得分。3、方法内部的业务:定义数组,录入评委的分数存入到数组中区,接着,我们就需要遍历数组中的分数,计算出总分,并找出最高峰、最低分、最后按照这些数据算出选手最终得分并返回即可。

package com.liu;

import java.util.Scanner;

public class Test3 {
    public static void main(String[] args) {
        //目标:需要完成评委打分案例
        System.out.println("当前选手得分是" + getAverageScore(6));
    }
    public static double getAverageScore(int number){
        //1、定义一个动态初始化的数组,负责后期存入评委的的打分
        int[] scores = new int[number];//6
        //scores = {0,0,0,0,0,0}

        //2、遍历数组的每个位置,依次录入评委的分数
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < scores.length; i++) {
            // i = 0 1 2 3 4 5
            System.out.println("请您录入第"+(i +1)+"个评委的分数:");
            int score = sc.nextInt();
            scores[i] = score;
        }
        //3、从数组中国计算出总分,找出最高分、最低分
        int sum = 0;
        int max = scores[0]; //求最大值的
        int min = scores[0];//求最小值的

        //遍历数组找出这些数据的
        for (int i = 0; i < scores.length; i++) {
            //i= 0 1 2 3 4 5
            int score =  scores[i];
            //求和
            sum += score;
            //求最大值
            if (score > max){
                max = score;
            }
            //最小值
            if (score < min){
                min = score;
            }

        }
        //4、计算出平均分并返回
       return 1.0 * (sum - max -min) / (number - 2);

    }
}

总结:

如何实现评委打分案例?

答:

1、定义一个动态初始化的数组,用于录入评委打分

2、提前定义三个变量用来记住数组中的最大值、最小值、总和

3、遍历数组中的每个数据,依次找出最大值、最小值、总和

4、遍历结束后,按照计算规则算出选手的最终得分,并返回即可


Java案例:数字加密


需求:

某系统的数字密码是一个四位数,如1983,为了安全,需要加密后再传输,加密规则是:堆密码中的每位数,都加5,再对10求余,最后将所有数字顺序反转,得到一串加密后的新数,请设计出满足本需求的加密程序!

分析:

1、方法是否需要接收数据进行处理?需要接收四位数字密码,进行加密处理。2、方法是否需要返回数据?需要返回加密后的结果。3、方法内部的业务:将四位数字密码拆分成一个一个的数字,存入到数字中,遍历数组中的每个数字,按照题目需求进行加密!最后,再把加密后的数字拼起来返回即可!

package com.liu;

public class Test4 {
    public static void main(String[] args) {
        //目标:完成数字加密程序的开发
        System.out.println("加密后的结果是:" + encrypt(1983));
    }

    public static String encrypt(int number){
        //number = 1983
        //1、把这个密码拆分成一个一个的数字,才可以对其进行加密
        int[] numbers = split(number);
        // number = [1,9,8,3]

        //2、遍历数组中的每个数字,对其进行加密处理
        for (int i = 0; i < numbers.length; i++) {
            // i = 0 1 2 3
            numbers[i] = (numbers[i] + 5) % 10;
        }
        //number = [6,4,3,8]

        //3、对数组反转,把对数组进行反转的操作交给一个独立的方法来完成
        reverse(numbers);
        //numbers = [8,3,4,6]

        //4、把加密的数字拼接起来来作为加密后的结果返回即可。
        String data = "";
        for (int i = 0; i < numbers.length; i++) {
            data += numbers[i];
        }
        return data;
    }

    public static void reverse(int[] numbers) {
        //反转数组
        // numbers = [6,4,3,8]
        //           i      j
        for (int i = 0,j = numbers.length - 1; i < j;i++,j--) {
            //交换i和j位置处的值
            //1、把后一个位置处的值交给一个临时变量先存起来
            int temp = numbers[j];
            //2、把前一个位置处的值赋值给后一个位置处
            numbers[j] = numbers[i];
            //3、把后一个位置处原来的值(由临时变量记住着)赋值给前一个位置
            numbers[i] = temp;

        }
    }

    public static int[] split(int number) {
        //number = 1983
        int[] numbers = new int[4];
        numbers[0] =  number / 1000;
        numbers[1] = (number / 100) % 10;
        numbers[2] = (number / 10) % 10;
        numbers[3] = number % 10;
        return numbers;
    }
}

总结:

1、回顾数组元素的反转、交换是如何完成的?

反转数组,就是对数组中的元素,按照前后位置,依次交换数字据。

2、如果一个方法李要做的事比较多,我们再开发中一般会怎么做?

一般会把多个事拆成多个方法去完成,也就是独立功能独立成一个方法。


Java案例:数组拷贝


需求:

请把一个整型数组,例如存了数据:11,22,33,拷贝成一个一模一样的新数组出来。

分析:

1、方法是否需要接收数据进行处理?需要接收一个整型数组(原数组)。2、方法是否需要返回数据?需要返回一个新的、一模一样的整型数组。3、方法内部的业务:创建一个长度一样的整型数组做为新数组,并把原数组的元素对应位置赋值给新数组,最终返回新数组即可。

package com.liu;

public class Test5 {
    public static void main(String[] args) {
        //目标:掌握数组拷贝
        int[] arr = {11,22,33};
        int[] arr2 = copy(arr);
        printArry(arr2);

        //注意:这个不是拷贝数值,叫把数组变量赋值给另一个数组变量
//        int[] arr3 = arr;
//        arr3[1] = 666;
//        System.out.println(arr[1]); //666

//        arr2[1] = 666;
//        System.out.println(arr[1]); //22

    }

    public static void printArry(int[] arr){
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(i == arr.length - 1 ? arr[i] : arr[i] + ",");
        }
        System.out.println("]");
    }

    public static  int[] copy(int[] arr){
        //arr = [11,22,33]
        //       0   1  2

        //1、创建一个长度一样的整型数组出来
        int[] arr2 = new int[arr.length];
        //arr2 = [0,0,0]
        //        0 1 2

        // 2、把原数组的元素值对应位置赋值给新数组
        for (int i = 0; i < arr.length; i++) {
            // i = 0 1 2
            arr2[i] = arr[i];
        }
        return arr2;




    }
}

总结:

数组的拷贝是什么意思?

答:创建一个与原数组一模一样的数组


Java案例:抢红包


需求:

一个大V直播时发起了抢红包活到,分别有:9、666、188、520、99999五个红包。请模拟粉丝来抽奖,按照先来先得,随机抽取,抽完即止,注意:一个红包只能被抽一次,先抽后抽哪一个红包是随机的,示例如下(不一定是下面得顺序):

分析:

1、方法是否需要接收数据进行处理?需要接收一个数组,里面是5个金额,表示5个红包。2、方法是否需要返回数据?不需。3、方法内部完成本需求的是一种方案:写个for循环控制抽奖5次,每次抽奖,都从数组中随机找出一个金额,如果该金额不是0,则代表抽奖中,接着用0替换该位置处的金额,然后继续下一个粉丝的抽奖;如果抽中的金额发现是0,代表该位置处的红包之前被别人抽走了,则重新从数组中随机找出一个金额,继续判断!直至抽中的金额不是0 !

package com.liu;

import java.util.Random;
import java.util.Scanner;

public class Test6 {
    public static void main(String[] args) {
        //目标:抢红包的案例开发
        int[] moneys = {9,666,188,520,99999};
        start(moneys);
    }

    public static void start(int[] moneys){
        //moneys = [9,666,188,520,99999]
        //          0  1   2   3    4

        Scanner sc = new Scanner(System.in);
        Random r = new Random();
        //1、定义一个for循环,控制抽奖五次
        for (int i = 1; i <= 5; i++) {
            //2、提示粉丝抽奖
            System.out.println("请您输入任意内容进行抽奖:");
            sc.next(); //等待用户输入内容,按了回车才往下走的

            //3、为当前粉丝找一个随机的红包出来
            while (true) {
                int index = r.nextInt(moneys.length); //0-4
                int money = moneys[index];

                //4、判断这个红包是否不为0
                if (money != 0){
                    System.out.println("恭喜您,您抽中了红包:" + money);
                    moneys[index] = 0;
                    break;//结束这次抽奖
                }
            }
        }
        System.out.println("活到结束...");
    }
}


Java案例:找素数的三种做法


需求:

判断101-200之间有多少个素数,并输出所有素数

(除了1和它本身以外,不能被其他整数整除,就叫素数。比如:3、7就是素数,而9、21等等不是素数)。

分析:

1、方法是否需要接收数据进行处理?需要接收101以及200,以便找该区间中的素数。2、方法是否需要返回数据?需要返回找到的素数个数。3、方法内部的实现逻辑:使用for循环来产生如101到200之间的每个数;每拿到一个数,判断该数是否是素数;判断规则是:从2开始遍历到该数的一半的数据,看是否有数据可以整除它,有则不是素数,没有则是素数;根据判定的结果来决定是否输出这个数据(是素数则输出);最后还需要统计素数的个数并返回。

package com.liu;

public class Test7 {
    public static void main(String[] args) {
        //目标:完成找素数
        System.out.println("当前素数的个数是:" + search(101, 200));
    }

    public static int search(int start,int end){
        int count = 0;
        //start = 101   end = 200
        //1、定义一个for循环找到101到200之间的每个数据
        for (int i = start; i <= end ; i++) {
            // i = 101 102 103  ... 199 200

            //信号位思想
            boolean flag = true;//假设的意思,默认认为当前i记住的数都是素数

            //2、判断当前i记住的这个数据是否是素数
            for (int j = 2; j < i / 2; j++) {
                if (i % j == 0){
                    // i 当前记住的这个数据不是素数了
                    flag = false;
                    break;
                }
            }

            //3. 根据判定的结果决定是否输出i当前记住的数据,是素数才输出展示。
            if (flag){
                System.out.println(i);
                count++;
            }

        }
        return count;
    }
}

总结:

如何确定出该数是素数的,具体如何实现?

答:定义了flag标记位。 遍历2到该数的一半的数据去判断是否有整数的数据,有则改变flag标记的状态。 最终通过flag的状态判断是否是素数

package com.liu;

public class Test7_2 {
    public static void main(String[] args) {
        //目标:完成找素数
        //1、定义一个for循环找到101到200之间的每个数据
        int count = 0;

        OUT://为外部循环指定标签
        for (int i =101;i <= 200 ; i++) {
            // i = 101 102 103  ... 199 200

            //2、拦截判断该数是否素数
            for (int j = 2; j < i / 2; j++) {
                if (i % j == 0){
                    //这个数肯定不是素数,不能打印
                    continue OUT;//结束外部循环的当次执行

                }
            }

            count++;
            System.out.println(i);

            }
        System.out.println("个数是:" + count);
    }
}
package com.liu;

public class Test7_3 {
    public static void main(String[] args) {
        for (int i = 101; i < 200 ; i++) {
            // i = 101 102 103 ... 199 200
            //i遍历到当前数据是否是素数,是则输出,不是则不输出
            if(check(i)){
                System.out.println(i);
            }
        }
    }
    
    public static  boolean check(int data){
        for (int i = 2; i <= data / 2 ; i++) {
            if (data % i == 0){
                return false;//不是素数
            }
        }
        return true;
    }
}


Java案例:打印乘法表


package com.liu;

public class Test8 {
    public static void main(String[] args) {
        //1、定义一个for循环控制打印多少行
        for (int i = 1; i < 9; i++) {
            // i = 1 2 3 4 5 6 7 8 9
            //2、定义一个内部循环控制每行打印多少次
            for (int j = 1; j <= i ; j++) {
                // i行   j列
                System.out.print(j + "X" + i + "=" +(i*j) + "\t");
            }
            System.out.println(); //换行

        }
    }
}


Java案例:打印三角形


package com.liu;

/**
 *     *
 *    ***
 *   *****
 *  *******
 *
 *  本质:计算机本质只能打印行,所以按照换行思考
 *  先找规律,再写程序
 *
 *  行(i)   先打空格(n-i)      再打星星(2i-1)    换行
 *  1          3                 1
 *  2          2                 3
 *  3          1                 5
 *  4          0                 7
 *
 */

public class Test9 {
    public static void main(String[] args) {
        //1、先定义一个循环控制打印多少行
        int n = 4;
        for (int i = 1; i <=n ; i++) {
            //2、控制打印多少个空格
            for (int j = 1; j <= (n-i) ; j++) {
                System.out.print(" ");
            }

            //3、控制打印多少个星星
            for (int j = 1; j <= (2*i - 1) ; j++) {
                System.out.print("*");
            }

            //4、换行
            System.out.println();
        }

    }
}


Java案例:模拟双色求[拓展案例] (业务分析、用户投注一组号码)


双色球业务介绍:

总体实现步骤介绍:

第一步:用户投注一组号码

注意:6个红球号码的范围是 1 - 33 之间且不能重复;1个篮球号码的范围在:1-16之间

package com.liu;

import java.util.Scanner;

public class Test10 {
    public static void main(String[] args) {
        //目标:完成双色球系统的开发
        int[] userNumbers = userSelectNumber();
        printArray(userNumbers);
    }

    public static void printArray(int[] arr){
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(i == arr.length-1 ? arr[i] :arr[i]+",");
        }
        System.out.println("]");
    }

    //1、设计一个方法,用于投注一组号码,并返回(前6个是红球号码,后1个是蓝球号码)
    public static int[] userSelectNumber(){
        //2、创建一个整型数组,用于存储用户投注的7个号码(前6个是红球号码,最后1个是篮球号码)
        int[] numbers = new int[7];
        //numbers = [0,0,0,0,0,0,0]
        //           0 1 2 3 4 5 6

        Scanner sc = new Scanner(System.in);

        //3、遍历前6个位置,让用户一次投注6好红球号码,存入
        for (int i = 0; i < numbers.length-1; i++) {
            //i = 0 1 2 3 4 5

            while (true) {
                //4、开始让用户为当前位置投入一个红球号码(1-33之间,不能重复)
                System.out.println("请您输入第"+(i+1)+"个红球号码(1-33之间,不能重复)");
                int number = sc.nextInt();

                //5、判断用户输入的红球是否在1-33之间
                if (number < 1 || number > 33){
                    System.out.println("对不起,您输入的红球号码不在1-33之间,请确认");
                }else {
                    //号码在1-33之间,接着继续判断这个号码是否重复,部重复才可以使用
                    if(exist(numbers,number)){
                        //number当前这个红球号码是重复了
                        System.out.println("对不起,您当前输入的红球号码前面选择过了,重复了,请缺人!");
                    }else {
                        //number记住的这个号码没有重复了,就可以使用了
                        numbers[i] = number;
                        break;//结束当前死循环
                    }
                }
            }
        }

        //6、投注最后一个篮球号码
        while (true) {
            System.out.println("请您输入最后一个蓝球号码(1-16):");
            int number = sc.nextInt();
            if (number < 1 || number> 16){
                System.out.println("对不起,您输入的蓝球号码范围不对!");
            }else {
                numbers[6] = number;
                break;//蓝球号码录入成功,结束循环
            }
        }
        return numbers;
    }

    private static boolean exist(int[] numbers, int number) {
        //需求:判断number这个数是否在numbers数组中存在
        //numbers = [12,25,18,0,0,0,0]
        //number = 25
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == 0){
                break;
            }
            if (numbers[i] == number){
                return true;
            }
        }
        return false;
    }
}

总结:

本次案例是如何去保证用户投注6个红球号码不重复的?

答:每次用户投注一个红球号码后,都去调用一个方法来判断这个号码是否已经选择过,如果选择过,让用户重新选号。


Java案例:模拟双色求[拓展案例] (随机生成一组中奖号码)


第二步:随机一组中奖号码出来

注意:6个红球号码的范围是1-32之间,且不能重复;1个蓝球号码的范围在:1-16之间

package com.liu;

import java.util.Random;
import java.util.Scanner;

public class Test10 {
    public static void main(String[] args) {
        //目标:完成双色球系统的开发
        int[] userNumbers = userSelectNumber();
        printArray(userNumbers);

        int[] luckNumbers = createLuckNumbers();
        printArray(luckNumbers);
    }

    public static void printArray(int[] arr){
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(i == arr.length-1 ? arr[i] :arr[i]+",");
        }
        System.out.println("]");
    }

    //1、设计一个方法,用于投注一组号码,并返回(前6个是红球号码,后1个是蓝球号码)
    public static int[] userSelectNumber(){
        //2、创建一个整型数组,用于存储用户投注的7个号码(前6个是红球号码,最后1个是篮球号码)
        int[] numbers = new int[7];
        //numbers = [0,0,0,0,0,0,0]
        //           0 1 2 3 4 5 6

        Scanner sc = new Scanner(System.in);

        //3、遍历前6个位置,让用户一次投注6好红球号码,存入
        for (int i = 0; i < numbers.length-1; i++) {
            //i = 0 1 2 3 4 5

            while (true) {
                //4、开始让用户为当前位置投入一个红球号码(1-33之间,不能重复)
                System.out.println("请您输入第"+(i+1)+"个红球号码(1-33之间,不能重复)");
                int number = sc.nextInt();

                //5、判断用户输入的红球是否在1-33之间
                if (number < 1 || number > 33){
                    System.out.println("对不起,您输入的红球号码不在1-33之间,请确认");
                }else {
                    //号码在1-33之间,接着继续判断这个号码是否重复,部重复才可以使用
                    if(exist(numbers,number)){
                        //number当前这个红球号码是重复了
                        System.out.println("对不起,您当前输入的红球号码前面选择过了,重复了,请缺人!");
                    }else {
                        //number记住的这个号码没有重复了,就可以使用了
                        numbers[i] = number;
                        break;//结束当前死循环
                    }
                }
            }
        }

        //6、投注最后一个篮球号码
        while (true) {
            System.out.println("请您输入最后一个蓝球号码(1-16):");
            int number = sc.nextInt();
            if (number < 1 || number> 16){
                System.out.println("对不起,您输入的蓝球号码范围不对!");
            }else {
                numbers[6] = number;
                break;//蓝球号码录入成功,结束循环
            }
        }
        return numbers;
    }

    private static boolean exist(int[] numbers, int number) {
        //需求:判断number这个数是否在numbers数组中存在
        //numbers = [12,25,18,0,0,0,0]
        //number = 25
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == 0){
                break;
            }
            if (numbers[i] == number){
                return true;
            }
        }
        return false;
    }

    //2、设计一个方法,随机一组中奖号码出来(6个红球号码,1个蓝球号码)
    public static int[] createLuckNumbers(){
        //1、创建一个整型数组用于存储7个号码
        int[] numbers = new int[7];

        Random r = new Random();
        //2、遍历前6个位置处,依次随机一个红球号码存入(1-33不重复)
        for (int i = 0; i < numbers.length - 1; i++) {
            // i = 0 1 2 3 4 5

            while (true) {
                //3、为当前这个位置随机一个红球号码出来存入:1-33  ==> (0,32)+1
                int number = r.nextInt(33)+1;

                //4、判断这个号码是否之前出现过(红球号码不能重复)
                if(!exist(numbers,number)) {
                    //number不重复
                    numbers[i] = number;
                    break; //结束死循环,代表找到了当前这个位置的一个不重复的红球号码了
                }
            }
        }
        //3、录入一个蓝球号码
        numbers[6] = r.nextInt(16)+1;
        return numbers;
    }

}

总结:

本次案例中是如何去保证随机的6个中奖的红球号码不重复的?

答:每次随机一个1-33之间俺的红球号码后,都去调用一个方法来判断这个号码是否已经出现过,如果出现过,让用户重新选号


Java案例:模拟双色求[拓展案例](判断中奖情况)


第三步:判断用户是否中奖

package com.liu;

import java.util.Random;
import java.util.Scanner;

public class Test10 {
    public static void main(String[] args) {
        //目标:完成双色球系统的开发
        int[] userNumbers = userSelectNumber();
        System.out.println("投注的号码");
        printArray(userNumbers);

        int[] luckNumbers = createLuckNumbers();
        System.out.println("中奖的号码");
        printArray(luckNumbers);

        judge(userNumbers,luckNumbers);
    }

    public static void printArray(int[] arr){
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(i == arr.length-1 ? arr[i] :arr[i]+",");
        }
        System.out.println("]");
    }

    //1、设计一个方法,用于投注一组号码,并返回(前6个是红球号码,后1个是蓝球号码)
    public static int[] userSelectNumber(){
        //2、创建一个整型数组,用于存储用户投注的7个号码(前6个是红球号码,最后1个是篮球号码)
        int[] numbers = new int[7];
        //numbers = [0,0,0,0,0,0,0]
        //           0 1 2 3 4 5 6

        Scanner sc = new Scanner(System.in);

        //3、遍历前6个位置,让用户一次投注6好红球号码,存入
        for (int i = 0; i < numbers.length-1; i++) {
            //i = 0 1 2 3 4 5

            while (true) {
                //4、开始让用户为当前位置投入一个红球号码(1-33之间,不能重复)
                System.out.println("请您输入第"+(i+1)+"个红球号码(1-33之间,不能重复)");
                int number = sc.nextInt();

                //5、判断用户输入的红球是否在1-33之间
                if (number < 1 || number > 33){
                    System.out.println("对不起,您输入的红球号码不在1-33之间,请确认");
                }else {
                    //号码在1-33之间,接着继续判断这个号码是否重复,部重复才可以使用
                    if(exist(numbers,number)){
                        //number当前这个红球号码是重复了
                        System.out.println("对不起,您当前输入的红球号码前面选择过了,重复了,请缺人!");
                    }else {
                        //number记住的这个号码没有重复了,就可以使用了
                        numbers[i] = number;
                        break;//结束当前死循环
                    }
                }
            }
        }

        //6、投注最后一个篮球号码
        while (true) {
            System.out.println("请您输入最后一个蓝球号码(1-16):");
            int number = sc.nextInt();
            if (number < 1 || number> 16){
                System.out.println("对不起,您输入的蓝球号码范围不对!");
            }else {
                numbers[6] = number;
                break;//蓝球号码录入成功,结束循环
            }
        }
        return numbers;
    }

    private static boolean exist(int[] numbers, int number) {
        //需求:判断number这个数是否在numbers数组中存在
        //numbers = [12,25,18,0,0,0,0]
        //number = 25
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == 0){
                break;
            }
            if (numbers[i] == number){
                return true;
            }
        }
        return false;
    }

    //2、设计一个方法,随机一组中奖号码出来(6个红球号码,1个蓝球号码)
    public static int[] createLuckNumbers(){
        //1、创建一个整型数组用于存储7个号码
        int[] numbers = new int[7];

        Random r = new Random();
        //2、遍历前6个位置处,依次随机一个红球号码存入(1-33不重复)
        for (int i = 0; i < numbers.length - 1; i++) {
            // i = 0 1 2 3 4 5

            while (true) {
                //3、为当前这个位置随机一个红球号码出来存入:1-33  ==> (0,32)+1
                int number = r.nextInt(33)+1;

                //4、判断这个号码是否之前出现过(红球号码不能重复)
                if(!exist(numbers,number)) {
                    //number不重复
                    numbers[i] = number;
                    break; //结束死循环,代表找到了当前这个位置的一个不重复的红球号码了
                }
            }
        }
        //3、录入一个蓝球号码
        numbers[6] = r.nextInt(16)+1;
        return numbers;
    }

    //3、设计一个方法用于判断用户的中奖情况
    public static void judge(int[] userNumbers,int[] luckNumbers){
        //userNumber = [12,14,16,18,23,26,8]
        //userNumber = [16,17,18,19,26,32,8]

        //2、分别定义2个变量用于记住红球命中几个以及蓝球命中了几个
        int redCount = 0;
        int blueCout = 0;

        //先判断红球命中的数量
        //遍历用户投注的号码的前6 个红球
        for (int i = 0; i < userNumbers.length; i++) {
            //userNumber[i]
            //开始遍历中奖号码的前6个红球号码,看用户当前选择的这个号码是否命中了
            for (int j = 0; j < luckNumbers.length; j++) {
                if (userNumbers[i] == luckNumbers[j]){
                    redCount++;
                    break;
                }
            }
        }
        //3、判断蓝球是否命中了
        blueCout = userNumbers[6] == luckNumbers[6] ? 1:0;

        System.out.println("您命中的红球数量是:" + redCount);
        System.out.println("您命中的蓝球数量是:" + blueCout);

        //4、判断中奖详情,并输出结果
        if (redCount == 6 && blueCout ==1){
            System.out.println("恭喜您,中奖1000万,可以开始享受人生了~");
        }else if (redCount == 6 && blueCout == 0){
            System.out.println("恭喜您,中奖500万,可以稍微开始享受人生了~");
        }else if (redCount == 5 && blueCout ==1){
            System.out.println("恭喜您,中奖3000元~");
        }else if (redCount == 5 && blueCout == 0 || redCount == 4 && blueCout == 1){
            System.out.println("恭喜您,中奖200元~");
        }else if (redCount == 4 && blueCout == 0 || redCount == 3 && blueCout == 1){
            System.out.println("恭喜您,中奖10元~");
        }else if (redCount < 3 && blueCout == 1 ) {
            System.out.println("恭喜您,中奖5元~");
        }else {
            System.out.println("感谢参与");
        }
    }
}

总结:

如何统计用户投注的红球的命中数量的?

遍历用户选择的每个红球号码,每遍历一个红球号码时,都去遍历中奖号码数组中的全部红球号码,看当前选的红球号码是否在中奖号码中存在,存在则红球命中数量加1。


面向对象基础:入门


面向对象编程快速入门:

Java是面向对象的程序设计语言,Java语言提供了定义类、成员变量、方法等最基本的功能。类可被认为是一种自定义的数据类型,可以使用类来定义变量,所有使用类定义的变量都是引用变量,它们将会引用到类的对象。类用于描述客观世界里的某以类对象的共同特征,而对象则是类的具体存在,Java程序使用类的构造器来创建该类的对象。

Java也支持面向对象的三大特征:封装、继承和多态,Java提供了private、protected和public三个访问控制修饰符来实现良好的封装,提供了extends关键字来让子类继承父类,子类继承父类就可以继承到父类的成员变量和方法,如果访问控制运行,子类实例可以直接调用父类里定义的方法。继承是实现类复用的重要手段,除此之外,也可通过组合关系来实现这种复用,从某种程度上来看,继承和组合具有相同的功能。使用继承关系来实现复用时,子类对象可以直接赋给父类变量,这个变量具有多态性,编程更加灵活;而利用组合关系来实现复用时,则不具备这种灵活性。

构造器用于对类实例进行初始化操作,构造器支持重载,如果多个重载的构造器里包含了相同的初始化代码,则可以把这些初始化代码放置在普通初始化块里完成,初始化块总在构造器执行之前被调用。除此之外,Java还提供了一种静态初始化块,静态初始化块用于初始化类,在类初始化阶段被执行。如果继承数里的某一个类需要被初始化时,系统将会同时初始化该类的所有父类。

Java是面向对象的程序设计语言,类是面向对象的重要内容,可以把类当成一种自定义类型,可以使用类来定义变量,这种类型的变量统称为引用变量。也就是说,所有类是引用类型。

计算机是用来处理数据的

package com.liu.object;

public class Student {
    String name;
    double chinese;
    double math;

    public void  printTotalScore(){
        System.out.println(name + "的总成绩是:" + (chinese + math));
    }

    public void  printAverageScore(){
        System.out.println(name + "的平均成绩是:" + (chinese + math)/2.0);
    }
}

package com.liu.object;

public class Test {
    public static void main(String[] args) {
        //目标:面向对象编程快速入门
        //1、创建一个学生对象,封装波妞的数据
        Student s1 = new Student();
        s1.name = "波妞";
        s1.chinese = 100;
        s1.math = 100;
        s1.printTotalScore();
        s1.printAverageScore();

        //2、再创建一个学生对象,封装波仔的数据
        Student s2 = new Student();
        s2.name = "波仔";
        s2.chinese = 59;
        s2.math = 100;
        s2.printTotalScore();
        s2.printAverageScore();
    }
}

面向对象的程序设计过程中有两个重要概念:类(class)和对象(object,也被称为实例,instance),其中类是某一批对象的抽象,可以把类理解成某种概念:对象才是一个具体存在的实体,从这个意义上来看,日常所说的人,其实都是人的实例,而不是人类。

Java语言是面向对象的程序设计语言,类和对象是面向对象的核心。Java语言提供了对创建类和创建对象简单的语法支持。

Java语言里定义类的简单语法如下:

[修饰符] calss 类名 {

零个到多个构造器定义 . . .

零个到多个成员变量 . . .

零个到多个方法 .  . . }

在上面的语法格式中,修饰符可以是public、final、abstract,或者完全省略这三个修饰符,类名只要是一个合法的标识符即可,但这仅仅满足的是Java的语法要求;如果从程序的可读性方面来看,Java类名必须是由一个或多个有意义的单词连缀而成的,每个单词首字母大写,其他字母全部小写,单词与单词之间不要使用任何分隔符。

对一个类定义而言,可以包含三种最常见的成员:构造器、成员变量和方法,三种成员都可以定义零个或多个,如果三种成员都只定义零个,就是定义了一个空类,这没有太大的实际意义。

类里各成员之间的定义顺序没有任何影响,各成员之间可以相互调用,但需要指出的是,static修饰的成员不能访问没有static修饰的成员。

成员变量用于定义该类或该类的实例所包含的状态数据,方法则用于定义该类或该类的实例的行为特征或者功能实现。构造器用于构造该类的实例,Java语言通过new关键字来调用构造器,从而返回该类的实例。

构造器是一个类创建对象的根本途径,如果一个类没有构造器,这个类通常无法创建实例。因此,Java程序员为一个类提供了构造器,系统将不再为该类提供构造器。

面向对象编程的快速入门

开发一个一个的对象,把数据交给对象,再调用对象的方法来完成对数据的处理。

定义方法的语法格式如下:

[修饰符] 方法返回值类型 方法名(形参列表)

{

//由零条到多条可执行语句组成的方法体

}

对定义方法语法格式的详细说明如下:

1、修饰符:修饰符可以省略,也可以是public、proteced、private、static、final、abstract,其中public、protected、private三个最多只能出现其中之一;abstract和final最多只能出现其中之一,它们可以与static组合起来修饰方法。

2、方法返回值类型:返回值类型可以是Java语言允许的任何数据类型,包括基本类型和引用类型:如果声明了方法返回值类型,则方法体内必须有一个有效的return语句,该语句返回一个变量或一个表达式,这个变量或者表达式的类型必须与此处声明的类型匹配。除此之外,如果一个方法没有返回值,则必须使用void来声明没有返回值。

3、方法名:方法名的命名规则与成员变量的命名规则基本相同,但由于方法用于描述该类或该类的实例的行为特征或功能实现,因此通常建议方法名以英文动词开头。

4、形参列表:形参列表用于定义该方法可以接受的参数,形参列表由零组到多组“参数类型  形参名”组合而成,多组参数之间以英文(,)隔开,形参类型和形参名之间以空格隔开。一旦在定义方法是指定了形参列表,则调用该方法时必须传入对应的参数值——谁调用方法,谁负责为形参赋值。

方法体里多条可执行性语句之间有严格的执行顺序,排在方法体前面的语句总是先执行,排在方法体后面的语句总是后执行。

static是一个特殊的关键字,它可用于修饰方法、成员变量等成员。static修饰的成员表面它属于这个类本身,而不属于该类的单个实例,因为通常把static修饰的成员变量和方法也称类变量、类方法。不使用static修饰的普通方法、成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用static修饰的成员变量和方法也称为实例变量、实例方法。

由于static的英文直译就是静态的意思,因此有时也把static修饰的成员变量和方法称为静态变量和静态方法,把不使用static修饰的成员变量和方法称为非静态变量和非静态方法。静态成员不能直接访问非静态成员


面向对象基础:深刻认识面向对象


面向对象编程的好处?

万物皆对象!

更加符合人类思维习惯,编程更简单、更直观

程序中的对象到底是个啥?

对象本质上是一种特殊的数据结构

对象是用类new出来的,有了类就可以创建出对象

例:

对象是怎么出来的?

class也就是类,也称为对象的设计图(或者对象的模板)。

祖师爷认为万物皆对象,谁的数据谁处理。

创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例。


面向对象基础:对象在计算机中的执行原理,类与对象注意事项


多个对象在计算机中的执行原理

对象在计算机中执行原理是怎么回事?

Student s1 = new Student();

每次new  Student(),就是在堆内存中开辟一块内存区域代表一个学生对象。

s1变量里面记住的是学生对象的地址。

如何识别引用类型的变量?

Student s1 = new Student();

s1变量中存储的是对象的地址,因此变量s1也称为引用类型的变量

类和对象的一些注意事项

package com.liu.object;

public class Test2 {
    public static void main(String[] args) {
        //目标:掌握类与对象的一些注意事项

        //成员变量存在默认值
        Student s = new Student();
        System.out.println(s.name);
        System.out.println(s.chinese);
        System.out.println(s.math);

        //多个变量指向同一个对象就会相互影响
        Student s1 = new Student();
        s1.name = "张三";
        Student s2 = s1;
        s2.name = "李四";
        System.out.println(s1.name);

       
    }
}

注意:

当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的 “垃圾”。

Java存在自动垃圾回收机制,会自动清楚掉垃圾对象,程序员不用操心。


面向对象基础:this关键字


Java提供了一个this关键字,this关键字总是指向调用该方法的对象。根据this出现位置的不同,this作为对象的默认引用有两种情形:构造器中引用该构造器正在初始化的对象; 在方法中引用调用该方法的对象。

this关键字最大的作用就是让类中一个方法,访问该类的另一个方法或实例变量。

大部分时候,一个方法访问该类中定义的其他方法、成员变量时加不加this前缀的效果是完全一样的。

this是什么

this就是一个变量,可以用在方法中,用来拿到当前对象。

哪个对象调用方法,this就指向哪个对象,也就是拿到哪个对象。

package com.liu.thisdemo;

public class Student {
    public void printThis(){
        System.out.println(this);
    }
}
package com.liu.thisdemo;

public class Test {
    public static void main(String[] args) {
        //目标:认识Test,账务this的应用场景。
        Student s1 = new Student();
        System.out.println(s1);
        s1.printThis();

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

        Student s2 = new Student();
        System.out.println(s2);
        s2.printThis();

    }
}

this的执行原理

this的应用场景

this主要用来解决:变量名称冲突问题的。

package com.liu.thisdemo;

public class Student {
    double score;

    public void printThis(){
        System.out.println(this);
    }

    public void printPass(double score){
        if (this.score > score){
            System.out.println("恭喜您成功考入哈佛大学!");
        }else{
            System.out.println("落选了");
        }
    }
}
package com.liu.thisdemo;

public class Test {
    public static void main(String[] args) {
        //目标:认识Test,账务this的应用场景。
        Student s1 = new Student();
        System.out.println(s1);
        s1.printThis();

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

        Student s2 = new Student();
        System.out.println(s2);
        s2.printThis();

        Student s3 = new Student();
        s3.score = 325;
        s3.printPass(250);

    }
}


面向对象基础:构造器


构造器是一个特殊的方法,这个特殊方法用于创建实例时执行初始化。构造器时创建对象的重要途经(即使 使用工厂模式、反射等方式创建对象,其实实质依然是依赖于构造器),因此,Java类必须包含一个或一个以上的构造器。

构造器最大的用处就是在创建对象时执行初始化。如果想改变系统默认的初始化,想让系统创建对象时就为该对象的实例变量显式指定初始值,就可以通过构造器来实现。

构造器是什么样子?

public class Student {
    
    //无参数构造器
    public Student(){

    }

    //有参数构造器
    public Student(String name,double score){

    }
}

构造器是一个特殊的方法,定义构造器的语法格式与定义方法的语法格式很像

定义构造器的语法格式如下:

[构造器]  构造器名 (形参列表)

{

// 由零条到多条可执行性语句组成的构造器执行体

}

对定义构造器语法格式的详细说明如下:

  • 1、修饰符:修饰符可以省略也可以是public、protected、private其中之一。
  • 2、构造器名:构造器名必须和类名相同
  • 3、形参列表:和定义方法形参列表格式完全相同
  • 值得指出的是,构造器既不能定义返回值类型,也不能使用void声明构造器没有返回值。如果为构造器定义了返回值类型,或使用void声明构造器没有返回值,编译时不会出错,但Java会把这个所谓的构造器当成方法来处理——它就不再是构造器。  

构造器有什么特点?

  • 创建对象时,对象会去调用构造器。
  • Student s = new Student () ;

构造器的常见应用场景

  • 创建对象时,同时完成对对象成员变量(属性)的初始化赋值。
package com.liu.constructor;

public class Student {
    String name;
    double score;

    //无参数构造器
    public Student(){
        System.out.println("无参数构造器");
    }

    //有参数构造器
    public Student(String name,double score){
        System.out.println("有参数构造器");
        this.name = name;
        this.score = score;
    }
}
package com.liu.constructor;

public class Test {
    public static void main(String[] args) {
        //目标:认识构造器,并掌握构造器的特点、应用场景、注意事项
        // Student s = new Student(); //无参数构造器
        Student s = new Student("懒羊羊",500); //有参数构造器

        Student s1 = new Student();
        s1.name = "过期的罐头";
        s1.score = 100;

        Student s2 = new Student("小懒",90);
        System.out.println(s2.name);
        System.out.println(s2.score);
    }
}

构造器的注意事项

  • 类在设计时,如果不写构造器,Java时是会为类自动生成一个无参构造器的。
  • 一旦定义了有参数构造器,Java就不会帮我们的类自动生成无参构造器了,此时就建议自己手写一个无参数构造器出来了。

构造器重载

同一个类里具有多个构造器,多个构造器的形参列表不同,即被称为构造器重载。构造器重载允许Java类里包含多个初始化逻辑,从而允许使用不同的构造器来初始化Java对象。

构造器重载和方法重载基本相似:要求构造器的名字相同,这一点无须特别要求,因为构造器必须与类名相同,所以同一个类的所有构造器名肯定相同。为了让系统能区分不同的构造器,多个构造器的参数列表必须不同。

使用this调用另一个重载的构造器只能在构造器中使用,而且必须作为构造器执行体的第一条语句。使用this调用重载构造器时,系统会根据this后括号里的实参来调用形参列表与之对应的构造器


面向对象基础:封装,实体JavaBean


面向对象的三大特征:封装、继承、多态

封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

封装是面向对象编程程序语言对客观世界的模拟,在客观世界里,对象的状态信息都被隐藏在对象内部,外界无法直接操作和修改。

什么是封装?

就是用类设计对象处理某一事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去。

封装的设计规范

  • 合理隐藏、合理暴露
package com.liu.encapsulation;

public class Student {

    private double score;

    public void setScore(double score){
        if (score >= 0 && score <= 100 ) {
            this.score = score;
        }else {
            System.out.println("数据非法");
        }
    }

    public double getScore() {
        return score;
    }

    public void printPass(){
        System.out.println(score >= 60 ? "成绩及格" : "成绩不合格");
    }
}
package com.liu.constructor;

import com.liu.encapsulation.Student;

public class Teacher {
    public static void main(String[] args) {
        //目标:掌握封装的设计规范,合理隐藏,合理暴露
        Student s1 = new Student();
        s1.setScore(99);
        System.out.println(s1.getScore()); //99
    }
}

对一个类或对象实现良好的封装,可以实现以下目的

  • 隐藏类的实现细节 
  • 让使用者只能通过实现预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对成员变量的不合理访问。
  • 可进行数据检查,从而有利于保证对象信息的完整性。
  • 便于修改,提高代码的可维护性。

为了实现良好的封装,需从两方面考虑

  • 将对象的成员变量和实现细节隐藏起来,不允许外部直接访问。
  • 把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作

因此,封装实际上由两个含义:把该隐藏的隐藏起来,把该暴露的暴露出来。这两个方面都需要通过使用Java提供的访问控制符来实现。

代码层面如何控制对象的成员公开或隐藏?

公开成员,可以使用public(公开)进行修饰

隐藏成员,使用private(私有,隐藏)进行修饰

访问控制符级别由小到大:private 》 default 》protected 》 public

private(当前类访问权限):

如果类里的一个成员(包括成员变量、方法、和构造器等)使用private访问控制符来修饰,则这个成员只能在当前类的内部被访问。很显然,这个访问控制符用于修饰成员变量最合适,使用它来修饰成员变量就可以把成员变量隐藏在该类的内部。

default(包访问权限):

如果类里的一个成员(包括成员变量、方法和构造器等等)或者一个外部类不使用任何访问控制修饰符,就称它是包访问权限的,default访问控制的成员或外部类可以被相同包下的其他类访问。default:并没有对应的访问控制符,当不使用任何访问控制符来修饰类或类成员时,系统默认使用该访问控制级别。

protected(子类访问权限):

如果一个成员(包括成员变量、方法和构造器等)使用protected访问控制修饰符,那么这个成员既可以被同一个包中的其他类访问,也可以被不同包中的子类访问。在通常情况下,如果使protected来修饰一个方法,通常是希望其子类来重写这个方法。

public(公共访问权限):

这是一个最宽松的访问控制级别,如果一个成员(包括成员变量、方法和构造器等)或者一个外部类使用public访问控制符修饰,那么这个成员或外部类就可以被所有类访问,不管访问类和被访问类是否处于同一个包中,是否具有父子继承关系。

访问控制符的使用,存在如下几条基本原则:

  • 类里的绝大部分成员变量都应该使用private修饰,只有一些static修饰的、类似全局变量的成员变量,才可能考虑使用public修饰。除此之外,有些方法只用于辅助实现该类的其他方法,这些方法被称为工具方法,工具方法也应该使用private修饰。
  • 如果某个类主要用作其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
  • 希望暴露出来给其他类自由调用的方法应该使用public修饰,因此,类的构造器通过使用public修饰,从而允许在其他地方创建该类的实例。因为外部类通常都希望被其他类自由使用,所以大部分外部类都使用public修饰。

实体类是什么

就是一种特殊形式的类

这个类中的成员变量都要私有,并且要对外提供相应的getXxx,setXxx方法。

类中必须要有一个公共的无参的构造器。

package com.liu.javabean;

public class Student {
    //1、必须私有成员变量,并为每个成员变量都提供get、set方法
    private String name;
    private double score;

    //2、必须为类提供一个公开的无参数构造器
    public Student() {
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

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

    public void setScore(double score) {
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public double getScore() {
        return score;
    }

}
package com.liu.javabean;

public class Test {
    public static void main(String[] args) {
        //目标:掌握实体类的书写要求、特点、应用场景
        Student s1 =new Student();
        s1.setName("懒羊羊");
        s1.setScore(99);
        System.out.println(s1.getName());
        System.out.println(s1.getScore());
    }
}

实体类的应用场景

实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离。

实体类对应的是软件开发里现在比较流行的开发方式,数据和数据的业务处理相分离。

package com.liu.javabean;

public class Student {
    //1、必须私有成员变量,并为每个成员变量都提供get、set方法
    private String name;
    private double score;

    //2、必须为类提供一个公开的无参数构造器
    public Student() {
    }

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

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

    public void setScore(double score) {
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public double getScore() {
        return score;
    }

}
package com.liu.javabean;

public class StudentOperator {
    private Student student;
    public  StudentOperator(Student student){
        this.student = student;
    }

    public void printPass(){
        if (student.getScore() >= 60){
            System.out.println(student.getName() + "学生成绩及格");
        }else {
            System.out.println(student.getName() + "学生成绩不及格");
        }
    }
}
package com.liu.javabean;

public class Test {
    public static void main(String[] args) {
        //目标:掌握实体类的书写要求、特点、应用场景
        Student s1 =new Student();
        s1.setName("懒羊羊");
        s1.setScore(99);
        System.out.println(s1.getName());
        System.out.println(s1.getScore());

        StudentOperator operator = new StudentOperator(s1);
        operator.printPass();
    }
}


面向对象基础:综合案例,成员变量、局部变量区别


案例:模仿电影信息系统

需求:

展示系统中的全部电影(每部电影展示:名称、价格)

运行用户根据电影编号(id)查询出某个电影的详细信息

目标:

使用所学的面向对象编程实现以上2个需求

package com.liu.demo;

public class Movie {
    private int id;
    private String name;
    private double price;
    private double score;
    private String director;
    private String actor;
    private String info;

    public Movie() {
    }

    public Movie(int id, String name, double price, double score, String director, String actor, String info) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.score = score;
        this.director = director;
        this.actor = actor;
        this.info = info;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

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

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}
package com.liu.demo;

public class MovieOperator {
    private Movie[] movies;
    public MovieOperator(Movie[] movies){
       this.movies = movies;
    }

    //1.展示系统全部电影信息 movies = 【m1,m2,m3 .....】
    public void printAllMovies(){
        System.out.println("-------系统全部电影信息如下:---------");
        for (int i = 0; i < movies.length; i++) {
           Movie m = movies[i];
            System.out.println("编号:" + m.getId());
            System.out.println("名称:" + m.getName());
            System.out.println("价格:" + m.getPrice());
            System.out.println("-----------------------------------------------------------");
        }
    }
    //2、根据电影的编号查询出该电影的详细信息并展示
    public void searchMovieById(int id){
        for (int i = 0; i < movies.length; i++) {
            Movie m = movies[i];
            if (m.getId() == id){
                System.out.println("该电影详细如下:");
                System.out.println("编号:" + m.getId());
                System.out.println("名称:" + m.getName());
                System.out.println("价格:" + m.getPrice());
                System.out.println("得分:" + m.getScore());
                System.out.println("导演:" + m.getDirector());
                System.out.println("主演:" + m.getActor());
                System.out.println("其他信息:" + m.getInfo());
                return; //已经找到了电影信息,没有必要再执行了
            }
        }
        System.out.println("没有该电影信息~");
    }
}
package com.liu.demo;

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        //1、设计一个电影类
        //2、设计一个电影的操作类
        //3、准备全部电影数据
        Movie[] movies = new Movie[4];
        Movie m1 = new Movie(1,"水门桥",38.9,9.8,"徐克","吴京","12万人想看");
        Movie m2 = new Movie(2,"出拳吧",39,7.8,"唐晓白","田甫","3.5万人想看");
        Movie m3 = new Movie(3,"月球陨落",42,7.9,"罗兰","贝瑞","17.9万人想看");
        Movie m4 = new Movie(4,"一点到家",35,8.7,"许宏宇","刘昊然","10.5万人想看");
        movies[0] = m1;
        movies[1] = m2;
        movies[2] = m3;
        movies[3] = m4;
        //4、创建一个电影操作类的对象,接收电影数据,并对其进行业务处理
        MovieOperator operator = new MovieOperator(movies);
        operator.printAllMovies();
        operator.searchMovieById(3);

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

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("==电影信息系统==");
            System.out.println("1、查询全部电影信息");
            System.out.println("2、根据id查询某个电影的详细信息展示");
            System.out.println("请您输入操作命令:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //展示全部电影信息
                    operator.printAllMovies();
                    break;
                case 2:
                    //根据id查询某个电影的详细信息展示
                    System.out.println("请您输入查询的电影id");
                    int id = sc.nextInt();
                    operator.searchMovieById(id);
                    break;
                default:
                    System.out.println("您输入的命令有问题~");
            }
        }
    }
}

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

package com.liu.variable;

public class Student {
    //成员变量(对象的属性,Field)
    String name;
    double score;
}
package com.liu.variable;

public class Test {
    public static void main(String[] args) {
        //局部变量
        int a = 20;

        //局部变量必须赋值
//        int b;
//        System.out.println(b); 报错

        String name = "懒羊羊";
        //name 从13行开始到最后一个 } 结束
    }
}

定义成员变量的语法格式如下:

[修饰符] 类型 成员变量名 [ = 默认值] ;

对定义成员变量语法格式的详细说明如下:

1、修饰符:修饰符可以省略,也可以是public、protected、private、static、final,其中public、protected、private三个最多只能出现其中之一,可以与static、final组合起来修饰成员变量。

2、类型:类型可以是Java语言运行的任何数据类型,包括基本类型和现在结束的引用类型。

3、成员变量名:成员变量名只要是一个合法的标识符即可,但这只是从语法角度来说的;如果从程序可读性角度来看,成员变量名应该由一个或多个有意义的单词连缀而成,第一个单词首字母小写,后面每个单词首字母大写,其他字母全部小写,单词与单词之间不要使用任何分隔符。成员变量用于描述类或对象包含的状态数据,因此成员变量名建议使用英文名词。

4、默认值:定义成员变量还可以指定一个可选的默认值。


总结:面向对象编程(oop)基础部分


面向对象的思想

面向:拿或者找

对象:东西

面向对象编程:拿或者找东西过来编程解决问题

面向对象:把现实世界中的事物全部看成一个一个的对象来解决问题的。(万物皆对象)

面向对象编程的好处:代码符号人类的思维习惯,编程程序更简单,看程序更容易理解吧。

类、对象

类(设计图):相同事物共同特征的描述

对象:对象是类的具体的实例。

对象 == 实例

在Java中必须定义类,才能得到对象

定义类来创建对象使用

定义类的格式:

定义类有一些注意事项:

1、类名首字母建议大写,有意义,满足驼峰,不要用关键字,合法的标识符

2、一个Java文件中可以定义多个类,但是只能一个类是public修饰的,而且public修饰的类名必须为Java代码的文件名称,否则报错!

类中具体怎么实现?

定义汽车类为实例

一般名词定义成成员变量(属性):修饰符 数据类型 变量名称 = 初始值 ;

private String name ;

private double price ;

成员变量不建议初始值,存在默认值,默认值的规则:整型是0,浮点型是0.0,引用类型null,布尔型是false 

一般动词定义成方法(行为)

具体定义类的例子:

创建对象

类名 对象名 = new 构造器();

对象怎么使用:

对象名 . 成员变量  ;     对象名 . 成员方法
 

构造器

作用:初始化一个类的对象并返回这个对象的地址

详细格式:修饰符 类名(形参) { ........... }


构造器的分类 :

无参数构造器:初始化一个类的对象,并返回这个对象的地址,里面的数据都是默认值

有参数构造器:初始化一个类的对象,并返回这个对象的地址,并且可以同时为对象赋值

构造器如何调用

类名 对象名称 = new 构造器;

注意:

任何类写出来自带一个无参数构造器,写不写都有 ;

如何在这个类定义了一个有参数构造器了,那么无参数构造器就消失了,此时,如果你还要使用无参构造器,你必须自己写一个。 
 

this 关键字

this的作用:代表了当前对象的地址,可以访问当前对象的成员变量和成员方法

this的具体用在哪?

  • 可以用在参构造器中

  • 可以用在方法中

封装

面向对象的三大特征:封装、继承、多态

封装的基本思想:决定属性和行为归属谁的问题

定义人类(名称,年龄,吃饭,睡觉)

定义图类(半径,画圆)

定义门类(开门,高宽)

定义票类(票价,地址,买票)


如何更好的封装呢?

成员变量建议private私有化,只能本类访问了。

合理暴露:提供成套的getter和setter方法暴露取值和赋值
 

封装JavaBean

是什么?就是所谓的实体类(学生类、老师类、汽车类、人类、票类)

作用:创建对象,封装数据的。

标准Bean的书写要求:

成员变量和局部变量

成员变量指的是在类里定义的变量,局部变量指的是在方法里定义的变量。

不管是成员变量还是局部变量,都应该遵循相同的命名规则:从语法角度来看,只要是一个合法的标识符即可,但从程序可读性角度来看,应该是多个有意义的单词连缀而成,其中第一个单词首字母小写,后面每个单词首字母大写。

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

成员变量被分为类变量和实例变量两种,定义成员变量时没有static修饰的就是实例变量,有static修饰的就是类变量。其中类变量从类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域与这个类的生存范围相同;而实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个实例,实例变量变量的作用域与对于实例的生存范围相同。

一个类在使用之前要经过类加载、类验证、类准备、类解析、类初始化等几个阶段。

其中类变量可以理解为类成员变量,它作为类本身的一个成员,与类本身共存亡;实例变量则可理解为实例成员变量,它作为实例的一个成员,与实例共存亡。

1、只要类存在,程序就可以访问该类的类变量。在程序中访问类变量通过如下语法:
类 . 类变量
2、只要实例存在,程序就可以访问该实例的实例变量。在程序中访问实例变量通过如下语法:
实例 . 实例变量
3、类变量也可以让该类的实例来访问。通过实例来访问变量的语法如下:
实例 . 类变量

成员变量无须显示初始化,只要为一个类定义了类变量或实例变量,系统就会在这个类的准备阶段或创建该类的实例时进行默认初始化,成员变量默认初始化时的赋值规则与数组动态初始化时数组元素的赋值规则完全相同。

类变量的作用域比实例变量的作用域更大,实例也可访问类变量,同一个类的所有实例访问类变量时,实际上访问的是该类本身的同一个变量,也就是说,访问了同一片内存区。

局部变量根据定义形式的不同,又可以被分为如下三种:

1、形参:在定义方法签名时定义的变量,形参的作用域在整个方法内有效。

2、方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量的地方生效,到该方法结束时失效。

3、代码块局部变量:在代码块中定义的局部变量,这个局部变量的作用域从定义该变量的地方生效,到该代码块结束时失效。


在同一个类里,成员变量的作用范围是整个类内有效,一个类里不能定义两个同名的成员变量,即使一个是类变量,一个是实例变量也不行;一个方法里不能定义两个同名的方法局部变量,方法局部变量与形参也不能同名;同一个方法中不同代码块内的代码局部变量可以同妈妈;如果先定义代码块局部变量,后定义方法局部变量,前面定义的代码块局部变量与后面定义的方法局部变量也可以同名。


常用API:课程介绍、包


为什么要学别人写好的程序?

不要重复造轮子

开发效率高!

Java提供了哪些API?

API文档

先学习包,为什么先学习包?

包是分门别类管理程序的。

Java引入了包(package)机制,提供了类的多层命名空间,用于解决类的命名冲突、类文件管理等问题。

Java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的类库单元。如果希望把一个类放在指定的包结构下,应该在Java源程序的第一个非注释行放置。

一旦在Java源文件中使用了这个package语句,就意味着该源文件里定义的所有类都属于这个包。位于包中的每个类的完整类名都应该是包名和类名的组合,如果其他人需要使用该包下的类,也应该使用包名加类名的组合。

什么是包?

  • 包是用来分门别类的管理各种不同程序的,类似于文件夹,建包有利于程序的管理和维护。
  • 建包的语法格式:

在自己程序中调用其他包下的程序的注意事项

  • 如果当前程序中,要调用自己所在包下的其他程序,可以直接调用。(同一个包下的类,互相可以直接调用)
  • 如果当前程序中,要调用其他包下的程序,则必须在当前程序中导包,才可以访问!导包格式:import 包名 . 类名
  • 如果当前程序中,要调用Java提供的程序,也需要先导包才可以使用;但Java . lang 包下的程序是不需要我们导包的,可以直接使用。
  • 如果当前程序中,要调用多个不同包下的程序,而这些程序名正好一样,此时默认只能导入一个程序,另一个程序必须带包名访问。

idea自动导包

package com.liu.pkg;

import com.liu.pkg.itcat.Demo1;
import com.liu.pkg.liu.Demo2;

import java.util.Random;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        //目标:掌握如何在自己的程序中调用其他包下的程序,有哪些注意

        //1、同一个包下的程序,可以直接调用
        Demo d = new Demo();
        d.print();

        //2、访问其他包下的程序,必须导包才可以访问
        Demo1 d2 = new Demo1();
        d2.print();

        //3、自己的程序中调用Java提供的程序,也需要先导包才可以使用,注意:java.lang包下的程序是不需要我们导包的,可以直接使用。
        Scanner sc = new Scanner(System.in);
        String s = "黑马";
        Random r = new Random();

        //4、访问多个其他包下的程序,这些程序名又一样的情况下,默认只能导入一个程序,另一个程序必须带包名和类名来访问。
        Demo2 d3 = new Demo2();
        d3.print();

        com.liu.pkg.itcat.Demo2 d4 = new com.liu.pkg.itcat.Demo2();
        d4.print();

    }
}

package com.liu.pkg.itcat;

public class Demo1 {
    public void print(){
        System.out.println("懒羊羊");
    }
}
package com.liu.pkg.itcat;

public class Demo2 {
    public void print(){
        System.out.println("itcast");
    }
}
package com.liu.pkg.liu;

public class Demo2 {
    public void print(){
        System.out.println("liu");
    }
}
package com.liu.pkg;

public class Demo {
    public void print(){
        System.out.println("Hello World");
    }
}

Java的核心类都放在Java包以及其子包下,Java扩展的许多类都放在javax包以及其子包下。这些实用类也就是API(应用程序接口),Oracle按这些类的功能分别放在不同的包下。

Java的常用包

  • java . lang :这个包下包含了Java语言的核心类,如String、Math、System和Thread类等,使用这个包下的类无须使用import语句导入,系统会自动导入这个包下的所有类。
  • java . util :这个包下包含了Java的大量工具类/接口和集合框架类/接口,例如Arrays和List、Set等。
  • java . net :这个包下包含了一些Java网络编程相关的类/接口。
  • java . io :这个包下包含了一些Java输入/输出编程相关的类/接口
  • java . text :这个包下包含了一些Java格式化相关的类
  • java . sql : 这个包下包含了Java进行JDBC数据库编程的相关类/接口
  • java . awt : 这个包下包含了抽象窗口工具集(Abstract Window Toolkits)的相关类/接口,这些类主要用于构建图形用户界面(GUI)程序。
  • java . swing :这个包下包含了Swing图形用户界面编程的相关类/接口,这些类可用于构建平台无关的GUI程序。
     

常用API:String、API


为什么要学字符串的处理呢?

java . lang . String 代表字符串 封装字符串数据 处理字符串的方法

1、创建你对象        2、封装字符串数据        3、调用String的方法

String创建对象封装字符串数据的方式

  • 方式一:Java程序中的所有字符串文字(例如:abc“)都为此类的对象

  • 方式二:调用String类的构造器初始字符串对象

package com.liu.string;

public class StringDemo1 {
    public static void main(String[] args){
        //目标:掌握创建String对象,并封装要处理的字符串的两种方式
        //1、直接双引号封装字符串对象,封装字符串数据
        String name = "liu";
        System.out.println(name);

        //2、new String 创建字符串对象,并调用构造器初始化字符串
        String rs1 = new String();
        System.out.println(rs1); // ”“

        String rs2 = new String("lang");
        System.out.println(rs2);

        char[] chars = {'a','c','n'};
        String rs3 = new String(chars);
        System.out.println(rs3);

        byte[] bytes = {97,98,99};
        String rs4 = new String(bytes);
        System.out.println(rs4);
    }
}

总结:

1、string是什么,可以做什么?

代表字符串,,可以用来创建对象封装字符串数据,并对其进行处理

2、String类创建对象封装字符串数据的方式有几种?

方式一:直接使用双引号“...”

方式二:new String类,调用构造器初始化字符串对象

String提供的操作字符串数据的常用方法

为什么是快速熟悉这些方法呢? API是解决需求的

package com.liu.string;

public class StringDemo2 {
    public static void main(String[] args) {
        //目标:快速熟悉String提供的处理字符串的常用方法
        
        String s = "喜欢的东西买了吗";
        //1、获取字符串的长度
        System.out.println(s.length());

        //2、提取字符串中某个索引位置处的字符
        char c = s.charAt(1);
        System.out.println(c);
        
        //字符串的遍历
        for (int i = 0; i < s.length(); i++) {
            // i = 0 1 2 3 4 5
            char ch = s.charAt(i);
            System.out.println(ch);
        }

        System.out.println("------------------------------------");
            
            //3、把字符串转换成字符数组,在进行遍历
            char[] chars = s.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                System.out.println(chars[i]);
        }

            //4、判断字符串内容,内容一样就返回true
        String s1 = new String("过期的罐头");
        String s2 = new String("过期的罐头");
        System.out.println(s1 == s2); //false
        System.out.println(s1.equals(s2)); //true

        //5、忽略大小写比较字符串内容
        String c1 = "34AeFG";
        String c2 = "34aEfg";
        System.out.println(c1.equals(c2)); //false
        System.out.println(c1.equalsIgnoreCase(c2)); //true

        //6、截取字符串内容(包前不包后)
        String s3 = "Java是最好的编程语言之一";
        String rs = s3.substring(0,8);
        System.out.println(rs);

        //7、从当前索引位置一直截取导字符串的末尾
        String rs2 = s3.substring(5);
        System.out.println(rs2);

        //8、把字符串中的某个内容替换成新内容,并返回新的字符串对象给我们
        String info = "这个电脑不好看";
        String rs3 = info.replace("好看","**");
        System.out.println(rs3);

        //9、判断字符串是否包含某个关键字
        String info2 = "java是最好的程序语言之一,我爱Java,Java不爱我";
        System.out.println(info2.contains("Java"));
        System.out.println(info2.contains("java"));
        System.out.println(info2.contains("Java2"));

        //10、判断字符串是否以某个字符串开头
        String rs4 = "张三丰";
        System.out.println(rs4.startsWith("张"));
        System.out.println(rs4.startsWith("张三"));
        System.out.println(rs4.startsWith("张三2"));

        //11、把字符串按照某个指定内容分割成多个字符串,放到一个字符串数组中返回给我们
        String rs5 = "张无忌,周芷若,殷素素,赵敏";
        String[] names = rs5.split(",");
        for (int i = 0; i < names.length; i++) {
            System.out.println(names[i]);
        }
    }
}


常用API:String的注意事项


String使用时的注意事项

第一点:String对象的内容不可改变,被称为不可变字符串对象

package com.liu.string;

public class StringDemo3 {
    public static void main(String[] args) {
        //目标:搞清楚String使用时的几个注意事项
        //1、String的对象是不可变的???
        String name = "林俊杰";
        name += "程序员";
        name += "靓仔";
        System.out.println(name);
    }
}

第二点:只要是以 “...” 


方式写出来的字符串对象,会存储到字符串常量池,且相同内容的字符串只存储一份;但是通过new方式创建字符串对象,每new一次都会产生一个新的对象在堆内容中。

package com.liu.string;

public class StringDemo3 {
    public static void main(String[] args) {
        //目标:搞清楚String使用时的几个注意事项
        //1、String的对象是不可变的???
        String name = "林俊杰";
        name += "程序员";
        name += "靓仔";
        System.out.println(name);

        //2、只要是双引号给出的字符串对象,存储在常量池中,而且内容相同时只会存储一份
        String s1 = "abc";
        String s2 = "abc";
        System.out.println(s1 == s2);

        //3、new  String 创建字符串对象,每次new出来 的都是一个新对象,就在堆内存中
        char[] chars = {'a','b','c'};
        String a1 = new String(chars);
        String a2 = new String(chars);
        System.out.println(a1 == a2 ); 
    }
}

案例:阅读程序并回答问题


常用API:String案例


案例:完成用户登录

需求:

系统正确的登录和密码是:liu/123456,请在控制台开发一个登录界面,接收用户输入的登录名和密码,判断用户是否登录成功,登录成功后展示:” 欢迎进入系统!“,即可停止程序(注意:要求最多给用户三次登录机会)

步骤:

1、开发登录界面,提示用户通过键盘输入登录名和密码。

2、设计一个登录方法,对用户的登录名和密码进行正确性认证。

3、根据登录方法返回认证结果,判断用户是否登录成功。

4、使用循环控制登录界面最多显示3次

package com.liu.string;

import java.util.Scanner;

public class StringTest4 {
    public static void main(String[] args) {
        //目标:完成用户的登录案例

        for (int i = 0;i < 3;i++) {
            //1、开发一个登录界面
            Scanner sc = new Scanner(System.in);
            System.out.println("请您输入登录名称:");
            String loginName = sc.next();
            System.out.println("请您输入登录密码:");
            String password = sc.next();

            //5、开始调用登录方法去判断调用是否成功
            boolean rs = login(loginName,password);
            if (rs){
                System.out.println("恭喜您,欢迎进入系统!");
                break;//跳出for循环,代表登录成功
            }else {
                System.out.println("登录名或者密码错误,请您确认!");
            }
        }
    }

    //2、开发一个登录方法,接收用户的登录名和密码,返回认证的结果
    public static boolean login(String loginName,String password){
        //3、准备一份正确的登录名和密码
        String okLoginName = "liu";
        String okPassword = "123456";

        //4、开始正式判断用户是否登录成功
//        if (okLoginName.equals(loginName) && okPassword.equals(password)){
//            //登录成功
//            return true;
//        }else {
//            return false;
//        }
        return okLoginName.equals(loginName) && okPassword.equals(password);
    }
}

总结:

1、字符串的比较使用==比较好吗?为什么?什么时候使用==?

  • 不好,对于字符串的比较,==比较的是地址,容易出业务bug
  • 基本数据类型的变量或者值应该使用==比较

2、开发中比较字符串推荐使用什么方法比较?

  • 使用String提供的equals方法,它只关心字符串内容一样就返回true
     

案例:使用String来开发验证码

需求:

实现随机产生验证码,验证码的每位可能是数字、大写字母、小写字母

分析:

1、设计一个方法,该方法接收一个整型参数,最终要返回对应位数的随机验证码

2、方法内定义2个字符串变量:1个用来记住生成的验证码,1个用来记住要用到的全部字符

3、定义for循环控制生成多少位随机字符,每次得到一个字符范围内的随机索引,根据索引提取

字符,把该字符交给code变量连接起来,循环结束后,在循环外返回code即可。

package com.liu.string;

import java.util.Random;

public class StringTest5 {
    public static void main(String[] args) {
        //目标:完成随机产生验证码,验证码的每位可能是数字、大写字母、小写字母
        System.out.println(createCode(4));
        System.out.println(createCode(6));
    }

    //1、设计一个方法,返回指定位数的验证码
    public static String createCode(int n){
        //2、定义2个变量 一个是记住最终产生的随机验证码 一个是记住可能用到的全部字符
        String code = "";
        String data = "abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ0123456789";

        Random r = new Random();
        //3、开始定义一个循环产生每位随机字符
        for (int i = 0; i < n; i++) {
            //4、随机一个字符范围内的索引
            int index = r.nextInt(data.length());
            //5、根据索引去全部字符串中提取该字符
            code += data.charAt(index); // code = code + 字符
        }
        //6、返回code即可
        return code;
    }
}


常用API:ArrayList概述,使用


什么是集合?

  • 集合是一种容器,用来装数据的,类似于数组

有数组,为啥还学习集合?

  • 数组定义完成并启动后,长度就固定了
  • 集合的特点:集合大小可变,开发中用的更多

集合的种类很多

ArrayList集合该怎么学呢?

ArrayList<E>

  • 是用的最多、最常见的一种集合。
     

package com.liu.arraylist;

import java.util.ArrayList;

public class ArrayListDemo1 {
    public static void main(String[] args) {
       //目标:掌握如何创建ArrayList集合的对象,并熟悉ArrayList提供的常用方法

        //1、创建ArrayList的集合对象
        //        ArrayList list = new ArrayList();

//        ArrayList<String> list = new ArrayList<String>();
//        从jdk1.7开始才支持的
        ArrayList<String> list = new ArrayList<>();

        list.add("懒羊羊");
//        list.add(500);
//        list.add(99.5);
        list.add("小懒");
        list.add("Java");
        System.out.println(list);

        //2、往集合中的某个索引位置处添加一个对象
        list.add(1,"Mysql");
        System.out.println(list);

        //3、根据索引获取集合中某个索引位置处的值
        String rs = list.get(1);
        System.out.println(rs);

        //4、获取集合的大小(返回集合中存储的元素个数)
        System.out.println(list.size());

        //5、根据索引删除集合中的某个元素值,返回被删除的元素值给我们
        System.out.println(list.remove(1));
        System.out.println(list);

        //6、直接删除某个元素值,删除成功会返回true,反之
        //若出现相同的数据,默认删除第一次出现的数据
        System.out.println(list.remove("Java"));
        System.out.println(list);

        //7、修改某个索引位置处的数据,修改后会返回原来的值给我们
        System.out.println(list.set(1, "勇敢懒羊羊"));
        System.out.println(list);
    }
}

ArrayList是什么?怎么使用?

  • 是集合最常用的一种,ArrayList是泛型类,可以约束存储的数据类型
  • 创建对象,调用无参构造器初始化对象:public ArrayLIst();
  • 调用相应的增删改查数据的方法


常用API:ArrayList的应用案例


案例:掌握从容器中找出某些书并成功删除的技巧


需求:

现在假如购物车中存储了如下这些商品:Java入门,宁夏枸杞,黑枸杞,人字拖,特级枸杞,枸杞子。现在用户不想买枸杞了,选择了批量删除,请完成该需求。

分析:

1、后台使用ArrayList集合表示购物车,存储这些商品名。

2、遍历集合中的每个数据,只要这个数据包含了“ 枸杞 ”则删除它。

3、输出集合看是否已经成功删除了全部枸杞数据了。

package com.liu.arraylist;

import java.util.ArrayList;

public class ArrayListTest2 {
    public static void main(String[] args) {
        //目标:掌握从集合容器中找数据并删除的技巧

        //1、创建一个ArrayList集合对象
        ArrayList<String> list = new ArrayList<>();
        list.add("Java入门");
        list.add("宁夏枸杞");
        list.add("黑枸杞");
        list.add("人字拖");
        list.add("特级枸杞");
        list.add("枸杞子");
        System.out.println(list); //[Java入门, 宁夏枸杞, 黑枸杞, 人字拖, 特级枸杞, 枸杞子]

        //[Java入门, 宁夏枸杞, 黑枸杞, 人字拖, 特级枸杞, 枸杞子
        //[Java入门, 黑枸杞, 人字拖, 枸杞子
        //2、开始完成需求,从集合中找出包含枸杞的数据 ,并删除它
//        for (int i = 0; i < list.size(); i++) {
//            // i = 0 1 2 3 4 5
//            //取出当前遍历到的数据
//            String ele = list.get(i);
//            //判断这个数据中包含枸杞
//            if (ele.contains("枸杞")){
//                //直接从集合中删除数据
//                list.remove(ele);
//            }
//        }
//        System.out.println(list);



        //[Java入门, 黑枸杞, 人字拖, 特级枸杞, 枸杞子
        //            i
        //方式一:每次删除一次数据,就让i往左边退一步
//        for (int i = 0; i < list.size(); i++) {
//            // i = 0 1 2 3 4 5
//            String ele = list.get(i);
//            //判断这个数据中包含枸杞
//            if (ele.contains("枸杞")){
//                //直接从集合中删除数据
//                list.remove(ele);
//                i--;
//            }
//        }
//        System.out.println(list);


        //方式二:从集合的后面倒着遍历并删除
        for (int i = list.size()-1; i >= 0 ; i--) {
            //取出当前遍历到的数据
            String ele = list.get(i);
            //判断这个数据中包含枸杞
            if (ele.contains("枸杞")){
                //直接从集合中删除该数据
                list.remove(ele);
            }
        }
        System.out.println(list);
    }
}

从集合中遍历元素,并筛选出元素删除它,应该如果操作才能不出bug?

  • 方式一:每次删除一个数据后,索引 -1
  • 方式二:从集合后面遍历然后删除,可以避免漏掉元素


常用API:ArrayList集合综合案例


案例:ArrayList的综合案例——模仿外卖系统中的商家系统

需求:

  • 完成菜品的上架、以及菜品信息浏览功能。

目标:

  • 使用所学的ArrayList集合结合面向对象编程实现以上2个需求。
package com.liu.arraylist;

import java.util.ArrayList;

public class ArrayListTest3 {
    public static void main(String[] args) {
        //目标:完成拓展案例,商品菜品上菜操作
        //1、设计一个菜品类Food,负责创建菜品对象,封装菜品数据
        //2、设计一个菜品的操作类FoodOpeartor,负责完成对菜品的业务实现,上架,浏览信息
        FoodOpeartor opeartor = new FoodOpeartor();
        opeartor.start();

    }
}
package com.liu.arraylist;

public class Food {
    private String name;
    private double price;
    private String desc;//描述

    public Food() {
    }

    public Food(String name, double price, String desc) {
        this.name = name;
        this.price = price;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
package com.liu.arraylist;

//菜品操作类:负责对菜品上架和浏览功能的实现

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

public class FoodOpeartor {
    //1、定义一个ArrayList集合对象,负责存储菜品信息
    private ArrayList<Food> foodList = new ArrayList<>();
    //foodList = []
    
    //2、开发功能,上架菜品功能
    public void addFood(){
        
        //3、创建一个菜品对象,封装上架的菜品信息
        Food f = new Food();
        
        //4、录入菜品信息进去
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入该菜品名称:");
        String name = sc.next();
        f.setName(name);

        System.out.println("请您输入该菜品价格:");
        double price = sc.nextDouble();
        f.setPrice(price);

        System.out.println("请您输入菜品描述:");
        String desc = sc.next();
        f.setDesc(desc);

        //5、把菜品对象存入到集合中去
        foodList.add(f);
        System.out.println("上架成功!");
    }
    
    //6、展示菜品
    //foodList = [ f1,f2,f3,......]
    public void showAllFood(){
        if (foodList.size() == 0){
            System.out.println("什么菜品都没有,先去上架!");
            return;
        }
        for (int i = 0; i < foodList.size(); i++) {
            Food f = foodList.get(i);
            System.out.println(f.getName());
            System.out.println(f.getPrice());
            System.out.println(f.getDesc());
            System.out.println("____________________________________________");
        }
    }

    //负责展示操作界面
    public void start(){
        while (true) {
            System.out.println("请选择功能:");
            System.out.println("1、上架商品");
            System.out.println("2、展示菜品");
            System.out.println("3、退出");

            Scanner sc = new Scanner(System.in);
            System.out.println("请选择您的操作:");
            String command = sc.next();
            switch (command){
                case "1":
                    addFood();
                    break;
                case "2":
                    showAllFood();
                    break;
                case "3":
                    System.out.println("下次再来!");
                    return; //干掉方法
                default:
                    System.out.println("您输入的命令不存在!");
            }
        }
    }
    
}


总结:常用API(String、ArrayList使用)


什么是API?

1、全称应用程序编程接口,就是Java自己写好的程序,给程序员调用的,方便完成一些功能的。

2、api文档:程序使用说明书

String

1、是什么?String是字符串类型,它定义的变量可以指向一个字符串对象

2、String创建对象的方式:方式一:直接使用双引号围起来 String name = ”懒羊羊“ ;方式二:new构造器得到字符串对象 。

3、两种方式的区别(面试笔试会问到):双引号给出的字符串对象,存在于堆内存中的常量池中,相同内容只会存储一份。new字符串对象,每new一次都会在堆内存中产生一个字符串对象。

4、Sting是不可变字符串

5、String的常用方法(常用API):判断字符串内容。背景:== 判断字符串对象是判断地址的,这样会引起很多业务问题。必要性:判断字符串开发中更多时候希望判断内容一样就返回true,不在乎地址是不是一样,此时需要用equals方法。结论一:之后只要是字符串进行内容比较,那必须使用字符串的equals方法。结论二:什么时候用 == 比较?基本数据类型的比较,那就用 ==

其他方法:

ArrayList

1、是什么?是一种集合

2、集合:代表的是一种容器,类似于数组

3、集合的特点:大小可变,类型可以不固定,功能更加强大,适合做 元素个数不能确定,同时存在怎么增删操作的业务场景。

4、如何构建ArrayList的对象代表一个集合容器,存储数据。public ArrayList();ArryList list = new ArrayList();

5、ArrayList的常用方法

6、泛型:集合都是支持泛型的。ArrayList<E>,约束集合在编译阶段只能操作某种数据类型。ArrayList<String> list = new ArrayList() ; ArrayList<Student> list = new ArrayList() ; ArrayList<Movie> list = new ArrayList() ; ArrayList<Integer> list = new ArrayList() ; 注意:集合和泛型都不支持基本数据类型,只能支持引用数据类型;以后定义集合都应该采用泛型。问题:我的集合就是要什么都存:ArrayList list = new ArrayList() ;推荐这样写: ArrayList<Object> list = new ArrayList() ;

7、ArrayList遍历并删除元素:从前往后边遍历边删除存在问题,可能存在漏掉元素。删除元素后,马上后退一步i--就可以了,从后往前遍历,边遍历边删除

8、ArrayList存储自定义类型的变量: ArrayList<Student> list = new ArrayList() ; ArrayList<Movie> list = new ArrayList() ; 注意:集合容器中存储的是每个对象的什么东西?在堆内存中的地址!!


项目实战:ATM项目介绍


模拟ATM系统

1、项目演示

2、项目技术分析

3、能得到哪些收获
 

ATM系统技术选型

完成本项目达成的能力


项目实战:ATM系统架构搭建,欢迎页面设计


系统架构搭建

1、定义一个账号类Account,至少需要包含(卡号、姓名、性别、密码、余额、每次取现额度)

2、定义一个ATM类,用来代表ATM系统,负责提供所有的业务需求,比如:展示ATM的系统欢迎页、开通账号、转账 . . . 

3、定义一个测试类Test,负责对我们开发的ATM系统进行测试。

系统欢迎页设计

在ATM类中设计一个方法start(),方法里负责展示欢迎界面。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
     private Scanner sc = new Scanner(System.in);
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    break;
                case 2:
                    //用户开户
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }
}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}

ATM类中使用什么来存储系统全部用户的账户信息的?

ArrayList<Account> accounts = new ArrayList<>();


项目实战:ATM开户


开户功能

就是新增一个账户,也就是往系统的账户集合中添加一个账户对象。
 

账户的要求

用户信息包含:姓名、性别、密码、每次取现额度、卡号。

注意:

卡号由系统生成,要求是8位的数字组成的(且卡号不能重复)

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
     private Scanner sc = new Scanner(System.in);
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:");
    }
}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}

开户功能的实现需要哪几步操作?

1、定义一个开户方法:creatAccount

2、在方法里创建Account账户对象,入职封装用户的账户信息(姓名、性别、密码、卡号等等)

3、卡号需要由系统自动生成(卡号要求是8位的数字组成,且不能 重复)

4、把账户对象存入到账户集合中去

5、提示开户成功!

为新开的账户生成一个新卡号:

新卡号要求是一个8位的数字,且不能与其他账户对象的卡号重复

新卡号得到后,需要赋值给当前账户对象

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}

账户的新卡号是如何生成的?

1、定义了一个方法:createCardId(),用来返回以后不重复的新卡号。

2、方法里,使用循环生成了8个随机的数字连接起来作为卡号。

3、接着判断该卡号是否与其他账户的卡号重复

4、根据该卡号去账户集合中查询账户对象,如果没有查询到账户对象,该卡号步重复,即可返回。

5、如果查询到了账户对象,则使用循环重复以上(2、3、4)步操作。


项目实战:ATM登录,登录后操作


用户登录功能

1、如果系统没有任何账户对象,则不允许登录。

2、让用户输入登录的卡号,先判断卡号是否正确,如果不正确要给出提示。

3、如果卡号正确,在让用户输入账号密码,如果密码不正确要给出提示,如果密码也正确,则给出登录成功的提示。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}

登录功能如何实现的?

设计一个登录方法:login,负责完成用户的登录。

方法里:如果系统无任何账户对象,直接结束登录操作。

有账户对象,则让用户输入卡号,根据卡号去去账户集合中查询账户对象。。

如果没有找到账户对象,说明登录卡号不存在,提示继续输入卡号。

如果找打了账户对象,说明卡号存在,继续输入密码。

如果密码不正确,提示继续输入密码。

如果密码也正确,则登录成功,并给出相应的提示。

用户操作页设计、查询账户、退出账户功能分析


1、用户登录成功后,需要进入用户操作页。

2、查询就是直接展示当前登录成功的用户的账户信息。

3、退出账户就是回到欢迎界面。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    private Account loginAcc; //记录登录后的用户账户
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        loginAcc = acc;
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                        //展示登录后的操作界面了
                       showUserCommand();
                        return;//跳出并结束当前登录方法
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //展示登录后的操作界面的
    private void showUserCommand(){
        while (true) {
            System.out.println("=="+loginAcc.getUserName() + "您可以选择如下功能进行账户的处理==");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、密码修改");
            System.out.println("6、退出账户");
            System.out.println("7、注销当前账户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //查询当前账户
                    showLoginAccountt();
                    break;
                case 2:
                    //存款
                    break;
                case 3:
                    //取款
                    break;
                case 4:
                    //转账
                    break;
                case 5:
                    //密码修改
                    break;
                case 6:
                    //退出账户
                    System.out.println(loginAcc.getUserName()+"您退出系统成功");
                    return; //跳出并结束当前方法
                case 7:
                    //注销当前登录的账户
                    break;
                default:
                    System.out.println("您当前选择的操作是不存在的,请确认!");
            }
        }

    }

    //展示当前登录的账户信息
    private void showLoginAccountt(){
        System.out.println("==当前用户信息如下:==");
        System.out.println("卡号:"+loginAcc.getCardId());
        System.out.println("户主:"+loginAcc.getUserName());
        System.out.println("性别:"+loginAcc.getSex());
        System.out.println("余额:"+loginAcc.getLimit());
        System.out.println("每次取现额度:"+loginAcc.getLimit());
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}


项目实战:ATM存款、取款


用户存款功能:

就是用户位自己的账户存钱,存钱后更新新账户的余额即可。

用户取款功能:

就是从自己的账户中取钱,取钱的要求:

1、需要先判断账户的余额是否大于>=100元,如果够,让用户输入取款金额。

2、需要判断取款金额是否超过了当次限额,以及余额是否足够。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    private Account loginAcc; //记录登录后的用户账户
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        loginAcc = acc;
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                        //展示登录后的操作界面了
                       showUserCommand();
                        return;//跳出并结束当前登录方法
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //展示登录后的操作界面的
    private void showUserCommand(){
        while (true) {
            System.out.println("=="+loginAcc.getUserName() + "您可以选择如下功能进行账户的处理==");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、密码修改");
            System.out.println("6、退出账户");
            System.out.println("7、注销当前账户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //查询当前账户
                    showLoginAccountt();
                    break;
                case 2:
                    //存款
                    depositMoney();
                    break;
                case 3:
                    //取款
                    drawMoney();
                    break;
                case 4:
                    //转账
                    break;
                case 5:
                    //密码修改
                    break;
                case 6:
                    //退出账户
                    System.out.println(loginAcc.getUserName()+"您退出系统成功");
                    return; //跳出并结束当前方法
                case 7:
                    //注销当前登录的账户
                    break;
                default:
                    System.out.println("您当前选择的操作是不存在的,请确认!");
            }
        }

    }

    private void drawMoney() {
        System.out.println("==取钱操作==");
        //1、判断账户余额是否达到100元,如果不到100元,就不让用户取钱了
        if (loginAcc.getMoney()<100){
            System.out.println("您的账户余额不足100元,不允许取钱!");
            return;
        }

        //2、让用户输入取款金额
        while (true) {
            System.out.println("请您输入取款金额:");
            double money = sc.nextDouble();

            //3、判断用户余额是否足够
            if (loginAcc.getMoney()>=money){
                //账户中的余额是足够的
                //4、判断当前取款金额是否超过了每次限额
                if (money > loginAcc.getLimit()){
                    System.out.println("您当前取款金额超过了每次限额,您每次最多可取:"+loginAcc.getLimit());
                }else {
                    //代表可以开始取钱了,更新当前账户的余额即可
                    loginAcc.setMoney(loginAcc.getMoney()-money);
                    System.out.println("您取款:"+money+"成功,取款后您剩余:"+loginAcc.getMoney());
                    break;
                }
            }else {
                System.out.println("余额不足,您的账户中的余额是:"+loginAcc.getMoney());

            }
        }
    }

    //存钱
    private void depositMoney() {
        System.out.println("==存钱操作==");
        System.out.println("请您输入存款金额:");
        double money = sc.nextDouble();

        //更新当前登录账户的余额
        loginAcc.setMoney(loginAcc.getMoney()+money);
        System.out.println("恭喜您,您存钱:"+money+"成功,存钱后余额是:"+loginAcc.getMoney());

    }

    //展示当前登录的账户信息
    private void showLoginAccountt(){
        System.out.println("==当前用户信息如下:==");
        System.out.println("卡号:"+loginAcc.getCardId());
        System.out.println("户主:"+loginAcc.getUserName());
        System.out.println("性别:"+loginAcc.getSex());
        System.out.println("余额:"+loginAcc.getMoney());
        System.out.println("每次取现额度:"+loginAcc.getLimit());
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}

存款、取款是如何实现账户余额更新的?

调用当前账户对象的setMoney方法完成金额的修改。


项目实战:ATM转账


用户转账功能

把钱转给别人,转账前需要判断:

1、自己账户是否有钱,系统中是否有其他账户。

2、接下来让用户输入对方卡号,判断对方账户是否存在,账户如果存在,还需要认证对方账户的户主姓氏。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    private Account loginAcc; //记录登录后的用户账户
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        loginAcc = acc;
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                        //展示登录后的操作界面了
                       showUserCommand();
                        return;//跳出并结束当前登录方法
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //展示登录后的操作界面的
    private void showUserCommand(){
        while (true) {
            System.out.println("=="+loginAcc.getUserName() + "您可以选择如下功能进行账户的处理==");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、密码修改");
            System.out.println("6、退出账户");
            System.out.println("7、注销当前账户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //查询当前账户
                    showLoginAccountt();
                    break;
                case 2:
                    //存款
                    depositMoney();
                    break;
                case 3:
                    //取款
                    drawMoney();
                    break;
                case 4:
                    //转账
                    transferMoney();
                    break;
                case 5:
                    //密码修改
                    break;
                case 6:
                    //退出账户
                    System.out.println(loginAcc.getUserName()+"您退出系统成功");
                    return; //跳出并结束当前方法
                case 7:
                    //注销当前登录的账户
                    break;
                default:
                    System.out.println("您当前选择的操作是不存在的,请确认!");
            }
        }

    }

    //转账
    private void transferMoney() {
        System.out.println("==用户转账==");
        //1、判断系统中是否存在其他账户
        if (accounts.size()<2){
            System.out.println("当前系统中只要你一个账户,无法为其他账户转账!");
            return;
        }
        //2、判断自己的账户中是否有钱
        if (loginAcc.getMoney() == 0){
            System.out.println("您自己都没钱,就别转了!");
            return;
        }
        //3、真正开始转账了
        while (true) {
            System.out.println("请您输入对方的卡号:");
            String cardId = sc.next();

            //4、判断这个卡号是否正确
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                System.out.println("您输入的对方的卡号不存在!");
            }else {
                //对方的账户存在,继续让用户认证姓氏
                String name = "*" + acc.getUserName().substring(1); // * + 羊羊
                System.out.println("请您输入【"+ name +"】姓氏:");
                String preName = sc.next();
                //5、判断这个姓氏是否正确啊
                if (acc.getUserName().startsWith(preName)){
                    while (true) {
                        //认证通过了,真正转账了
                        System.out.println("请您输入转账给对方的金额:");
                        double money = sc.nextDouble();
                        //6、判断金额是否没有超过自己的余额
                        if (loginAcc.getMoney() >= money){
                            //转给对方
                            //更新自己的账户余额
                            loginAcc.setMoney(loginAcc.getMoney() - money);
                            //更新对方的账户余额
                            acc.setMoney(acc.getMoney() + money);
                            System.out.println("您转账成功了!");
                            return;//直接跳出转账方法
                        }else {
                            System.out.println("您余额不足,无法给对方转这么多钱,最多个转:"+loginAcc.getMoney());
                        }
                    }
                }else {
                    System.out.println("对不起,您认证的信息有问题!");
                }
            }
        }

    }

    private void drawMoney() {
        System.out.println("==取钱操作==");
        //1、判断账户余额是否达到100元,如果不到100元,就不让用户取钱了
        if (loginAcc.getMoney()<100){
            System.out.println("您的账户余额不足100元,不允许取钱!");
            return;
        }

        //2、让用户输入取款金额
        while (true) {
            System.out.println("请您输入取款金额:");
            double money = sc.nextDouble();

            //3、判断用户余额是否足够
            if (loginAcc.getMoney()>=money){
                //账户中的余额是足够的
                //4、判断当前取款金额是否超过了每次限额
                if (money > loginAcc.getLimit()){
                    System.out.println("您当前取款金额超过了每次限额,您每次最多可取:"+loginAcc.getLimit());
                }else {
                    //代表可以开始取钱了,更新当前账户的余额即可
                    loginAcc.setMoney(loginAcc.getMoney()-money);
                    System.out.println("您取款:"+money+"成功,取款后您剩余:"+loginAcc.getMoney());
                    break;
                }
            }else {
                System.out.println("余额不足,您的账户中的余额是:"+loginAcc.getMoney());

            }
        }
    }

    //存钱
    private void depositMoney() {
        System.out.println("==存钱操作==");
        System.out.println("请您输入存款金额:");
        double money = sc.nextDouble();

        //更新当前登录账户的余额
        loginAcc.setMoney(loginAcc.getMoney()+money);
        System.out.println("恭喜您,您存钱:"+money+"成功,存钱后余额是:"+loginAcc.getMoney());

    }

    //展示当前登录的账户信息
    private void showLoginAccountt(){
        System.out.println("==当前用户信息如下:==");
        System.out.println("卡号:"+loginAcc.getCardId());
        System.out.println("户主:"+loginAcc.getUserName());
        System.out.println("性别:"+loginAcc.getSex());
        System.out.println("余额:"+loginAcc.getMoney());
        System.out.println("每次取现额度:"+loginAcc.getLimit());
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}


项目实战:ATM销户、密码修改


销户操作的基本要求:

销户就是从系统中删

除当前账户,销户的要求:

1、首先要询问用户是否确定要销户,如果不确定,则回到操作界面。

2、如果确定,要判断用户的账户中是否有钱,有则不允许销户,并回到操作界面。

3、如果没钱,则完成销户,并回到欢迎页。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    private Account loginAcc; //记录登录后的用户账户
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        loginAcc = acc;
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                        //展示登录后的操作界面了
                       showUserCommand();
                        return;//跳出并结束当前登录方法
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //展示登录后的操作界面的
    private void showUserCommand(){
        while (true) {
            System.out.println("=="+loginAcc.getUserName() + "您可以选择如下功能进行账户的处理==");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、密码修改");
            System.out.println("6、退出账户");
            System.out.println("7、注销当前账户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //查询当前账户
                    showLoginAccountt();
                    break;
                case 2:
                    //存款
                    depositMoney();
                    break;
                case 3:
                    //取款
                    drawMoney();
                    break;
                case 4:
                    //转账
                    transferMoney();
                    break;
                case 5:
                    //密码修改
                    break;
                case 6:
                    //退出账户
                    System.out.println(loginAcc.getUserName()+"您退出系统成功");
                    return; //跳出并结束当前方法
                case 7:
                    //注销当前登录的账户
                    if (deleteAccount()){
                        //销户成功了,回到欢迎界面
                        return;
                    }
                    break;
                default:
                    System.out.println("您当前选择的操作是不存在的,请确认!");
            }
        }

    }

    //销户操作
    private boolean deleteAccount() {
        System.out.println("==进行销户操作==");
        //1、问问用户是否确定销户
        System.out.println("请问您确认销户吗?y/n");
        String command = sc.next();
        switch (command){
            case "y":
                //确实销户
                //2、判断用户的账户中是否有钱
                if (loginAcc.getMoney() == 0){
                    //真的销户了
                    accounts.remove(loginAcc);
                    System.out.println("您好,您的账户已经成功销户!");
                    return true;
                }else {
                    System.out.println("对不起,您的账户存在金额,不允许销户!");
                    return false;
                }
            default:
                System.out.println("好的,您的账户保留!");
                return false;
        }
    }

    //转账
    private void transferMoney() {
        System.out.println("==用户转账==");
        //1、判断系统中是否存在其他账户
        if (accounts.size()<2){
            System.out.println("当前系统中只要你一个账户,无法为其他账户转账!");
            return;
        }
        //2、判断自己的账户中是否有钱
        if (loginAcc.getMoney() == 0){
            System.out.println("您自己都没钱,就别转了!");
            return;
        }
        //3、真正开始转账了
        while (true) {
            System.out.println("请您输入对方的卡号:");
            String cardId = sc.next();

            //4、判断这个卡号是否正确
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                System.out.println("您输入的对方的卡号不存在!");
            }else {
                //对方的账户存在,继续让用户认证姓氏
                String name = "*" + acc.getUserName().substring(1); // * + 羊羊
                System.out.println("请您输入【"+ name +"】姓氏:");
                String preName = sc.next();
                //5、判断这个姓氏是否正确啊
                if (acc.getUserName().startsWith(preName)){
                    while (true) {
                        //认证通过了,真正转账了
                        System.out.println("请您输入转账给对方的金额:");
                        double money = sc.nextDouble();
                        //6、判断金额是否没有超过自己的余额
                        if (loginAcc.getMoney() >= money){
                            //转给对方
                            //更新自己的账户余额
                            loginAcc.setMoney(loginAcc.getMoney() - money);
                            //更新对方的账户余额
                            acc.setMoney(acc.getMoney() + money);
                            System.out.println("您转账成功了!");
                            return;//直接跳出转账方法
                        }else {
                            System.out.println("您余额不足,无法给对方转这么多钱,最多个转:"+loginAcc.getMoney());
                        }
                    }
                }else {
                    System.out.println("对不起,您认证的信息有问题!");
                }
            }
        }

    }

    private void drawMoney() {
        System.out.println("==取钱操作==");
        //1、判断账户余额是否达到100元,如果不到100元,就不让用户取钱了
        if (loginAcc.getMoney()<100){
            System.out.println("您的账户余额不足100元,不允许取钱!");
            return;
        }

        //2、让用户输入取款金额
        while (true) {
            System.out.println("请您输入取款金额:");
            double money = sc.nextDouble();

            //3、判断用户余额是否足够
            if (loginAcc.getMoney()>=money){
                //账户中的余额是足够的
                //4、判断当前取款金额是否超过了每次限额
                if (money > loginAcc.getLimit()){
                    System.out.println("您当前取款金额超过了每次限额,您每次最多可取:"+loginAcc.getLimit());
                }else {
                    //代表可以开始取钱了,更新当前账户的余额即可
                    loginAcc.setMoney(loginAcc.getMoney()-money);
                    System.out.println("您取款:"+money+"成功,取款后您剩余:"+loginAcc.getMoney());
                    break;
                }
            }else {
                System.out.println("余额不足,您的账户中的余额是:"+loginAcc.getMoney());

            }
        }
    }

    //存钱
    private void depositMoney() {
        System.out.println("==存钱操作==");
        System.out.println("请您输入存款金额:");
        double money = sc.nextDouble();

        //更新当前登录账户的余额
        loginAcc.setMoney(loginAcc.getMoney()+money);
        System.out.println("恭喜您,您存钱:"+money+"成功,存钱后余额是:"+loginAcc.getMoney());

    }

    //展示当前登录的账户信息
    private void showLoginAccountt(){
        System.out.println("==当前用户信息如下:==");
        System.out.println("卡号:"+loginAcc.getCardId());
        System.out.println("户主:"+loginAcc.getUserName());
        System.out.println("性别:"+loginAcc.getSex());
        System.out.println("余额:"+loginAcc.getMoney());
        System.out.println("每次取现额度:"+loginAcc.getLimit());
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}


密码修改
 


就是更改账户的密码,修改密码的要求:

1、需要先认证用户当前的密码。

2、认证通过后,需要让用户输入2次新密码。

3、两次密码一样,则更新账户密码,并回到欢迎界面。

package com.liu;

public class Account {
    private String cardId;
    private String userName;
    private char sex;
    private String passWord;
    private double money;
    private double limit; //限额

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getUserName() {
        return userName + (sex == '男' ? "先生" : "女士");
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }
}
package com.liu;

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

public class ATM {
    private ArrayList<Account> accounts = new ArrayList<>(); //[]
    private Scanner sc = new Scanner(System.in);
    private Account loginAcc; //记录登录后的用户账户
    //启动ATM系统,展示欢迎界面
    public void start(){
        while (true) {
            System.out.println("==欢迎您进入ATM系统==");
            System.out.println("1、用户登录");
            System.out.println("2、用户开户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //用户登录
                    login();
                    break;
                case 2:
                    //用户开户
                    createAccount();
                    break;
                default:
                    System.out.println("没有该操作!");
            }
        }
    }

    //完成用户的登录操作
    private void login(){
        System.out.println("==系统登录==");
        //1、判断系统中是否存在账号对象,存在才能登录,如果不存在,我们直接结束登录操作
        if (accounts.size() == 0){
            System.out.println("当前系统中无任何账户,请先开户,再来登录!");
            return;//直接跳出登录操作
        }

        //2、系统中存在账号对象,可以开始进行登录操作
        while (true) {
            System.out.println("请您输入您的登录卡号:");
            String cardId = sc.next();
            //3、判断卡号是否存在
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明这个卡号不存在
                System.out.println("您输入的卡号不存在,请确认!");
            }else {
                while (true) {
                    //卡号存在,接着让用户输入密码
                    System.out.println("请您输入登录密码:");
                    String passWord = sc.next();
                    //4、判断密码是否正确
                    if (acc.getPassWord().equals(passWord)){
                        loginAcc = acc;
                        //密码正确,登陆成功
                        System.out.println("恭喜您"+acc.getUserName()+"成功登录了系统,您的卡号是:"+acc.getCardId());
                        //展示登录后的操作界面了
                       showUserCommand();
                        return;//跳出并结束当前登录方法
                    }else {
                        System.out.println("您输入的密码不正确,请确认!");
                    }
                }
            }
        }
    }

    //展示登录后的操作界面的
    private void showUserCommand(){
        while (true) {
            System.out.println("=="+loginAcc.getUserName() + "您可以选择如下功能进行账户的处理==");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、密码修改");
            System.out.println("6、退出账户");
            System.out.println("7、注销当前账户");
            System.out.println("请选择:");
            int command = sc.nextInt();
            switch (command){
                case 1:
                    //查询当前账户
                    showLoginAccountt();
                    break;
                case 2:
                    //存款
                    depositMoney();
                    break;
                case 3:
                    //取款
                    drawMoney();
                    break;
                case 4:
                    //转账
                    transferMoney();
                    break;
                case 5:
                    //密码修改
                    updatePassword();
                    return; //跳出并结束当前方法
                case 6:
                    //退出账户
                    System.out.println(loginAcc.getUserName()+"您退出系统成功");
                    return; //跳出并结束当前方法
                case 7:
                    //注销当前登录的账户
                    if (deleteAccount()){
                        //销户成功了,回到欢迎界面
                        return;
                    }
                    break;
                default:
                    System.out.println("您当前选择的操作是不存在的,请确认!");
            }
        }

    }

    //账户密码修改
    private void updatePassword() {
        System.out.println("==账户密码修改操作==");
        //1、提醒用户认证当前密码
        while (true) {
            System.out.println("请您输入当前账户的密码:");
            String passWord = sc.next();

            //2、认证当前密码是否正确
            if (loginAcc.getPassWord().equals(passWord)){
                //认证通过
                while (true) {
                    //3、真正开始修改密码了
                    System.out.println("请您输入新密码:");
                    String newPassword = sc.next();

                    System.out.println("请您再次输入密码:");
                    String okPassword = sc.next();

                    //4、判断2次,密码是否一种
                    if (okPassword.equals(newPassword)){
                        //可以正式修改密码了
                        loginAcc.setPassWord(okPassword);
                        System.out.println("恭喜您,您的密码修改成功!");
                        return;
                    }else {
                        System.out.println("您输入的2次密码不一致!");
                    }
                }
            }else {
                System.out.println("您当前输入的密码不正确!");
            }
        }
    }

    //销户操作
    private boolean deleteAccount() {
        System.out.println("==进行销户操作==");
        //1、问问用户是否确定销户
        System.out.println("请问您确认销户吗?y/n");
        String command = sc.next();
        switch (command){
            case "y":
                //确实销户
                //2、判断用户的账户中是否有钱
                if (loginAcc.getMoney() == 0){
                    //真的销户了
                    accounts.remove(loginAcc);
                    System.out.println("您好,您的账户已经成功销户!");
                    return true;
                }else {
                    System.out.println("对不起,您的账户存在金额,不允许销户!");
                    return false;
                }
            default:
                System.out.println("好的,您的账户保留!");
                return false;
        }
    }

    //转账
    private void transferMoney() {
        System.out.println("==用户转账==");
        //1、判断系统中是否存在其他账户
        if (accounts.size()<2){
            System.out.println("当前系统中只要你一个账户,无法为其他账户转账!");
            return;
        }
        //2、判断自己的账户中是否有钱
        if (loginAcc.getMoney() == 0){
            System.out.println("您自己都没钱,就别转了!");
            return;
        }
        //3、真正开始转账了
        while (true) {
            System.out.println("请您输入对方的卡号:");
            String cardId = sc.next();

            //4、判断这个卡号是否正确
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                System.out.println("您输入的对方的卡号不存在!");
            }else {
                //对方的账户存在,继续让用户认证姓氏
                String name = "*" + acc.getUserName().substring(1); // * + 羊羊
                System.out.println("请您输入【"+ name +"】姓氏:");
                String preName = sc.next();
                //5、判断这个姓氏是否正确啊
                if (acc.getUserName().startsWith(preName)){
                    while (true) {
                        //认证通过了,真正转账了
                        System.out.println("请您输入转账给对方的金额:");
                        double money = sc.nextDouble();
                        //6、判断金额是否没有超过自己的余额
                        if (loginAcc.getMoney() >= money){
                            //转给对方
                            //更新自己的账户余额
                            loginAcc.setMoney(loginAcc.getMoney() - money);
                            //更新对方的账户余额
                            acc.setMoney(acc.getMoney() + money);
                            System.out.println("您转账成功了!");
                            return;//直接跳出转账方法
                        }else {
                            System.out.println("您余额不足,无法给对方转这么多钱,最多个转:"+loginAcc.getMoney());
                        }
                    }
                }else {
                    System.out.println("对不起,您认证的信息有问题!");
                }
            }
        }

    }

    private void drawMoney() {
        System.out.println("==取钱操作==");
        //1、判断账户余额是否达到100元,如果不到100元,就不让用户取钱了
        if (loginAcc.getMoney()<100){
            System.out.println("您的账户余额不足100元,不允许取钱!");
            return;
        }

        //2、让用户输入取款金额
        while (true) {
            System.out.println("请您输入取款金额:");
            double money = sc.nextDouble();

            //3、判断用户余额是否足够
            if (loginAcc.getMoney()>=money){
                //账户中的余额是足够的
                //4、判断当前取款金额是否超过了每次限额
                if (money > loginAcc.getLimit()){
                    System.out.println("您当前取款金额超过了每次限额,您每次最多可取:"+loginAcc.getLimit());
                }else {
                    //代表可以开始取钱了,更新当前账户的余额即可
                    loginAcc.setMoney(loginAcc.getMoney()-money);
                    System.out.println("您取款:"+money+"成功,取款后您剩余:"+loginAcc.getMoney());
                    break;
                }
            }else {
                System.out.println("余额不足,您的账户中的余额是:"+loginAcc.getMoney());

            }
        }
    }

    //存钱
    private void depositMoney() {
        System.out.println("==存钱操作==");
        System.out.println("请您输入存款金额:");
        double money = sc.nextDouble();

        //更新当前登录账户的余额
        loginAcc.setMoney(loginAcc.getMoney()+money);
        System.out.println("恭喜您,您存钱:"+money+"成功,存钱后余额是:"+loginAcc.getMoney());

    }

    //展示当前登录的账户信息
    private void showLoginAccountt(){
        System.out.println("==当前用户信息如下:==");
        System.out.println("卡号:"+loginAcc.getCardId());
        System.out.println("户主:"+loginAcc.getUserName());
        System.out.println("性别:"+loginAcc.getSex());
        System.out.println("余额:"+loginAcc.getMoney());
        System.out.println("每次取现额度:"+loginAcc.getLimit());
    }

    //完成用户开户操作
    private void createAccount(){
        System.out.println("==系统开户操作==");
        // 1、创建一个账号对象用于封装对象的开户信息
        Account acc = new Account();

        //2、需要用户输入自己的开户信息,赋值给账户对象
        System.out.println("请您输入您的账号名称:");
        String name = sc.next();
        acc.setUserName(name);
        while (true) {
            System.out.println("请您输入您的性别:");
            char sex = sc.next().charAt(0); //'男'
            if (sex=='男' || sex=='女'){
                acc.setSex(sex);
                break;
            }else {
                System.out.println("您输入的性别有误,只能是男或者女");
            }
        }
        while (true) {
            System.out.println("请您输入您的账户密码:");
            String passWord = sc.next();
            System.out.println("请你输入您的确认密码:");
            String okPassword = sc.next();
            //判断2次密码是否一样
            if (okPassword.equals(passWord)){
                acc.setPassWord(okPassword);
                break;
            }else {
                System.out.println("您输入的2次密码不一样,请您确认!");
            }
        }
        System.out.println("请您输入您的取现额度:");
        double limit = sc.nextDouble();
        acc.setLimit(limit);

        //重点:我们需要为这个账号生成一个卡号(由系统自动生成,8位数字表示,不能与其他账户的卡号重复)
        String newCardId = createCardId();
        acc.setCardId(newCardId);

        //3、把这个账号对象,存入到账号集合中去
        accounts.add(acc);
        System.out.println("恭喜您:" + acc.getUserName() + "开户成功,您的卡号是:" + acc.getCardId());
    }

    //返回一个8位数字的卡号,而且这个卡号不能与其他账户的卡号重复
    private String createCardId(){
        while (true) {
            //1、定义一个String类型的变量记住8位数字作为卡号
            String cardId = "";
            //2、使用循环,循环8次每次产生一个随机数给cardID连接起来
            Random r = new Random();
            for (int i = 0; i < 8; i++) {
               int data = r.nextInt(10);
               cardId += data;
            }
            //3、判断cardID中记住的卡号是否与其他账户的卡号重复了,没有重复才可以作为一个新卡号返回。
            Account acc = getAccountByCardId(cardId);
            if (acc == null){
                //说明cardId没有找到账户对象,因此cardID没有与其账户的卡号重复,可以返回它做为一个新卡号
                return cardId;
            }
        }
    }

    //根据卡号查询账户对象返回 account = [c1,c2,c3 ....]
    private Account getAccountByCardId(String cardId){
        //遍历全部的账户对象
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            //判断这个账户对象acc中的卡号是否是我们要找的卡号
            if (acc.getCardId().equals(cardId)){
                return acc;
            }
        }
        return null; //查无此账户,这个卡号不存在
    }

}
package com.liu;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //创建一个ATM对象,代表ATM系统
        ATM atm = new ATM();

        //2、调用ATM对象的start方法,启动系统
        atm.start();

    }
}


面向对象高级一:static修饰成员变量、类变量应该场景


static

叫静态,可以修饰成员变量、成员方法。

成员变量按照有无static修饰,分为两种:

  • 类变量:有static修饰,属于类,在计算机里只有一份,会被类的全部对象共享。

  • 实例变量(对象的变量):无static修饰,属于每个对象的。实例对象属于对象,每个对象中都有一份。

package com.liu.d1_staticdemo;

public class Student {
    //类变量
    static String name;
    //实例变量
    int age;
}
package com.liu.d1_staticdemo;

public class Test {
    public static void main(String[] args) {
        //掌握有无static修饰成员变量的用法、特点
        //1、类变量的用法
        //类名.类变量(推荐)
        Student.name = "懒羊羊";

        //对象.类变量(不推荐)
        Student s1 = new Student();
        s1.name = "小羊";

        Student s2 = new Student();
        s2.name = "小懒";

        System.out.println(s1.name); //小懒
        System.out.println(Student.name); //小懒

        //2、实例变量的用法,属于每个对象的变量
        //对象.实例变量
        s1.age = 22;
        s2.age = 21;
        System.out.println(s1.age); //22

//        System.out.println(Student.age); //报错

    }
}

成员变量的执行原理
 

类变量:属于类,与类一起加载一次,在内存中只有一份,可以被类和类的所有对象共享。

类变量的应用场景

在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。

案例导学:

系统启动后,要求用户类可以记住自己创建了多少个用户对象了。

package com.liu.d1_staticdemo;

public class User {
    //类变量
    public static int number;

    public User(){
//        User.number++;
        //注意:在同一个类中,访问自己类的变量,才可以省略类名不写
        number++;
    }
}
package com.liu.d1_staticdemo;

public class Test2 {
    public static void main(String[] args) {
        //目标:通过案例理解类变量的应用场景
        User u1 = new User();
        User u2 = new User();
        User u3 = new User();
        User u4 = new User();

        System.out.println(User.number);

    }
}

成员变量有几种?各自在什么情况下定义?

  • 类变量:数据只需要一份,且需要被共享时(访问,修改)
  • 实例变量:每个对象都要有一份,数据各不同(如:name、score 、age)

访问自己类中的类变量,是否可以省略类名不写?

  • 可以的
  • 注意:在某个类中访问其他类例的类变量,必须带类名访问


面向对象高级一:static修饰成员变量方法


成员方法的分类

  • 类方法:有static修饰的成员方法,属于类。

  • 实例方法:无static修饰的成员方法,属于对象

package com.liu.d2_static_method;

public class Student {

    double score;
    //类方法
    public static void printHelloWorld(){
        System.out.println("Hello World");
        System.out.println("Hello World");
    }

    public void printPass(){
        System.out.println("成绩:"+
                (score >= 60 ? "及格":"不及格"));
    }
}
package com.liu.d2_static_method;

public class Test {
    public static void main(String[] args) {
        //目标:掌握有无static修饰方法的用法
        //1、类方法的用法
        //类名.类方法()
        Student.printHelloWorld();

        //对象.类方法(不推荐)
        Student s = new Student();
        s.printHelloWorld();

        //2、实例方法的用法
        //对象.实例方法
        s.printPass();
//        Student.printPass(); //报错

    }
}

成员方法的执行原理

补充知识:搞懂main方法


面对对象高级一:static修饰类方法的应用场景——工具类


类方法的常见应用场景

类方法最常见的应用场景是做工具类。

工具类是什么?

工具类中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的。

使用类方法来设计工具类有啥好处?

提高了代码复用:调用方便,提高了开发效率。

案例:

优化后

package com.liu.d3_util;

import java.util.Random;

public class MyUtil {
    public static String createCode(int n){
        String code = "";
        String data = "abvdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ";

        Random r = new Random();
        //定定义一个循环产生每位随机字符
        for (int i = 0; i < n; i++) {
            //随机一个字符范围内的索引
            int index = r.nextInt(data.length());
            //根据索引去全部字符中提取该字符
            code += data.charAt(index); //code = code + 字符
        }
        return code;
    }
}
package com.liu.d3_util;

public class LoginDemo {
    public static void main(String[] args) {
        System.out.println(MyUtil.createCode(4));
    }
}
package com.liu.d3_util;

public class RegisterDemo {
    public static void main(String[] args) {
        System.out.println(MyUtil.createCode(6));
    }
}

为什么工具类中的方法要用类方法,而不用实例方法?

  • 实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,这样会浪费内存。
  • 类方法,直接用类名调用即可,调用方便,也能节省内存。

多学一招:

  • 工具类没有创建对象的需求,建议将工具类的构造器进行私有。


面向对象高级一:static的注意事项


使用类方法、实例方法时的几点注意事项

  • 类方法中可以直接访问类的成员,不可以直接访问实例成员。
  • 实例方法中既可以直接访问类成员,页可以直接访问实例成员。
  • 实例方法中可以出现this关键字,类方法中不可以出现this关键字的。
package com.liu.d3_static_attention;

public class Test {
    public static void main(String[] args) {
        //目标:掌握使用类方法、实例方法的几点注意事项
//        类方法中可以直接访问类的成员,不可以直接访问实例成员。
//        实例方法中既可以直接访问类成员,页可以直接访问实例成员。
//        实例方法中可以出现this关键字,类方法中不可以出现this关键字的。

    }
}
package com.liu.d3_static_attention;

public class Student {

    static String schoolName; //类变量
    double score; //实例变量

    //1、类方法中可以可以直接访问类的成员变量,不可以直接访问实例成员
    public static void printHelloWorld(){
       //注意:同一个类中,访问类成员,可以省略类名不写
//        Student.schoolName = "懒羊羊"; //Student可以省略
        schoolName = "懒羊羊";
        printHelloWorld2();

//        System.out.println(score); //报错
//        printPass(); //报错

//        System.out.println(this); //报错的

    }

    //类方法
    public static void printHelloWorld2(){

    }

    //实例方法
    //实例方法中既可以直接访问类成员,页可以直接访问实例成员。
    public void printPass(){
        schoolName = "玫瑰";
        printHelloWorld2();

        System.out.println(score);
//        this.printPass2(); //this可以省略
        printPass2();

        System.out.println(this);
    }

    //实例方法
    public void printPass2(){

    }
}


面向对象高级一:static应用——代码块


代码块概述

代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。

代码块分为两种:

  • 静态代码块:

格式:static { }

特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。

作用:完成类的初始化,例如:对类变量的初始化赋值。

package com.liu.d5_block;

public class Student {
    static int number = 80;
    static String schoolName;
    //静态代码块
    static {
        System.out.println("静态代码块执行!");
        schoolName = "重要的东西眼睛是看不见的";
    }
}
package com.liu.d5_block;

public class Test {
    public static void main(String[] args) {
        //目标:认识两种代码块,了解他们的特点和基本作用
        System.out.println(Student.number);
        //静态代码块执行!
        //80

        //静态代码块执行! 只会加载一次 只会执行一次
        System.out.println(Student.number);//80
        System.out.println(Student.number);//80

        System.out.println(Student.schoolName); //重要的东西眼睛是看不见的


    }
}

  • 实例代码块:

格式:{ }

特点:每次创建对象时,执行实例代码块,并在构造器前执行。

作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值

package com.liu.d5_block;

public class Student {
    static int number = 80;
    static String schoolName;
    //静态代码块
    static {
        System.out.println("静态代码块执行!");
        schoolName = "重要的东西眼睛是看不见的";
    }

    int age;
    //实例代码块
    {
        System.out.println("实例代码块执行!");
        age = 18;
        System.out.println("有人创建了对象" + this);
    }
    public Student(){
        System.out.println("无参构造器执行!");
//        System.out.println("有人创建了对象" + this);
    }
    public Student(String name){
        System.out.println("有参构造器执行!");
//        System.out.println("有人创建了对象" + this);
    }
}
package com.liu.d5_block;

public class Test {
    public static void main(String[] args) {
        //目标:认识两种代码块,了解他们的特点和基本作用
        System.out.println(Student.number);
        //静态代码块执行!
        //80

        //静态代码块执行! 只会加载一次 只会执行一次
        System.out.println(Student.number);//80
        System.out.println(Student.number);//80

        System.out.println(Student.schoolName); //重要的东西眼睛是看不见的

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

        Student s1 = new Student();
        Student s2 = new Student("鹦鹉");
        System.out.println(s1.age);
        System.out.println(s2.age);
    }
}


面向对象高级一:static应用——单例设计模式、饿汉式单例、懒汉式单例


什么是设计模式(Design pattern)?

  • 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为式设计模式。
  • 设计模式有20多种,对应20多种软件开发中遇到的问题。

关于设计模式的学习,主要学什么?

1、解决什么问题?

2、怎么写?

单例设计模式

  • 确保一个类只有一个对象。

单例写法

  • 把类的构造器私有。
  • 定义一个类变量记住类的一个对象。
  • 定义一个类方法,返回对象。
package com.liu.d6_singleInstance;

public class A {

    //2、定义一个类变量记住类的一个对象
    private static A a = new A();

    //1、必须私有类的构造器
    private A(){

    }

    //3、定义一个类方法返回类的对象
    public static A getObject(){
      return a;
    }
}
package com.liu.d6_singleInstance;

public class Test1 {
    public static void main(String[] args) {
        //目标:掌握单例模式的写法
        A a1 = A.getObject();
        A a2 = A.getObject();
        System.out.println(a1);
        System.out.println(a2);

    }
}

单例模式的应用场景和好处?

1、Runtime

2、任务管理器对象、获取运行时对象

在这些业务场景下,使用单例模式,可以避免浪费内存。

单例设计模式的实现方式很多

  • 饿汉式单例:拿对象时,对象早就创建好了。
  • 懒汉式单例:拿对象时,才开始创建对象。
  • ......
  • ......
  • ......

懒汉式单例设计模式

  • 拿对象时,才开始创建对像。

写法

  • 把类的构造器私有。
  • 定义一个类变量用于存储对象。
  • 提供一个类方法,保证返回的是同一个对象。
package com.liu.d6_singleInstance;

public class B {
    //2、定义一个类变量,用于存储这个类的一个对象
    private static B b;

    //1、把类的构造器私有
    private B(){

    }
    //3、定义一个类方法,这个方法要保证第一次调用时才创建一个对象,后面调用时都会用这同一个对象返回
    public static B getInstance(){
        if (b == null){
            System.out.println("第一次创建对象!");
            b = new B();
        }
        return b;
    }
}
package com.liu.d6_singleInstance;

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

        B b1 = B.getInstance(); //第一次拿对象
        B b2 = B.getInstance();
        System.out.println(b1 == b2);
    }
}


面向对象高级一:继承:使用继承的好处


Java使用extends作为继承的关键字,extends关键字在英文中时扩展,而不是继承!这个关键字很好地体现了子类和父类地关系:子类时对父类地扩展,子类是一种特殊地父类。从这个意义上来看,使用继承来描述子类和父类地关系是错误的,用扩展更恰当。

子类扩展了父类,将可以获得父类的全部成员变量和方法,值得指出的是,Java子类不能获得父类的构造器。

什么是继承呢?

  • Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。实现继承的类被称为子类,被继承的类被称为父类,有的也称其为基类、超类。父类和子类的关系,是一种一般与特殊的关系。

继承的特点

  • 子类能继承父类的非私有成员(成员变量、成员方法)
  • 继承后对象的创建
  • 子类的对象是由子类、父类共同完成的。
package com.liu.d7_extends;

//父类
public class A {
    //公开成员
    public int i ;
    public void print1(){
        System.out.println("==print1==");
    }

    //私有成员
    private int j;
    private void print2(){
        System.out.println("==print2==");
    }


}
package com.liu.d7_extends;

//子类
public class B extends A{
    public int k ;
    private int z;
    //子类可以继承父类的非私有成员
    public void print3(){
        System.out.println(i);
        print1();

//        System.out.println(j); //报错
//        print2(); //报错
    }
}
package com.liu.d7_extends;

public class Test {
    public static void main(String[] args) {
        //目标:认识继承,掌握继承的特点。
        B b = new B();
        System.out.println(b.i);
//        System.out.println(b.j);//报错
        System.out.println(b.k);
//        System.out.println(b.z); //报错

        b.print1();
//        b.print2(); //报错
        b.print3();
    }
}

继承的执行原理

带继承关系的类,Java会怎么创建它的对象?对象创建出来后,可以直接访问哪些成员?

  • 带继承关系的类,Java会用类和其父类,这多张设计图来一起创建类的对象。
  • 对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员

使用继承有啥好处?

  • 减少重复代码的编写。

需求

  • 黑马的员工管理系统中
  • 需要处理讲师、咨询师的数据
  • 讲师的数据有:姓名、具备的技能
  • 咨询的数据有:姓名、解答问题的总人数

package com.liu.d8_extends_application;

public class People {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.liu.d8_extends_application;

public class Teacher extends People{
    private String skill;

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public void printInfo(){
        System.out.println(getName()+"具备的技能:"+skill);
    }
}
package com.liu.d8_extends_application;

public class Tets {
    public static void main(String[] args) {
        //目标:高清楚继承的好处
        Teacher t = new Teacher();
        t.setName("玫瑰");
        t.setSkill("陪伴小王子");
        System.out.println(t.getName());
        System.out.println(t.getSkill());
        t.printInfo();

    }
}


面向对象高级一:继承:权限修饰符


 什么是权限修饰符?

  • 就是用来限制类中的成员(成员变量、成员方法、构造器、代码块...)能够被访问的范围。

权限修饰有几种?各自的作用是什么?

package com.liu.d9_modifer;

public class Fu {
    //1、私有:只能在本类中访问
    private void privateMethod(){
        System.out.println("==private==");
    }

    //2、缺省:本类,同一个包下的类
    void method(){
        System.out.println("==缺省==");
    }

    //3、protected:本类,同一个包下的类,任意包下的子类
    protected void protectedMethod(){
        System.out.println("==protected==");
    }

    //4、public:本类,同一个包下的类,任意包下的子类,任意包下的任意类
    public void publicMethod(){
        System.out.println("==public==");
    }

    public void test(){
        privateMethod();
        method();
        protectedMethod();
        publicMethod();
    }
}
package com.liu.d9_modifer;

public class Demo {
    public static void main(String[] args) {
        //目标:掌握不同权限修饰符的作用
        Fu f = new Fu();
//        f.privateMethod();//报错
        f.method();
        f.protectedMethod();
        f.publicMethod();

    }
}
package com.liu.d10_modifer;

import com.liu.d9_modifer.Fu;

public class Zi extends Fu {
    public void test(){
//        privateMethod(); //报错
//        method(); //报错
        protectedMethod();
        publicMethod();
    }

}
package com.liu.d10_modifer;

import com.liu.d9_modifer.Fu;

public class Demo2 {
    public static void main(String[] args) {
        Fu f = new Fu();
//        f.privateMethod();//报错
//        f.method();//报错
//        f.protectedMethod();//报错
          f.publicMethod();

          Zi zi = new Zi();
//          zi.protectedMethod();//报错
    }
}


面向对象高级一:继承:单继承、Object、方法重写


Java是单继承,Java中的类不支持多继承,但是支持多层继承

package com.liu.d11_extends_feature;

public class Test {
    public static void main(String[] args) {
    //目标:掌握继承的两个注意事项
    //1、Java是单继承的:一个类只能继承一个直接父类:Java中的类不支持多继承,但是支持多层继承。
    //2、Object类是Java中所有类的祖宗

    }
}

class A{}
class B extends A{}

//class C extends B,A{} //报错
class C extends B{}

class D extends B{}

为何Java中的类不支持多继承

请看如下反证法:

Object类

  • object类是Java所有类的祖宗类。我们写的任何一个类,其实都是object的子类或子孙类
package com.liu.d11_extends_feature;

public class Test {
    public static void main(String[] args) {
    //目标:掌握继承的两个注意事项
    //1、Java是单继承的:一个类只能继承一个直接父类:Java中的类不支持多继承,但是支持多层继承。
    //2、Object类是Java中所有类的祖宗

        A a = new A();

    }
}

class A {}
//class A extends Object{}//默认继承Object类
class B extends A{}

//class C extends B,A{} //报错
class C extends B{}

class D extends B{}

什么是方法重写?

  • 当子类决定父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
  • 注意:重写后,方法的访问,Java会遵循就近原则。
  • 方法的重写要遵循“两同大小一大”规则,“两同”即方法名相同、形参列表相同;“两小”指的是子类方法返回值类型应比父类返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;“一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。
package com.liu.d12_extends_override;

public class A {
    public void print1(){
        System.out.println("积极向上永远时主旋律");
    }

    public void print2(int a,int b){
        System.out.println("希望我希望的有希望");
    }
}
package com.liu.d12_extends_override;

public class B extends A{
    //方法重写
    public void print1(){
        System.out.println("做真正自己喜欢的事");
    }

    //方法重写
    public void print2(int a,int b){
        System.out.println("不是因为有希望才坚持,是因为坚持才有希望");
    }

}
package com.liu.d12_extends_override;

public class Test {
    public static void main(String[] args) {
        //目标:认识方法重写,掌握方法重写的常见应用场景
        B b = new B();
        b.print1();
        b.print2(5,500);

    }
}

方法重写的其它注意事项

  • 重写小技巧:使用Override注解,它可以指定Java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。建议加上注解
  • 子类重写父类方法时,访问权限必须大于或者等于父类方法的权限(public>protected>缺省)。
  • 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
  • 私有方法、静态方法不能被重写,如果重写会报错的。

方法重写在开发中的常见应用场景

  • 子类重写Object类的toString()方法,以便返回对象的内容。
package com.liu.d12_extends_override;

public class Student extends Object{
    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.liu.d12_extends_override;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //目标:认识方法重写,掌握方法重写的常见应用场景
       

        Student s = new Student("懒羊羊",18);
        //System.out.println(args.toString()); //com.liu.d12_extends_override.Student@4554617c
        System.out.println(s);//com.liu.d12_extends_override.Student@4554617c

        ArrayList list = new ArrayList();
        list.add("立刻!");
        System.out.println(list);

    }
}


面向对象高级一:继承:子类访问成员变量的特点


1、 在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的。

package com.liu.d13_extends_visit;

public class F {
    String name = "治愈懒羊羊";

    public void print1(){
        System.out.println("==维持关系的最好办法是分享==");
    }
}
package com.liu.d13_extends_visit;

public class Z extends F{
    String name = "小懒";
    public void showName(){
        String name = "玫瑰";
        System.out.println(name); //局部名称
        System.out.println(this.name); //子类成员变量name
        System.out.println(super.name);//父类的成员变量
    }

    @Override
    public void print1(){
        System.out.println("请立刻学习!");
    }
    public  void  showMethod(){
        print1();//父类的
        super.print1();
    }
}
package com.liu.d13_extends_visit;

public class Test {
    public static void main(String[] args) {
        //目标:掌握子类中访问其他成员的特点:就近原则
        Z z = new Z();
        z.showName();
        z.showMethod();
    }
}

  • 先子类局部范围找。
  • 然后子类成员范围找。
  • 然后父类成员范围找,如果父类范围还没有找到则报错。

2、如果子类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?

  • 可以通过super关键字,指定访问父类的成员:super . 父类成员变量/父类成员方法


面向对象高级一:继承:子类构造器的特点,super、this调用兄弟构造器


子类构造器的特点:

  • 子类的全部构造器,都会先调用父类的构造器,再执行自己。
package com.liu.d14_extends_constructor;

class F{
//    public F(){
//        System.out.println("==父类F的 无参构造器 执行了==");
//    }

    public F(String name,int age){

    }
}

class Z extends F{
    public Z(){
//        super();//默认存在的
        super("小懒",18);
        System.out.println("==子类的 无参构造器 执行了==");
    }

    public Z(String name ){
        //        super();//默认存在的
        super("小懒",18);
        System.out.println("==子类的 有参构造器 执行了==");
    }
}

public class Test {
    public static void main(String[] args) {
    //目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景
        Z z = new Z();
        Z z2 = new Z("懒羊羊");

    }
}

子类构造器是如何实现调用父类构造器的:

  • 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器。
  • 如果父类没有无参数构造器,则我们必须再子类构造器的第一行手写super(...),指定去调用父类的有参数构造器。

子类构造器的特点

  • 子类的全部构造器都会先调用父类的构造器
package com.liu.d14_extends_constructor;

public class Test2 {
    public static void main(String[] args) {
        //目标:搞清楚子类构造器为什么要调用父类构造器,有啥应用场景
        Teacher t = new Teacher("小懒",36,"java");
        System.out.println(t.getName());
        System.out.println(t.getAge());
        System.out.println(t.getSkill());
    }
}

class Teacher extends People{
    private String skill;

    public Teacher(String name,int age,String skill){
        super(name,age);
        this.skill = skill;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
}

class People{
    private String name;
    private int age;

    public People() {
    }

    public People(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;
    }
}

子类构造器调用父类构造器的常见应用场景

  • 子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化赋值,再回来把对象里包含子类这部分的数据也进行初始化赋值。

补充知识:this(...)调用兄弟构造器

  • 任意类的构造器中,是可以通过this(...)去调用该类的其他构造器的。
package com.liu.d14_extends_constructor;

public class Test3 {
    public static void main(String[] args) {
        //目标:掌握在类的构造器中,通过this(...)调用兄弟构造器的作用
        Student s1 = new Student("懒羊羊",18,"牛津大学");

        //需求:如果学生没有填写学校,那么学校默认就是黑马程序员
        Student s2 = new Student("玫瑰",20);
        System.out.println(s2.getName());
        System.out.println(s2.getAge());
        System.out.println(s2.getSchoolName());

    }
}

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

    public Student() {
    }

    public Student(String name,int age){
        this(name,age,"清华大学");
//        super(); //this和super不能同时出现在构造器里面
    }

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

    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 getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}

1、子类构造器的特点:

  • 子类中的全部构造器,都必须先调用父类的构造器,在执行自己。

2、super(...)调用父类有参数构造器的常见应用场景是什么?

  • 为对象包含父类这部分的成员变量进行赋值。

3、this(...)的作用是什么?

  • 在构造器中调用本类的其他构造器。

4、this(...)和super(...)的使用需要注意什么?

  • 都必须放在构造器的第一行


面向对象高级二:多态、使用多态的好处


java引用变量有两个类型:一个时编译时的类型,一个时运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋值给变量的对象决定。如果编译时类型和运行类型不一致,就可能出现所谓的多态(Polymorphism)。

什么是多态?

多态是在继承/实现的情况下的一种现象,表现为:对象多态、行为多态。

多态的具体代码体现

package com.liu.d1_polymorphism;
//父类
public class People {
    public String name = "父类People的名称!";
    public void run(){
        System.out.println("我自己就是太阳,我需要找个并肩的人!");
    }
}
package com.liu.d1_polymorphism;

public class Student extends People{
    @Override
    public void run(){
        System.out.println("故事的开头总是这样!");
    }
}
package com.liu.d1_polymorphism;

public class Teacher extends People{
    @Override
    public void run(){
        System.out.println("如果心动了,那为何不坚定呢?");
    }
}
package com.liu.d1_polymorphism;

public class Test {
    public static void main(String[] args) {
        //目标:认识多态,对象多态,行为多态
        //1、对象多态
        People p1 = new Teacher();
        p1.run();//识别技巧:编译看左边,运行看右边
        System.out.println(p1.name);//编译看左边,运行看右边

        People p2 = new Student();
        p2.run();//识别技巧:编译看左边,运行看右边
        System.out.println(p2.name);//编译看左边,运行看右边


    }
}

使用多态的好处

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护。

  • 定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强、更便利。
package com.liu.d2_polymorphism;
//父类
public class People {
    public String name = "父类People的名称!";
    public void run(){
        System.out.println("我自己就是太阳,我需要找个并肩的人!");
    }
}
package com.liu.d2_polymorphism;

public class Student extends People {
    public String name ="子类Student的名称";

    @Override
    public void run(){
        System.out.println("故事的开头总是这样!");
    }
    public void test(){
        System.out.println("学生需要考试");
    }
}
package com.liu.d2_polymorphism;

public class Teacher extends People {

    public String name = "子类Teacher的名称";
    @Override
    public void run(){
        System.out.println("如果心动了,那为何不坚定呢?");
    }
    public void teacher(){
        System.out.println("老师需要教知识");
    }
}
package com.liu.d2_polymorphism;

public class Test {
    public static void main(String[] args) {
        //目标:理解多态的好处
        //1.可以实现解耦合,右边对象可以随时切换,后续业务随机改变
        People p1 = new Student();
        p1.run();//识别技巧:编译看左边,运行看右边
//        p1.test();//多态下存在的问题,无法直接调用子类的独有功能

        Student s = new Student();
        go(s);

        Teacher t = new Teacher();
        go(t);
    }

        //2、可以使用父类类型的变量作为形参,可以接受一切子类对象
        public static void go(People p){

        }

}

多态下会产生的一个问题,怎么解决?

  • 多态下不能使用子类的独有功能。

类型转换

  • 自动类型转换:父类 变量名 = new 子类();
  • 强制类型转换:子类 变量名 = new  父类变量();


强制类型转换的一个注意事项

  • 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
  • 运行时,如果发现对象的真实类型与强转后的类型不同,就会类型转换异常(CalssCastException)的错误出来。

强转前,Java建议:

  • 使用instanceof关键字,判断当前对象的真实类型,再进行强转

package com.liu.d2_polymorphism;
//父类
public class People {
    public String name = "父类People的名称!";
    public void run(){
        System.out.println("我自己就是太阳,我需要找个并肩的人!");
    }
}
package com.liu.d2_polymorphism;

public class Student extends People {
    public String name ="子类Student的名称";

    @Override
    public void run(){
        System.out.println("故事的开头总是这样!");
    }
    public void test(){
        System.out.println("学生需要考试");
    }
}
package com.liu.d2_polymorphism;

public class Teacher extends People {

    public String name = "子类Teacher的名称";
    @Override
    public void run(){
        System.out.println("如果心动了,那为何不坚定呢?");
    }
    public void teach(){
        System.out.println("老师需要教知识");
    }
}
package com.liu.d2_polymorphism;

public class Test {
    public static void main(String[] args) {
        //目标:理解多态的好处
        //1.可以实现解耦合,右边对象可以随时切换,后续业务随机改变
        People p1 = new Student();
        p1.run();//识别技巧:编译看左边,运行看右边
//        p1.test();//多态下存在的问题,无法直接调用子类的独有功能
        //强制类型转换
        Student  s1 = (Student) p1;
        s1.test();

        //强制类型转换可能存在的问题,编译阶段有继续或者实现关系就可以强制转换,但是运行时可能出现类型转换异常
//        Teacher t1 = (Teacher)p1;
        if(p1 instanceof  Student){
            Student s2 = (Student) p1;
            s2.test();
        }else if (p1 instanceof  Teacher){
            Teacher t2 = (Teacher) p1;
            t2.teach();
        }

        Student s = new Student();
        go(s);

        Teacher t = new Teacher();
        go(t);
    }


        //2、可以使用父类类型的变量作为形参,可以接受一切子类对象
        public static void go(People p){
        p.run();
        if (p instanceof Student){
            Student s = (Student) p;
                s.test();
            }else if (p instanceof Teacher){
                Teacher t = (Teacher) p;
                t.teach();
            }
        }

}



面向对象高级二:final、常量


final

  • final关键字是最终的意思,可以修饰(类、方法、变量)
  • 修饰类:该类称为最终类,特点是不能被继承了。
  • 修饰方法:该方法称为最终方法,特点是不能被重写了。
  • 修饰变量:该变量只能被赋值一次。
package com.liu.d3_final;

public class Test {
    /**
     * 常量:public static final修饰的成员变量,建议名称全部大写,多个单词下划线连接
     */
    public static final String schoolName = "小懒";

    private final String name = "小羊";

    public static void main(String[] args) {
        //目标:认识final作用
        //3、final可以修饰变量:总规则:只能赋值一次值
        //变量:
        //1局部变量 2成员变量
        //成员变量:1实例变量 2类变量(静态成员变量)

        final  int a ;
        a = 12;
//        a = 13; //第二次赋值,出错了

        final double r = 3.14;
        // r=0.1; //第二次赋值,出错了

//        schoolName = "玫瑰"; //第二次赋值,出错了

        Test t = new Test();
//        t.name = "总负责人";//第二次赋值,出错了
    }

    public static void buy(final double z){
        // z=0.1; //第二次赋值,出错了
    }
}

//1、final修饰类,类不能被继承了
final class A{

}
//class B extend A{}
//2、final修饰方法,方法不能被重写了
class C{
    public final void test(){

    }
}
class D extends C{
//    @Override
//    public void test(){}
}

final修饰变量的注意

  • final修饰基本类型的变量,变量存储的数据不能被改变
  • final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。

常量

  • 使用了static final修饰的成员变量就被称为常量
  • 作用:通常用于记录系统的配置信息

  • 注意:常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来

使用常量记录系统配置信息的优势、执行原理

  • 代码可读性更好,可维护性也更好
  • 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
package com.liu.d3_final;

public class Test2 {

    public static final String SCHOL_NAME = "阳光万里";

    public static void main(String[] args) {
        //目标:认识常量
//        System.out.println("阳光万里");
//        System.out.println("阳光万里");
//        System.out.println("阳光万里");
//        System.out.println("阳光万里");
//        System.out.println("阳光万里");
//        System.out.println("阳光万里");
        System.out.println(SCHOL_NAME);
        System.out.println(SCHOL_NAME);
        System.out.println(SCHOL_NAME);
        System.out.println(SCHOL_NAME);
        System.out.println(SCHOL_NAME);
    }
}


面向对象高级二:抽象类——认识抽象类和其好处


什么是抽象类?

  • 在Java中有一个关键字叫abstract,它就是抽象的意思,可以用它修饰类、成员方法
  • abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
     

抽象类的注意事项、特点

  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类。
  • 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
package com.liu.d4_abstract;

//抽象类
public abstract class A {

    private String name;
    public static String schoolName;

//    public abstract void run(){
//    }
    //抽象方法:必须用abstract修饰,只要方法签名,一定不能有方法体
    public abstract void run();

    public A(){

    }

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

    public String getName() {
        return name;
    }

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

    public static String getSchoolName() {
        return schoolName;
    }

    public static void setSchoolName(String schoolName) {
        A.schoolName = schoolName;
    }
}
package com.liu.d4_abstract;

public class Test {
    public static void main(String[] args) {
        //目标:认识抽象类和其特点
        //注意:抽象类不能创建对象
//        A a = new A() ; //报错


    }
}
package com.liu.d4_abstract;

//一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则自己也是抽象类
public class B extends A{

    @Override
    public void run() {

    }
}

抽象类的场景和好处

  • 父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类重写实现,我们设计这样的抽象类,就是为了更好的支持多态

案例

package com.liu.d5_abstract2;

public abstract class Animal {
    private String name;

    public abstract void cry();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.liu.d5_abstract2;

public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println(getName() + "喵喵的叫!");
    }
}
package com.liu.d5_abstract2;

public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println(getName() + "汪汪的叫!");
    }
}
package com.liu.d5_abstract2;

public class Test {
    public static void main(String[] args) {
        //目标:掌握抽象类的好处
        Animal a = new Cat();
        a.setName("小猫咪");
        a.cry(); //更好的支持了多态
    }
}


面向对象高级二:抽象类的应用——模板方法设计模式


模板方法设计模式解决了什么问题?

  • 解决方法中存在重复代码的问题。

模板方法设计模式的写法

1、定义一个抽象类。

2、在里面定义2个方法
一个是模板方法:把相同代码放里面去。
一个是抽象方法:具体实现交给子类完成。

package com.liu.d6_abstract_template;

public abstract class People {
    //设计模板方法模式
    //1、定义一个模板方法出来
    public final void write(){
        System.out.println("\t\t\t\t\t我的爸爸");
        System.out.println("\t\t不是因为有希望才坚持,是因为坚持才有希望");
        //2、模板方法并不清楚正文部分到底应该怎么写,但是它知道子类肯定要写
        System.out.println(writeMain());

        System.out.println("不要在饿肚子的时候进超市,会买错东西,会把本来不想要的东西放进购物车");

    }
    //3、设计一个抽象方法写正文,具体的实现交给子类来完成
    public abstract String writeMain();

}
package com.liu.d6_abstract_template;

public class Student extends People{


    @Override
    public String writeMain() {
        return "我自己就是太阳,我需要找个并肩的人!";
    }
}
package com.liu.d6_abstract_template;

public class Teacher extends People{

    @Override
    public String writeMain() {
        return "在无人问津的地方历练,在万众瞩目的地方出现!!!";
    }

}
package com.liu.d6_abstract_template;

public class Test {
    public static void main(String[] args) {
        //目标:搞清楚抽象类的应用场景之一,经常用来设计模板方法模式
        //场景:学生,老师都要写一篇作文:我的爸爸
        //第一段 是一样的
        //正文部分自由发挥
        //最后一段也是一样的
        Teacher t = new Teacher();
        t.write();

        Student s = new Student();
        s.write();

    }
}

多学一招:建议使用final关键字修饰模板方法,为什么?

  • 模板方法是给对象直接用的,不能被子类重写。
  • 一旦子类重写了模板方法,模板方法就失效了。


面向对象高级二:接口:认识接口,使用接口的好处


认识接口

  • Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口

  • 注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的称为实现类。

  • 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
package com.liu.d7_interface;

public interface A {
    //成员变量(常量)
    String SCHOOL_NAME = "玫瑰";

    //成员方法(抽象方法)
    void test();

}
package com.liu.d7_interface;

public interface B {
    void testB1();
    void testB2();
}
package com.liu.d7_interface;

public interface C {
    void test1();
    void test2();
}
package com.liu.d7_interface;

public class D implements B,C{
    @Override
    public void testB1() {

    }

    @Override
    public void testB2() {

    }

    @Override
    public void test1() {

    }

    @Override
    public void test2() {

    }
}
package com.liu.d7_interface;

public class Test {
    public static void main(String[] args) {
        //目标:认识接口
        System.out.println(A.SCHOOL_NAME);

//        A  a = new A();

        D d = new D();
        d.test1();

    }
}

接口的好处(重点)

  • 弥补了类单继承的不足,一个类同时可以实现多个接口
  • 让程序可以面对接口编程,这样程序员就可以灵活方便的切换各种业务实现。
package com.liu.d7_interfance2;

import com.liu.d5_abstract2.Animal;
import com.liu.d5_abstract2.Cat;

public class Test {
    public static void main(String[] args) {
        //目标:搞清楚使用接口的好处
        Driver s = new A();
        s.driver();
        
        Driver d = new B();
        d.driver();

        Animal a = new Cat();
        a.cry();

    }
}
class B implements Driver{

    @Override
    public void driver() {
        
    }
}

class A extends Student implements Driver,Singer{

    @Override
    public void driver() {

    }

    @Override
    public void sing() {

    }
}

class Student{

}

interface Driver{
    void driver();

}

interface Singer{
    void sing();

}


面向对象高级二:接口:综合案例


案例:接口的应用案例:班级学生信息管理模块

package com.liu.d7_interface_demo;

public class Student {
    private String name;
    private char sex;
    public double score;

    public Student() {
    }

    public Student(String name, char sex, double score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}
package com.liu.d7_interface_demo;

import java.util.ArrayList;

public class ClassManager {
    private ArrayList<Student> students = new ArrayList<>();
    private StudentOPerator studentOPerator = new StudentOperatorImpl1();
//    private StudentOPerator studentOPerator = new StudentOperatorImpl2();

    public ClassManager(){
       students.add(new Student("喜欢的东西买了吗",'女',20));
        students.add(new Student("陌生人",'女',18));
        students.add(new Student("玫瑰",'女',21));
        students.add(new Student("懒羊羊",'女',3));
    }
    //打印全班全部学生的全部信息
    public void printInfo(){
        studentOPerator.printAllInfo(students);

    }
    //打印全班全部学生的平均分
    public void printScore(){
        studentOPerator.printAverageScore(students);

    }
}
package com.liu.d7_interface_demo;

import java.util.ArrayList;

public interface StudentOPerator {
    void printAllInfo(ArrayList<Student> students);
    void printAverageScore(ArrayList<Student> students);
}
package com.liu.d7_interface_demo;

import java.util.ArrayList;

public class StudentOperatorImpl1 implements StudentOPerator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("---------------全班全部学生信息如下:------------------------");
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println("姓名:"+s.getName()+"性别:"+ s.getSex()+"成绩:"+s.getScore());
        }
        System.out.println("--------------------------------------------------------");
    }

    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore = 0.0;
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            allScore += s.getScore();
        }
        System.out.println("平均分:"+(allScore)/students.size());

    }
}
package com.liu.d7_interface_demo;

import java.util.ArrayList;

public class StudentOperatorImpl2 implements StudentOPerator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("---------------全班全部学生信息如下:------------------------");
        int count1 = 0;
        int count2 = 0;
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            System.out.println("姓名:"+s.getName()+"性别:"+ s.getSex()+"成绩:"+s.getScore());
            if (s.getSex() == '男'){
                count1++;
            }else {
                count2++;
            }
        }
        System.out.println("男生人数是:" + count1 + ",女生人数是" + count2);
        System.out.println("班级总人数是:"+ students.size());
        System.out.println("--------------------------------------------------------");
    }

    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore = 0.0;
        double max = students.get(0).getScore();
        double min = students.get(0).getScore();
        for (int i = 0; i < students.size(); i++) {
            Student s = students.get(i);
            if (s.getScore() >= max) max = s.getScore();
            if (s.getScore() <= min) min = s.getScore();
            allScore += s.getScore();
        }
        System.out.println("学生的最高分是:" + max);
        System.out.println("学生的最低分是:" + min);
        System.out.println("平均分:"+ (allScore-max-min)/(students.size()-2));

    }
}
package com.liu.d7_interface_demo;

public class Test {
    public static void main(String[] args) {
        //目标:完成班级学生信息管理的案例
        ClassManager class2 = new ClassManager();
        class2.printInfo();
        class2.printScore();

    }
}
  •  
  • StudentOperatorImpl1() 或 StudentOperatorImpl2()不同运行出来的结果也会不同


面向对象高级二:接口:JDK8开始接口新增的方法、接口的多继承、注意事项


package com.liu.d8_interface_jdk8;

public interface A {
    //1、默认方法,必须使用interface修饰,默认会被public修饰
    //实例方法,对象的方法,必须使用实现类的对象访问
     default void test(){
        System.out.println("==默认方法==");

        //私有方法的访问
//        test2();
    }

    //2、私有方法,必须使用private修饰(JDK9才开始支持的)
//    private void test2(){
//        System.out.println("==私有方法==");
//
//    }

    //3、静态方法,必须使用static修饰,默认会被public修饰
    static void test3(){
        System.out.println("==静态方法==");
    }

    void test4();
     void test5();
     default void test6(){}
}
package com.liu.d8_interface_jdk8;

public class B implements A{
    @Override
    public void test4() {

    }

    @Override
    public void test5() {

    }
}
package com.liu.d8_interface_jdk8;

public class Test {
    public static void main(String[] args) {
        //目标:掌握接口新增的三种方法模式
        B b = new B();
        b.test();

//        b.test3(); //错误访问

        A.test3();


    }
}


JDK开始,接口新增了三种形式的方法:

JDK8开始,接口中为啥要新增这些方法?

  • 增强了接口的能力,更便于项目的扩展和维护。
     

接口的多继承

  • 一个接口可以同时继承多个接口

package com.liu.d9_interface_attention;

public class Test {
    public static void main(String[] args) {
        //目标:理解接口的多继承
    }
}

interface A{
    void test1();
}
interface B{
    void test2();
}
interface C{}
//接口是多继承的
interface D extends C,B,A{}

class E implements D{

    @Override
    public void test1() {
        
    }

    @Override
    public void test2() {

    }
}

接口多继承的作用

  • 便于实现类的实现

接口其他注意事项(了解)

1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承

2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现

3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的

4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

package com.liu.d9_interface_attention;

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

    //目标:接口其他注意事项(了解)
        Zi zi = new Zi();
        zi.run();
    }
}

// 1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承
interface I{
    void test1();
}
interface J{
    String test1();
}
//interface K extends I,J{}

// 2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现
//class E implements I,J{}

// 3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的
class Fu{
    public  void  run(){
        System.out.println("==父类的run方法执行了==");
    }
}
interface IT{
    default void run(){
        System.out.println("==接口IT中的run方法执行了==");
    }
}
class Zi extends Fu implements IT{

}
//class Zi implements IT extends Fu{} //写法错误

//4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
interface It1{
    default void test1(){
        System.out.println("IT1");
    }
}
interface It2{
    default void  test1(){
        System.out.println("IT2");
    }
}
class N implements It1,It2{
    @Override
    public void test1() {
        System.out.println("自己的");
    }
}


 


面向对象高级三:内部类概述、成员内部类、静态内部类


内部类

  • 是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类
  • 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。

内部类有四种形式

  • 1、成员内部类
  • 2、静态内部类
  • 3、局部内部类
  • 4、匿名内部类(重点)

成员内部类

  • 就是类中的一个普通成员,类似普通的成员变量、成员方法。

package com.liu.d1_inner_class1;


public class Outer {

    private  int age = 99;
    public static String o;

    //成员内部类
    public class Inner{
        private String name;
//        public static String schoolName; //JDK16 才开始支持定义静态成员的
        private int age = 88;

        public void test(){
            System.out.println(age);
            System.out.println(o);

            int age = 66;
            System.out.println(age); //66
            System.out.println(this.age);//88
            System.out.println(Outer.this.age);//99
            //66
            //88
            //99
        }

        public String getName() {
            return name;
        }

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

    public void test2(){
        System.out.println(age);
        System.out.println(o);
    }
}
package com.liu.d1_inner_class1;

public class Test {
    public static void main(String[] args) {
        //目标:了解成员内部类和其特点
        Outer.Inner in = new Outer().new Inner();
        in.test();


    }
}

注意:

  • JDK16之前,成员变量内部类中不能定义静态成员,JDK16开始也可以定义静态成员了。

创建对象的格式:

成员内部类中访问其他成员的特点:

  • 1、和前面学过的实例方法一样,成员内部类的实例方法中,同样可以直接访问外部的实例成员、静态成员。
  • 2、可以在成员内部类的实例方法中,拿到当前外部类对象,格式是:外部类名 . this 

什么是静态内部类?

  • 有static修饰的内部类,属于外部类自己持有

package com.liu.d2_inner_class2;

public class Outer {

    private int age;
    public static String schoolName;

    //静态内部类
    public static class Inner{
        private String name;
        public static int a ;

        public void test(){
            System.out.println(schoolName);
//            System.out.println(age);
        }

        public String getName() {
            return name;
        }

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

    public static void test2(){
        System.out.println(schoolName);
//        System.out.println(age);
    }
}
package com.liu.d2_inner_class2;

public class Test {
    public static void main(String[] args) {
        //目标:了解静态内部类
        Outer.Inner in = new Outer.Inner();
        in.test();
    }
}

创建对象的格式:

静态内部类中访问外部类成员的特点

  • 可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。

 局部内部类

  • 局部内部类是定义在方法中、代码块中、构造器等执行体中


面向对象高级三:认识匿名内部类、匿名内部类的使用场景和应用场景


匿名内部类 

  • 就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字。

package com.liu.d3_inner_class3;

import jdk.nashorn.internal.ir.CatchNode;

public class Test {
    public static void main(String[] args) {
        //目标:认识匿名内部类,并掌握其作用
//        Animal a = new Cat();
//        a.cry();

        //1、把这个匿名内部类编译成子类,然后它会立即创建一个子类对象出来,
        Animal a = new Animal(){
            @Override
            public void cry() {
                System.out.println("喵喵喵的叫!");
            }
        };
        a.cry();
    }
}

//class Cat extends Animal{
//
//    @Override
//    public void cry() {
//        System.out.println("喵喵喵的叫!");
//    }
//}

abstract class Animal{
    public abstract void cry();
}

  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
  • 作用:用于更方便的创建一个子类对象。

匿名内部类在开发中的使用场景

  • 通常作为一个参数传输给方法

需求:

猫、狗参加游泳比赛。

package com.liu.d3_inner_class3;

public class Test2 {
    public static void main(String[] args) {
        //目标:掌握匿名内部类的使用场景
//       Swimming s1 = new Swimming(){
//            @Override
//            public void swim() {
//                System.out.println("狗游泳飞快!");
//            }
//        };
//       go(s1);

        go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("狗游的飞快!");
            }
        });
    }
    //设计一个方法,可以接收swimming接口的一切实现类对象进来参加游泳比赛
    public static void go(Swimming s){
        System.out.println("开始——————————————————————————————————");
        s.swim();
    }
}

//猫和狗都要参加游泳笔试
interface Swimming{
    void swim();
}

拓展:匿名内部类在开发中的使用场景

package com.liu.d5_inner_class5;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test {
    public static void main(String[] args) {
        //拓展:匿名内部类在开发中的使用场景
        //BUI编程
        //1、创建窗口
        JFrame win = new JFrame("登录界面");
        JPanel panel = new JPanel();
        win.add(panel);

        JButton btn = new JButton("登录");
        panel.add(btn);

        //给按钮绑定单击事件监听器
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(win,"登陆一下!");
            }
        });
        //最终的核心目的是:简化代码

        win.setSize(400,400);
        win.setLocationRelativeTo(null);
        win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        win.setVisible(true);
    }
}


面向对象高级三:认识枚举,枚举的作用和应用场景


枚举

  • 枚举是一种特殊类。

枚举类的格式:

注意:

  • 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开
  • 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
package com.liu.d6_enum;

public class Test {
    public static void main(String[] args) {
        //目标:认识枚举
        A a1 = A.X;
        System.out.println(a1);

    }
}
package com.liu.d6_enum;

public enum A {
    //注意:枚举类的第一行必须罗列的是枚举对象名字
    X,Y,Z;

    private String name;

    public String getName() {
        return name;
    }

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

枚举类的特点

  • 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
  • 枚举类的构造器都是私有的(写不写都只能是私有的对象),因此,枚举类对外不能创建对象。
  • 枚举都是最终类,不可以被继承。
  • 枚举类中,从第二行开始,可以定义类的其他各自成员。
  • 编译器为枚举类新增了几个方法,并且枚举类都是继承:java . lang . Enum 类的,从enum类也会继承到一些方法。

package com.liu.d6_enum;

public class Test {
    public static void main(String[] args) {
        //目标:认识枚举
        A a1 = A.X;
        System.out.println(a1);

        //枚举类的构造器是私有的,不能对外创建对象
//        A a = new A();

        //枚举类的第一行都是常量,记住的是枚举类的对象
        A a2 = A.Y;

        //枚举类提供一个额外的API
        A[] as = A.values();
        A a3 = A.valueOf("Z");
        System.out.println(a3.name()); //Z
        System.out.println(a3.ordinal()); //索引

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

        B y = B.Y;
        y.go();
    }
}
package com.liu.d6_enum;

public enum A {
    //注意:枚举类的第一行必须罗列的是枚举对象名字
    X,Y,Z;

    private String name;

    public String getName() {
        return name;
    }

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

package com.liu.d6_enum;

//拓展:抽象枚举

public enum B {
    X(){
        @Override
        public void go() {

        }
        }, Y("懒羊羊"){
        @Override
        public void go() {
            System.out.println(getName()+"在吃东西");
        }
    };

    private String name;

    B() {
    }

    B(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public abstract void go();
}

多学一招

使用枚举类实例单路设计模式

package com.liu.d6_enum;

public enum C {
    X; //单例
    
}

枚举的常见应用场景:

用来表示一组信息,然后作为参数进行传输

package com.liu.d7_enum2;

public class Constant {
    public static final int BOY = 0;
    public static final int GIRL = 1;
}
package com.liu.d7_enum2;

public enum Constant2 {
    BOY , GIRL;
}
package com.liu.d7_enum2;

public class Test {

    public static void main(String[] args) {
        //目标:掌握枚举的应用场景,做信息标志和分类
//        check(1);
//        check(Constant.BOY);
//        check(21);

        check(Constant2.BOY);
    }

    public static  void check(Constant2 sex ){
        switch (sex){
            case BOY:
                System.out.println("展示一些游戏信息!");
                break;
            case GIRL:
                System.out.println("展示一些电视剧!");
                break;
        }
    }

//    public static  void check(int sex ){
//        switch (sex){
//            case Constant.BOY:
//                System.out.println("展示一些游戏信息!");
//                break;
//            case Constant.GIRL:
//                System.out.println("展示一些电视剧!");
//                break;
//        }
//    }
}


面向对象高级三:认识泛型,泛型类和泛型接口


泛型

  • 定义类、接口、方法时,同时声明一个或者多个类型变量(如:<E>),称为泛型类、泛型接口,泛型方法、它们统称为泛型。

  • 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的故障。
  • 泛型的本质:把具体的数据类型作为参数传给类型变量
package com.liu.d8_generices;

import java.util.ArrayList;

public class Test1 {
    public static void main(String[] args) {
        //目标:认识泛型
        ArrayList list = new ArrayList();
        list.add("java1");
        list.add("java2");
        list.add("java3");
//        list.add(new Cat());

        for (int i = 0; i < list.size(); i++) {
            String e = (String) list.get(i);
            System.out.println(e);
        }
        System.out.println("--------------------------------");

//        ArrayList<String> list1 = new ArrayList<String>();
        ArrayList<String> list1 = new ArrayList<>(); //JDK1.7开始,后面的数据类型可以不申请
        list1.add("Java1");
        list1.add("Java2");
        list1.add("Java3");
//        list.add(new Cat());

        for (int i = 0; i < list1.size(); i++) {
            String e = list1.get(i);
            System.out.println(e);
        }

    }
}
class Cat{

}

泛型类

  • 注意:类型变量建议用大写的英文字母,常用的有:ETKV
package com.liu.d9_generics_class;

public class Test {
    public static void main(String[] args) {
        //目标:掌握泛型类的定义和使用
        MyArrayList<String> list = new MyArrayList<>();
        list.add("java1");
        list.add("java2");
        String ele = list.get(1);
        System.out.println(ele);

        MyClass2<Cat,String> c2 = new MyClass2<>();

        MyClass3<Animal> c3 = new MyClass3<>();
        MyClass3<Dog> c4 = new MyClass3<>();

    }
}
package com.liu.d9_generics_class;

//泛型类
public class MyArrayList<E> {
    private Object[] arr = new Object[10];
    private int size;//记录当前位置的

    public boolean add(E e){
        arr[size++] = e;
        return true;
    }
    public E get(int index){
        return (E) arr[index];
    }
}
package com.liu.d9_generics_class;

public class MyClass2<E ,T>{
    public void put(E e,T t){

    }
}
package com.liu.d9_generics_class;

public class MyClass3<E extends Animal> {
}
package com.liu.d9_generics_class;

public class Animal {
}
package com.liu.d9_generics_class;

public class Cat extends Animal{
}

package com.liu.d9_generics_class;

public class Dog extends Animal{
}

泛型接口

注意:类型变量建议用大写的英文字母,常用的有: E T K V
package com.liu.d10_generics_interface;

public class Test {
    //目标:掌握泛型接口的定义和使用
    //场景:系统需要处理学生和老师的数据,需要提供2个功能,保存对象数据,根据名称查询数据

}
package com.liu.d10_generics_interface;

public class Teacher {
}
package com.liu.d10_generics_interface;

public class Teacher {
}
package com.liu.d10_generics_interface;

import java.util.ArrayList;

//泛型接口
public interface Data<T> {
    void add(T t);
    ArrayList<T> getByName(String name);
}
package com.liu.d10_generics_interface;

import java.util.ArrayList;

public class TeacherData implements Data<Teacher> {
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public ArrayList<Teacher> getByName(String name) {
        return null;
    }
}
package com.liu.d10_generics_interface;

import java.util.ArrayList;

public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {

    }

    @Override
    public ArrayList<Student> getByName(String name) {
        return null;
    }
}

面向对象高级三:泛型方法、泛型的通配符和泛型的上下限、泛型注意事项


泛型方法

package com.liu.d11_generices_method;

public class Dog {
}
package com.liu.d11_generices_method;

public class Car {
}
package com.liu.d11_generices_method;

public class BENZ extends Car{
}
package com.liu.d11_generices_method;

public class BMW extends Car{
}
package com.liu.d11_generices_method;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        //目标:掌握泛型方法的定义和使用
        String rs = test("Java");
        System.out.println(rs);

        Dog d = test(new Dog());
        System.out.println(d);

        //需求:所有的汽车可以一起参加比赛
        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new BMW());
        cars.add(new BENZ());
        go(cars);

        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

//        ArrayList<Dog> dogs = new ArrayList<>();
//        dogs.add(new Dog());
//        dogs.add(new Dog());
//        go(dogs);
    }

    // ? 通配符:在使用泛型的时候可以代表一切类型  ? extends Car(上限)  ? super Car(下限)
    public static void go(ArrayList<? extends Car> cars){

    }

//    public static <T extends Car> void go(ArrayList<T> cars){
//
//    }


    //泛型方法
    public static <T> T test(T t){
        return t;
    }
}

通配符

  • 就是 “? 可以在“使用泛型”的时候代表一切类型  E T K V 是在定义泛型的时候使用。

泛型的上下限:

  • 泛型上限:   ? extends Car:   ? 能接收的必须是Car或者其子类
  • 泛型下限:  ?  super Car ?  能接收的必须是Car或者其父类

泛型的擦除问题和注意事项

  • 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
  • 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
  • package com.liu.d12_generics_attention;
    
    import com.liu.d6_enum.A;
    
    import java.util.ArrayList;
    
    public class Test {
        public static void main(String[] args) {
            //目标:理解泛型的注意实现
    
            //1、泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
            ArrayList<String> list = new ArrayList<>();
            list.add("java1");
            list.add("java2");
            list.add("java3");
            String rs = list.get(2);
            System.out.println(rs);
    
            //2、泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
    //        ArrayList<int> list1 = new ArrayList<>();
    //        ArrayList<double> list2 = new ArrayList<>();
            ArrayList<Integer> list3 = new ArrayList<>();
            list3.add(12);
    
            ArrayList<Double> list4 = new ArrayList<>();
            list4.add(23.3);
    
        }
    }
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值