JavaSE IDEA 使用-面向对象

文章目录

  • 第九章 IntelliJ IDEA 使用
    • 9.1 介绍
      • 9.1.1 介绍
      • 9.1.2 下载与安装
      • 9.1.3 卸载
      • 9.1.4 详细的教程
    • 9.2 创建普通 JavaSE 项目
      • 9.2.1 创建普通项目
      • 9.2.2 切换项目
      • 9.2.3 删除项目、模块
      • 9.2.4 窗口结构
      • 9.2.5 可能会遇见的错误
      • 9.2.6 创建 Java 源文件
    • 9.3 常用的设置
      • 9.3.1 Appearance & Behavior
      • 9.3.2 Editor
      • 9.3.3 Build,Execution,Deployment
      • 9.3.4 其它
    • 9.4 常用快捷键
      • 9.4.1 文本编辑
      • 9.4.2 查找浏览
      • 9.4.3 修改快捷键
      • 9.4.4 常见问题
    • 9.5 自定义模板
      • 9.5.1 常用模板缩写
      • 9.5.2 后缀模板
      • 9.5.3 实时模板
    • 9.6 断点调试
      • 9.6.1 运行类
      • 9.6.2 debug 设置
      • 9.6.3 debug 调试快捷键
      • 9.6.4 debug 实际操作
    • 9.7 其它
    • 9.x 总结回顾
    • 9.y 实战演练
  • 第十章 面向对象基础-对象
    • 10.1 类与对象
      • 10.1.1 对象是什么
      • 10.1.2 面向过程与面向对象
    • 10.2 实例变量
      • 10.2.1 实例变量的定义
      • 10.2.2 访问实例变量
      • 10.2.3 变量的作用域
      • 10.2.4 堆、栈、方法区
    • 10.3 实例方法
      • 10.3.1 实例方法的定义
      • 10.3.2 调用实例方法
      • 10.3.3 返回值类型
      • 10.3.4 形式参数列表
      • 10.3.5 方法重载
      • 10.3.6 可变参数
    • 10.4 构造方法
      • 10.4.1 构造方法定义
      • 10.4.2 默认无参构造器
      • 10.4.3 this
    • 10.x 总结回顾
    • 10.y 头脑风暴
  • 参考答案
    • 第一到五章
      • 第一章答案
      • 第二章答案
      • 第三章答案
      • 第四章答案
      • 第五章答案
    • 第六到十章
      • 第六章答案
      • 第七章答案
      • 第八章答案
      • 第九章答案
      • 第十章答案
  • 资源地址
    • 网盘链接
      • JDK 下载
      • IDE 工具
      • 自己写的小玩意
    • 工具网址
      • 可能会使用到的在线工具网址
      • 可能会使用到的工具下载链接
  • 参考文献
    • 参考视频
      • 参考视频链接
      • 引用视频观点
    • 参考书籍
      • 参考书籍观点
      • 引用书籍原句
    • 参考文章
      • 参考文章链接
      • 引用文章原句
  • 鸣谢名单

如果嫌太长,下翻,目录在左边。

第九章 IntelliJ IDEA 使用

内容导视:

  • 介绍
  • 创建普通 JavaSE 项目
  • 常用的设置
  • 常用快捷键
  • 自定义模板
  • 断点调试
  • 其它

9.1 介绍

内容导视:

  • 介绍
  • 下载与安装
  • 卸载
  • 详细的教程

9.1.1 介绍

IDE 即集成开发环境,可以把编写代码、组织项目、编译、运行、调试放在一个环境下,极大提高开发效率。

有快捷键一键生成代码与注释;写代码会有自动提示补全方法名;会自动检查代码中有误的地方并给出提示选择方案修改错误;查看类与类的关系、此类的所有方法和字段等。

目前最流行用于 Java 开发的 IDE 是 IntelliJ IDEA,因为确实好用,整合主流框架十分轻松,极大提升开发代码的效率。

介绍

IDEA 是 JetBrain 公司的其中一款产品,官网:https://www.jetbrains.com

其它产品如 WebStorm 用于开发 JavaScript、HTML5、CSS3 等前端技术。

IDEA 全称 IntelliJ IDEA,是 Java 语言的集成开发环境,在业界被公认为是最好的 java 开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE 支持、Ant、JUnit、CVS 整合、代码审查、创新的 GUI 设计等方面的功能可以说是超常的。

IDEA 也支持主流的技术与框架,擅长企业应用、移动应用和 WEB 工具的开发。

相比 Eclipse 的优势

  • 强大的整合能力,比如 Git、Maven、Spring 等
  • 提示功能的快速、便捷
  • 提示功能的范围广
  • 好用的快捷键与代码模板
  • 精准搜索

9.1.2 下载与安装

下载地址:https://www.jetbrains.com/idea/download/#section=windows

有 Ultimate 旗舰版和 Community 社区版,社区版是免费的,旗舰版支持的功能更多,如协同远程开发、数据库工具、前端语言、JavaEE 等,两个版本的详细对比:JetBrains Products Comparison,需要付费,可以先试用一个月,选择其一点击 Download 下载,.exe 与 .zip 随意(exe 直接双击,zip 需要解压缩)

您不需要安装 Java 来运行 IntelliJ IDEA,因为 JetBrains 运行时与 IDE 捆绑在一起(基于 JRE 11)。但是,如果要开发 Java 应用程序,还需要一个独立的 JDK。

安装方法:IDEA 的安装 - 阿龙er、知了(zhile.io)、【汇总】Jetbrains 全家桶

请勿无限制重置,有能力请支持正版!本文中资源全部收集整理于网络并无偿提供,仅可用于个人学习交流;请勿转载、售卖或商用;侵权删!

汉化:https://blog.csdn.net/qq_35067322/article/details/105429832

目录结构

  • bin:启动文件、虚拟机配置信息等
  • help:帮助文档
  • jbr:自带的 jre
  • lib:依赖的类库
  • license:插件的许可信息
  • plugins:插件

bin 目录下的 idea64.exe.vmoptions 文件是虚拟机的配置信息

-Xmx750m// 最大内存,将数值调大可以提高程序性能
-Xms128m// 初始内存
-XX:ReservedCodeCacheSize=512m// 保留代码的缓存大小
-XX:+UseG1GC// 垃圾优先收集器

请勿添加注释

C:\Users\用户名\AppData\Local\JetBrains\IntelliJIdea2021.2 存放(system)系统临时、缓存、本地历史文件等

C:\Users\用户名\AppData\Roaming\JetBrains\IntelliJIdea2021.2 存放(config)插件、文件模板、快捷键等文件

9.1.3 卸载

控制面板/卸载程序,或 Windows 设置/应用

点击要卸载的应用;且手动删除内容如下:软件的安装目录、system 与 config、代码存放目录。

一个 project 项目就是一个工作窗口,一个项目可以有多个 module 模块,每个模块里面都有 src 目录存放着 *.java 源文件;除了创建空项目,每个项目都自带一个模块。

9.1.4 详细的教程

官方详细使用文档:https://www.jetbrains.com/help/idea/installation-guide.html#standalone

IntelliJ IDEA使用教程:https://lixuekai.blog.csdn.net/article/details/77449117,作者:请叫我大师兄

9.2 创建普通 JavaSE 项目

内容导视:

  • 创建普通项目
  • 切换项目
  • 删除项目、模块
  • 窗口结构
  • 可能会遇见的错误
  • 创建 Java 源文件

9.2.1 创建普通项目

创建一个新项目:Projects/New Project/java

JavaSE IDEA 使用-面向对象_第1张图片

如果没有配置 JAVA_HOME 环境变量,就不会显示 SDK,需要 Add JDK… 指定 JDK 的安装目录;

JavaSE IDEA 使用-面向对象_第2张图片

Project name 是项目名,Project location 是此项目的路径,Finish 即可。

创建空项目

还可以创建一个空项目,模块由自己手动创建。

