变量

1. 变量的基本概念

当需要在程序中记录单个数据时,声明一个变量即可。声明变量本身是在内存中申请一个存储单元,由于该存储单元中的数据内容可以发生改变,因此称之为变量。
注意:
根据存储的内容不同,申请的存储单元的大小也不相同。数据类型对此进行限制。
为了下次方便调用,在申请存储单元时声明变量的名称。

2. 变量的声明方式

数据类型 变量名(标识符) = 变量初始值(可省略);

参考代码:VarTest.java

/*
    编程实现变量的声明和使用
*/ 
public class VarTest {
    public static void main(String[] args) {
        //  初始化一个 integer 声明
        int age = 18;
        //  打印变量的值,+为连接符 用于将两边的内容拼接起来
        System.out.println("your age is" + age);
    }

}

变量的几个种类

  • 局部变量 作用范围:从声明开始一直到方法体结束

  • 块变量 作用范围:从声明开始一直到当前语句块结束

3. 标识符的命名规则

  • 由数字,字母,下划线及 $ 构成,但请记住,不可以用数字开头。能用字母命名的标识符尽量用字母命名。

  • 不能使用 java 关键字。

  • 区分大小写。长度没有限制,但由于理解性原则不宜过长命名。

4. 变量输入输出

介绍了 Scanner 的导入和调用。
案例:实现将用户输入的姓名和年龄输出。
参考代码:VarIOTest.java

/*
    realize the input and out put
*/
// 导入 Scanner
import java.util.Scanner;

public class VarIOTest {
    public static void main(String[] args) {
        // 1. 声明两个变量用于记录年龄和信息(申请内存空间)
        String name;
        int age;
        // 2. 提示用户从键盘输入姓名和年龄并存入变量中
        System.out.println("请输入姓名和年龄:");
        // 创建一个扫描器来扫描键盘输入的内容,其中 system.in 为键盘输入内容
        Scanner sc = new Scanner(System.in);
        // 通过分别调用定义好的 sc 扫描器扫描用户输入的姓名和年龄并分别放入 name 和 age 中
        name = sc.next();
        age = sc.nextInt();
        // 3. 打印变量的数值
        System.out.println("您的名字为" + name);
        System.out.println("您的年龄为" + age);
    }
}

VarIOTest.java 实现了基本的功能,但不够优化。主要体现在如下两方面。

  • 变量随声明随使用原则

姓名和年龄声明之后并没有立刻使用,占用了内存。

String name;
int age;
  • 尽可能减少重复的代码

如下输出可以同时进行。

System.out.println("您的名字为" + name);
System.out.println("您的年龄为" + age);

优化后的代码:

import java.util.Scanner;

public class VarIOTest {
    public static void main(String[] args) {
        System.out.println("请输入姓名和年龄:");
        Scanner sc = new Scanner(System.in);
        String name = sc.next();
        int age = sc.nextInt();
        System.out.println("您的名字为" + name + ", 您的年龄为" + age);
    }
}

5. 官方库的使用

JDK 中有大量的 API 类,是 Java 系统带来的工具库,是 Java 官方程序员的技术积累,可以帮助我们简化编程,提高开发效率。
具体的API类功能可以参阅 Java 的参考手册。

详情可参考我的 Github 项目中的 JDK 11 API中文帮助文档.CHM 文件。

数据类型

1. 数据类型的分类

基本数据类型

byet, short, int, long, float, double, boolean, char

引用数据类型

数组, 类, 接口, 枚举, 标注

2. 常用进制

  • 生活中采用十进制,十进制的特点为逢十进一,十进制的权重为10^0, 10^1, 10^2…

  • 计算机世界采用二进制,二进制的特点为逢二进一,二进制的权重为2^0, 2^1, 2^2…

二进制中的最高位(最左位)代表符号位,若为 0 则表示非负数,为 1 则表示负数。

  • 为了简化二进制出现了八进制和十六进制。

3. 进制转化

正十进制转化二进制

a. 除 2 取余法
使用十进制整数不断除以 2 取出余数,直到商为 0 时将余数逆序排序。
例如十进制45的二进制表现为10 1101,在java中区分数列为二进制还是十进制时要加入前缀,比如0b101101为二进制。(0开头为八进制,0x开头为十六进制)
注意,10 1101 中的最高位并不是最左边的1,而是 64 位系统将前面的 0 省略掉了,具体可以借用计算器计算。

b. 拆分法
将十进制整数拆分为若干个二进制权重的和,有该权重的下面写 1 否则写 0。
例:将十进制 45 转化为二进制。

