image.png

前言

上一篇文章 手写的第一个 Java 应用程序,执行的时候发生了什么,我们用 Java 做了实践编程,并简单了解了它运行的原理。但这些还只是表象和皮毛,Java 的知识博大而精深,需要慢慢深入理解和领会,蜗牛就带大家来啃这块硬骨头吧!

学习一门新知识,基础是最重要的。就像起一座大楼,地基打的够坚实,大楼才会更稳固。另一个角度讲,所有的复杂都是简单元素的加工和组合,百变不离其宗,基础就是这种简单元素。

所以,我们先来学习下 Java 最基础的部分!

Java 程序的结构

学习一个新东西,我建议先看它的结构,这样有了整体的认知之后,再去学习细节,就能更好的认识到每个细节点在整体中的位置和作用,可以更好的理解整体和局部之间的关系。

比如我们现在学的是 Java 程序语言设计,那它的表现形式就是 Java 代码。写一个能跑的 Java 程序,那就需要写个 class,class 里要有个 main 方法,这样就构成了一个完整的 Java 程序。

其实我们上篇提到的 HelloWorld 程序就是一个完整的 Java 程序,它由访问修饰符类类型类命名main 方法执行语句花括号注释这几个核心要素构成。

很清晰!带你图解 Java 程序的结构,变量和类型 - 图2

访问修饰符决定了被修饰对象的可访问范围,被修饰对象可以是类、变量和方法,访问范围的标识有 public、protected、缺省和 private。

类类型表明当前类的类型,有 class(普通类)、enum(枚举类)、interface(接口类)和 @interface(注解类)。

类名是当前类的标识,通过它来区别其它类。命名的时候一般大写字母开头,可以是字母数字下划线的组合,不过最规范的是大写字母开头的驼峰式命名。

main 方法是 Java 程序必备的一个东西,它是 Java 程序的执行入口,声明也是固定的。

执行语句就是我们要编写的程序逻辑了,每条语句都要用 ; (分号)结束。

花括号 {} 代表了当前内容的作用域,它总是成对出现。比如 HelloWorld 后边的 {} 里的内容,就只影响到当前这个 class,main(String[] args) 后边的 {} 里的内容,就只影响到当前这个 main 方法。

注释是对代码逻辑的解释,它不是写一个 Java 程序必备的,也不会被编译到字节码文件里。但在我的经验里,有它比没有它强,因为代码虽说是给机器执行的,但却是给人看的,好的代码注释,是能够提升代码的可读性和可维护性的。我这个例子里写的注释有类注释、方法注释、行注释和多行注释。

变量和数据类型

变量

HelloWorld 程序一般用来辅助我们判断自己环境有没有配置好,如果 HelloWorld 能运行,就说明我们 Java 环境是好的,就可以专心编程和调试了。

编程躲不开的一个概念就是变量。

什么是变量呢?顾名思义,就是变化的量,这个概念起源于初中数学的代数,比如方程式中的 x 和 y 都是变量,x 是自变量,y 是因变量,如果基于一定的规则,只要给定一个 x 的值,就一定能得到 y 的值。

  1. y = x + 1

这就非常契合我们编程的场景了,给一个输入,跑一下程序,就能得到一个确定的输出。至于输出什么样的值,取决于这个程序要实现的功能以及给定输入的值。

我们回过头来看下刚才那个方程式 y=x+1 ,如果没有限定的话,x 其实可以是整数,也可以是小数,还可以是字符串。可是如果是个字符串,就无法按数学规则进行运算了。所以即便是方程式的场景,一般也会约定变量的一个类型,比如 x 是个整数。

同样的,反映到 Java 里,Java 是一种静态类型语言,这意味着每个变量和每个表达式在编译时就需要知道类型。如果我们想定义一个变量 x,就需要指定一下它的类型,以便能够通过编译以及进行后续的运算。

这也是 Java 变量的一个原则:先定义后使用,定义必须指定数据类型