会弹出一个 Project Structure 窗口,点击 New Module 创建模块。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ad7M6DPT-1652792332775)(https://s2.loli.net/2022/05/08/V4CPKuk9jfIdUTi.png)]

或者 Alt + F 快捷键选择 New 可以创建 Module,或项目右键 New Module,或 Ctrl + Shift + Alt + S 打开 Project Structure/Modules 按下 + 号,点击 New Module。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-11Aob7Ch-1652792332775)(https://s2.loli.net/2022/05/08/uRJX4bfpGNeSmqK.png)]

9.2.2 切换项目

在多个项目之间切换是 Open Recent,关闭项目 Close Project;

JavaSE IDEA 使用-面向对象_第3张图片

9.2.3 删除项目、模块

JavaSE IDEA 使用-面向对象_第4张图片

可以单击想要操作的项目即可进入或者点击 Open Selected。

Show in Explorer 可以打开文件资源管理器的项目所在目录;Remove from Recent Projects 是删除此项目,但硬盘上还在;删除此项目后把文件资源管理器对应的项目选中按下 Shift + Del 快捷键永久删除。

而删除模块有两个步骤,右键模块 Remove Module,可以看到模块右下角的蓝色方块消失,意味着它变成了普通目录,再次右键 Delete(Del 是普通删除,Alt + Del 是安全删除)即可删除。

JavaSE IDEA 使用-面向对象_第5张图片

JavaSE IDEA 使用-面向对象_第6张图片

9.2.4 窗口结构

分为菜单栏、工作列表、编辑区域、快捷栏。

在编辑区域编写源代码,按下 Ctrl + Shift + F10 即可运行 main 方法。

9.2.5 可能会遇见的错误

Java 版本问题

打开项目结构,或快捷键 Ctrl + Alt + Shift + S

打开 Project Structure

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SNnyb3m3-1652792332782)(https://s2.loli.net/2022/05/08/J6ueAVc7m8RPBCQ.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQoFDrhK-1652792332782)(https://s2.loli.net/2022/05/08/Fqjrk6UCOi7HX1D.png)]

这个地方没设置会出错无法运行代码。

Project name:当前项目的名字

Project SDK:控制项目使用的 JDK 版本

Project language level:项目语言级别

当使用的新特性所在版本超过设定的 JDK 版本,就会报错。

例:在 JDK7 版本,新增了一个特性:自动类型推断机制(钻石表达式),使用泛型 new 对象时后面的 <> 中可以省略数据类型,会通过前面 <> 的内容自动推断类型。

一旦设置 level 为小于 7,如 level 6 就会报错:

JavaSE IDEA 使用-面向对象_第7张图片

Project language level 是编译时检查源码是否符合指定版本的语法。如果 level 设置为 6,则代码使用的 JDK7 和 JDK8 版本的新特性会被认为是语法错误。

一般 level 等级与 JDK 版本一致即可,但如果自己开发使用的 JDK 版本大于部署时服务器的 JDK 版本,可以把 level 往下调至服务器的 JDK 版本,且不使用高版本的新特性。

JDK8 新增了 Lambda 表达式、函数式接口等新特性;特性只能往下兼容,如 JDK8 版本可以使用 JDK7、JDK6 … 的特性,而不能使用 JDK9 的特性。

Project compiler output:用于指定项目中的 java 源文件编译后生成的这些 *.class 文件存放的根目录

修改成如下即可,记得修改后点击 Apply 或 OK,否则不生效。如 01-module 模块的 class 文件会在 out/production/01-module 下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TjrEVmHV-1652792332783)(https://s2.loli.net/2022/05/08/OvrnmdJVeBLi9hl.png)]

9.2.6 创建 Java 源文件

module 下有个蓝色的 src 文件夹,用于存放源文件,src 右键/new/Java Class

New Java Class

或按下 Alt + Ins scrlk 快捷键,此键在 Backspace 退格键的上面。

JavaSE IDEA 使用-面向对象_第8张图片

通过上下左右箭头定位到 Java Class 然后回车或点击 Java Class,输入源文件名后回车。(不用写后缀 .java

导入其它模块的类

在类中使用其它模块的类时,在错误处(将光标定位到红色波浪处)按下 Alt + Enter,选择 Add dependency on module ‘模块名’ 后回车。

实际在模块下的 iml 文件中添加了 标签。

9.3 常用的设置

内容导视:

  • Appearance & Behavior
  • Editor
  • Build,Execution,Deployment
  • 其它

首先打开设置 File/Settings(快捷键:Ctrl + Alt + S)

从上至下依次为:外观与行为、快捷键、编辑、插件、版本控制、构建执行部署、语言和框架、工具、高级设置

依次介绍:

9.3.1 Appearance & Behavior

设置主题

Appearance/Theme

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ofjehht9-1652792332785)(https://s2.loli.net/2022/05/09/V3L1ZcJINRsYntj.png)]

设置菜单栏字体大小

Appearance/Size

如果觉得菜单项或设置中的字体太小,Size 可以往上调,一般设置为 12。

JavaSE IDEA 使用-面向对象_第9张图片

重新启动项目时,如何打开一个项目

  • New window:新创建一个窗口
  • Current window:使用当前窗口
  • Ask:总是询问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79rgpHcV-1652792332785)(https://s2.loli.net/2022/05/12/o629CidIzfFAYvW.png)]

9.3.2 Editor

内容如下:

  • 设置使用鼠标滚轮调节字体大小
  • 自动导包
  • 行号与分隔符
  • 显示方法参数信息
  • 忽略大小写提示
  • 取消单行显示文件标签
  • 设置悬浮提示
  • 设置编辑区域字体
  • 单独设置控制台字体
  • 设置文档注释的字体颜色
  • 添加文件头部信息
  • 设置项目文件字符编码

设置使用鼠标滚轮调节字体大小

General/Mouse Control,勾上 Change font size with Ctrl + Mouse Wheel,回到编辑页面按住 Ctrl 同时滚动鼠标滚轮即可调整字体大小。

Move code fragments with drag-and-drop:可以拖拽选中的代码片段到别的位置

自动导包

General/Auto Import

  • Add unambiguous imports on the fly:编写代码时,写的简单类名是唯一的,自动添加 import 导入该类
  • Optimize imports on the fly:当 import 导入的类没用上时,自动删去该 import

Insert imports on paste(在粘贴时导入),Always:总是,Never:从不,Ask:询问

如想使用 Date 类,但有多个简单类名为 Date,需要 Alt + Enter 键 import class 选择一个。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xKA35irc-1652792332786)(https://s2.loli.net/2022/05/09/spIMU5ZG9WQ4bfl.png)]

输入 DateFormat,类名唯一,会自动在首行添加 import 此类的完整类名;删去 DateFormat 会自动删除首行的 import 导入语句。

行号与分隔符

General/Appearance,勾选 Show method separators,显示方法之间的分隔符;勾选 Show line numbers 显示行号。

关闭文档弹窗

General/Code Completion 取消勾选 Show the documentation popup in…

显示方法参数信息

General/Code Completion 勾选 Show the paramerter info…

Show parameter name hints…:提示方法参数名称和类型

Show the paramerter info…:弹出方法参数名和类型

Show full method signatures:弹出完整的方法签名

显示方法参数信息

忽略大小写提示

General/Code Completion

老版将 Case sensitive completion 改为 None;

新版取消勾选 Match case(区分大小写)

JavaSE IDEA 使用-面向对象_第10张图片

First letter only:仅首字母区分大小写,如 String 等同于 STRing

All letters:所有都区分大小写,String 不等同于 string

取消单行显示文件标签

如果设置单行显示,当编辑区即代码书写区域,编辑了或者浏览很多文件,可以看到 Number.java、Object.java …这样展示不下的文件就会被隐藏。

General/Editor Tabs 取消勾选 Show tabs in one row(在同一行显示,可能会造成文件名显示不完全)

Hide tabs if there is no space:如果空间不足就隐藏标签

JavaSE IDEA 使用-面向对象_第11张图片

设置悬浮提示

当指针停在方法或某处时,会自动显示对应的文档注释信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s9w9jbaW-1652792332787)(https://s2.loli.net/2022/05/09/HmwiWAyfTJ7qLV2.png)]

Code Editing 勾选 Show quick documentation on hover

翻到最下面,Editor Tooltips/Tooltip delay:500,延迟 500 毫秒后再提示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67hgyT94-1652792332788)(https://s2.loli.net/2022/05/09/nqsOD3KMLaWEd1Q.png)]

设置编辑区域字体

Font/Size

font 可以选择喜欢的字体,size 是字体大小,line height 是每行间距。

JavaSE IDEA 使用-面向对象_第12张图片

设置编辑区域主题

Color Scheme/Scheme

Scheme 与整体主题风格一致即可,下面就不太搭。

JavaSE IDEA 使用-面向对象_第13张图片

除了 Font/size 可以设置字体外,通过 Color Scheme/Color Scheme Font,勾选 Use color scheme font instead of the,也可以设置。

单独设置控制台字体

Color Scheme/Console Font 勾选 Usb console font instead of the

设置文档注释的字体颜色

Color Scheme/Language Defaults,Comments/Doc comment/Text

**同一个包下超过指定个数的 import 会自动转为 ***

Code Style/java/Imports

Class count to use import with ‘*’:5,导入同一个包的类累计 5 次时,自动转为 *

Names count to use static import with ‘*’:3,导入同一个包下静态的类累次 3 次时,自动转为 *

例:导入 5 个 java.util 包下的类会转为 import java.util.*;

JavaSE IDEA 使用-面向对象_第14张图片

添加文件头部信息

File and Code Templates/Includes/File Header 写入信息,每当创建文件时,自动在头部加入这段文字,在 Description: 中有各个变量的含义,如 ${DATE} 是当前系统日期。

我习惯在 java 源文件头部添加文档注释;作者处可以使用 ${USER} 替代。

设置项目文件字符编码

File Encodings/Global Encoding 等为 UTF-8(统一编码才不会乱码,UTF-8 是全球通用的)

勾选 Transparent native-to-ascii conversion:将 properties 文件输入的所有字符转换成 ASCII 序列码保存

UTF-8 BOM 又叫 UTF-8 签名。(BOM:byte order mark)

UTF-8 的 BOM 是为了支援 UTF-16、UTF-32;BOM 签名的意思就是告诉编辑器当前文件采用何种编码,方便编辑器识别。BOM 虽然在编辑器中不显示,但是会产生输出,就像多了一个空行。

有很多软件不能识别 BOM,也会被当作编码的一部分造成乱码,所以最好选择 with NO BOM。

JavaSE IDEA 使用-面向对象_第15张图片

取消方法形参名提示

取消方法形参名提示

想要取消显示 second:、minute:、hour:

Inlay Hints,将 java 取消勾选,确定保存。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYfccUmr-1652792332790)(https://s2.loli.net/2022/05/09/RrkC7yQsKMWjnap.png)]

或者右键 Disable Hints

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8oEMABb-1652792332790)(https://s2.loli.net/2022/05/09/SJlYNQAsdrzCyEH.png)]

若想重新显示提示,Inlay Hinst/java,Parameter hints,勾上 Show parameter hints for

9.3.3 Build,Execution,Deployment

自动编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zRYery96-1652792332791)(https://s2.loli.net/2022/05/09/yYEtL4j6fsaRveP.png)]

Build project automatically:项目自动编译

Compile independent modules in parallel:多个模块并行编译

9.3.4 其它

内容导视:

  • 省电模式
  • 文件的显示位置
  • 保存及导入原有配置

省电模式

File/Power Save Mode会关闭代码检查与提示等功能

如果没有了提示功能,可以看看是否误点了

文件的显示位置

JavaSE IDEA 使用-面向对象_第16张图片

Split Right:将文件在右边分屏

Split and Move Right:将文件移到右边分屏

Split Down:将文件在下边分屏

Split and Move Down:将文件移到下边分屏

设置单个文件的字符编码

设置单个文件的字符编码

编辑区右下角修改文件编码

Reload:暂时改成 xxx 编码显示,但文件还是原来的编码

Convert:真正的转换

保存及导入原有配置

File/Manage IDE Settings,Export Settings 导出设置;以后 Import Settings 导入,恢复原本设置。

9.4 常用快捷键

内容导视:

  • 文本编辑
  • 查找浏览
  • 修改快捷键
  • 常见问题

的确很便捷对吧。up、down、left、right 分别对应上下左右箭头。

9.4.1 文本编辑

选择要粘贴的内容 Ctrl + Shift + V
粘贴带包名的类名 先 Ctrl + Shift + Alt + C 复制类名,再 Ctrl + Shift + Alt + V 粘贴
撤销 Ctrl + Z
反撤销 Ctrl + Shift + Z
逐渐选中区域 Ctrl + W
删除一行(Delete Line) Ctrl + Y
向下复制一行(Duplicate Line Or Selection) Ctrl + D
在域的范围内上下移动行 Shift + Ctrl +上下箭头
上下移动行 Shift + Alt +上下箭头
整体移动 Tab
向上开始新的一行(Start New Line Before Current) Ctrl + Alt + Enter
向下开始新的一行(Start New Line) Shift + Enter
自动在语句末尾加上分号 Ctrl + Shift + Enter
单行注释 Ctrl + /
多行注释 Ctrl + Shift + /,再按还原
格式化代码 Ctrl + Alt + L
大小写转换 Ctrl + Shift + U
重命名 Shift + F6
提示补全(Basic) Ctrl + 空格
收起代码块或方法 Ctrl + . 或 Ctrl + - 或右键/Folding
打开代码块或方法 Ctrl + . 或 Ctrl + +
收起全部代码块 Ctrl + Shift + -
打开全部代码块 Ctrl + Shift + +
提示方法形参类型(Parameter Info) Ctrl + P(先将光标定位到方法的括号里)
查看文档(Quick Documentation),将光标定位方法名或类名上 Ctrl + Q 、 Alt +鼠标中键
快速定位至错误处 F2 、 Shift + F2
解决错误 Alt + Enter
快速生成构造和其他方法如 getset 、 toString 等方法 Alt + Ins Scrlk
局部变量抽取为成员变量 Ctrl + Alt + F
生成 try-catch 等常用代码块 Ctrl + Alt + T
抽取成方法 Ctrl + Alt + M
自动分配变量名 Ctrl + Alt + V
清除多余的 import Ctrl + Alt + O
重写方法 Ctrl + O
实现接口方法 Ctrl + i

选择单词填入(Cyclic Expand Word): Alt +(Shift)+ /,Shift 是反方向

当你什么都不写,按下此快捷键从当前行的上方选择并填入单词;当你已经输入开头,如 s,就会寻找本类 s 开头的单词自动填人。(可以多按几次找到想要的单词)

多行操作:Shift + Alt + Ins Scrlk,再按住 Shift 和上下箭头,或者按住鼠标左键不放拖动鼠标,会增加光标个数。(期间左键单击光标变为 1)

多行操作

另一种方法,按住 Alt 和鼠标左键不放,鼠标往下滑。

快速生成方法

Select None 是无参构造,如果想同时选中多个字段,可以通过 Shift + 上下键或 Ctrl + A 或 Ctrl + 鼠标点击选择生成的有参构造为哪些字段赋值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KI68duOc-1652792332793)(https://s2.loli.net/2022/05/09/AuZOrv7xLp4G5Km.png)]

9.4.2 查找浏览

关闭当前编辑页面 Ctrl + F4、右键编辑区的文件标签点击 Close、Shift + 单击标签
关闭/隐藏页面 (Shift)+ Esc、Ctrl + Shift + F4
编辑窗口全屏显示 Ctrl + Shift + F12
左右移动标签查看对应文件 Alt +左右箭头
光标不动,上下翻页 按住 Ctrl 不松,按下 Up/Down
光标至当前显示的内容首尾 Ctrl + Pgup/Pgdn
光标至文件首尾 Ctrl + Home/End
光标在方法之间移动 Alt + 上下箭头(up/down)
光标返回上一次编辑的位置 Ctrl + Alt + 左右箭头(left+right)
查看光标最近到过的位置(Recent Locations) Ctrl + Shift + E
跳转至某行某列 Ctrl + G
打开对应菜单栏 Alt + 划横线的字母
打开对应快捷栏 Alt + 数字
打开当前文件所在文件夹(Show In Explorer) 按住 Ctrl 点击文件标签 或 Ctrl + Alt + F12
打开最近修改的文件 Ctrl + E 、Ctrl + Tab(Ctrl 不要松,按下 Tab 键或按下画横线的字母和数字)

Alt + 1 、 Alt + Home 进入工作列表,上下箭头选择文件,回车或按下 F4。

查找所有文件 双击 Shift
查找类文件 Ctrl + N
查找文件 Shift + Ctrl + N
查找(全局) Ctrl +(Shift)+ F
选中查找的结果之一 (Shift)+ F3、 Ctrl +(Shift)+ L
替换 Ctrl + R
标记某行 Ctrl + Shift + 数字(再按取消标记)
标记某行 Ctrl + F11,点击对应序号标记
跳转至标记的某行 Ctrl + 数字
添加书签 F11
查看收藏与书签 Alt + 2
跳转书签所在位置 Shift + F11
查找已有的模板缩写 Ctrl + J
查看源码 按住 Ctrl 再单击类名、Ctrl + B
查看父类方法(Go To Super Method) 将光标定位到子类方法名处,按下 Ctrl + U
查看一个类的结构 Ctrl + F12、Alt + 7
查看类的继承关系 Ctrl + H
查看有关所有实现或者覆写了当前方法的类的结构图(Method Hierarchy) Ctrl + Shift + H
查看类的继承结构图(Show UML Diagram) Ctrl + Alt +(Shift)+ U、右键 Diagrams
呈现当前方法的调用层级结构(Call Hierarchy) Ctrl + Alt + H

查看此文件在磁盘的位置:按住 Ctrl 键,点击此文件标签,或者右键 Open In/Explorer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PdpGvhAu-1652792332794)(https://s2.loli.net/2022/05/09/lYqhw6bRWSDAKda.png)]

添加到收藏(Add To Favorites):Shift + Alt + F、或者文件右击 Add To Favorites 选择已有的收藏夹,Add To New Favorites List 创建新的收藏夹。

替换:Ctrl + R,Replace 一个个替换,All 全部替换,include 排除(被排除的不会被替换)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QlpTRyCq-1652792332794)(https://s2.loli.net/2022/05/09/yrbPWXsiuqIBkS2.png)]

9.4.3 修改快捷键

打开 Settings/keymap,有两个放大镜,左边输入功能名称;点击右边的放大镜按下快捷键,寻找快捷键对应的功能;

比如修改复制当前行操作的快捷键,搜索 Duplicate,右键 Add keyboard Shortcut,更换快捷键。不用输入字母,而是把你希望的组合键同时按下。

JavaSE IDEA 使用-面向对象_第17张图片

Add Keyboard Shortcut:键盘快捷键

Add Mouse Shortcut:鼠标快捷键,例 Ctrl + 左键单击

Add Abbreviation:添加操作的缩写

Remove:移除快捷键

Reset Shortcuts:重新设置快捷键

你怎么知道输入 Duplicate?在 IDEA 安装路径下有个 help 目录,里面有两个 pdf 文件,打开查看对组合键作用的描述;如 Ctrl + D,Duplicate current line or selected block:复制当前行及选中的文本,与上面的解释大同小异,配合显示的快捷键即可快速定位想要修改的组合键。

如 Ctrl + Alt + L 格式化代码,在第一列第 19 个,搜索 Reformat code

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ouz20kpF-1652792332795)(https://s2.loli.net/2022/05/09/uJnLyZ8HOaTqSzB.png)]

如果习惯使用 Eclipse 的快捷键,可以将 keymap 改为 Eclipse。

JavaSE IDEA 使用-面向对象_第18张图片

9.4.4 常见问题

按下快捷键时,如果没有反应,那么这组快捷键可能是被其他软件占用了,需要更改快捷键组合方式。

或者你觉得快捷键很别扭,易混淆;比如 Ctrl + D,在其他软件是 delete 删除的意思,而在 IDEA 却是 add 增加一行的意思。

Ctrl + 空格、Ctrl + . 等快捷键已被 Windows 系统占用;

打开 Windows 设置,时间和语言/语言/键盘/输入语言热键,可以看到 Ctrl + 空格已被占用,所以 IDEA 的自动补全失效了。

或者首选语言选择中文(简体、中国)选项,键盘/微软拼音/选项/按键,看看快捷键组合方式是否被占用了。

JavaSE IDEA 使用-面向对象_第19张图片

中英切换

9.5 自定义模板

内容导视:

  • 常用模板缩写
  • 后缀模板
  • 实时模板

Templates,代码片段对应的字母缩写,输入缩写按下 Tab 键后可以出现预定义的固定模式的代码,提高了开发效率;如 sout 是 System.out.println(),Ctrl + J 快捷键可以查看所有模板缩写。

9.5.1 常用模板缩写

输入缩写后按下 Tab 键,如 main 方法的缩写:main、psvm。

输出语句 缩写
普通输出语句 sout
输出方法参数名及值 soutp
输出方法名 soutm
输出变量值 soutv 或 xxx.sout
输出变量名及值 xxx.soutv
for 语句 缩写
i 从 0 到 ?,i++ fori
增强 for 循环 iter、xxx.for
遍历数组 itar
迭代器遍历 itit
顺序遍历 xxx.fori
逆序遍历 xxx.forr
if 语句 缩写
if (xxx == null) ifn、xxx.null
if (xxx != null) inn、xxx.nn

9.5.2 后缀模板

打开 Settings,Editor/General/Postfix Completion,没法修改预定义的代码模板,倒是可以修改缩写(先选择要修改的地方,然后点击 + 右边的铅笔)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8nCgX3kH-1652792332797)(https://s2.loli.net/2022/05/11/iksAal1Jb3OjfRZ.png)]

Enable postfix completion:启动后缀模板

Expand templates with Tab:输入xxx.缩写后按下 Tab 键后生成模板,一般还未输入完时 IDEA 会自动弹出提示回车就行。

打个比方,定义了一个 int 类型的数组 arr,fori 是后缀模板缩写,输入 arr.fori 按下 Tab 键后出现预定义的代码。

自定义后缀模板

自定义后缀模板,按下 +,选择将模板应用在哪里,比如 java。

介绍含义:

key:缩写,这里我填写的是 syso

Minimum language level:此模板生效的最低 JDK 版本。例:假如 level 设置为 9,那么在 JDK8 中此模板不生效

Use static import if possible:如果可能的话使用静态导入

$EXPR$:引用目标表达式

JavaSE IDEA 使用-面向对象_第20张图片

点击 OK,在 java 源文件中,假设现在有变量,名为 i,输入 i.syso 按下 Tab 键后生成 System.out.println("i的值:" + i);

那么 $EXPR$ 就是 i。

Applicable expression types:应用至哪些类型,如果不选择,默认任意类型都可以使用此模板;

​ void:没有返回类型才能使用此模板

​ not primitive type:包装类型

​ array:数组类型

​ choose class in xxx:选择自己的模块中哪些类可以使用此模板

​ enter class name:选择哪些类可以使用此模板

$END$:生成模板后光标所在位置

例:设置只有数组类型的变量才能使用此模板,有 int 类型的数组 arr,输入 arr.cqhsort 后按下 Tab 键才会生效。

if ($EXPR$ instanceof int[]) {
    int temp = 0;
    for (int i = 0; i < $EXPR$.length - 1; i++) {
        int min = i;
        for (int j = i + 1; j < $EXPR$.length; j++) {
            if($EXPR$[j] < $EXPR$[min]) {
                min = j;
            }
        }
        if (min != i) {
            temp = $EXPR$[min];
            $EXPR$[min] = $EXPR$[i];
            $EXPR$[i] = temp;
        }
    }
}
System.out.println(Arrays.toString($EXPR$));$END$

9.5.3 实时模板

Edit/Live Templates

单词翻译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u5WLqmpx-1652792332797)(https://s2.loli.net/2022/05/11/BUkxmsEnhdL6wJ4.png)]

By default expand with Tab:默认情况按下 Tab 生成模板

Abbreviation:模板的缩写词

Description:模板的描述

Template text:预定义的模板文本

Applicable in Java: statement:将此模板应用至 java 中的语句声明

Expand with Tab:按下 Tab 键后生成模板

Reformat according to style:格式化预定义的模板

Use static import if possible:如果可能的话使用静态导入

模板应用范围

点击 Change 改变模板应用范围

Comment:注释

Consumer function:方法

Declaration:变量声明

Expression:表达式

Statement:语句声明

JavaSE IDEA 使用-面向对象_第21张图片

自定义模板

按下 + 号(Alt + Ins scrlk),创建组,任意取名如 cqh;

Live Template:定义模板

Template Group … :创建模板组

选中自己刚刚创建的组按下 + 号,点击 Live Template,可以模仿如下设置:

点击 Define 选择模板应用范围如 java;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fkqqjqCb-1652792332798)(https://s2.loli.net/2022/05/11/eP4pCIJchBRF16S.png)]

点击 Edit variables,为变量 $VAR$ 设值为第一个变量名,默认值为 var,跳过定义(如果 skip if defined 不勾选,光标会停在 $VAR$ 处)

suggestFirstVariableName("Object"):获取第一个变量名

常见的 Expression(预定义函数)请看实时模板变量。

点击 OK 后,在 java 文件中输入 try 按下 Tab 后即可生成模板。

9.6 断点调试

  • 运行类
  • debug 设置
  • debug 调试快捷键
  • debug 实际操作

9.6.1 运行类

run 即调用某个类的 main 方法,快捷键:Shift + Ctrl + F10,也可以右键或点击绿色三角图标也可以运行此类;运行过后右上角会多出此类的运行配置信息,下拉框选中此类,Shift + F10 即可运行,Shift + F9 即可调试。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uPUe8yzT-1652792332799)(https://s2.loli.net/2022/05/11/Kzai7468SC2NYvc.png)]

Edit Configurations 用来编辑每个类的运行配置

JavaSE IDEA 使用-面向对象_第22张图片

Alt + Shift + F9/F10,会列出已运行过的类,可以通过左右上下箭头选择 Run 后回车。

JavaSE IDEA 使用-面向对象_第23张图片

常用的 run 和 debug 快捷键

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Cn2KN10-1652792332799)(https://s2.loli.net/2022/05/11/LzIuGlvTQBFYJ9W.png)]

9.6.2 debug 设置

减少内存占用

打开 Settings/Build,Execution,Deployment/Debugger,设置 Debug 连接方式,默认是 Socket。

Shared memory 是 Windows 特有的一个属性,一般在 Windows 系统下建议使用此设置,内存占用相对较少。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5tsmdKqd-1652792332800)(https://s2.loli.net/2022/05/11/GdqfItkZKHxeDNc.png)]

步入源码

Debugger/Stepping

Do not step into the classes:不要进入此类

取消勾选 java.*、javax.*

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WwLxjsDi-1652792332800)(https://s2.loli.net/2022/05/11/XVNJ6bOnAfsT8D7.png)]

显示完整实例信息

Debugger/Data Views/Java

取消勾选 Enable alternative view for Collections classes

JavaSE IDEA 使用-面向对象_第24张图片

9.6.3 debug 调试快捷键

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AeGshOcF-1652792332801)(https://s2.loli.net/2022/05/11/pNWJ5u3jKkSy48x.png)]

1:step over(F8):进入下一行,如果当前行断点是方法,不进入方法内
2:step into(F7):进入下一行,如果当前行断点是方法,则进入方法体内
3:force step into(Alt + Shift +F7):同上,但有些进不去的方法可以使用此键强制进入(比如源码)
4:step out(Shift + F8):跳出方法
5:Drop Frame:回退到上一个调用的方法
6:Run to Cursor(Alt + F9):运行到光标位置,只能前进
7:Ctrl + F5:重新 debug
8:Resume Program(F9):恢复程序运行,但如果下面还有断点则停到下个断点处,没有断点直接跑完
9:stop(Ctrl + F2):结束进程
10:View Breakpoints(Ctrl + Shift + F8):查看所有断点,Condition:为断点设置执行的条件

条件断点

11:Mute Breakpoints:忽略剩下的断点

12:Evaluate Expression …(Alt +F8):计算表达式,输入表达式查看结果。按下Alt + ↓ 或下拉框查看历史记录

JavaSE IDEA 使用-面向对象_第25张图片

9.6.4 debug 实际操作

debug 就是断点调试,在某一行设置一个断点,debug 时,程序运行到这一行就会卡住,可以一步步执行代码(按下 F7 或 F8),定位错误的地方。

设置断点

单击此处

单击红点的位置处生成断点,再单击就是取消断点。点击绿色小虫图标开始 debug,代码自动在断点处停下。

设置条件

JavaSE IDEA 使用-面向对象_第26张图片

当断点处于循环内时,右击红点,在条件处输入布尔表达式,如 i == 6,那么只有 i == 6 为 true 时,程序才会停下,不用 i = 1,2,3… 慢慢步进。

或者点击 Set Value(F2)修改值加快进程。

JavaSE IDEA 使用-面向对象_第27张图片

9.7 其它

内容如下:

  • 展开包名
  • 新增 JDK 与源码
  • 生成 JavaDoc
  • 清理缓存
  • 取消更新
  • 插件使用

展开包名

使用 Alt + Ins scrlk 创建 package 后,包名都重叠在一起。

点击 Project 右边的设置图标,取消 Compact Middle Packages 的对勾

查看文件历史修改记录

Show History

对比两个文件

右键 Compare with 选择比较的文件,或者按住 Ctrl 不放选中两个文件,再按下 Ctrl + D

Do not ignore:不要忽视,Ignore whitespaces:忽略空格

官方比较文件的详细说明

新增 JDK 与源码

Project Structure/SDKs,点击 +/Add JDK…

选择 JDK 安装目录

SDK 是软件开发工具包,辅助开发某一类软件的相关文档、范例和工具的集合都可以叫做SDK;JDK是SDK的子集。

SDKs/Sourcepath/+,导入源码,方便以后 Ctrl + B 查看。


生成 JavaDoc

Tools/Generate JavaDoc…

JavaSE IDEA 使用-面向对象_第28张图片

Generate JavaDoc Scope:生成 API 文档的范围
	Whole project:当前项目的所有模块
	Module '01-package':当前模块
	File:当前文件
	Custome scope: 自定义范围

Include JDK and library sources in -sourcepath:包含 JDK 源码
Link to JDK documentation:链接 JDK 的 API 文档

Output directory:生成的 API 文档的位置
显示 protected 以上级别的内容:private 私有和 package 包级别不显示

Locale:语言类型,如 zh_CN
Other command line arguments:其它命令行参数:-encoding UTF-8 -charset UTF-8
	-charset 是告知浏览器此文件采用什么编码方式读取这个文件
	-encoding 是告知 java 源代码的字符编码

Open generated documentation in browser:在浏览器打开生成的文档

点击 OK 后,生成了一大堆 html 文件,点击 index.html 即可。

清理缓存

我没有经历过,用的挺好,下面是尚硅谷资料的原话。

IntelliJ IDEA 首次加载项目的时候,都会创建索引,创建索引的时间跟项目的文件多少成正比。IntelliJ IDEA的缓存和索引主要是用来加快文件查询,从而加快各种查找、代码提示等操作的速度。

在某些特殊条件下,IntelliJ IDEA 的缓存和索引文件也是会损坏的,比如:断电、蓝屏引起的强制关机,当你重新打开 IntelliJ IDEA,很可能 IntelliJ IDEA 会报各种莫名其妙错误,甚至项目打不开,IntelliJIDEA 主题还原成默认状态。

即使没有断电、蓝屏,也会有莫名奇怪的问题的时候,也很有可能是 IntelliJ IDEA 缓存和索引出现了问题,这种情况还不少。遇到此类问题也不用过多担心。我们可以清理缓存和索引。

File/Invalidate Caches…

清理缓存

Invalidate Caches:清除缓存

Reload All from Disk:从磁盘重新加载所有内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9j7EBYsO-1652792332804)(https://s2.loli.net/2022/05/11/8nVQj7BRlosWUzu.png)]

Clear file system cache and Local History:清除文件的系统缓存和本地历史修改记录(即清除C:/Users/用户名/AppData/Local/JetBrains/IntelliJIdea2021.2/LocalHistory,一般不建议勾选)

Clear VCS Log caches and indexes:清除 VCS(版本控制系统) 日志缓存和索引

Clear downloaded shared indexes:清除下载的共享索引

Ask before downloading new shared indexes:请在下载新的共享索引之前进行询问

Invalidate and Restart:清除并重启(老版会全部清除,记得备份 config)

cancel:取消

Just Restart:仅重启

取消更新

打开 Settings,Appearance & Behavior/System Settings/Updates

老版取消勾选 Automatically check updates for

下面根据自己的情况取消勾选

Check IDE updates for Stable Releases:检查 IDEA 稳定版的更新

Check for plugin updates:检查插件的更新

Show What’s New in the editor after an IDE update idea:更新后显示更新的内容

插件使用

Settings/Plugins,在 Marketplace 中搜自己想要的插件,installed 是已安装的插件。(官方的插件库:https://plugins.jetbrains.com/)

也可以点击设置从磁盘上安装插件。

JavaSE IDEA 使用-面向对象_第29张图片

插件名 功能 网址
Key promoter 快捷键提示 https://plugins.jetbrains.com/plugin/4455?pr=idea
CamelCase 驼峰式命名和下划线命名交替变化 https://plugins.jetbrains.com/plugin/7160?pr=idea
Checkstyle-IDEA 代码样式检查 https://plugins.jetbrains.com/plugin/1065?pr=idea
FindBugs-IDEA 代码 Bug 检查 https://plugins.jetbrains.com/plugin/3847?pr=idea
Statistice 代码统计 https://plugins.jetbrains.com/plugin/4509?pr=idea
JRebel Plugine 热部署 https://plugins.jetbrains.com/plugin/?id=4441
CodeGlance 在编辑代码最右侧,显示一块代码小地图 https://plugins.jetbrains.com/plugin/7275?pr=idea
Eclipse Code Formatter 使用 Eclipse 的代码格式化风格,在一个团队中如果公司有规定格式化风格,这个可以使用 https://plugins.jetbrains.com/plugin/6546?pr=idea
GsonFormate 把 JSON 字符串直接实例化成类 https://plugins.jetbrains.com/plugin/7654?pr=idea
IDE Eval Reset 重置 IDEA 使用 https://zhile.io/2020/11/18/jetbrains-eval-reset-deprecated.html
Translation 中英文翻译 Ctrl + Shift + O,或选中单词 后 Ctrl + Shift + Y https://plugins.jetbrains.com/plugin/8579-translation
Xcode-Dark Theme 一种 IDEA 主题 https://plugins.jetbrains.com/plugin/13106-xcode-dark-theme

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7YyBU2y-1652792332805)(https://s2.loli.net/2022/05/11/P8eZYImkryDCGHt.png)]

9.x 总结回顾

其实也没有什么好回顾的,我又不擅长做视频,内容也不太全面,大家百度就行。虽然使用 IDEA 体验更好,方便整合,但是如果是因为 Eclipse 太卡了,才考虑使用 IDEA,但 IDEA 占用内存只会更多,大概 40% 的内存。

9.y 实战演练

9.1 使用 debug 测试创建对象时的代码执行顺序。

第十章 面向对象基础-对象

内容导视:

  • 类与对象
  • 实例变量
  • 实例方法
  • 构造方法

10.1 类与对象

内容导视:

  • 对象是什么
  • 面向过程与面向对象

问题:

借助韩老师的例子;张老汉也养了两只狗:一只地狱犬,名字叫黑魔王,今年 2340 高寿,红黑相加的花纹十分地炫。

另一只种类为恐惧魔王,名字叫提克迪奥斯,今年 12242 岁,是个不按常理出牌的绿色的恶魔。

要求:当输入名字时,就显示对应的狗的全部信息。

// 狗 1 的所有信息
String dog1Type = "地狱犬";
String dog1Name = "黑魔王";
int dog1Age = 2340;
String dog1Color = "红黑相加的花纹";
String dog1State = "死亡";

// 狗 2 的所有信息
String dog2Type = "恐惧魔王";
String dog2Name = "提克迪奥斯";
int dog2Age = 12242;
String dog2Color = "绿色";
String dog2State = "萎靡不振";

Scanner scanner = new Scanner(System.in);
System.out.println("A:我的狗被你拐到这了?");
System.out.print("B:你好,这里是正规的收容所,");
System.out.print("请输入遗失的狗的名字:");
String name = scanner.next();
if (dog1Name.equals(name)) {
    System.out.print("种类:" + dog1Type);
    System.out.print(",名字:" + dog1Name);
    System.out.print(",年龄:" + dog1Age);
    System.out.print(",状态:" + dog1State);
    System.out.println(";很抱歉,我们已经尽力了!");
} else if (dog2Name.equals(name)) {
    System.out.print("种类:" + dog2Type);
    System.out.print(",名字:" + dog2Name);
    System.out.print(",年龄:" + dog2Age);
    System.out.print(",状态:" + dog2State);
    System.out.println(";这就还给你!");
} else {
    System.out.println("对不起,我们没有查到此狗的信息!请你到别处咨询!");
}

使用局部变量将所有信息拆卸,数据管理麻烦,将来也不好利用,只能将一个个的变量作为方法实参。

目前就两只狗,如果有 n 条狗,那就需要定义 5n 个变量,效率低下。

如果使用数组:

String[] dog1 = {"地狱犬", "黑魔王", "2340", "红黑相加的花纹", "死亡"};
String[] dog2 = {"恐惧魔王", "提克迪奥斯", "12242", "绿色", "萎靡不振"};

数据类型无法得到体现,因为数组只能存储同一种类型的数据。

只能通过下标来取数据,造成变量名与内容对应关系不明确,比如单看代码,究竟地狱犬是名字还是黑魔王是名字,没有提示,还有 “2340” 是什么;而使用 String dog1Name = "黑魔王"; 一看就知道这是第 1 只狗的名字。

10.1.1 对象是什么

对象

每个可以进行研究的任何事物都可以当作一个对象,如整数、棋盘、沙发、狗、飞机…,每个对象都有自己的行为和状态,比如他家的狗的状态有颜色、品种、名字…;行为、动作有吃、睡觉、玩耍…。

状态也可以被称为属性,实际指代每个对象的数据(信息),但属性还另有他指,注意区分别混淆。

通过观察现实的种种事物,把具有共同特征的一类事物抽象出来得到一个类;比如金毛犬、比特犬、田园犬都是狗,是狗类,再抽象一点就是动物类,可以称狗类是动物类的子类。

用类 class 描述这类事物的共同特征(行为和状态);用字段 field 代表状态,方法 method 代表行为。

当然也可以把类当作组织变量、让变量之间形成联系的一种方式。

// 自定义的狗类
class Dog {
    // 字段,保存了狗的状态
    String type;
    String name;
    int age;
    String color;
    String state;
    
    // 方法,表示狗的行为
    void eat(){
        System.out.println(name + "边吃饭边打 Tom 猫。");
    }
    void sleep(){
        System.out.println(name + "满足的打起了瞌睡。");
    }
    
    // 构造器与继承来的方法以后再讲
    public Dog(String type1, String name1,
               int age1, String color1, String state1) {
        type = type1;
        name = Objects.requireNonNull(name1);;
        age = age1;
        color = color1;
        state = state1;
    }
    @Override
    public String toString() {
        return "Dog{种类:" + type + ",姓名:" 
            + name + ",年龄:" + age + ",颜色:" + color 
            + ",状态:" + state + "}";
    }
}

实例化

既然类描述了某类事物的共同特征,那么可以把类当成创建对象的模板,只需要创建对象时指定不同的参数,如年龄、品种…,就可以得到不同的具体对象(实例),这个过程就叫实例化。

例:金毛、比特都是狗,甚至同一种品种的狗,但不同的狗性别、年龄、习惯各有不同。可以把 Dog 类当作模板,使用 new 关键字(调用构造方法传进参数)创建很多的狗,创建的每个狗都是一个实例 instance。

还记得之前讲的引用数据类型吗,我们自定义的类型 Dog 就是。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R89zEors-1652792332806)(https://s2.loli.net/2022/05/15/s6Xk1wz2EDGIu7N.jpg)]

那么之前的问题就可以解决了:

创建人类:

class Person {
    // 主人的姓名
    String name;
    // 主人拥有的狗
    List<Dog> dogList = new ArrayList<Dog>(3);
    
    // 收养狗的方法
    public void add(Dog... dogs) {
        for (int i = 0; i < dogs.length; i++) {
            dogList.add(dogs[i]);
        }
    }
    
    // 寻找狗的方法
    public void find(String dogName) {
        System.out.println("你每天都在找狗...");
        for (Dog dog : dogList) {
            if (dog.name.equals(dogName)) {
                System.out.print("你脑海浮现出一段信息:");
                System.out.println(dog);
                System.out.println("你突然想起,这只是回忆罢了,都已过去很久了。");
                return;
            }
        }
        System.out.println("你甩了甩脑袋,记忆已经模糊不清了。");
    }
    
    public Person(String name) {
        this.name = name;
    }
}

在入口方法中勾勒出不同对象之间的行为、交互:

public static void main(String[] args){
    // 以狗类为模板创建两个狗对象
    Dog dog1 = new Dog("地狱犬", "黑魔王", 2340, "红黑相加的花纹", "死亡");
    Dog dog2 = new Dog("恐惧魔王", "提克迪奥斯", 12242, "绿色", "死亡");
    
    // 以人类为模板创建一个主人对象
    Person zhangSan = new Person("张三");
    
    // 人类收养了两只狗
    zhangSan.add(dog1, dog2);
    
    // dog1 睡觉时遗失了
    dog1.sleep();
    System.out.println("突然有一天再也找不到" + dog1.name + "了。");
    
	// 人类开始找狗
    zhangSan.find(dog1.name);
}

虽然设计类比较麻烦,但是比之前,数据的联系更紧密,使用 dog1 这个引用就可以获取此狗的所有信息,如 dog1.name,dog1.age,一目了然。

像 dog1、dog2 变量,它保存了对象的内存地址,这样的变量称为对象引用。可以把引用当作电视遥控器,而对象是电视机,通过遥控器访问电视机的不同频道和调节音量大小。

补充来说,变量有数据类型、变量名、存储的值。dog1 是变量名,使用变量名访问保存的数据。如果变量保存的值是对象的内存地址,则这个变量称为引用,真正的对象在堆中。

关于“引用保存了对象的内存地址,指向了堆中的对象,可以通过引用修改对象的状态”我一直抱有疑问,引用真的保存了对象的内存地址吗?究竟是如何通过引用影响对象的,无奈隐藏的比较深,暂时看不出来。

JavaSE IDEA 使用-面向对象_第30张图片

首先在方法区加载相关类的信息、静态变量初始化,执行到 Dog dog1 这行代码时使用 new 创建了一个狗对象,实例变量有默认值,再调用构造器完成实例变量的初始化,最后把地址赋给 dog1 引用。

字符串是引用类型,字符串一般放在方法区中的字符串常量池,如对象的 type 字段保存的是字符串的内存地址。

在 JDK7 后,字符串常量池被移到了堆中。

10.1.2 面向过程与面向对象

其实我有我自己的理解,但是一搜,有那么多博客都转载类似的言论,那就姑且当作是正确的吧。

面向过程

碰到了一个问题,需要解决。面向过程是分析出解决问题所需要的步骤,先做什么,再做什么…然后用方法把这个步骤一步一步实现,使用时依次调用就可以了。(自顶而下、逐步求精)

例:新学期学生到校注册流程

JavaSE IDEA 使用-面向对象_第31张图片

假如这些信息要存到 txt 文件中,按照以上步骤解决问题,如第一步把学生的年龄、身份证号等写入文件中,编写一个方法实现它,需要的时候再调用。(若某一步太过繁杂,难度很大,可以将此步再次细分)

public static void main(String[]args) {
    // 准备相关变量保存数据
    String schoolName = "怕踢中学";
    String studentName = "阿衰";
    .....
        
    // 把年龄和身份证号写入登记表文件中...
    	// 获取输出流
        // 把年龄,身份证号写入
    // 减去学生银行卡号的钱,增加学校的钱...
        // 先判断余额是否大于支付金额
        // 是否支付成功
        // 增加学校钱
        // 哪一步失败就回退
  	// 把经过认证过的人的信息添加到班级中,成为学生...
        // ...
}

面向对象

不再针对解决问题的先后步骤,而是先从问题中分析出完成事件的有哪些要素和参与对象,设计好模板(类),创建出对象,描述出各个对象在整个过程中发生的动作与行为、与其他对象的交互。

例:上述有学生、老师、学校、班级,可以先定义类描述共同特征,通过实例化创建对象,让这些对象去执行相应的动作完成学生的注册。

入口类:

public static void main(String[]args) {
    // 创建对象
	Student aShuai = new Student(12, "420425201209099090", "阿衰");
    School school = new School("怕踢中学");
    
    school.registerStudent(aShuai, 9000);
}

用到的类:

public class Student {
    private int age;
    private String idNumber;
    private String name;
    ...
    
    public Student(int age, String idNumber, String name) {
        setAget(age);
        setIdNumber(idNumber);
        setName(name);
    }
    
    public void decrease(School school,int money) {
        // 扣阿衰的钱...
        	// 获取阿衰的银行卡号
        	// 卡减钱
        	// 给学校加钱
    }
}
public class School {
    private String name;
    ...
    
    // 注册流程
    public boolean registerStudent(Student studnet, int money){
        // 阿衰给学校加钱
        aShuai.decrease(school, money);
        
        // 怕踢中学添加阿衰的信息
    	school.addStudent(aShuai);
    
        // 班级添加阿衰信息
        c.addStudent(aShuai);
    }
    ...

面向过程与面向对象的区别

面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix 等一般采用面向过程开发,性能是最重要的因素。

缺点:没有面向对象易维护、易复用、易扩展的优点。

面向对象

优点:易维护、易复用、易扩展;由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。

缺点:性能比面向过程低。

自己的想法

面向对象并不与面向过程对立,面向过程的程序设计是面向对象的基础,而从全局的角度来看采用面向对象,但对象调用的方法内部仍是面向过程思想来设计的,如阿衰扣钱的方法里内部使用面向过程的方法解决。

当逻辑比较简单时,使用面向过程能够更快的实现功能,而面向对象要设计出需要的类,考虑需要字段和方法,很麻烦;

当逻辑比较复杂时,采用面向对象的思维方式更贴近生活,相比与面向过程零零散散毫无联系的代码,更容易维护,在合理使用配置文件和接口后,可以做到基本不修改原有代码,就可以新增功能;而面向过程一环扣一环,每一步过程的结果都是下一步的前提条件,有了新的需求,又要全盘修改。

面向对象在我看来就是分类整理,同类数据归于一类。

10.2 实例变量

内容导视:

  • 实例变量的定义
  • 访问实例变量
  • 变量的作用域
  • 堆、栈、方法区

10.2.1 实例变量的定义

定义在方法外、类体内的变量称为字段(field),也称成员变量、全局变量。

字段是类的组成部分,字段的数据类型可以是基本数据类型,也可以是引用数据类型。(数组、接口、其它类)

一个类拥有的东西(has a),可以以字段的方式存在。

class Person{
    String name;
    int age;
    String id;
    static String nationality;
    String PhoneNumber;
}

成员变量分为实例变量、静态变量。简单区分,带 static 关键字的字段就是静态变量否则就是实例变量。

我们之前的例子绝大部分都是实例变量。通过引用.变量名访问、赋值。

定义实例变量

访问权限修饰符 数据类型 变量名;
private String name;
protected Dog dog;

访问权限修饰符,是用于控制访问范围,有 4 种:public、protected、默认(什么都不写)、private。用在变量上,是控制变量的访问范围,用在方法上是控制方法使用的范围。

你可以先试下,后面封装时再讲。

class Dog {
    private int age;
    int age;
    String name;
    boolean sex;
}
class Hello {
    public static void main(String[]args){
        Dog dog = new Dog();
		int dogAge = dog.age;
    }
}
// 错误: age 在 Dog 中是 private 访问控制
// 有 private 修饰的字段,无法在其他类使用引用.字段名访问

字段如果不赋值,有默认值,与数组元素默认值一致,这里不再赘述。

Dog dog = new Dog();
System.out.println(dog.age);// 0
System.out.println(dog.name);// null
System.out.println(dog.sex);// false

10.2.2 访问实例变量

首先我们需要创建对象,然后通过引用访问实例变量。

创建对象

引用数据类型 变量名 = new 引用数据类型();
Dog dog = new Dog();

也可以先声明,后赋值:

Dog dog;// 此时变量没有保存任何值
dog = new Dog();// 开辟存储空间创建一个对象,把对象的地址赋给 dog,dog 被称为对象引用

引用类型的变量可以赋值为 null,代表空,没有指向任何对象;使用值为 null 的引用访问对象的实例变量、方法时,就会报 java.lang.NullPointException 空指针异常。

Dog dog = null;
int age = dog.age;

访问实例变量

引用名.字段名

System.out.println(dog.name);
int name = dog.name;// 使用变量接收

赋值

dog.name = "大黄";

10.2.3 变量的作用域

全局变量的作用域为整个类体,局部变量的作用域为声明它时的域({})中。

class Test {
	int age = 22;// 作用域为整个类体,如 some 方法中可以访问到 age
    
    public void some() {
        System.out.println(age);// 2
        //System.out.println(i);// 找不到符号,变量 i
    }
    
    public void other() {
        int i = 3;// 局部变量 i 只在 other 方法内有效
    }
}

全局变量可以不赋值直接使用,因为有默认值;局部变量必须赋值后才能使用。

其他规则

  1. 全局变量可以与局部变量重名,直接访问变量时,遵循就近原则。

    class Person {
        int age;// 实例变量
    
        public void some() {
            int age = 5;
            String name = "小名";
            System.out.println(age);// 5
            System.out.println(name);// 小名
    
            /*
            	要是实在想访问实例变量 age
            	this 代表当前调用此方法的对象
            */
            System.out.println(this.age);// 0
        }
    }
    
  2. 实例变量和静态变量的生命周期较长,实例变量伴随对象的创建而分配空间,伴随对象的销毁而销毁;静态变量只要程序加载了此类,该类的静态变量就会被分配空间,程序结束后释放空间。

    局部变量生命周期较短,伴随代码块、方法的执行而被创建,执行结束被销毁。比如调用方法时会在栈中开辟空间,创建局部变量,方法执行结束后,栈空间被释放,局部变量被销毁。

  3. 全局变量可以被本类和其它类使用(只要有对象引用即可),局部变量只能在本类声明它时的域中使用。

  4. 不同方法之间的局部变量即使名字相同,也不是同一块空间。(以后还会详细说明)

    public static void some(int i) {
        i = 6;// 你修改的是这个方法的 i 变量保存的值,不影响下面的 i
    }
    public static void main(String[] args) {
        int i = 3;
        some(i);
        System.out.println(i);// 3
    }
    
  5. 局部变量不能加访问权限修饰符 和 static 修饰符。

10.2.4 堆、栈、方法区

粗略的介绍,因为这东西不是能够一眼看穿,比较底层,难以感知它的存在。

方法区

方法区最先有东西,存储类的加载信息(代码片段)、字符串常量池、静态变量等。

方法被调用时,在栈中分配空间,存储局部变量(基本数据类型的值和对象的内存地址)及运行过程需要的内存。

数据进来叫“进栈”、“入栈”、“压栈”、“push”,出去叫“出栈”、“弹栈”、“pop”。最先进来的最后出去,最后进来的最先出去。

JavaSE IDEA 使用-面向对象_第32张图片

每调用一个方法,就会开启新的一个栈(方法不调用,不会开启新栈),压在原有栈的上面。栈帧指的是栈顶部的元素(如现在的 b),只有栈帧才有活跃权,调用者 a 需要等待被调用的方法 b 执行完毕释放空间后才能执行接下的代码。

当最上面的栈执行完毕后,就会释放空间,轮到下一个。

每个栈中的局部变量是相互独立的,不会互相影响。

当不停的开启新栈,而不释放空间,栈内存满了会报 java.lang.StackOverflowError 栈溢出错误。方法递归和循环引用时,最容易出现此问题。

class Test{
    Test test = new Test();
    public static void main(String[] args) {
        new Test();
        /*
        	new Test();创建了一个对象,会调用此无参构造完成初始化
        	而无参构造会先调用父类即 Object 的无参构造方法;
        	
        	接着显示初始化实例变量 test,然而 Test test = new Test();
        	也创建了对象,会调用无参构造,而无参构造会先调用父类即
            Object 的无参构造方法;接着显示初始化 test...
        	
        	一直循环下去,直到栈内存和堆内存总有一个空间不够
        */
    }
}

使用 new 关键字创建的对象都会保存在堆中。对象中的实例变量、包括从父类继承过来的实例变量都有默认值,通过调用构造器完成对象的初始化。

堆只有一个,被所有栈共享。

short、byte、int、long 类型的字段的默认值是 0
float、double 是 0.0
char 是空,对应十六进制是 0x0000
boolean 是 false
String 和其它引用类型是 null

直接输出引用时,会自动调用 toString 方法(是从顶级父类 Object 继承得来的),toString 方法默认会返回对象数据类型的完整类名@十六进制的哈希码值

hashCode 方法会返回一个整数(哈希码值),哈希码值是将对象的内部地址转为整数得到的,可以看做是对象的内存地址。同一个对象调用 hashCode 方法时,返回的哈希码值一定相同。

10.3 实例方法

内容导视:

  • 实例方法的定义
  • 调用实例方法
  • 返回值类型
  • 形式参数列表
  • 方法重载
  • 可变参数

10.3.1 实例方法的定义

定义在类体中的方法称为成员方法,对应对象的行为。

成员方法分为实例方法和静态方法。

简单的讲下它们的区别:实例方法需要创建对象,使用引用.方法名调用。而静态方法多了一个 static 修饰,使用类名.方法名调用,如果在同类下可以省略类名。

也就是说光定义方法不用,方法里的语句是不会执行的;换言之,因为 main 方法是由 JVM 调用,那么我们需要在 main 方法中写调用此方法的语句即可。

定义实例方法的语法

访问权限修饰符 返回值数据类型 方法名(形式参数1, 形式参数2, ...) {
    方法体
}

方法体由一句句的 java 语句构成;

方法名遵循驼峰命名,在实际工作中,要见名知意,表明这个方法的功能。

我们先从最简单的没有返回值 void、没有形式参数列表讲起。

10.3.2 调用实例方法

想要调用某类的实例方法,首先需要此类的实例,通过引用.方法名调用。

class Test {
    public void some() {
        System.out.println("执行 some 方法中的语句...");
    }
    public static void main(String[] args) {
        // 先创建此类的实例,再通过引用.方法名调用
        Test test = new Test();
        
        test.some();
        // new Test().some(); 如果此对象不再使用,这样也行
    }
}

另外我还听过一种有趣的说法:“调用方法的行为有时被称为向对象发送消息。面向对象编程可以总结为:向对象发送消息”。

此外在实例方法中调用本类方法,直接通过方法名调用即可。

public void some() {
    other();
}
public void other() {
    System.out.println("其它方法");
}

因为调用实例方法,一定先要有实例,如 引用.some(),那么当执行到 other()这句时,就是此实例在调用 other 方法,所以引用.可以省去。

方法的好处

需求:遍历 10 遍二维数组

int[][] arr = {{52, 621, 1, 5}, {14, 51}, {1, 5, 52}};

for(int i = 0; i < arr.length; i++) {
    for(int j = 0; j < arr[i].length; j++) {
		System.out.print(arr[i][j] + "\t");
	}
    System.out.println();
}
for(int i = 0; i < arr.length; i++) {
    for(int j = 0; j < arr[i].length; j++) {
		System.out.print(arr[i][j] + "\t");
	}
    System.out.println();
}
...

这时需求又改了,在遍历之前打印“好嗨呦”,捉急啊!

但是如果将遍历封装成一个方法:

public void toString(int[][] arr) {
    System.out.println("好嗨呦");
    for(int i = 0; i < arr.length; i++) {
        for(int j = 0; j < arr[i].length; j++) {
            System.out.print(arr[i][j] + " ");
        }
        System.out.println();
    }
}

然后使用引用调用此方法即可;现在代码不长,感觉没什么,以后几百行,千行代码完成一个功能,你在 A、B、C…类都要用这个方法,难道还要手动把这些代码复制到 A、B、C 的 main 方法内吗?如果把代码放入某类的方法中,只需要写一次,让其它类通过方法名调用即可。

方法提高了代码的复用性,可以把它当成为了完成某个特定功能,且可以重复利用的代码片段。

将实现的细节封装起来,其它人只需看 API 文档知晓方法作用后调用即可,不需要关心底层细节,如 Arrays.sort(arr); 你并不需要了解排序算法,也能够使用它对数组进行排序。

10.3.3 返回值类型

返回值类型为 void

void 代表什么都不返回。

其它返回值类型

如果期待方法执行完毕后需要返回一个值,这个值的类型就是返回值类型;使用 return 值;。(如果返回的值可以自动转成返回值类型也算)

一个方法最多只能返回一个值,由于 return 语句的执行代表着方法的结束,程序回到调用者处,所以 return 只能是最后执行的一条语句。(确保 return 语句一定能够执行)(同一个域中,在 return 之后不能再有其它语句,否则执行不到,是无效的语句)

作为调用者而言,可以接收有返回值的方法返回的值,也可以不接收。

// int 代表返回值的类型为 int,或者可以自动转成 int 类型
public int some() {
    ...
    return 4;
}
public void other() {
    // 调用 some 方法,可以选择接收返回值,或者不接收
    some();
    int num = some();
}

10.3.4 形式参数列表

方法括号中定义的变量,简称形参,每个参数都是局部变量,调用方法时传入实参赋值:

  • 参数可以是 0 到 n 个
  • 参数之间使用逗号分隔
  • 调用方法时,按对应类型、个数、顺序传入实际参数。
public void some(int a, String b, char c) {}

比如上面,那我们调用时传入三个实参,分别是 int、String、char 类型

引用.some(5, "你好", 'a');

这相当于

int a = 5;
String b = "你好";
char c = 'a';

也可以使用变量作为实参。

10.3.5 方法重载

方法签名

方法名与形式参数列表合并称为方法签名(signature of the method),方法签名作为方法的唯一标识,同一个类不能存在重复的方法,即方法签名不能重复,否则就无法区分调用的是哪个方法。

方法重载

同一个类中,方法名相同,但形参列表不同的两个方法构成重载。

方法名相同很好理解,而形参列表不重复,是指参数的个数、类型、顺序至少有一样不同。

如下面就构成重载:

public void some(int i, String s) {}
public void some(int i, String s, char c) {}
public void some(char c, boolean b) {}
public void some(String s, int i) {}

注意了,顺序不同,是指不同类型的顺序,而不是靠变量名区分顺序:

public void some(int i, int s) {}
public void some(int s, int i) {}// some(int,int)方法已定义

返回值类型、变量名都与方法重载无关,这个很好理解:

public void some(int i) {}
public int some(int j) {return 1;}

现在使用调用方法:引用.some(2); 是不是没办法区分调用的是谁?返回值有但我可以不接收。

方法重载的好处

减轻了起名与记名的麻烦,拿打印方法举例:

JavaSE IDEA 使用-面向对象_第33张图片

10.3.6 可变参数

可变参数的本质是数组,可以直接将同类型的数组实例当成实参。

类似于将同名、参数类型相同但参数个数不同的方法封装成了一个方法。

语法

数据类型... 变量名
String... strs    

它代表着 0 ~ n 个此数据类型的参数。

public int sum(int... nums) {
    int sum = 0;
    for (int i = 0; i < nums.length; i++) {
        sum += nums[i];
    }
    return sum;
}

调用此方法,可以传递 0 ~ n 个 int 类型的实参,如:

引用.sum();
引用.sum(1);
引用.sum(1, 5);
引用.sum(4, 6, 2, 7, 5);
...
int[] arr1 = {4, 5, 3};
引用.sum(arr1);
引用.sum(new int[5]);
引用.sum(new int[]{4, 5, 3});

由于可变参数长度无法确定,所以它只能放在形参列表中的最后 1 个位置;换言之,形参列表中最多只能出现一个可变参数。

10.4 构造方法

内容导视:

  • 构造方法定义
  • 默认无参构造器
  • this

10.4.1 构造方法定义

构造方法也称构造器,调用时在栈中分配空间,是一种特殊的方法,定义时不用写返回值类型,方法名必须与类名一致!

语法:

访问权限修饰符 类名(形参列表) {
    方法体...
}

在调用构造方法之前,对象已经创建好了,在堆中分配了空间,实例变量有默认值;构造方法执行结束后,返回这个对象的地址,赋给引用,从而让外部程序可以访问到此对象。

一般我们通过调用构造方法来完成实例变量的初始化,在创建对象时根据传入实参的不同调用对应构造器。对的,构造器可以不止一个。

class Person {
    String name;
    int age;
    // 构造器1
    public Person(String name1) {
        // 接收到实参,将实参保存的值赋给 name
        name = name1;
    }
    
    // 构造器2
    public Person(int age1) {
        age = age1;
    }
}
class Test {
    public static void main(String[] args) {
        // 调用构造器1,传入实参"张三"
        Person zs = new Person("张三");
        System.out.println(zs.name);// 张三
        
        // 调用构造器2
        Person ls = new Person(5);
        System.out.println(ls.age);// 5
        
        System.out.println(zs.age);// 0
        System.out.println(ls.name);// null
    }
}

虽然调用的可能是同一个构造器,通过传入实参的不同,每个实例都有自己独有的一份数据。

10.4.2 默认无参构造器

不知道你们发现没有?如果手动定义了有参构造器,则 new Test()就会报错;

class Test {
    public Test(int name) {}
    public static void main(String[] args) {
        new Test();
    }
}

这是因为当没有定义构造器时,编译器会自动生成一个默认的无参构造器,它的访问权限修饰符与声明类时的访问权限修饰符一致;当定义了构造器时,默认无参构造就失效了;可以通过反编译 javap 类名 命令测试。

class Test {}
// 编译后生成了 Test.class,再执行 javap Test,结果如下:
class Test {
	Test();
}
public class Test {
	public Test(int i) {}
}
// 反编译字节码,可以看到没有提供无参构造
public class Test {
	public Test(int);
}

面对这种情况,我们通常会手动添加无参构造。

10.4.3 this

每个对象都有 this 引用,保存着自身的内存地址。

class Person {
    String name;
    
    public void setName(String name1) {
        // this 指代调用此方法的对象
        this.name = name1;
    }
}
Person p1 = new Person();
Person p2 = new Person();

p1.setName("张胜男");
p2.setName("张三");

// 可以通过引用.变量名区分
String name = "它";
p1.name = name;
p2.name = "不好";

this 类似于中文的“自己”,“自己”指的不是“张三”,也不是“李四”,而是说出这句话的人。

p1 实例调用 setName 方法,那么方法中的 this 指向的就是 p1 实例;p2 实例调用 setName 方法,那么 setName 方法中的 this 指向的就是 p2 实例。

this 指向 “调用此方法的实例”,实例方法肯定需要实例调用,那么谁调用的方法,this 就是谁。

一般情况下,this. 可以省去,但是尤其是在构造器中,局部变量与实例变量重名时,需要添加 this. 加以区分。

class Person {
    String name;
    int age;
    String hobby;

	// 由于可以通过 this. 区分,所以没必要刻意取名
	public Person(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }
}

除了访问字段,this 也可以调用方法,this.方法名(实际参数列表)。

调用其它构造器

this(实际参数列表),只能在构造方法中的第一句出现。

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

可以减少重复代码,不过这种方式,当实例变量太多时,很容易就不小心就传错参数,看着也很累赘。

this 只能在实例方法、构造器中使用。(因为访问静态方法不需要实例)

10.x 总结回顾

数据类型 引用名 = new 数据类型();
引用名.实例变量名
引用名.方法名(实际参数列表)    

构造方法用于完成实例变量的初始化;this 指代自身,只能出现在与实例相关的地方。

同一个类中,方法名相同但形式参数列表不同(顺序、个数、类型至少有一个不同)的方法构成重载。

每调用一个方法就是开启了一个新的栈,栈中存储局部变量及运行过程需要的内存;不同方法内创建的局部变量即使名字相同,也不是同一块内存空间,互不影响。

创建的对象存储在堆中。

10.y 头脑风暴

10.1 在 AA 类编写一个静态方法,判断一个整数是奇数还是偶数,奇数返回 false,偶数返回 true。

10.2 分析如下代码,控制台上会输出什么?

1)在类 A 中:

public void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    System.out.println("swap 中 a:" + a);
    System.out.println("swap 中 b:" + b);
}

public static void main(String[] args) {
    int a = 5;
    int b = 1;
    new A().swap(a, b);
    
    System.out.println("main 中 a:" + a);
	System.out.println("main 中 b:" + b);
}

2)在类 B 中:

public void some(int[] arr) {
    arr[0] = 1234;
}
public static void main(String[] args) {
    int[] arr = new int[3];
    new B().some(arr);
    System.out.println(arr[0]);
}

10.3 类 Person 中,分析输出什么?

1)

