diff --git a/docs/courses/java/01-Java语法入门/05-变量和常量.md b/docs/courses/java/01-Java语法入门/05-变量和常量.md new file mode 100644 index 000000000..c52eebbd6 --- /dev/null +++ b/docs/courses/java/01-Java语法入门/05-变量和常量.md @@ -0,0 +1,360 @@ +--- +title: 变量和常量 +author: 查尔斯 +date: 2020/10/06 23:56 +categories: + - Java基础快速入门 +tags: + - Java + - Java基础 +--- + +# 变量和常量 + +## 前言 + +**C:** 上一篇,笔者给你加了点“料”,捋了捋一个 QQ 程序从安装到运行起来究竟做了哪些事儿。在上一篇的最后,我们还分析到了一个结果就是当程序运行在内存中后,程序产生的数据也要在内存中妥善的管理起来,以方便使用和复用,这种基础的数据管理概念就是 **变量** 。 + +![202010061318922](../../../public/img/2020/10/06/202010061318922.jpeg) + +不知道,大家是否还记得在[《开发环境搭建》](./01-开发环境搭建)中我们介绍过一个环境变量的概念,**环境变量就是操作系统里存储的一些环境参数或关键值,每个在操作系统里运行的程序都可以获取到这些存储的内容** 。因为它存储的是环境信息,又因为这些信息是可变的值,所以它叫环境变量。 + +而本篇我们也要正式学习下 Java 程序中的变量,它是我们学习的第一个基础知识点,先来感受下它的用处吧,例如下方代码,在进行输出个人介绍时,如果想修改姓名的话,需要单个依次修改。 + +此时我们就可以将个人介绍中的姓名存储成变量,然后就可以很方便的修改或重复使用了。 + +```java +// 未使用变量 +System.out.println("我是时间管理大师:小罗"); +System.out.println("我是时间管理大师:小罗"); +System.out.println("我是时间管理大师:小罗"); +System.out.println("我是时间管理大师:小罗"); +``` + +```java +// 使用变量 +String name = "小罗"; +System.out.println("我是时间管理大师:" + name); +System.out.println("我是时间管理大师:" + name); +System.out.println("我是时间管理大师:" + name); +System.out.println("我是时间管理大师:" + name); +``` + +## 变量概述 + +::: tip 笔者说 +变量来源于数学,是计算机语言中能 **储存计算结果或能表示值** 的抽象概念。在一些语言中,变量可能被明确为是能表示可变状态、具有存储空间的抽象(如在 Java 和 Visual Basic 中)。[1~2] +::: + +如下图,当 Java 程序运行过程中,我们需要存储一些数据,此时就可以在内存开辟一个个变量空间来存储这些可变的数据。 + +![202010061319222](../../../public/img/2020/10/06/202010061319222.png) + +通俗的来讲:变量就是一个数据存储空间的表示,不同数据存入具有不同内存地址的空间,彼此相互独立。 + +## 变量的组成 + +将数据以 变量 形式存入内存之后,我们怎么找到和使用它呢? + +- 第1种方式:可以通过内存地址值去寻找。但是这地址值是类似于:0x12345….这种无关联的组成,每次记忆极其繁琐。 +- 第2种方式:使用变量名来快速简便的找到存入的变量,找到变量自然也就找到数据了。 + +其实变量这个概念,可以去类比生活中去酒店入住的场景。 + +酒店就是 `JVM` 内存,房间就是一个个的 `变量`,房间的名字就是 **变量名**(毕竟你想想酒店前台告诉你房间位置时,应该都是告诉你房间号,而不是给你指路:上3楼直走5个房间,右转后第3个房间对面); + +酒店还会为不同客人提供不同类型的房间,满足特别的需求。`JVM` 内存中,也是这么来安排数据的,我们称之为**变量类型** ;房间里入住的客人就是 **变量里存储的值** 。 + +而且变量即可以变化的量,酒店房间的客人也是变动的,这么理解起来,简直太容易了。所以笔者建议你,以后想到变量就多想想开房。 + +![202010061319719](../../../public/img/2020/10/06/202010061319719.png) + +::: tip 笔者说 +所以,变量的组成是由:变量名、变量类型、变量值三个部分组成。 + +变量值就没必要看了,它就是你要存储的数据,爱存啥就存啥,但是其他的两个部分我们需要详细研究研究。 +::: + +### 变量名 + +**变量名也就是标识符,其实就是为了方便区分不同的变量。但这个名也不是随便起的,在长久的演化中,我们有了约定俗成的规范。** + +::: warning 变量名命名规范 +1. 可以使用数字、字母,下划线和 `$` 符号组成,但数字不能开头。 + +2. 不能使用关键字(`public`、`void`等)和保留字(`goto`、`def`等)!**关键字:被系统定义了特殊含义的单词。保留字:现在还不是关键字,未来可能有特殊含义。** + +3. 起名要见名知意。 例如:`name` 一看就知道是名字,`password`是密码等。 + +4. 采用小驼峰式命名法(Lower Camel Case)。(所谓小驼峰命名法,即首字母小写,如果有多个单词那么后面的每个单词首字母大写。`e.g. userPassword`) ;另外因为支持下划线,所以有些时候会有下划线连接法命名的变量。`e.g. user_password`。 + + ![202010061319888](../../../public/img/2020/10/06/202010061319888.jpeg) + +5. 要么名称全为拼音,要么全为英文单词。`e.g.(X)myMingZi`。 + + ![202010061320187](../../../public/img/2020/10/06/202010061320187.jpeg) +::: + +### 数据类型 + +不同类型的值要以不同的形式存储,那么在 Java 中,它将不同的值划分了多少类型呢? + +**数值型有:** + +- 整型:byte、short、int、long +- 浮点型:float、double + +**非数值型:** char(字符型) 、boolean(布尔型) 、String(字符串型,一个比较特别的类型,先记住它不是基本数据类型,是引用数据类型即可) + +下方是数值型数据类型的取值范围表: + +| 数据类型 | 大小 | 取值范围 | +| :------: | :-------------: | :--------------------------------------------: | +| byte | 1字节8位 | -128 ~ +127 | +| short | 2字节16位 | -32768 (-2^15^) ~ +32767 (+2^15^ - 1) | +| int | 4字节32位 | -2147483648 (-2^31^) ~ +2147483647 (2^31^ - 1) | +| long | 8字节64位 | -2^63^ ~ +2^63^ - 1 | +| float | 4字节32位浮点数 | 1.4E-45 ~ 3.4E+38, -1.4E-45 ~ -3.4E+38 | +| double | 8字节64位浮点数 | 4.9E-324 ~ 1.7E+308, -4.9E-324 ~ -1.7E+308 | + +::: tip 笔者说 +在 Java 中,如果定义一个变量,**整数数据默认为 int 类型,小数数据默认为 double 类型。** + +因为 int 和 double 的取值范围已经满足了我们大多数时的使用要求了。 +::: + +## 变量的使用步骤 + +聊完了概念后,我们接下来一起用一下吧! + +第一步:声明变量,根据数据类型在内存申请空间。 + +```java +// 数据类型 变量名; +int money; +``` + +第二步:赋值,即“将数据存储至对应的内存空间”。 + +```java +// 变量名 = 数值; +money = 1000; +``` + +tips:第一步和第二步可以合并。 + +```java +// 数据类型 变量名 = 数值; +int money = 1000; +``` + +第三步:使用变量,即“取出数据使用”。(也就是拿着变量名去使用) + +```java +public class Demo1{ + public static void main(String[] args){ + // 在方法中声明的变量 被称为局部变量 局部变量如果没赋值前是无法使用的 + // 第1种使用方式 先声明再赋值 + // 声明变量(联想记忆:在内存中开好201双人房间) + // 此变量将用来存储银行卡存款 + int money; + // 赋值 =号不再是数学里的相等,而是表示将右边的内容赋值给左边的 + money = 1000; + + // 第2种使用方式 声明的同时并赋值 + int money1 = 1000; + // 使用变量 + System.out.println("我的银行存款为:" + money1 + "元"); + } +} +``` + +再来个小练习,吸收一下吧,案例需求如下: + +**要求使用变量来完成如下操作:** +- 输出Java课考试最高分:98.5 +- 输出最高分学员姓名:张三 +- 输出最高分学员性别:男 + +```java +// 声明一个变量用来存储最高分 +double score = 98.5; +// 如果是float类型来存储数据,那么必须在值后添加 f/F +// 其实double类型的后面也应该加d/D,但Java中出现的浮点类型默认为double,所以不需要加 +// float score1 = 98.5F; + +// 声明一个变量用来存储学员姓名 +// 双引号包裹的内容是一个字符串 +String name = "张三"; +// 声明一个变量用来存储学员性别 +// 单引号包裹的事一个字符 +char gender = '男'; + +// 使用变量:使用+号来拼接使用变量 +// 只要是与字符串用+号拼接的都成为了字符串 +System.out.println("最高分为:" + score); +System.out.println("姓名为:" + name); +System.out.println("性别为:" + gender); +// 等价于下方 +System.out.println("最高分为:" + score + "\n姓名为:" + name + "\n性别为:" + gender); +``` + +## 常量概述 + +在程序运行中,我们需要使用一些数据,但是这些数据在存储好后不应该再次发生变化(例如:`π`)。这时候,单纯使用变量存储,毕竟叫变量,难保未来可能被不小心重新赋值。 + +此时我们可以使用常量来解决此问题。 + +::: tip 笔者说 +在Java中,其值不能改变的变量被称为常量。常量被final修饰,被final修饰则无法二次修改值。 +::: + +为了和变量做出区别,常量在命名上也有一些小要求。 + +::: warning 常量名命名规范 +1. 常量名所有字母都要大写。 + +2. 如果有多个单词,多个单词之间使用下划线分隔。例如:`MY_NAME` + +3. 只能被赋值一次(被final修饰),通常定义时即对其初始化。 +::: + +```java +public class Demo2{ + public static void main(String[] args){ + // 声明一个变量 用来表示π + // 被final修饰的变量,无法再进行第二次改值 必须进行初始赋值,不能分开声明和赋值 + final double PI = 3.14; + // 声明一个变量用来表示半径 + int radius = 7; + + // 计算圆的面积 π * r * r + double area = PI * radius * radius; + System.out.println("圆的面积为:" + area); + } +} +``` + +## 程序交互 + +在上述的练习使用中,笔者定义的变量全是自己直接定义好值的。如果现在想要让变量值变成一个灵活动态的内容,通过键盘来灵活输入,这时候我们就需要使用 Java 给我们准备好的 `Scanner` 工具来解决。 + +**Scanner的使用需要一个固定的步骤!前期牢记即可!后期学习`类`之后就懂了。** + +第一步:导入`Scanner`类。 + +```java +import java.util.Scanner; +``` + +第二步:创建`Scanner`对象。 + +```java +Scanner input = new Scanner(System.in); +``` + +第三步:获得键盘输入的数据,并自动将其转换存储为`int`类型的变量`now`。 + +```java +int now = input.nextInt(); +``` + +```java +// 1.在类声明上方 添加导入语句 +import java.util.Scanner; + +public class Demo3{ + public static void main(String[] args){ + // Scanner 可以用来进行键盘录入的API + // 2.创建Scanner对象 input就是个变量名 + Scanner input = new Scanner(System.in); + + // 3.使用Scanner的方法 对象名.xxx()来调用方法 + System.out.print("请输入您的年龄:"); + int age = input.nextInt(); + + System.out.println("输入的年龄为:" + age); + } +} +``` + +## 类型转换 + +上述就是变量的基本玩法,简单吗?接下来我们再了解一些特别的小知识,加深你对数据类型的理解。 + +### 自动类型转换 + +看一下下方的代码,`double `类型的变量竟然在存储整数类型?而且它不会出现任何语法错误? + +```java +// 自动类型转换 +double num1 = 10; +System.out.println(num1); // 10.0 +// 两个操作数只要其中一个是double类型的,那么计算结果就会提升为double类型 +// 取值范围小的 自动类型转换为 取值范围大的 +double num2 = 10 + 10.1; +System.out.println(num2); // 20.1 +``` + +这是因为在 Java 中,如果两种类型相互兼容(例如整型和浮点型同属数值类型),那么取值范围小的类型(精度低),可以自动类型转换为取值范围大的类型(精度高)。 + +### 强制类型转换 + +有自动类型转换,那应该也有非自动的,我们称之为强制类型转换。 + +看个小例子:去年Apple笔记本所占市场份额是20,今年增长市场份额是9.8,求今年所占份额? + +```java +// apple 笔记本市场份额 +int before = 20; +// 增长的份额 +double rise = 9.8; +// 现在的份额 +int now = (int)before + rise; // 29 不是四舍五入,是直接取整了 +``` + +我们发现,上面的代码最后结果使用了`int`来存储,但是却需要用`(int)`来标注一下,否则会提示语法错误。这是因为当`int`和`double`型数据计算后,它们的结果值已经自动类型转换为了`double`型,而最后又要将其转换为`int`型,也就是将一个取值范围大(精度高)的数据,存储到取值范围小的(精度低)类型里,那自然会损失精度(小数点位的值全丢了),所以需要自己手动标注一下,表明我们自己认可这件事。 + +::: tip 帮助理解类型转换的故事 +假设现在有一个100斤的小麦口袋,还有一个40斤的大米口袋,如果我想把两个口袋换着装东西,40斤大米口袋内的大米自然可以放到100斤小麦口袋里(自动类型转换),但是反之则不行,如果非要这么做,多余的小麦肯定会洒出来(强制类型转换)。 +::: + +```java +// 口袋:100斤小麦 +double mian = 100; +// 口袋:40斤大米 +int mi = 40; + +mi = (int)mian; +``` + +## 出题环节 + +### 变量练习 + +::: details 需求:使用变量分别存储个人基本信息,然后逐行输出个人基本信息。 +提示:个人基本信息可包括:姓名、年龄、性别、身高、体重、婚否等 +::: + +::: details 需求:使用 Scanner 分别录入个人基本信息、并逐行输出。 +提示:个人基本信息可包括:姓名、年龄、性别、身高、体重、婚否等 +::: + +## 参考文献 + +[1]谭浩强. C程序设计(第4版):清华大学出版社,2010.6 + +[2]明日科技. Visual Basic从入门到精通:清华大学出版社 ,2017.6 + +## 后记 + +无论是学习任何编程语言,变量都是必不可少的一个基础内容,所以,结合上一篇《Java语法 | 程序的那点事儿》好好在脑海中构想一下变量在内存中的使用吧。 + +![202010061320866](../../../public/img/2020/10/06/202010061320866.jpeg) + +::: info 笔者说 +对于技术的学习,笔者一贯遵循的步骤是:先用最最简单的 demo 让它跑起来,然后学学它的最最常用 API 和 配置让自己能用起来,最后熟练使用的基础上,在空闲时尝试阅读它的源码让自己能够洞彻它的运行机制,部分问题出现的原因,同时借鉴这些技术实现来提升自己的代码高度。 + +所以在笔者的文章中,前期基本都是小白文,仅仅穿插很少量的源码研究。当然等小白文更新多了,你们还依然喜欢,后期会不定时专门对部分技术的源码进行解析。 +::: + diff --git a/docs/public/img/2020/10/06/202010061318922.jpeg b/docs/public/img/2020/10/06/202010061318922.jpeg new file mode 100644 index 000000000..f08e7c780 Binary files /dev/null and b/docs/public/img/2020/10/06/202010061318922.jpeg differ diff --git a/docs/public/img/2020/10/06/202010061319222.png b/docs/public/img/2020/10/06/202010061319222.png new file mode 100644 index 000000000..9db5addf7 Binary files /dev/null and b/docs/public/img/2020/10/06/202010061319222.png differ diff --git a/docs/public/img/2020/10/06/202010061319719.png b/docs/public/img/2020/10/06/202010061319719.png new file mode 100644 index 000000000..4c3ed5115 Binary files /dev/null and b/docs/public/img/2020/10/06/202010061319719.png differ diff --git a/docs/public/img/2020/10/06/202010061319888.jpeg b/docs/public/img/2020/10/06/202010061319888.jpeg new file mode 100644 index 000000000..860d6b3a6 Binary files /dev/null and b/docs/public/img/2020/10/06/202010061319888.jpeg differ diff --git a/docs/public/img/2020/10/06/202010061320187.jpeg b/docs/public/img/2020/10/06/202010061320187.jpeg new file mode 100644 index 000000000..0696d1c23 Binary files /dev/null and b/docs/public/img/2020/10/06/202010061320187.jpeg differ diff --git a/docs/public/img/2020/10/06/202010061320866.jpeg b/docs/public/img/2020/10/06/202010061320866.jpeg new file mode 100644 index 000000000..fbc23dcbe Binary files /dev/null and b/docs/public/img/2020/10/06/202010061320866.jpeg differ