比如较小的整数可以用 byte num; 表示。变量也可以做赋值操作,比如 num = 10; 就把 10 这个整数赋值给了 num 这个变量。另外,变量也支持传递,比如 byte num2 = num; 就是把 num 的值传递给了 num2。

很清晰!带你图解 Java 程序的结构,变量和类型 - 图3

在计算机上,CPU 负责计算,内存负责存储待计算的数据。上图的方块你可以理解成一块内存,你会发现它是一块一块的,这就是内存的基本单位——byte(字节)。一个字节是 8 bit(位),也就是一个字节能容纳二进制 00000000~11111111 所有的数字。

我们的程序也是字节维度使用内存,而内存空间是有限的,就需要有指标能衡量待存储的数据大小,以避免内存超限而引起程序崩溃。

因此,程序运行的时候,需要告诉内存,我要申请多大的内存空间,也就是图里面会用多少个小方块,其次是我存的值是什么,也就是图里面小方块里的值。我们的变量 num 就是申请了一个字节的空间,然后存了数字 10。

那么如果 num 要用的值超过了一个字节的限度,我们其实就无法使用 byte 这个数据类型了,就需要定义一种新的数据类型来支撑,好在 Java 已经帮我们做好了这件事!

类型的种类和值

那 Java 支持哪些数据类型呢?

在 Java 的世界里,有基本类型引用类型两种。相应地,有两种数据值可以存储在变量中,作为参数传递,由方法返回,并对其进行操作: 原始值和引用值。

image.png

基本类型和值

我们先看下基本类型。

分类

基本数据类型在 Java 里可分为布尔类型和数字类型两大类:

大类类型 细分类型 关键字 内存占用 取值范围
布尔类型 布尔类型 boolean 1 字节或 4 字节 true 和 false
数字类型 整型类型 byte 1 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图5 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图6
数字类型 整型类型 short 2 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图7 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图8
数字类型 整型类型 int 4 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图9 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图10
数字类型 整型类型 long 8 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图11 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图12
数字类型 整型类型 char 2 字节 0 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图13
数字类型 浮点类型 float 4 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图14 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图15
数字类型 浮点类型 double 8 字节 很清晰!带你图解 Java 程序的结构,变量和类型 - 图16 ~ 很清晰!带你图解 Java 程序的结构,变量和类型 - 图17

布尔类型表达是或者否,只有 trueflase 两个值,用关键字 boolean 表示,但 JVM 没有针对 boolean 的字节码指令,因此在虚拟机规范里,boolean 类型在编译后会被 int 代替,占用 4 个字节,如果是 boolean 数组,会被编译成 byte 数组类型,每个 boolean 数组元素占 1 个字节。实际情况就取决于各厂商发布的 JVM 实现了。

数字类型包括了整型类型和浮点类型。

整型类型根据取值范围的不同,细分成了 byteshortintlongchar五种,分别是 8 位、16 位、32 位、64 位有符号整数和 16 位无符号整数,分别占用一个字节、两个字节、四个字节、八个字节和两个字节的内存空间。

整型类型的值是以下范围的整数:

  • byte: -128 到 127,包括边界值
  • short: -32768 到 32767,包括边界值
  • int: -2147483648 到 2147483647,包括边界值
  • long: -9223372036854775808 到 9223372036854775807,包括边界值
  • char: ‘\u0000’ 到 ‘\uffff’,包括边界值,也就是从 0 到 65535。char 可表示标准的 ASCII 或一个 Unicode 字符。ASCII 字符集占据 Unicode 字符集中的前 127 个值。

浮点数指小数,科学计数法表示的时候,小数点是可以“浮动”的,所以称为浮点数。

浮点类型有 floatdouble 两种,其值分别为 32 位 IEEE 754 浮点数和 64 位 IEEE 754浮点数。

float 可选地以后缀 f或F 结尾,double 可选地以后缀 d或D 结尾。表格中的取值范围仅表示幅度,它可以是正也可以是负,负数场景在前面加个负号即可。