int age;
public void some(Person p){
    p = null;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    p.some(p);
    System.out.println(p.age);
}

2)

int age;

public Person some(Person p) {
    return p;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    Person p1 = p.some(p);
    System.out.println(p == p1);
    System.out.println(p.age == p1.age);
}

3)

int age;

public Person some(Person p) {
    Person p1 = new Person();
    p1.age = p.age;
    return p1;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    Person p1 = p.some(p);
    System.out.println(p == p1);
    System.out.println(p.age == p1.age);
}

10.4 一共有 ?个桃子。每天猴子吃其中的一半加 1 个桃子,当第 10 天时,准备吃,一看,只剩 1 个桃子了,请问 ?的值为?

10.5 有 1 个迷宫由二维数组组成。1 代表墙,0 代表可通行。现有一球在左上角(1,1)处,要求到右下角(7,7),记录小球走过的路径。

1 1 1 1 1 1 1 1 1
1 q 0 0 0 0 0 0 1
1 0 1 0 0 0 0 0 1
1 0 1 0 0 0 0 0 1
1 1 1 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1

10.6 如图,把 A 中的 n 个圆盘全部移到 C 中。要求:大圆盘不能放在小圆盘上面,每次只能移动一个圆盘,如何移动。

JavaSE IDEA 使用-面向对象_第34张图片