Step 1
45 = 32 + 8 + 4 + 1
Step 2 
128 64 32 16 8 4 2 1
0   0  1  0  1 1 0 1
Result
0010 1101
正二进制转化十进制

加权法
将二进制各位的权重进行十进制的转化并加和。
例:将二进制 10 1101 转化为十进制。

10 1101
1*2^5 + 0*2^4 + 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 32 + 8 + 4 + 1 = 45
负十进制转化为二进制

例:将负十进制 -45 转化为二进制。

步骤一:将 -45 的绝对值转化为二进制
|-45| = 45
45 的二进制为: 0010 1101

步骤二:按位取反(0 变成 1,1 变成 0)
结果为:1101 0010

步骤三:在步骤二的基础上末位加一
结果为:1101 0011

检验:
-45 + 45 = 0

  0010 1101
  1101 0011 +
--------------
1 0000 0000
最先头的 1 高位溢出无效,所以结果为 0,验证成功。
负二进制转化为十进制

例:将负二进制 1101 0011 转化为十进制。

步骤一:二进制最后位减一
1101 0011
0000 0001 -
------------
1101 0010

步骤二:按位取反
1101 0010
      取反
---------
0010 1101

步骤三:转为十进制
0010 1101
0*2^7 + 0*2^6 + 1*2^5 + 0*2^4 + 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 32 + 8 + 4 + 1 = 45

步骤四;取反
45 👉 -45

4. 单个字节所能表示的整数范围

在计算机中单个字节表示八位二进制位,其中最高位代表符号位,0 代表非负数,1 代表负数,所以具体能表示的范围如下:

  • 非负数表示范围:0000 0000 ~ 0111 1111 👉 0 ~ 127(0 ~ 2^7 -1)

  • 负数表示范围: 1000 000 ~ 1111 1111 👉 -128 ~ -1(-2^7 ~ -2^0)

综上所述,单个字节所能表示的整数范围为 -128 ~ 127。

5. 整数类型的概念

Java 语言中描述整数数据的类型有:Byte, short, int, long。他们分别所占字节和表示范围如下所示:

byte: 占用一个字节,表示范围 -2^7 ~ 2^7 -1
short: 占用两个字节,表示范围 -2^15 ~ 2^15 -1
int: 占用四个字节,表示范围 -2^31 ~ 2^31 -1
long: 占用八个字节,表示范围 ^2^63 ~ 2^63-1

日常开发中推荐使用 int 类型。在 java 中直接输入整数也默认为 int 类型,但 Java 自身会对这个数进行判断,如果这个数在小与 Int 的类型的表示范围内,则可以以指定类型表示,但实质上还是 Int 类型。因此在定义 byte 等的时候,如果超出其表示范围则会提示从 int 转换到 byte 可能会有损失

注意,long 的定义不能以没有超出表示范围为理由,直接以 long 定义一个超出 int 类型的整数时,会报错:整数太大, 因此在这种情况下应在要定义的整数后加 f 或 F (若描述比 long 类型还大的数据则使用 java.math.BigInteger 类型)。

关于表示范围的直观体现参考代码 IntTest.java

/*
    编程实现整数类型的使用
 */
public class IntTest {

    public static void main(String[] args) {

        // 1.声明一个 byte 类型的变量并初始化
        byte b1 = 25;
        //byte b1 = 250;     // 错误: 不兼容的类型: 从 int 转换到 byte 可能会有损失  250 这样直接写出的整数数据叫做直接量/常量/字面值 默认为 int 类型 
        // 2.打印变量的数值
        System.out.println("b1 = " + b1); // b1 = 25

        System.out.println("---------------------------------------------");
        // 3.声明一个 short 类型的变量并初始化
        short s1 = 250;
        //short s1 = 250250;  // 错误:不兼容的类型:从 int 转换到 short 可能会有损失
        System.out.println("s1 = " + s1); // s1 = 250

        System.out.println("---------------------------------------------");
        // 4.声明一个 int 类型的变量并初始化
        int i1 = 250250;
        //int i1 = 2502505006; // 错误: 整数太大   默认为 int 类型,这个数据自身已经出错,无法表示
        //int i1 = 2502505006L;  // 错误:不兼容的类型:从 long 转换到 int 可能会有损失
        System.out.println("i1 = " + i1); // i1 = 250250

        System.out.println("---------------------------------------------");
        // 5.声明一个 long 类型的变量并初始化,若描述比 long 类型还大的数据则使用 java.math.BigInteger 类型
        long g1 = 2502505006L;
        System.out.println("g1 = " + g1); // g1 = 2502505006
    }
}