了解基本概念后,我们举个例子看下 Java 中如何使用吧!

  1. package cn.java4u.codebase;
  2. /**
  3. * 基础类型变量
  4. *
  5. * @author 蜗牛
  6. * @from 公众号:蜗牛互联网
  7. */
  8. public class BaseVar {
  9. /**
  10. * 主函数
  11. *
  12. * @param args args
  13. */
  14. public static void main(String[] args) {
  15. /*
  16. * 变量定义格式:
  17. * 数据类型 变量名;
  18. * 数据类型 变量名 = 变量值;
  19. */
  20. /*
  21. 布尔类型
  22. */
  23. // 布尔未赋值
  24. boolean boolNoValue;
  25. // 布尔赋值 true
  26. boolean boolTrue = true;
  27. // 布尔赋值一个计算结果
  28. boolean boolWithResult = 2 > 1;
  29. // 布尔赋值 非 true 或 false 会编译报错
  30. // boolean boolCompileError = 123;
  31. /*
  32. 整数类型
  33. */
  34. // 字节赋值 8
  35. byte byteDemo = 8;
  36. // 赋值越界会编译报错
  37. // byte byteOutOfBounds = 188;
  38. // 短整型赋值 188
  39. short shortDemo = 188;
  40. // 整型赋值 38888
  41. int intDemo = 38888;
  42. // 整型赋值带下划线,提高辨识度
  43. int intDemoWithUnderLine = 1888_888_888;
  44. // 十六进制表示 16711680
  45. int intDemoWithHex = 0xff0000;
  46. // 二进制表示的512
  47. int intDemoWithBinary = 0b1000000000;
  48. // long型的结尾需要加 L
  49. long longWithSuffix = 2147483649L;
  50. /*
  51. 浮点数类型
  52. 浮点类型的数就是通常意义上的小数,因为小数用科学计数法表示的时候,小数点是可以“浮动”的,所以称为浮点数。
  53. */
  54. // 单精度浮点数赋值,加 f 后缀
  55. float floatDemo = 9.18f;
  56. // 负的单精度浮点数
  57. float floatNegDemo = -9.18f;
  58. // 科学计数法表示的 3.14x10^38,float 类型可表示的最大数
  59. float floatDemoWithSci = 3.14e38f;
  60. // 科学计数法表示的1.79x10^308,double类型可表示的最大数
  61. double doubleDemo = 1.79e308;
  62. /*
  63. 字符类型
  64. Java 的 字符类可表示标准的 ASCII 和一个 Unicode 字符。
  65. */
  66. // char 用 ascii 字符赋值
  67. char charWithAscii = '.';
  68. // char 用 Unicode 字符赋值
  69. char charWithUnicode = '牛';
  70. // char 多字符会编译报错
  71. // char charCompileError = '蜗牛';
  72. }
  73. }

看完示例代码,你应该能清楚变量定义的格式是 数据类型 变量名; 或者 数据类型 变量名 = 变量值; ,数据类型相当于锁定了这个变量的一个数据范围,等号是赋值符号,代表把等号右边的值赋给左边的变量,使得这个变量在后边的运算中就携带了这个值的信息。

Java 是强类型语言,所以如果等号右边给的值不在变量定义的数据类型范围内,就会编译报错,这也一定程度上避免了我们写错代码。

引用类型

上面提到的变量都是基本类型的,表达的都是非常基础的数值类的信息,那如果想表达更复杂的一些信息,那就要用到引用类型了。

小结

本文从 HelloWorld 程序为例,介绍了 Java 程序的整体结构,帮助大家了解了一个完整的 Java 程序需要具备哪些要素。接着介绍了编程实践的时候躲不开的 Java 变量相关的知识,以及 Java 作为强类型语言,在 Java 规范里所涉及的类型。也通过示例代码的方式,帮助大家加深了认识。