10.7 在一个 8*8 格的棋盘摆放 8 个棋子,要求:任意两个棋子之间不能处于同一行、同一列、同一斜线。共有几种摆法?

10.8 设计一个类,完成与电脑的猜拳,电脑随机出石头、布、剪刀,要求显示输赢次数。

参考答案

第一到五章

第一章答案

1.1 JDK 和 JRE 的区别?

JVM(Java Virtual Machine)Java 虚拟机,Java 程序需要运行在虚拟机上,根据不同平台的虚拟机,能够实现跨平台的功能。(编译一次,生成的字节码文件可以在不同平台运行)

JDK(Java Development Kit)Java开发工具包,包含了 JRE 和开发工具(javac.exe、javadoc.exe、javap.exe 等),不仅可以运行 Java 程序,也可以开发 Java 程序。

JRE(Java Runtime Environment)Java运行环境,包括 JVM、核心类库(常用类)等。

JDK 中包含 JRE,如果只想运行 class 文件,JRE 就足够。

JDK > JRE > JVM


1.2 什么是编程?

编程:解决某个问题而使用某种编程语言编写程序代码控制电脑得到结果的过程。

使用高级语言编写的源代码需要进行编译或解释,能够让操作系统识别,理解你的意图,接收一系列的指令去一步步操纵硬件工作,最终解决某个问题。