有时会出现如下问题:

// 6.请问下面的代码是否有错误?若有请指出并说明原因
//int i2 = 25;
//byte b2 = i2;  // 错误: 不兼容的类型: 从 int 转换到 byte 可能会有损失
//System.out.println("b2 = " + b2);

注意:不可以将表示范围大的变量赋值给表示范围小的变量,虽然在本题目中 25 在 byte 类型的表示范围中,但 int 是变量,将来有可能保存大于 byte 类型表示范围的值,因此会报错。

6. 浮点类型的概念

Java中用于描述小树数据的类型称之为浮点类型,包括 float类型double类型,推荐使用 double类型

  • float 类型 占用四个字节,叫做单精度浮点数,可以表示 7 位有效数字,范围:-3.403E38 ~ 3.403E38

  • double 类型 占用八个字节,叫做双精度浮点数,可以表示 15 位有效数字,范围:-1.798E308 ~ 1.798E308

  • Java 程序中直接写出的小数数据叫做直接量,默认为 double 类型(整数默认为 int 类型), 若希望表达 float 类型的话,需要在直接量后加上 f 或 F

具体代码实现请参考 DoubleTest.java

/*
    编程实现浮点类型的使用
 */
public class DoubleTest {

    public static void main(String[] args) {

        // 1.声明一个float类型的变量并初始化
        //float f1 = 3.1415926;   // 错误: 不兼容的类型: 从double转换到float可能会有损失   小数数据叫做直接量,默认为double类型
        float f1 = 3.1415926f;
        // 2.打印变量的数值
        System.out.println("f1 = " + f1); // f1 = 3.1415925     一般是7位有效数字

        System.out.println("---------------------------------------------------------");
        // 3.声明一个double类型的变量并初始化
        double d1 = 3.1415926;
        System.out.println("d1 = " + d1); // d1 = 3.1415926     一般是15位有效数字

        System.out.println("---------------------------------------------------------");
        // 4.笔试考点
        System.out.println(0.1 + 0.2);  // 0.30000000000000004  运算时可能会有误差,若希望实现精确运算则借助java.math.BigDecimal类型 
    }
}

通过如上代码可知, float有效位少,所以不精确,double较为精确但在涉及精确计算时要借助 java.math.BigDecimal

6. 布尔类型的概念

用于描述真假信息,数值只有 false 和 true。
Java 官方并没有给出关于布尔类型占用字节数的描述,通常认为占用一个字节。但其实由于 boolen 的值只有 false 和 true 因此即使只占用一个 byte 也是足够的。

实现代码请参照 BooleanTest.java

/*
    编程实现布尔类型的使用
 */
public class BooleanTest {

    public static void main(String[] args) {

        // 1.声明一个boolean类型的变量并初始化
        boolean b1 = true;
        // 2.打印变量的数值
        System.out.println("b1 = " + b1); // b1 = true

        System.out.println("-------------------------------------------");
        // 3.修改变量b1的数值   = 赋值运算符,用于将=右边的数据赋值给=左边的变量,覆盖变量中原来的数值
        b1 = false;
        System.out.println("b1 = " + b1); // b1 = false

        System.out.println("-------------------------------------------");
        //b1 = 1; // 错误: 不兼容的类型: int无法转换为boolean
    }
}

7. 字符类型的概念

用于描述单个字符的类型叫做字符类型,也叫做 char 类型。例如:’a’ 等。
char 类型在内存空间中占用 2 个字节,且没有符号位,表示范围: 0 ~ 65535,由于现实生活中很少有数据能被单个字符描述,因此以后的开发中更多的使用由多个字符串起来组成的字符串,使用 String 类型加以描述。

  • 关于 ASCII 码

计算机只能识别由 0 和 1 组成的二进制序列,’a’ 这样的字符对于计算机来讲仅仅是图案而已,因此无法直接在计算机中存储,但有存储的需求,为了使得该数据能够存储起来就给定字符一个编号,只要将编号存储起来就相当于将 ‘a’ 这样的字符串存储起来,问题就解决了,解决这个问题的编号叫做 ASCII 码。

要求掌握的常用 ASCII 码有:’0’:48 ‘A’:65 ‘a’:97 空格:32 换行符:10

  • 关于 Unicode

    ASCII 码可表示的字符有限,有时需要引入 Unicode 码,Unicode 是世界通用的定长字符集,所有的字符都是十六位。在代码中可以参考到 Unicode 编码的实现。

    • 关于转义字符

    特殊字符的使用中,比如 "" 有两个作用,作用一是作为字符串开头和结尾的标志,作用二则作为文章中的双引号本身来使用,当需要 "" 作为作用二来使用时,则需要用到转义字符 \ 。 主要的转义字符有四个,分别为: \", \', \t(制表符), \n(换行符)