1.3 Swing 组件是什么?

Swing 包含了构建图形界面(GUI)的各种组件,如按钮、标签、窗口、面板、文本框等组件。你现在看到的 QQ、微信等软件就是一个图形界面,里面是各种类型的组件组成。


1.4 JAR 包是什么?

jar 包也称类库。源码编译后生成对应的 .class 字节码文件,为了完成某些功能通常需要多个 .class 文件的配合。jar 包主要对多个 .class 文件打包,类似 zip 压缩格式的文件,但不同的是 jar 多了 META-INF/MANIFEST.MF 文件,里面有 jar 包的创建人、版本等信息;若是可执行的 jar 包(有 main 方法),会包含 Main-Class 属性,表示 main 方法在哪个类中。


1.5 软件与程序指的是什么?

软件可以完成特定的功能,可以理解为应用程序的集合。而应用程序是软件的一个组成部分,它是软件的必要元素。简单来说,软件 = 程序 + 文档 = 数据结构 + 算法 + 文档。

程序指计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合。


1.6 什么是编译型语言和解释型语言?

使用计算机语言(一大串二进制数)或汇编语言,一个指令只能对应一个操作中的一个细微的动作,太繁琐,不利于记忆,容易出错,开发效率极低。计算机语言能够被计算机直接识别,执行效率最高。(面向机器)

后来生成了高级语言,方便让人类理解,开发效率高。但是编写的源代码不能被机器识别,需要翻译成机器可以识别的语言,请看下答的平台无关性


1.7 Java 语言特性?

1)面向对象

面向对象虽然执行效率没有面向过程高,但是以类的方式管理大量代码时(一个类中有变量、方法、代码块、内部类),更加方便程序员组织和管理代码,思路更清晰不易出错。

由此才有了对象、继承、封装、多态等概念。

① 对象:使用类为模板指定参数创建的实例,通过实例可以调用类中定义的方法、访问类中的字段,不会混乱。

② 继承:解决多个类中重复出现的代码,只要继承了一个类,自动拥有这个类的全部字段和方法。(私有、构造器、静态、final除外)

③ 封装:为了保护数据,不被错误的修改;在类、字段、方法上添加访问权限修饰符,如 private,只允许在本类中访问,再提供公开的 set 与 get 方法以供别人修改(在方法中可以添加判断逻辑来决定是否赋值)或访问本类的字段。此外还有包机制可以管理大量的类,可以区分两个同名类、将类似功能的类放在同一个包下…

④ 多态:子类继承了父类,但不满意父类的方法实现,可以重写此方法,表面是父类型,但可能底层为子类实例,调用的方法是子类重写后的方法,展现了不同的结果。

① 对象:把自己当作上帝,想要创建一只狗,想一想狗的特征、行为有哪些,在类中定义字段用以保存狗的颜色、大小、品种信息,定义方法体现狗的行为。

public class Dog {
    //private私有化,防止坏人直接修改狗的年龄
    private int age;//定义age变量用以保存年龄
    private String name;//name保存姓名
	
    //方便别人访问狗的年龄,但不允许修改就不提供set方法
    public int getAge() {
        return this.age;
    }
    
    //狗吃饭时的表现
    public void eat() {
        System.out.println(this.name + "开心地摇起了尾巴!");
    }
    //有参构造器略
}

然后使用 new 关键字创建狗,同时指定狗的初始属性值。

new Dog(3, "土狗");

② 继承:想一想子女能够继承父母的财产吧。

③ 封装:父母可不能什么都让你访问,总要有自己私人的东西吧。

④ 多态:你老爸有事不能去了,你可以代替老爸,以他的身份参加这次宴席,你要是不满意老爸继承给你的如何为人处事的方法,可以使用自己的方法应对这些客人。

Father huYingJun = new Father();
huYingJun.call();// 您好啊,真高兴见到你。

Father huTuTu = new Son();
huTuTu.call();// 我会动耳神功,你要看吗?

当然你如果不想使用面向对象,嫌麻烦还要设计字段、方法,也可以把所有变量、方法都塞进一个类中,只是看着乱糟糟的,不好维护。(代码量很少时,没有必要使用面向对象)

2)平台无关性

编写出的代码不可直接被机器识别,需要工具进行转换。

先讲编译器与解释器的区别:

① 编译器将源代码一次性全部翻译,生成一个二进制码文件,这个文件可以直接被机器识别,执行效率高。如果源代码改动需要重新编译生成新的二进制码文件。

② 解释器将源代码逐行解释成特定平台的机器码,解释一行执行一行。每次执行都需要翻译,跨平台性好。

Java 的做法:

③ Java 源代码会被编译成字节码文件,这个字节码文件是与任何平台都无关的中间代码,由 JVM 启动解释器翻译成对应平台上的机器码,所以一份字节码可以在任何平台上运行。前提:不同平台上要安装对应的 JVM,JVM 不跨平台。

之所以这么做,是 Java 既想保持解释语言的跨平台性(可移植性),又想解决解释语言执行效率低的问题。

但效率还是不如编译性语言。为了避免解释型语言带来的执行效率低的问题,Java 设计者制作了 JIT(just in time compilation)实时编译程序,将运行频率很高的字节码直接编译为机器指令执行来提高性能。

① 给一个英语文件,你看不懂,有人直接将英语文件翻译成汉文,将翻译的结果保存在一本书中,给你发过去;这样你每次就直接看这本翻译后的书即可,缺点是原著改了,你又需要请他翻译一下。

② 有人跟在你身边,你看一句,他就说一句这是什么意思;即使你换了一本英语书,他照样解释给你听,只不过效率低。

③ 有的人没有直接翻译成汉文,而是记录了源文件的重要信息、文章主题、中心思想、具体脉络等,再以后看到这份批注,能够迅速理解原文含义,get 到这个点,能够不假思索说给你听。

后来发现也挺麻烦,他干脆挑出你最喜欢、频繁看的部分,将这部分先翻译好了,等你需要看别的地方时,再请教他。

所以不要纠结这个语言究竟是编译执行、还是解释执行,没有多大意义。

3)支持多线程

a)线程与进程

① 进程:每个运行的程序都会开启一个独立的进程,如 QQ、酷狗音乐;操作系统为进程分配内存空间。

② 线程:由线程创建,是线程的最小执行单位,一个进程至少有一个线程,用以完成任务。比如迅雷同时下载多个文件、QQ 打开多个窗口等,多个任务同时执行。

单线程:一个进程同一时刻只有一个线程。

多线程:同一时刻有多个线程用以完成任务。

b)CPU 处理线程的方式

① 并行:同一个时刻,多个任务同时执行(多个 CPU)

② 并发:同一个时刻,多个任务交替执行(单个 CPU),通过 CPU 调度,速度十分快,造成貌似同时执行的错觉。

③ 串行:按先后顺序依次执行任务,一次只做一件事。后面的任务想要执行,必须等前面的任务执行完毕。

① 并行:吃饭时来了电话,你叫老婆接,自己吃饭;接电话与吃饭同时执行。

② 并发:吃饭时来了电话,边吃饭边接电话,感觉像是同时,但是不可能真正在同一个时刻做到吃饭和说话,这样会呛到鼻子去。

③ 串行:吃饭时来了电话,先吃完饭,再打电话。

并发和并行可以同时存在,比如两个 CPU,一个 CPU 在处理 QQ 线程,另一个 CPU 来回切换处理浏览器和音乐播放器。

c)线程之间的关系

① 同步:一个线程需要等待另一个线程执行完毕,返回了消息,才能继续往下运行。

② 异步:一个线程 A 对另一个线程 B 发起请求,可以不用等待 B 返回消息,因为 B 线程执行完后会通知你,你直接去干别的事情了;等到接受通知后,再处理。

d)单个线程的状态

① 阻塞:一个线程在等待的过程啥也不干。

② 非阻塞:没必要一直等待,可以干别的事。

同步阻塞:快递员给你打电话,说楼下有你的快递;当你没拿之前,他就一直在原地等你,不能走开,啥也干不了。

同步非阻塞:快递员给你打电话,说楼下有你的快递;当你没拿之前,他觉得一直在原地等你很无聊,决定跑下步、玩手机、时不时观察你下来了没有、直接上楼…

异步非阻塞:快递员给你发短信,说快递放到菜鸟驿站了;随后没有等你来拿,直接把短信继续发给下一个人。直到你签收后,他那边才接收到消息,然后做相应处理。

异步阻塞:别人拿完快递后,自然会有信息通知你,你完全可以做其他事情,却还在那傻等。

4)安全性

双亲委派机制可以防止恶意加载同名字节码。

5)健壮性

异常处理机制:对可能出现异常的代码实现进行预先处理,防止遇见问题时,程序直接挂掉。

垃圾回收机制:自动清除长时间没使用的对象,防止内存泄漏(内存满了),这也算是简单性吧。

6)简单性

  • 封装、继承、多态很贴近生活。
  • 没有指针这复杂的概念。
  • 只支持类的单继承,多继承可以使用接口实现。
  • 垃圾回收机制,不需要手动释放内存。

1.8 能说下 JavaSE、JavaEE、JavaME 吗?

JavaSE 标准版,包含核心类库。主要用来开发桌面应用,允许在桌面、服务器开发和部署 Java 应用程序。

JavaEE 企业版,帮助企业开发和部署可移植、可伸缩且安全的服务端 Java 应用程序,包括 Web 网页后台开发等。

JavaME 微型版,专门为在移动设备和嵌入设备上运行的应用程序提供一个健壮且灵活的环境。

第二章答案

2.1 为什么 Java 代码可以做到一次编译,到处运行?

编译生成的 .class 文件与具体平台、系统无关。

JVM 虚拟机是关键。程序运行时,由 JVM 负责解释执行 .class 文件,将其翻译成不同平台下的机器码并运行。需要注意的是,.class 文件是与操作系统平台无关的中间代码,不能直接运行。

JVM 不跨平台,不同平台需要安装不同的 JVM。

这么做的目的,在可移植的同时兼顾执行效率。此外还加入了 JIT(just in time)编译器,把运行频繁的代码直接编译成与本地平台相关的机器码,需要时直接使用,不用再次翻译。


2.2 一个源文件可以生成多个 class 文件吗?

可以,源文件只要按规则定义了多个类,编译后会生成多个对应的 class 文件。


2.3 Java 源文件定义的类名必须与文件名一致吗?

不是,只有被 public 修饰的类名必须与源文件名一致。

第三章答案

3.1 下面语句能够通过编译吗?

1)

byte b = 2;
b = b * 2 + 10L;

不能,从 long 转换到 byte 可能会有损失。

2)

int i = 3;
float f = i + 2.22;

不能,从 double 转换到 float 可能会有损失。(2.22 默认被当作 double 处理)

3)

int i = 21;
long l = 231;
double d = 3.23;

long l2 = i + l + d;

不能,从 double 转换到 long 可能会有损失。

4)

int x = (int)3.14 * 3 + 6.2 * 10;

不能,从 double 转换到 int 可能会有损失。(强转符号只针对最近的操作数有效,只是把 3.14 转成了 int 类型,可以使用小括号提升优先级)

5)

short s1 = 34;
short s2 = s1 - 3;

不能,从 int 转换到 short 可能会有损失。

6)

int i = 3;
char c = (char)i;

可以。

7)

byte b1 = 4 * 3;
byte b2 = b1 + (byte)4;

short s = b1 + b2;

不能,第 2 行报从 int 转换到 byte 可能会有损失;第 4 行报从 int 转换到 short 可能会有损失。

8)

double d = 3;
float f = (float)d + .234F;

可以。

9)

long l = 3L;
double d = l + 3.24F;

可以。


3.2 下面输出结果?

1)

int x = (int)3.14 * 3 + 6 * 10;
System.out.println(x);// 69

2)

int x = (int)(3.14 * 3 + 6.2 * 10);
System.out.println(x);// 71

先算小括号里,得出结果再强转成 int。


3.3 想在控制台上输出 \,怎么写?

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


3.4 想在控制台上输出如下,怎么写?

特别厉害的那个迦

System.out.println("动漫名称\t编剧\t价格\t销量\n微笑超人\t坂本\t1000\t0001");

第四章答案

4.1 求 i 的值。

double i = 5 / 2; 中的 i 的值为 2.0。


4.2 输出什么?

1)

String s = "张三";
int i = 3;
System.out.println(s + i * 2 + "b");// 张三6b

2)

int x = 5;
int y = 5;
System.out.println(++x < 6);
System.out.println(y++ < 6);
System.out.println(y);

先++,x = 6,再判断,输出 false;先判断,输出 true,再++,y = 6,输出 6

3)

int x = 10;
int a = x + (x++);
int b = x + (++x);
System.out.println(a);
System.out.println(b);
System.out.println(x);

a = 10 + 10 = 20,x++ 后为 11;b = 11 + 12 = 23,x 为12。输出 20、23、12。

4)

int i = 34;
int j = i--;
int z = --i;
System.out.println(i);
System.out.println(j);
System.out.println(z);

j = 34,i = 33;i = 32,z = 32。输出 32、34、32。

5)

int i = 2;
int j = 2 + i++;
System.out.println(i);
System.out.println(j);

j = 2 + 2 = 4,随后 i 自加一为 3,输出 3、4.

6)

int i = 10;
i = ++i;
System.out.println(i);

这道题,不是那么好讲,使用 javap -c 反编译(先弹出栈顶的数)看看就行,不用了解,没有人会这么用的。

什么是栈顶,就是容器最上面的一个元素。打个比方,一个空羽毛球筒,现在放入羽毛球 a(称为入栈),此时栈顶是羽毛球 a;现在又放入一个羽毛球 b,b 把 a 压住了,b 在 a 的上面,此时 b 就是栈顶;想要拿出 a,必须先拿出 b(称为弹栈,把最上面的元素取出来),这就是后进先出先进后出

JavaSE IDEA 使用-面向对象_第35张图片

对代码进行反汇编,反编译后得到的结果:

Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

public static void main(java.lang.String[]);
Code:
0: bipush        10 // 将 10 压入操作数栈中,此时栈顶为 10
2: istore_1 // 从操作数栈中弹出一个数也就是 10 赋给第 1 个局部变量 i
3: iinc          1, 1 // 对第 1 个局部变量 i 自增 1,i = 11
6: iload_1 // 将第 1 个局部变量的值 11 压入操作数栈,栈顶为 11
7: istore_1 // 从栈中弹出一个 11 赋给第 1 个变量 i
8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
15: return

根据 JVM 指令手册翻译:https://blog.csdn.net/qq_40109475/article/details/117134802

人话就是:将 10 赋给变量 i,i 自增一为 11,将 11 赋给 i。

7)

int i = 10;
i = i++;
System.out.println(i);

反编译部分节选:

0: bipush        10		// 将 10 压入栈
2: istore_1				// 将 10 弹出赋给第 1 个变量 i
3: iload_1				// 将第 1 个变量 i 的值 10 压入栈
4: iinc          1, 1	// 对第 1 个变量 i 自增 1,i = 11
7: istore_1				// 将 10 弹出赋给第 1 个变量 i
8: return

所以 i 为 10。为了方便理解:首先 i = 10,有个临时变量 temp 保存 i 的值,temp = 10;后 i++ 为11,再把 temp 的值赋给 i,i = 10。

8)

byte b = 1;
byte b1 = b++;
byte b2 = --b;
System.out.println(b);
System.out.println(b1);
System.out.println(b2);

反编译部分节选:

0: iconst_1	# 直接取常量(整数 1),压入栈中。(栈中从上至下的值:11: istore_1	# 弹栈,赋给第 1 个变量 b,此时 b = 1。(空)
2: iload_1	# 将第 1 个变量 b 的值压入栈中。(13: iload_1	# 将第 1 个变量 b 的值压入栈中。(114: iconst_1	# 将 1 压入栈中。(1115: iadd		# 取出栈中最上面两个值相加,并将结果 2 压入栈中。(216: i2b		# 将 int 类型的值转为 byte7: istore_1	# 弹栈,赋给第一个变量 b,此时 b = 2。(18: istore_2 # 弹栈,赋给第二个变量 b1,此时 b1 = 1。(空)
9: iload_1	# 将第 1 个变量 b 的值压入栈中。(210: iconst_1# 将 int 类型的常量 1 压入栈中。(1211: isub	# 取出栈中最上面两个值相减,并将结果 1 压入栈中。(112: i2b		# 将 int 类型的值转为 byte13: istore_1# 弹栈,赋给第 1 个变量,此时 b = 1。(空)
14: iload_1	# 将第 1 个变量 b 的值压入栈中。(115: istore_3# 弹栈,赋给第 3 个变量 b2,此时 b2 = 1。(空)
16: return	# 结束。

由于汇编语言太麻烦,很不好理解。还是按老法解释:b1 = 1,后 b++,b = 2;–b,b = 1,b2 = 1,输出 1、1、1。

9)

boolean b = false;
System.out.println(b = true);
System.out.println(b == false);

b = true,输出 b 的值,即 true。true 等于 false 为假,输出 false。

10)

int x = 9;
int y = 12;

int z = x < y ? x + y : x - y;
System.out.println(z);

9 < 12 为 true,返回 x + y = 21,赋给 z,输出 21。

11)

int a = 10;
int b = 99;

int result = a > b ? a++ : b--;
System.out.println(result);
System.out.println(a);
System.out.println(b);

10 > 99 为 false,返回 b–:先将 b 的值 99 赋给 result,后 b–,b = 98。输出 99、10、98。


4.3 利用三目表达式求出三个数之间的最大数。

先定义三个变量保存数值,先让其中两数比较,返回大值赋给 max1;再让 max1 与剩下的数比较返回大值。

int n1 = 241;
int n2 = 324;
int n3 = 242;

int max1 = n1 > n2 ? n1 : n2;
int max2 = max1 > n3 ? max1 : n3;
System.out.println(max2);

4.4 利用所学知识求出 33 天是多少个星期零几天?

其实很简单,让 33 除以 7,商就是星期数,余数就是天数。

int day = 33;
int week = day / 7;
int RemainDay = day % 7;
System.out.println(day + "天是" + week
	+ "个星期零" + RemainDay + "天");

4.5 求值。

3 / 9 * (242.2 - 100) = 0

因为 3 / 9 = 0,所以结果为 0;要想不偏离原意,请至少把其中一个数转为 double 类型。


4.6 下面代码输出什么?

1)

boolean x = true;
boolean y = false;

byte num = 2;

if ((num++ == 2) && (y = true)) {num++;}
if ((x = false) || (++num == 5)) {num++;}

System.out.println(num);
System.out.println(x);
System.out.println(y);

只有 if () 中为 true,才会执行 {} 中的语句。

直接快进到 if 语句
num++ == 2:
先判断 num 是否等于 2,为 true
再自加一,num = 3;此时不能断定结果,继续看右边

y = true:给 y 赋值为 true
两边条件都为 true,&& 后的结果为 true,执行 num++
num = 4

接着看第 2 个 if 语句
x = false:给 x 赋值 false
既然 x 为假,不能断定结果,继续看第 2 个条件

++num == 5:
先自加一,num = 5
再判断 num 是否等于 5,为 true

两个条件一假一真,|| 后的结果为 true,执行 num++
num = 6

输出 6、false、true

2)

int i = 342;
int b = ++i + i;

System.out.println(b);

先 ++i,i = 343,再赋值:b = 343 + 343 = 686。

3)

int i = 342;
int b = i++ + ++i;

System.out.println(i);
System.out.println(b);
i++ + ++i
先进行加法运算再自加一
即 342 + ++(i),此时 i++ 后,i = 343

现在再看右边的 ++i,先自加一,即 i = 344,再运算
int b = 342 + 344 = 686
i = 344
输出 344、656

正好呢,之前有个类似的题,但反编译麻烦,试着使用韩老师教的 temp 方法举例,再试试吧:

int i = 342;
i = i++ + i++;

System.out.println(i);
先进行加法运算 342 + i++,后自加 1,i = 343

先进行加法运算 342 + 343
使用 temp 保存运算结果,即 685
后 i 自加 1,i = 344

i = temp,i = 685

第 2 个例子:

int i = 342;
i = i++ + ++i;

System.out.println(i);
先进行加法运算 342 + ++i,后自加 1,i = 343

++i 先自加一,i = 344,再进行加法运算 342 + 344
使用 temp 保存运算结果,即 686

i = temp,i = 686

第 3 个例子:

int i = 342;
i = ++i + ++i;

System.out.println(i);
先自加一,i = 343,得到:343 + ++i
先自加一,i = 344,得到:343 + 344

使用 temp 保存运算结果,即 687

i = temp,i= 686

像极了茴香豆的“茴”有几种写法,大家看个乐呵就行。

第五章答案

5.1 打印 [n,m] 之间的所有是 x 倍数的整数,统计个数及总和。

先考虑输出 [1,50] 之间所有是 5 的倍数:

// (1)输出 1 ~ 50
for (int i = 1; i <= 50; i++) {
    System.out.println(i);
}
// (2)只有当 i 是 5 的倍数时,才输出
for (int i = 1; i <= 50; i++) {
    if (i % 5 == 0) {
    	System.out.println(i);
    }
}
// (3)定义变量保存统计个数、和
int count = 0;
int sum = 0;
for (int i = 1; i <= 50; i++) {
    if (i % 5 == 0) {
        count++;
    	sum += i;
    }
}
System.out.println("总和:" + sum);
System.out.println("是 5 的倍数的数的个数:" + count);
// (4)扩展到一般情况
// 这里可以考虑接收键盘输入,得到整数值
int n = 1;
int m = 50;
int x = 5;

int count = 0;
int sum = 0;
for (int i = n; i <= m; i++) {
    if (i % x == 0) {
        count++;
    	sum += i;
    }
}
System.out.println("总和:" + sum);
System.out.println("是 " + x + " 的倍数的数的个数:" + count);

5.2 输出 1 + (n - 1)= n、2 + (n - 2)= n、…、50 + (n - 50)= n。

观察变的部分,1 ~ 50,将其提取出来,定义为 i:

for (int i = 1; i <= 50; i++) {
    System.out.println(i + " + (n - " + i + ") = n");
}

5.3 打印九九乘法口诀表。

效果如图:

JavaSE IDEA 使用-面向对象_第36张图片

由于我们是按行输出的,所以观察递增的部分:1 ~ 9;也就是乘号右边。

for (int i = 1; i <= 9; i++) {
    System.out.println(i);
}

观察乘号左边与 i 的关系

当 i = 1 时,输出 1
i = 2 时,输出 1、2
i = 3 时,输出 1、2、3
...
i = 8 时,输出 1、2、3、4、5、6、8
i = 9 时,输出1、2、3、4、5、6、8、9

可以发现输出的开始都是 1,结束都是 i
定义一个变量 j,使用 for 循环输出这些值
for (int i = 1; i <= 9; i++) {
    System.out.print(i + "\t");
    for (int j = 1; j <= i; j++) {
        System.out.print(j + " ");
    }
    System.out.println();
}

开始组合 “j * i = 某值” 字符串:

for (int i = 1; i <= 9; i++) { 
    for (int j = 1; j <= i; j++) {
        System.out.print(j + "x" + i 
			+ "=" + (i * j) + "\t");
    }
    System.out.println();
}

注意同行显示的乘法口诀,别用 ln 换行了;应该输出完这行所有的乘法口诀后,再换行。


5.4 打印一个 n 层的空心金字塔。例:当 n = 5 时,输出如下:

    *
   * *
  *   *
 *     *
*********

简化 1:打印实心金字塔

    *
   ***
  *****
 *******
*********

简化 2:将星号前面空格去掉

*
***
*****
*******
*********

第 2 层是 1+2 = 2*2 - 1
第 3 层是 1+2+2 = 2*3 - 1
第 4 层是 1+2+2+2 = 2*4 - 1

通过观察,发现每层都比上层多 2 个星号,通过归纳得出第 i 层为 2 * i - 1 个星号。

先打印 5 层。i 控制层数 1 ~ 5 层;j 控制每层的星号数,一共输出 2 * i - 1 个星号。

for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 2 * i - 1; j++) {
        System.out.print("*");
    }
    System.out.println();
}

接下来观察简化 1:

第 1 行前面有 4 个空格
第 2 行前面有 3 个空格
第 3 行前面有 2 个空格
第 4 行前面有 1 个空格
第 5 行前面有 0 个空格
所以当第 i 行前面应该打印 5 - i 个空格后再打印 *
for (int i = 1; i <= 5; i++) {
    for (int z = 1; z <= 5 - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        System.out.print("*");
    }
    System.out.println();
}

接下来观察最初的空心版本,除了最后一层,其它层除了开始的和结束的星号,都输出空格:

for (int i = 1; i <= 5; i++) {
    for (int z = 1; z <= 5 - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        // 不是最后一层,除了开始与结束输出星号,其它都输出空格
        if (i != 5) {
            if (j == 1 || j == 2 * i - 1) {
                System.out.print("*");   
            } else {
                System.out.print(" ");   
            }
        } else {
            System.out.print("*");
        }
    }
    System.out.println();
}

最后将 5 改为 n:

int n = 10;
for (int i = 1; i <= n; i++) {
    for (int z = 1; z <= n - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        if (i != n) {
            if (j == 1 || j == 2 * i - 1) {
                System.out.print("*");   
            } else {
                System.out.print(" ");   
            }
        } else {
            System.out.print("*");
        }
    }
    System.out.println();
}

5.5 找出 3 位数的水仙花数,水仙花数是各位数的三次方之和等于此数,比如 153 = 13 + 53 + 33 = 153。

首先需要得到各位上的数:

设一个三位数的整数 i,把百位、十位、个位上的数得到
百位 = i / 100
十位 = i % 100 / 10
或
十位 = i / 10 % 10
个位 = i % 10

那么从 100 ~ 999 范围内查找,当满足水仙花就输出:

for (int i = 100; i < 1000; i++) {
    int h = i / 100;
    int t = i % 100 /10;
    int u = i % 10;
    // 可用 Math 的 pow 方法求幂
    if (i == h * h * h + t * t * t + u * u * u) {
        System.out.println(i);
    }
}

扩充内容:

得到四位数上的各位数,以 1234 为例

千 1234 / 1000    
百 1234 % 1000 / 100 或 1234 / 100 % 10
十 1234 % 100 / 10 或 1234 / 10 % 10
个 1234 % 10

5.6 计算 1 - 1/2 + 1/3 - 1/4 + … - 1/100。

观察规律:

分子都为 1,分母以 1 递增到 100;设为 i,当 i 为偶数时,符号为负。

double sum = 0;
for (int i = 1; i <= 100; i++) {
    if (i % 2 == 0) {
        sum += -1.0 / i;
    } else {
        sum += 1.0 / i;
    }
    /*
    double num = i % 2 == 0 ? -1.0 / i : 1.0 / i;
    sum += num;
    */
}
System.out.println(sum);// 0.688172179310195

分子的 1 必须写成小数,否则除了第一项其它式子的结果都为 0;sum 必须为 double 类型,如果为 int 类型,+= 会被强转为整数,恰巧结果小于 1,统统转成 0。


5.7 计算 1 + (1 + 2)+ (1 + 2 + 3)+ … + (1 + 2 + 3 + 4 + … + 100)。

方法 1:

一共有 100 个式子相加
第 1 个式子是 1
第 2 个式子是 1+2
第 3 个式子是 1+2+3

得出规律,当 i > 1 时
第 i 个式子是从 1 加到 i,想办法把 1 到 i 这几个数弄到手,累加

定义 i 控制式子的个数,从 1 到 100
定义 j 控制每个式子,从 1 加到 i
int sum = 0;
for (int i = 1; i <= 100; i++) {
    for (int j = 1; j <= i; j++) {
        sum += j;
    }
}
System.out.println(sum);// 171700

方法 2:

第 1 个式子是 1 = 1
第 2 个式子是 1+2 = 3
第 3 个式子是 1+2+3 = 6

得出规律,当 i > 1 时
第 i 个式子是第 i-1 个式子的结果 + i

i 从 1 到 100
考虑使用 formula 记录第 1 个式子的和,然后不停地累加 i。
第一次循环,formula = 1
第二次循环,formula + i = 1 + 2 = 3
第三次循环,formula + i = 3 + 3 = 6
...
每个式子的和得到了,再定义 sum 变量将这些式子的和累加,即 sum += formula
同时为了和谐,修正 formula = 0;第一次循环 formula + i = 0 + 1 = 1
int formula = 0;
int sum = 0;
for (int i = 1; i <= 100; i++) {
    formula += i;
    sum += formula;
}
System.out.println(sum);

方法 3:

观察式子
发现 1 出现了 100 次,2 出现了 98 次...100 出现了 1 次
所以总和为 1 * 100 + 2 * 99 + ... + 100 * 1
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i * (101 - i);
}
System.out.println(sum);

扩展为一般情况:

int n = 100;
int sum = 0;
for (int i = 1; i <= n; i++) {
    sum += i * (n + 1 - i);
}
System.out.println(sum);

第六到十章

第六章答案

6.1 编写方法用于拷贝数组。

思路:创建一个新的数组实例,长度为源数组的长度,然后遍历得到源数组的每个元素,同时将值拷贝到新的数组。

public static int[] copy(int[] arr1) {
    int[] arr2 = new int[arr1.length];

    for (int i = 0; i < arr1.length; i++) {
        arr2[i] = arr1[i];
    }
    return arr2;
}

注意我们并不是拷贝地址,如 int[] arr2 = arr1,而是重新创建新的实例,如现在调用此方法传入的数组为 {1,2,6}:

JavaSE IDEA 使用-面向对象_第37张图片

JDK 已提供现成的方法供我们调用:

/*
    将 arr1 数组的元素拷贝到 arr2 中;从下标 0 开始拷贝,从 arr2 下标 0 开始放;
    一共拷贝 arr1.length 个元素
*/
System.arraycopy(arr1, 0, arr2, 0, arr1.length);

/*
    创建新的长度为 arr1.length 的数组,同时将 arr1 数组中 arr1.length 
    个元素拷贝到新的数组中,并返回此数组。
*/    
int[] arr3 = Arrays.copyOf(arr1, arr1.length);

6.2 编写方法用于反转数组,例:{12,25,67,2} -----> {2,67,25,12}。

方法 1:创建新的数组接收值。

arr2[length - 1] 是 arr1[0]

arr2[length - 2] 是 arr1[1]

可以发现和为 length - 1,所以得到 arr2[i] 对应 arr1[length - i - 1]。

public static int[] reverse(int[] arr1) {
    int n = arr1.length;
    int[] arr2 = new int[n];

    for (int i = 0; i < n; i++) {
        arr2[i] = arr1[n - i - 1];
    }
    return arr2;
}

方法 2:自身的元素交换位置。

以 {1,2,3,4,5,6,7,8,9,10} 为例:1、10 交换,2、9 交换,一直到 arr[length / 2 - 1] 与 arr[length / 2] 交换,即 5、6 交换;一共 length / 2 次交换。

public static void reverse(int[] arr) {
    int n = arr.length;
    int temp;
    for (int i = 0; i < n / 2; i++) {
        temp = arr[i];
        arr[i] = arr[n - i - 1];
        arr[n - i - 1] = temp;
    }
}

6.3 编写一个类,有成员变量 int size、int[] arr;

  • 编写方法使用 arr 添加元素,要求:能够自动扩容,而不会越界。
  • 可以通过 size 获取已添加元素的个数。
  • 编写方法删除元素,要求:数组长度同时也跟着缩减。示例:{42, 26, 6, 4, 9, 97} 删除 6 后,得到 {42, 26, 4, 9, 97}。

1)add 方法添加元素

数组初始容量设为 10
每次添加元素之前判断 size + 1 是否大于数组容量
若大于数组容量则扩容为原来的 1.5 倍
class IntList {
    private int size;
    private int[] arr;
    private static final int INIT_CAPACITY = 10;

    public IntList() {
        arr = new int[INIT_CAPACITY];
    }

    public boolean add(int element) {
        ensureCapacityInternal(size + 1);
        arr[size++] = element;
        return true;
    }

    public void ensureCapacityInternal(int minCapacity) {
        if (minCapacity > arr.length) {
            int oldCapacity = arr.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            arr = Arrays.copyOf(arr, newCapacity);
        }
    }

    public int size() {
        return size;
    }
}

2)编写 remove 方法删除元素

顺序查找元素的下标
如果存在,则让此元素的后面所有元素前移一位,size--
    使用 JDK 自带的 arraycopy 方法,让下标 index + 1 及之后的元素从下标 index 开始放置,
    这样就覆盖了原来的下标为 index 的元素
不存在返回 false
public boolean remove(int element) {
    int index = -1;
    for (int i = 0; i < size; i++) {
        if (arr[i] == element) {
            index = i;
            break;
        }
    }

    if (index != -1) {
        System.arraycopy(arr, index + 1, arr, index, size - (index + 1));
        // 将最后一个元素归 0,因为上一步中已被前移一位
        arr[size - 1] = 0;
        size--;
        return true;
    } else {
        return false;
    }
}

3) 遍历

public void foreach() {
    System.out.print("[");
    for (int i = 0; i < size - 1; i++) {
        System.out.print(arr[i] + ", ");
    }
    // 为了去掉逗号但不在循环中每次都判断是不是最后一个元素的做法
    if (size - 1 >= 0) {
        System.out.print(arr[size - 1]);
    }
    System.out.println("]");
}

6.4 创建一个任意类型的一维数组,不手动赋值,元素的默认值为?

数组动态初始化后,如果没有赋值,不同类型的数组中的元素有默认值,如下:

short byte int long 类型的数组默认值是 0
float double 是0.0
char 是空 ,对应 16 进制是 0x0000;即 char c = '\u0000' 或 char c = '\0';
boolean 是 false
String 和其它引用类型是 null

我尝试复制那个符号,却发现就是空,通过混合运算自动升级成 int 类型的特性,才知道它在字库表中的序号是 0,而不是空格 32:

JavaSE IDEA 使用-面向对象_第38张图片


6.5 输出如下图形:

     1
    1 1
   1 2 1
  1 3 3 1
 1 4 6 4 1

先考虑打印如下图形:

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

观察规律:

1. 开头和结尾都是 1
2. 第 i 行有 i 个数
3. 从第 3 行开始,中间的数 = 上一行同列的数 + 上一行列数减一的数
将其看做二维数组,以第 4 行为例,arr[3][1] = arr[2][1] + arr[2][0]

考虑:

(1)定义长度为 5 的二维数组 arr 保存这些值
(2)由于一维数组长度在变,使用动态初始化
(3)遍历二维数组,i 从 0 开始,则 arr[i].length 为 i + 1
(4)遍历一维数组,开头与结尾都赋值 1,中间的元素为
 arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1]
int[][] arr = new int[5][];
for (int i = 0; i < arr.length; i++) {
    // 一维数组的长度为 i + 1
    arr[i] = new int[i + 1];
    
    // 开头与结尾都为 1
    arr[i][0] = 1;
    arr[i][i] = 1;
    
    // 中间的元素
    for (int j = 1; j < i; j++) {
		arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
    }
}

假设 arr.length = 5;

    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1

第 1 行前面有 4 个空格,输出 arr[0] 前先输出 arr.length - 1 个空格;

第 2 行前面有 3 个空格,输出 arr[1] 前先输出 arr.length - 2 个空格;

第 i + 1 行前面有 arr.length -(i + 1)个空格,输出 arr[i] 前先输出 arr.length - i - 1 个空格。

for (int i = 0; i < arr.length; i++) {
    for (int m = 0; m < arr.length - i - 1; m++) {
        System.out.print(" ");
    }
    for (int j = 0; j < arr[i].length; j++) {
        System.out.print(arr[i][j] + " ");
    }
    System.out.println();
}

6.6 x 是二维数组,y 是一维数组。以下语句能够通过编译的有:

a) x[0] = y;
b) x[0][0] = y[0];
c) x = y[0];
d) x[0][0] = y;
e) x = y;

能通过编译的有:a、b

c 报错误: 不兼容的类型: int 无法转换为 int[][]
d 报错误: 不兼容的类型: int[] 无法转换为 int
e 报错误: 不兼容的类型: int[] 无法转换为 int[][]

第七章答案

7.1 bn = 1 + 1 2 \frac{1}{2} 21 + 1 3 \frac{1}{3} 31 + … + 1 n \frac{1}{n} n1 - ln ⁡ n \ln n lnn,n 为正整数,证明 {bn} 收敛。

证:bn - bn+1 = − 1 n + 1 + ln ⁡ ( n + 1 ) − ln ⁡ n = − 1 n + 1 − ln ⁡ n n + 1 = − 1 n + 1 − ln ⁡ ( 1 − 1 n + 1 ) -\frac{1}{n+1}+\ln(n+1)-\ln n=-\frac{1}{n+1}-\ln\frac{n}{n+1}=-\frac{1}{n+1}-\ln(1-\frac{1}{n+1}) n+11+ln(n+1)lnn=n+11lnn+1n=n+11ln(1n+11)

g ( x ) = x − ln ⁡ ( 1 + x ) , g ′ ( x ) = 1 − 1 1 + x g(x)=x-\ln(1+x),g\prime(x)=1-\frac{1}{1+x} g(x)=xln(1+x)g(x)=11+x1,令 g ′ ( x ) = 0 g\prime(x)=0 g(x)=0,求得 x = 0;当 x > 0 时, g ′ ( x ) > 0 g\prime(x)>0 g(x)>0,-1 < x < 0 时, g ′ ( x ) < 0 g\prime(x)<0 g(x)<0,所以 g ( 0 ) g(0) g(0) 是极小值点;在定义域内(x = 0 除外),有 g ( x ) > g ( 0 ) = 0 g(x)>g(0)=0 g(x)>g(0)=0,即 x > ln ⁡ ( 1 + x ) x>\ln(1+x) x>ln(1+x)