实现代码请参照 CharTest.java

public class CharTest {

    public static void main(String[] args) {

        // 1.声明一个char类型的变量并初始化
        char c1 = 'a';
        // 2.打印变量的数值
        System.out.println("c1 = " + c1); // c1 = a   
        System.out.println("对应的编号是:" + (int)c1); // 表示将char类型的c1强制转换为int类型并打印   97 

        System.out.println("-------------------------------------------------------------------------");
        // 2.声明一个char类型的变量并初始化
        char c2 = 98;
        System.out.println("c2 = " + c2); // c2 = b   
        System.out.println("对应的编号是:" + (int)c2); // 98

        System.out.println("-------------------------------------------------------------------------");
        // 3.使用Unicode字符集来表示一下我的名字   奇点  对应的编号是: \u5947\u70b9
        char c3 = '\u5947';
        char c4 = '\u70b9';
        System.out.println("最终的结果是:" + c3 + c4); // 奇点

        System.out.println("-------------------------------------------------------------------------");
        // 4.特殊字符的使用   双引号本身有2个含义:a.字符串的开头和结尾标志    b.双引号自身    \ 转义就是转换原有的含义
        System.out.println("我想过过\"过过过过的生活!");   //  \"  - "
        System.out.println("我想过过\'过过过过的生活!");
        System.out.println("我想过过\\过过过过的生活!");
        System.out.println("我想过过\t过过过过的生活!");
        System.out.println("我想过过\n过过过过的生活!");
    }
}

通过代码可知,通过 char 定义的变量在输出时将输出 char 类型。如果希望输出 ASCII 编码则需要强制转化为 Int 类型后再输出。反之,定义 char 类型时直接输入 ASCII 编码也同样可以定义变量。

8. 基本数据类型之间的转换

数据类型转换分为自动类型转换强制类型转换

  • 自动类型转换

从小类型到大类型的转换。

byte short int long float double

     char

所谓小类型和大类型指的是类型的表示范围,比如 long 占用 8 个字节的内存,但对于 float 来说它是小类型,原因就在于 long 的表示范围为 2^63 级别,而 float 的表示范围为 10^38 级别。

  • 强制类型转换

从大类型到小类型的转换。

强制类型转换的语法格式:

目标类型 变量名 = (目标类型)源类型变量名

注意:强制转换有内存溢出的风险

数据类型的转换方式如代码 TransformTest.java 所示

/*
    编程实现基本数据类型之间转换的使用
 */
public class TransformTest {

    public static void main(String[] args) {

        // 1.声明两个变量并初始化
        byte b1 = 10;
        short s1 = 20;
        // 2.打印变量的数值
        System.out.println("b1 = " + b1); // b1 = 10
        System.out.println("s1 = " + s1); // s1 = 20

        System.out.println("----------------------------------------------");
        // 3.实现自动类型转换的使用
        // 表示将变量b1的数值赋值给变量s1,并覆盖变量s1中原来的数值,相当于从byte类型到short类型的转换,小到大  自动转换
        s1 = b1;
        System.out.println("b1 = " + b1); // b1 = 10
        System.out.println("s1 = " + s1); // s1 = 10

        System.out.println("----------------------------------------------");
        // 4.实现强制类型转换的使用
        // 表示将变量s1的数值赋值给变量b1,并覆盖变量b1中原来的数值,相当于从short类型到byte类型的转换,大到小  强制转换
        //b1 = s1;   // 错误: 不兼容的类型: 从short转换到byte可能会有损失
        s1 = 128;    // 故意加该行代码      128:0000 0000 1000 0000  => 1000 0000 => 0111 1111 => 1000 0000 => 128 => -128
        b1 = (byte)s1;
        System.out.println("b1 = " + b1); // b1 = 10   -128 
        System.out.println("s1 = " + s1); // s1 = 10   128
    }
}

如代码所示,当定义 short 类型为 128 并赋值给 byte 类型时,由于 byte 类型的表示范围最大为 127 且占用 1 个字节,而 short 类型占用两个字节,转换为二进制也就是 0000 0000 1000 0000,因此 byte 类型只保存 1000 0000的部分,也就是编译器所输出的结果 -128


文章作者: Ruoyu Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ruoyu Li !
  目录