令 x = − 1 n + 1 -\frac{1}{n+1} n+11,有 − 1 n + 1 > ln ⁡ ( 1 − 1 n + 1 ) -\frac{1}{n+1}>\ln(1-\frac{1}{n+1}) n+11>ln(1n+11),所以 bn - bn+1 > 0,bn 单调递减;

令 x = 1 n \frac{1}{n} n1,有 1 n > ln ⁡ ( 1 + 1 n ) = ln ⁡ n + 1 n \frac{1}{n}>\ln(1+\frac{1}{n})=\ln\frac{n+1}{n} n1>ln(1+n1)=lnnn+1,例 1 2 \frac{1}{2} 21 > ln ⁡ 3 2 \ln\frac{3}{2} ln23

bn = 1 + 1 2 \frac{1}{2} 21 + 1 3 \frac{1}{3} 31 + … + 1 n \frac{1}{n} n1 - ln ⁡ n \ln n lnn > ln ⁡ 2 1 + ln ⁡ 3 2 + ln ⁡ 4 3 + . . . + ln ⁡ n + 1 n − ln ⁡ n \ln\frac{2}{1}+\ln\frac{3}{2}+\ln\frac{4}{3}+...+\ln\frac{n+1}{n}-\ln n ln12+ln23+ln34+...+lnnn+1lnn

= ln ⁡ 2 − ln ⁡ 1 + ln ⁡ 3 − ln ⁡ 2 + ln ⁡ 4 − ln ⁡ 3 + . . . + ln ⁡ ( n + 1 ) − ln ⁡ n − ln ⁡ n \ln2-\ln1+\ln3-\ln2+\ln4-\ln3+...+\ln(n+1)-\ln n-\ln n ln2ln1+ln3ln2+ln4ln3+...+ln(n+1)lnnlnn

= ln ⁡ ( n + 1 ) − ln ⁡ n \ln(n+1)-\ln n ln(n+1)lnn > 0,bn 有下界;

根据单调有界数列收敛定理,记 lim ⁡ x → ∞ ( 1 + 1 2 + 1 3 + . . . + 1 n − ln ⁡ n ) \lim\limits_{x\to\infty}(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n}-\ln n) xlim(1+21+31+...+n1lnn) = γ \gamma γ

第八章答案

8.1 编写方法返回长度为 n 的斐波那契数组。(包括 0)

/**
 * 创建长度为 n 的斐波那契数组
 */
public static int[] fibonacciArr(int n) {
    
    if (n < 2) {
        return new int[]{0};
    } else if (n == 2) {
        return new int[]{0, 1};
    }
    
    int[] f = new int[n];
    f[0] = 0;
    f[1] = 1;
    for (int i = 2; i < n; i++) {
        f[i] = f[i - 1] + f[i - 2];
    }
    return f;
}

第九章答案

9.1 使用 debug 测试创建对象时的代码执行顺序。

创建子类对象时,会先显示初始化父类的实例变量,再执行父类的构造方法,接着显示初始化子类的实例变量,执行子类的构造方法。

// 父类
class A {
    int age = 22;
    String name;
    String flag;

    public A() {
        age = 33;
        name = "33";
    }
}
// 子类
class B extends A {
    {
    	tag = "无聊";
    }
    String tag;

    public B() {
        System.out.println(tag);
    }
}
class test {
    public static void main(String[] args) {
        // new 对象
        new B();
    }
}

在 new 对象的地方打个断点,使用 debug 得知:

new 先创建了 B 类的对象,age、name、flag、tag 等实例变量附上默认值 0 或 null。随之调用 B 类的无参构造器,构造器省略了两句话 :

  1. 调用父类的无参构造器
  2. 显示初始化本类的实例变量和执行实例代码块(自上而下顺序执行)

JavaSE IDEA 使用-面向对象_第39张图片

忽略 Object 类的存在,最开始显示初始化的是 A 类的实例变量,接着执行可见部分的 A 类无参构造器给实例变量赋值。返回到 B 类的无参构造器,执行实例语句块给 tag 赋值,执行可见部分的 B 类的构造器输出 tag 的值。

符合看到的现象(先显示初始化父类实例变量,执行父类的构造方法;接着显示初始化子类的实例变量,执行子类的构造方法)。

第十章答案

10.1 在 AA 类编写一个静态方法,判断一个整数是奇数还是偶数,奇数返回 false,偶数返回 true。

考虑返回一个 boolean 类型的值,判断一个整数是否是偶数,那么需要一个 int 类型的参数。

class AA {
    public static boolean isEvenNumber(int num) {
        if (num % 2 == 0) {
            return true;
        }
        return false;
    }
}

也可以直接返回 return num % 2 == 0;


10.2 分析如下代码,控制台上会输出什么?

1)在类 A 中:

public void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    System.out.println("swap 中 a:" + a);
    System.out.println("swap 中 b:" + b);
}

public static void main(String[] args) {
    int a = 5;
    int b = 1;
    new A().swap(a, b);
    
    System.out.println("main 中 a:" + a);
	System.out.println("main 中 b:" + b);
}

main

当代码执行到 swap(a,b)这行时,会开启一个新栈,分配此方法运行所需要的内存空间,同时将实参赋给形参。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-89l9f2hc-1652792332811)(https://s2.loli.net/2022/05/16/KIOl51WCXxpjJUS.png)]

只有栈顶部的元素才有活跃权,调用者 main 陷入等待,直到 swap 方法执行完毕后才能执行接下的代码。

执行 swap 中的代码,int temp = a = 5; a = b = 1; b = temp = 5;

JavaSE IDEA 使用-面向对象_第40张图片

接着输出 swap 中 a:1swap 中 b:5

swap 方法执行完毕,释放空间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijRd1fPk-1652792332811)(https://s2.loli.net/2022/05/16/CQIoKl7H2O46BWf.png)]

回到 main 方法,执行剩下的代码,输出 main 中 a:5main 中 b:1,最后 main 方法执行结束,释放了空间,程序结束。

可以看到栈中的局部变量,保存的值是独立的,互不干扰,这两个栈的空间是独立的数据空间。

swap 方法声明的 a 变量与 main 方法声明的 a 变量存储的值互不影响,同理 b 变量也是如此,不要以为 main 方法中的 a 与 b 的值也互换了。


2)在类 B 中:

public void some(int[] arr) {
    arr[0] = 1234;
}
public static void main(String[] args) {
    int[] arr = new int[3];
    new B().some(arr);
    System.out.println(arr[0]);
}

int[] arr = new int[3],在堆中创建了一个 int 类型的一维数组。(我说一下啊,0x??? 是内存地址转化得来的十六进制整数,是实例的唯一标识,每 new 一个实例,就会分配新的空间)

JavaSE IDEA 使用-面向对象_第41张图片

随后 arr 作为实参传入并调用 some 方法,开启了新栈。将 main 方法中的 arr 变量保存的值赋给了 some 方法中的 arr 变量,这样有两个引用指向数组实例了。

JavaSE IDEA 使用-面向对象_第42张图片

arr[0] = 1234; 将 arr 指向的数组实例的第一个元素保存的值修改为 1234;随后 some 方法栈空间释放。

JavaSE IDEA 使用-面向对象_第43张图片

回到 main 方法,输出 arr[0],即 1234。


10.3 类 Person 中,分析输出什么?

1)

int age;
public void some(Person p){
    p = null;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    p.some(p);
    System.out.println(p.age);
}

这里就不画内存图了

main 方法,0x677327b6 {age -> 32},p -> 0x677327b6

调用 some 方法,p -> 0x677327b6,随后 p = null,p -> null。some 方法执行结束,释放空间,回到 main 方法。

输出 p.age,即 32。

别将两个方法中的 p 变量混为一谈,some 中的 p = null,与 main 方法中的 p 互不影响。


2)

int age;

public Person some(Person p) {
    return p;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    Person p1 = p.some(p);
    System.out.println(p == p1);
    System.out.println(p.age == p1.age);
}

main 方法,0x677327b6 {age -> 32},p -> 0x677327b6

some 方法,返回了 p -> 0x677327b6

回到 main 方法,将返回值赋给 p1,p1 -> 0x677327b6

双等号比较的是变量保存的值,这里 p、p1 保存的内存地址相同,都指向 0x677327b6 实例,所以为 true。那么两个引用访问同一个实例变量 age 进行比较,自然也为 true。


3)

int age;

public Person some(Person p) {
    Person p1 = new Person();
    p1.age = p.age;
    return p1;
}

public static void main(String[] args) {
    Person p = new Person();
    p.age = 32;

    Person p1 = p.some(p);
    System.out.println(p == p1);
    System.out.println(p.age == p1.age);
}

main 方法,0x677327b6 {age -> 32},p -> 0x677327b6

some 方法,p -> 0x677327b6,0x14ae5a5 {age -> 32},p1 -> 0x14ae5a5,返回 p1

回到 main 方法,将 0x14ae5a5 赋给 p1,p1 -> 0x14ae5a5,所以 p == p1 为 false,它们指向的不是同一个实例,但两个实例的 age 都是 32,为 true。


10.4 一共有 ?个桃子。每天猴子吃其中的一半加 1 个桃子,当第 10 天时,准备吃,一看,只剩 1 个桃子了,请问 ?的值为?

设第 i 天有 n 个桃子,吃了 n/2 + 1 个桃子,还剩 n - n/2 - 1 个桃子,则第 i+1 天有 n - n/2 - 1 个桃子。

记 n - n/2 - 1 = x,解得 n =(x+1)* 2;

转述为第 i 天有(x+1)* 2 个桃子,第 i+1 天有 x 个桃子。

所以第 i 天的桃子的个数 = (第 i+1 天的桃子的个数+1)* 2。

设计方法求第 i 天的桃子的个数 peach(i),则第 i+1 天的桃子的个数 peach(i+1);

有 peach(i)=(peach(i+1)+ 1) * 2;

当 i = 10 时,桃子个数为 1,peach(10)= 1。

private static int peach(int i) {  
    if (i >= 10) {
        return 1;
    }
    int count = (peach(i + 1) + 1) * 2;
    return count;
}

我们求的 ?是第 1 天的桃子的个数:

public static void main(String[] args) {
    int n = peach(1);
    System.out.println(n);// 1534
}

10.5 有 1 个迷宫由二维数组组成。1 代表墙,0 代表可通行。现有一球在左上角(1,1)处,要求到右下角(7,7),记录小球走过的路径。(注意上下移动的是 x,左右移动的是 y,与坐标系相反)

1 1 1 1 1 1 1 1 1
1 q 0 0 0 0 0 0 1
1 0 1 0 0 0 0 0 1
1 0 1 0 0 0 0 0 1
1 1 1 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1

在 Maze 类中,首先先有一个二维数组作为全局变量;

创建 step 方法记录小球走过的路径,自定义寻路规则:

  • 已经走过的路:死路记为 3,通路记为 2
  • 假设当前坐标为通路记为 2
  • 每一步都先尝试向下走,尝试成功返回 true,否则再尝试右、上,左
int[][] arr;
private boolean step(int x, int y) {
    // 假设当前为通路
    arr[x][y] = 2;
    // 尝试向下、右、上、左,成功返回 true
    if (step(x + 1, y)) {
    	return true;
    } else if (step(x, y + 1)) {
        return true;
    } else if (step(x - 1, y)) {
        return true;
    } else if (step(x, y - 1)) {
        return true;
    }
}
  • 经过以上分支尝试都失败,则返回 false;说明假设错误,不是通路,同时将当前坐标记为 3,代表死路
int[][] arr;
private boolean step(int x, int y) {
    arr[x][y] = 2;
    if (step(x + 1, y)) {
    	return true;
    } else if (step(x, y + 1)) {
        return true;
    } else if (step(x - 1, y)) {
        return true;
    } else if (step(x, y - 1)) {
        return true;
    } else {
        // 尝试失败,标记为死路
        arr[x][y] = 3;
        return false;
    }
}
  • 尝试失败条件之一:遇墙 arr[x][y] = 1,之二:已经走过的路不走,arr[x][y] == 2 或 3

    将失败条件结合,只有当 arr[x][y] = 0 时才能走,否则返回 false

    成功条件,小球走到了终点,即 arr[7][7] = 2

int[][] arr;
private boolean step(int x, int y) {
    if (arr[7][7] == 2) {
        return true;
    }
    if (arr[x][y] != 0) {
        return false;
    }
    arr[x][y] = 2;
    if (step(x + 1, y)) {
    	return true;
    } else if (step(x, y + 1)) {
        return true;
    } else if (step(x - 1, y)) {
        return true;
    } else if (step(x, y - 1)) {
        return true;
    } else {
        arr[x][y] = 3;
        return false;
    }
}
// 构造器初始化二维数组,化为迷宫
public Maze() {
    arr = new int[9][9];
    // 将四周都标记为墙
    for (int i = 0; i < arr.length; i++) {
        // 第一列、最后一列标记为墙
        arr[i][0] = 1;
        arr[i][8] = 1;

        // 第一行、最后一行标记为墙
        arr[0][i] = 1;
        arr[8][i] = 1;
    }

    // 按题目设置墙
    arr[4][0] = 1;
    arr[4][1] = 1;
    arr[4][2] = 1;
    arr[2][2] = 1;
    arr[3][2] = 1;
}
public static void main(String[] args) {
    Maze m = new Maze();
    // 小球的初始坐标
    boolean b = m.step(1, 1);
    System.out.println(b ? "小球找到了路,标记为 2" : "小球迷失了,标记为 3");
    toString(m.arr);
}
public static void toString(int[][] arr) {
    for(int i = 0; i < arr.length; i++) {
        for(int j = 0; j < arr[i].length; j++) {
            System.out.print(arr[i][j] + " ");
        }
        System.out.println();
    }
}

10.6 如图,把 A 中的 n 个圆盘全部移到 C 中。要求:大圆盘不能放在小圆盘上面,每次只能移动一个圆盘,如何移动。

JavaSE IDEA 使用-面向对象_第44张图片

先将 n - 1 个小盘从 a 移到 b 处,再将 1 个大盘从 a 移到 c 处,最后将 b 上的 n - 1 个盘移到 c 处。

public static void move(int n, String a, String b, String c) {
    move(n - 1, a, c, b);
    move(1, a, b, c);
    move(n - 1, b, a, c);
}

当只有一个盘时,直接从 a 移到 c。

public static void move(int n, String a, String b, String c) {
    if (n <= 1) {
        System.out.println("将最上面的盘子从 " + a + " 移动到 " + c);
        return;
    }
    move(n - 1, a, c, b);
    move(1, a, b, c);
    move(n - 1, b, a, c);
}

测试一下,比如移动 2 个盘子,从 A 到 C

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ka5IXo9e-1652792332813)(https://s2.loli.net/2022/05/17/BIMhTrqWk1LnUZH.png)]

调用方法 move(2, "a", "b", "c") 结果如下:

将最上面的盘子从 a 移动到 b
将最上面的盘子从 a 移动到 c
将最上面的盘子从 b 移动到 c

从 a 移动到 b

从 a 移动到 c

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0fEi7Yr-1652792332814)(https://s2.loli.net/2022/05/17/zxChPt7MOjT1Yv8.png)]

从 b 移动到 c

JavaSE IDEA 使用-面向对象_第45张图片


10.7 在一个 8*8 格的棋盘摆放 8 个棋子,要求:任意两个棋子之间不能处于同一行、同一列、同一斜线。共有几种摆法?

使用穷举法,第 1 个棋子放在第 1 行的第 1 ~ 8 个,第 2 个棋子放在第 2 行的第 1 ~ 8 个…只不过在放置棋子后,判断它的下标是否与之前的棋子冲突,如果冲突,则将其移一位,然后继续判断…

那么只需要长度为 8 的一维数组就可以保存结果。如 arr[0] 代表第 1 个棋子在第 1 行的下标,arr[1] 代表第 2 个棋子在第 2 行的下标…将其作为成员变量。

判断是否冲突的方法

同一行:arr[i] = arr[j],处于同一斜线上即斜率为 ± \pm ± 1:j - i = ± \pm ±(arr[j] - arr[i]),这里使用 Math.abs 求绝对值省去判断正负的功夫

检查方法需要遍历得到之前的棋子的位置

// 判断第 n + 1 个棋子的位置是否与之前棋子冲突
public boolean isSuitable(int n) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == arr[n] || Math.abs(n - i)
            == Math.abs(arr[n] - arr[i])) {
            return false;
        }
    }
    return true;
}

放置棋子的方法

// n 从 0 开始,放置第 n + 1 个棋子
public void place(int n) {
    for (int i = 0; i < 8; i++) {
        arr[n] = i;
        // 检查第 n + 1 个棋子的位置是否与之前冲突
        if (isSuitable(n)) {
            // 如果没有冲突,则放置下一个棋子
            place(n + 1);
        }
    }
}

当 n = 8 时,说明正准备放置第 9 个棋子,那么前 8 个棋子已摆好,创建方法打印数组查看摆法,同时 count++。

int[] arr = new int[8];
int count = 0;

public void place(int n) {
    if (n >= arr.length) {
        // 摆法又多了一种
		count++;
        print();
        return;
    }
    for (int i = 0; i < arr.length; i++) {
        arr[n] = i;
        if (isSuitable(n)) {
            place(n + 1);
        }
    }
}

public void print() {
    System.out.println("第" + count + "种摆法如下:");
    for(int i = 0; i < arr.length; i++) {
        System.out.println("第" + (i + 1) + "个棋子放在第"
			+ (i + 1) + "行的第" + (arr[i] + 1) + "列");
    }
}

然后创建实例调用 place(0)方法后,访问实例的 count 得到 92,所以一共 92 种摆法。


10.8 设计一个类,完成与电脑的猜拳,电脑随机出石头、布、剪刀,要求显示输赢次数。

类名为 ManMachineFingerGuessingGame;我的想法是这样的,首先一局比赛需要两个参赛者(或人机),设他们的类型为 GuessingBoxer。

class ManMachineFingerGuessingGame {
    private GuessingBoxer b1;
    private GuessingBoxer b2;
}

需要记录他们的姓名、赢的次数、出的招式;

就可以编写一个 throwFinger 方法用于出招,通过 scanner 对象获取输入招式,因为输入字符串容易出错,所以用整数代表招式,0:石头,1:布,2:剪刀;出招后就调用 print 方法就将整数转为招式打印出来。

class GuessingBoxer {
    private String name;
    private int winCount;
    private int finger;
    private static Random random = new Random();

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

    public int getFinger() {
        return finger;
    }

    public String getName() {
        return name;
    }

    public int getWinCount() {
        return winCount;
    }

    public void addWinCount() {
        winCount++;
    }

    // 出招
    public void throwFinger() {
        Scanner scanner = new Scanner(System.in);
        System.out.print(this.name + "请出招:");

        if (scanner.hasNextInt()) {
            finger = scanner.nextInt();
        } else {
            System.out.print("你不会猜拳,扑该了,我帮你出; ");
            finger = random.nextInt(3);
        }

        if (finger < 0 || finger > 2) {
            System.out.print("你不会猜拳,扑该了,我帮你出; ");
            finger = random.nextInt(3);
        }
        print();
    }

    public void throwFinger(boolean isAuto) {
        if (!isAuto) {
            throwFinger();
            return;
        }
        finger = random.nextInt(3);
        print();
    }

    // 根据整数打印招式
    public void print() {
        String move;
        switch (finger) {
            case 0:
                move = "石头";
                break;
            case 1:
                move = "布";
                break;
            case 2:
                move = "剪刀";
                break;
            default:
                System.out.print(this.name + "竖起了中指!");
                return;
        }
        System.out.print(this.name + "出" + move + "; ");
    }
}

好,回到 ManMachineFingerGuessingGame 类,让两个参赛者出招后 vs,谁赢谁的 winCount 就++,记录他的赢的次数;当比赛结束后,调用 statistics 方法打印他们赢的次数,并宣布胜利者。

class ManMachineFingerGuessingGame {
    private GuessingBoxer b1;
    private GuessingBoxer b2;

    public ManMachineFingerGuessingGame(GuessingBoxer b1, GuessingBoxer b2) {
        this.b1 = b1;
        this.b2 = b2;
    }

    public void throwFinger() {
        b1.throwFinger();
        b2.throwFinger(true);

        vs(b1, b2);
    }

    public void vs(GuessingBoxer b1, GuessingBoxer b2) {
        int b1Finger = b1.getFinger();
        int b2Finger = b2.getFinger();

        String winName = b1.getName();
        if (b1Finger == 0 && b2Finger == 2) {
            b1.addWinCount();
        } else if (b1Finger == 1 && b2Finger == 0) {
            b1.addWinCount();
        } else if (b1Finger == 2 && b2Finger == 1) {
            b1.addWinCount();
        } else if (b1Finger == b2Finger) {
            System.out.println("两人平局!");
            return;
        } else {
            b2.addWinCount();
            winName = b2.getName();
        }
        System.out.println(winName + "赢!");
    }

    public void statistics() {
        System.out.print("比赛结束,");
        int c1 = b1.getWinCount();
        int c2 = b2.getWinCount();
        System.out.print(b1.getName() + "赢了 " + c1 +" 场, ");
        System.out.print(b2.getName() + "赢了 " + c2 +" 场, ");
        if (c1 == c2) {
            System.out.println("两人打平。");
        } else if (c1 < c2) {
            System.out.println(b2.getName() + "赢了!!!");
        } else {
            System.out.println(b1.getName() + "赢了!!!");
        }
    }
}

那么入口方法,就需要创建一个比赛场地实例、两个参赛者实例,并设置比赛回合,每次回合调用 throwFinger 方法让参赛者出招后 vs;当所有回合结束,调用 statistics 统计。

class GamePlay {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("请设置你的名字:");
        String b1Name = scanner.next();

        GuessingBoxer b1 = new GuessingBoxer(b1Name);
        GuessingBoxer b2 = new GuessingBoxer("电脑");
        ManMachineFingerGuessingGame game = new ManMachineFingerGuessingGame(b1, b2);

        System.out.print("设置比赛回合:");
        int total = 0;
        if (scanner.hasNextInt()) {
            total = scanner.nextInt();
        } else {
            total = 10;
        }
        System.out.println("比赛一共 " + total + " 回合,招式如下:");
        System.out.println("0:石头,1:布,2:剪刀");
        for (int i = 0; i < total; i++) {
            System.out.println("第 " + (i + 1) + " 回合开始");
            game.throwFinger();
            System.out.println("======================");
        }
        game.statistics();
    }
}

资源地址

下面资源全部收集整理于网络并无偿提供,仅可用于个人学习交流;请勿转载、售卖或商用。侵权删!

文章中已经出现的网址可能不再出现,望谅解!

网盘链接

百度网盘太慢了,一百兆的文件隔了一天才下好,所以就弃用了。

JDK 下载

JDK8

阿里云盘链接:https://www.aliyundrive.com/s/xu2ZbDSbf61

天翼云盘链接:(访问码:8qwi)https://cloud.189.cn/web/share?code=JR7rEbvI32mm

奶牛快传传输链接:打开【奶牛快传】cowtransfer.com 使用传输口令:a7khbp 提取;或 传输链接:https://cowtransfer.com/s/4370c88f111d4e

JDK11

阿里云盘链接:https://www.aliyundrive.com/s/XwaEENBMMs2

天翼云盘链接:(访问码:uw75)https://cloud.189.cn/web/share?code=YZJBRf77ZBzu

JDK17

阿里云盘链接:https://www.aliyundrive.com/s/uoYfGWEAknU

天翼云盘链接:(访问码:tcu5)https://cloud.189.cn/web/share?code=UzuuYbeEjUry

奶牛快传传输链接: 打开【奶牛快传】cowtransfer.com 使用传输口令:zn46qi 提取;或 传输链接:https://cowtransfer.com/s/ad936bbebca445

IDE 工具

IDEA 下载

阿里云盘链接:https://www.aliyundrive.com/s/TM9rvAjEeJu

天翼云盘链接:(访问码:4gn2)https://cloud.189.cn/web/share?code=VNFvqyE3YvMj

奶牛快传传输链接:打开【奶牛快传】cowtransfer.com 使用传输口令:e63ydj 提取; 或 传输链接:https://cowtransfer.com/s/6737a08627ee45

Eclipse 下载

天翼云盘链接:(访问码:upy6)https://cloud.189.cn/web/share?code=eIfAzqvYZrim

奶牛快传传输链接: 打开【奶牛快传】cowtransfer.com 使用传输口令:xywy0y 提取;或 传输链接:https://cowtransfer.com/s/9f126bbf83d242

自己写的小玩意

合并多个 md 文件为一个文件

天翼云盘链接:(访问码:qg9y)https://cloud.189.cn/web/share?code=Un2iuamInI7z

奶牛快传传输链接: 打开【奶牛快传】cowtransfer.com 使用传输口令:omy5y8 提取;或 传输链接:https://cowtransfer.com/s/b995725decea4c

工具网址

书中源码地址:https://gitee.com/ccqqhh/JavaSE-grammar

可能会使用到的在线工具网址

  • 查看 IP 地址:http://ip111.cn
  • ioDraw 思维导图:https://www.iodraw.com/template
  • Process On 思维导图:https://www.processon.com/diagrams/new#template
  • JDK 8 API 文档:https://docs.oracle.com/javase/8/docs/api/index.html
  • JDK 8 中文文档:https://www.matools.com/api/java8
  • 进制转换:https://tool.lu/hexconvert/
  • 汉字编码查询:https://www.qqxiuzi.cn/bianma/zifuji.php
  • 编程书籍:https://www.bookstack.cn/
  • 集合符号:http://www.52unicode.com/not-a-subset-of-unicode
  • 集合符号:http://www.fhdq.net/sx/95.html
  • Unicode 字符集:https://www.qqxiuzi.cn/zh/unicode-zifu.php
  • 谷歌插件市场:https://zhuanlan.zhihu.com/p/76634823
  • 生成 ico 图标:https://www.ico51.cn/
  • 自动采集文章并发布:https://www.lmcjl.com/
  • 自动构建文档:https://readthedocs.org/
  • 一文多发:https://openwrite.cn/
  • PDF 转成 MD:https://pdf2md.morethan.io/

可能会使用到的工具下载链接

  • 有道词典:https://dict.youdao.com/
  • 搜狗五笔输入法:https://wubi.sogou.com/
  • Sublime Text:https://www.sublimetext.com/
  • 谷歌浏览器:https://www.google.cn/intl/zh-CN/chrome/
  • Win RAR 解压缩:https://www.win-rar.com/download.html?&L=0
  • Win RAR 中文版:https://www.winrar.com.cn/
  • 比邻云盘:https://www.bilnn.com/
  • 比邻云盘升级版:https://link.bilnn.com/

参考文献

版权声明:本文版权著作权归以下链接的作者共有,遵循 CC 4.0 BY-SA 版权协议。商业转载请联系原作者获得授权,非商业转载请附上原文出处链接,未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

参考视频

参考视频链接

  • 作者:遇见狂神说,内容:JavaSE 基础,https://www.bilibili.com/video/BV12J41137hu

引用视频观点

  • 作者:SchelleyYuki,内容:前后端是做什么的,https://www.bilibili.com/video/BV1DV411B7v5

  • 作者:韩顺平,内容:JavaSE 基础,https://www.bilibili.com/video/BV1fh411y7R8

  • 作者:动力节点,内容:JavaSE 基础,https://www.bilibili.com/video/BV1Rx411876f

  • 作者:尚硅谷,内容:JavaSE 基础,https://www.bilibili.com/video/BV1Kb411W75N

  • 作者:尚硅谷,内容:IDEA教程,https://www.bilibili.com/video/BV1PW411X75p

参考书籍

参考书籍观点

  • 书名:《Think in Java》《Java编程思想》,作者:【美】Bruce Eckel,译者:陈昊鹏、绕若楠,出版社:机械工业出版社,时间:2003
  • 书名:《啊哈!算法》,作者:啊哈磊,出版社:人民邮电出版社,时间:2014.5

引用书籍原句

  • 书名:《大话数据结构》,作者:程杰,出版社:清华大学出版社,时间:2011.6

  • 书名:《阿里巴巴Java开发手册》,发布者:gujin520,https://github.com/alibaba/p3c

  • 书名:《Effective Java 第三版》,作者:【美】Joshua Bloch(约书亚 · 布洛克),译者:俞黎敏,出版社:机械工业出版社,时间:2018

参考文章

参考文章链接

  • 作者:喵酱向前冲,内容:mathjax 语法渲染错误,https://blog.csdn.net/weixin_45073562/article/details/120289648

  • 作者:Serena_tz,内容:用 gitee 搭建博客,https://blog.csdn.net/serena_tz/article/details/115482336

  • 作者:乔小乔jojo,内容:hexo d ERROR Deployer not found: git,https://blog.csdn.net/weixin_36401046/article/details/52940313

  • 提问:如何搭建个人网站,有关网站:

    https://www.zhihu.com/question/22197688

    https://hexo.io/zh-cn/docs/configuration

    https://github.com/blinkfox/hexo-theme-matery/blob/develop/README_CN.md

  • 作者:闪烁之狐,内容:Hexo 博客主题之 hexo-theme-matery 的介绍,https://blinkfox.github.io/2018/09/28/qian-duan/hexo-bo-ke-zhu-ti-zhi-hexo-theme-matery-de-jie-shao/

  • 作者:MorKANA,内容:时间复杂度,https://blog.csdn.net/qq_41297896/article/details/104223612

  • 作者:看见代码就想敲,内容:shell 脚本语法,https://blog.csdn.net/weixin_43288201/article/details/105643692

  • 作者:我真的不知道的啦,内容:极限符号,https://jingyan.baidu.com/article/414eccf6be0a6d6b431f0ae0.html

  • 作者:二十三岁的有德,内容:本地自动发布文章到博客园,https://www.cnblogs.com/nickchen121/p/11132957.html

  • 作者:二十三岁的有德,内容:Python 从入门到放弃,https://www.cnblogs.com/nickchen121/p/10718112.html

  • 作者:lightzhan,内容:Joplin 网页剪辑,https://lightzhan.xyz/index.php/2020/03/18/joplin-web-clipper-tutorial/

  • 来源:互联网,内容:查看博客园的 MetaWebLog API,https://www.icode9.com/content-4-664692.html

  • 作者:蓝蓝223,内容:双击可以执行 jar 包,https://blog.csdn.net/qq_21808961/article/details/78442858

  • 作者:故里江添_,内容:使用 exe4j 将 jar 包打包成 exe 命令,https://blog.csdn.net/weixin_44678104/article/details/101015065

  • 作者:知乎用户,内容:GB2312、GBK、GB18030 这几种字符集的主要区别是什么,https://www.zhihu.com/question/19677619

  • 作者:张大昭,内容:为什么计算机能读懂 1 和 0,https://www.zhihu.com/question/20112194

  • 作者:热心网友,内容:ASCII 码是几位二进制码,https://wenwen.sogou.com/z/q657498179.htm

  • 作者:malecrab,内容:ANSI 是什么编码,https://www.cnblogs.com/malecrab/p/5300486.html

  • 转载:imxiangzi,内容:ANSI 是什么编码,https://blog.csdn.net/imxiangzi/article/details/77370160

  • 作者:黑泽君,内容:如何查看 Windows 操作系统的默认编码,https://cloud.tencent.com/developer/article/1353937

  • 作者:沈万三gz,内容:什么是 JIT,https://blog.csdn.net/shenwansangz/article/details/95601232

  • 作者:猪_队友,内容:什么是多态,https://www.jianshu.com/p/68ddb5484ca2

  • 作者:Duktig丶,内容:方法的重载是多态性吗,https://blog.csdn.net/qq_42937522/article/details/106563188

  • 作者:springinwinter_4all,内容:Java8 Instant 时间戳,https://blog.csdn.net/chunzhilianxue/article/details/80974202

  • 作者:树上的疯子^,内容:ThreadLocalRandom,https://blog.csdn.net/xingxiupaioxue/article/details/104796276/

  • 作者:流浪的雨,内容:集合概述,https://www.cnblogs.com/xfeiyun/p/15837566.html

  • 作者:pNull,内容:IntelliJ IDEA 单元测试入门,https://blog.csdn.net/u011138533/article/details/52165577

  • 作者:Town125,内容:boolean 类型数据到底占有几个字节,https://www.cnblogs.com/tangshun100/p/13173006.html

  • 作者:微笑的小小刀,内容:一篇文章搞清楚 boolean 到底占几个字节,https://blog.csdn.net/weixiaodedao/article/details/109506667

  • 作者:公众号-老炮说Java,内容:Java 中 boolean 类型占多少字节,https://blog.csdn.net/qq_17231297/article/details/106621963

  • 作者:冬天里的懒喵,内容:在java中 boolean 类型占多少字节,https://www.jianshu.com/p/4d0ae2bac610

引用文章原句

  • 作者:zolalad,内容:时间复杂度与空间复杂度,https://blog.csdn.net/zolalad/article/details/11848739

  • 作者:夏2同学,内容:Typora 中使用图床,https://zhuanlan.zhihu.com/p/137310314

  • 作者:陌上花开luckly,内容:Java 用途,https://zhidao.baidu.com/question/138993898.html

  • 作者:百度百科,内容:eclipse,https://baike.baidu.com/item/eclipse/61703

  • 作者:廖雪峰,内容:Java 教程,https://www.liaoxuefeng.com/wiki/1252599548343744

  • 作者:Jackson蜜蜂,内容:什么是 Java Bean,https://blog.csdn.net/qq_42245219/article/details/82748460

  • 作者:公众号/头条号:技术很有趣,内容:数组下标为什么从 0 开始,https://blog.csdn.net/bengxu/article/details/83477690

  • 作者:渣一个,内容:数组下标索引为什么从 0 开始,https://blog.csdn.net/weichi7549/article/details/108064848

  • 作者:陆顺治,内容:数组下标为什么从 0 开始,https://blog.csdn.net/qq_40670946/article/details/83061993

  • 提问:JavaScript 中的 Date 对象取值 month 为什么是从 0 开始的,https://www.zhihu.com/question/263804983

  • 作者:卢钧轶,内容:什么是字符编码、字符集,http://cenalulu.github.io/linux/character-encoding/

  • 作者:Hern(宋兆恒),内容:Unicode 与 UTF-8 的区别,https://blog.csdn.net/qq_36761831/article/details/82291166

  • 作者:老马达,内容:含 BOM 的 UTF-8 与 不含的区别,https://blog.csdn.net/weixin_45025727/article/details/106799649

  • 作者:金麟十三少,内容:BOM 是什么意思,https://blog.csdn.net/u012373281/article/details/91410698

  • 作者:DreamTech1113,内容:ASCII 及其它编码,https://blog.csdn.net/lili13897741554/article/details/82053351

  • 作者: zwbg,内容:类的加载时机,https://www.cnblogs.com/zwbg/p/5903527.html

  • 作者:不断前行的菜鸟_,内容:字符串常量池深入解析,https://blog.csdn.net/weixin_40304387/article/details/81071816

  • 作者:你想要怎样的未来,内容:字符串常量池,https://www.jianshu.com/p/039d6df30fea

  • 作者: 小勇DW3,内容:字符串常量池,https://www.cnblogs.com/gxyandwmm/p/9495923.html

  • 来源:互联网,内容:String Pool 的实现,https://www.isolves.com/it/cxkf/yy/JAVA/2019-12-23/10492.html

  • 作者: cosmoswong,内容:字符串常量池和运行时常量池在哪,https://www.cnblogs.com/cosmos-wong/p/12925299.html

  • 作者:小奔的早晨,内容:深入浅出 Java 常量池,https://www.cnblogs.com/syp172654682/p/8082625.html

  • 作者:懒杰,内容:JDK 8 中字符串常量池在哪,https://blog.csdn.net/weixin_44765605/article/details/110737251

  • 作者: 人菜话多帅瓜皮,内容:字符串常量池处在 JVM 的堆中,那么是在堆的哪个部分呢,https://www.cnblogs.com/skyvalley/p/13818240.html

  • 作者:manDD_HH,内容:还搞不定方法区、常量池、字符串常量池吗,https://www.it610.com/article/1292596715873968128.htm

  • 作者:TomAndersen,内容:Java 字符串字面量是何时进入到字符串常量池中的,https://blog.csdn.net/TomAndersen/article/details/107147344

  • 作者: holos,内容:Java 中几种常量池的区分,https://www.cnblogs.com/holos/p/6603379.html

  • 作者: Aj小菜,内容:JVM 中的堆的新生代、老年代、永久代详解,https://www.cnblogs.com/byqin/p/12512528.html

  • 作者:剑客手中拿把刀,内容:类加载过程:三大阶段,https://zhuanlan.zhihu.com/p/346333194

  • 作者:跃小云,内容:41. JVM 方法区的内部结构(方法区中存储的是什么) ,https://www.cnblogs.com/yuexiaoyun/articles/14001254.html

  • 作者:笨比乔治,内容:对方法区和永久代的理解,https://www.jianshu.com/p/797ec081a4aa

  • 作者:不二尘,内容:JVM 类的加载机制,https://www.cnblogs.com/chenpt/p/9777367.html

  • 作者:不二尘,内容:JVM 运行时数据区,https://www.cnblogs.com/chenpt/p/8953435.html

  • 作者:vanlyy,内容:关于常量池,字符串常量池的整理,https://blog.csdn.net/weixin_38719347/article/details/80907944

  • 作者:sdky,内容:JavaSE 基础,https://sdky.gitee.io/

  • 作者:phial03,内容:Java 集合超详解,https://blog.csdn.net/feiyanaffection/article/details/81394745

  • 作者:ThinkWon,内容:Java 知识体系最强总结(2021版),https://blog.csdn.net/ThinkWon/article/details/103592572

鸣谢名单

以下排名不分先后:

  • 一饭名厨姚鲲鲲纠正了 Java 安装为 JDK 安装

你可能感兴趣的:(java)