package cn.ideal.javase;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld !");
}
}
上面的代码,就是一个最简单的 Java 程序 —— HelloWorld,它也是梦开始的地方。
别看程序虽小,但是五脏俱全,package、public、class、static 关键字, 类注释,HelloWorld 类名,main 主函数,println() 输出打印方法,"HelloWorld !" 关键字。各个不同的语法结合,就构成了这个入门的程序。
如果看不明白,没关系,这就是这一篇文章想要讲解的。
1. 关键字关键字是被Java语言赋予特定含义的单词,他们有着特定的使用位置和方式。
注意:
-
关键字全都是小写。
-
goto 和 const 作为保留字存在。
-
常见的 IDE 如 IDEA、Eclipse,以及 Noepad++、Sublime Text 等编辑器对关键字有特殊颜色标记,这也是人们常说的代码高亮。
列举:
虽然下面表格中,你或许大部分关键字都没有见过,这里不必细究其含义,也不必去刻意记忆,因为后面都会涉及到,但是你只需要记住一点:下面表格中 接近 100% 的关键字将会陪伴你的 Java 生涯!
| 类别 | 关键字 |
|---|---|
| private | 私有的 |
| protected | 受保护的 |
| public | 公共的 |
| abstract | 声明抽象 |
| class | 类 |
| extends | 扩充,继承 |
| final | 最终值,不可改变的 |
| implements | 实现(接口) |
| interface | 接口 |
| native | 本地,原生方法(非Java实现) |
| new | 新,创建 |
| static | 静态 |
| strictfp | 严格,精准 |
| synchronized | 线程,同步 |
| transient | 短暂 |
| volatile | 易失 |
| break | 跳出循环 |
| case | 定义一个值以供switch选择 |
| continue | 继续 |
| default | 默认 |
| do | 运行 |
| else | 否则 |
| for | 循环 |
| if | 如果 |
| instanceof | 实例 |
| return | 返回 |
| switch | 根据值选择执行 |
| while | 循环 |
| assert | 错误处理,断言表达式是否为真 |
| catch | 捕捉异常 |
| finally | 有没有异常都执行 |
| throw | 抛出一个异常对象 |
| throws | 声明一个异常可能被抛出 |
| try | 捕获异常 |
| import | 引入包 |
| package | 包 |
| boolean | 布尔型 |
| byte | 字节型 |
| char | 字符型 |
| double | 双精度浮点 |
| float | 单精度浮点 |
| int | 整型 |
| long | 长整型 |
| short | 短整型 |
| super | 父类,超类 |
| this | 本类 |
| void | 无返回值 |
| goto | 保留关键字,是关键字,但不能使用 |
| const | 保留关键字,是关键字,但不能使用 |
| null | 空 |
标识符就是给类,接口,方法,变量等起名字的字符序列。
-
PS:这几个概念不熟悉没关系,这一篇和下一篇会依次讲到。
组成规则:
-
首字符:字母(A-Z、a-z)、美元符($)、下划线(_)
-
首字符之后:字母(A-Z、a-z)、美元符($)、下划线(_)或者数的任何字符组合
注意事项:
-
区分大小写
-
不能以数字开头
-
关键字不能作为标识符
组成规范:
命名规范是我们不得不提的一个话题,虽说命名本应该是自由的,但是仍然有一定的“潜规则”,通过你对命名的书写,别人一眼就能看出你是不是一个“行家”。而且往往这些规范,能巧妙的帮助我们规避很多潜在的风险。
-
例如 《阿里巴巴 Java 开发手册》《代码整洁之道》等都对命名做出了不同程度的限制推荐。
下面的引用来自 《阿里巴巴 Java 开发手册》:
3. 注释 3.1 定义
【强制】所有编程相关命名均不能以下划线或美元符号开始,也不能以下划线或美元符 号结束。
反例:name / __name / Object / name / name/ Object
【强制】所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 变量 = 3;
正例:ali / alibaba / taobao /cainiao / aliyun / youku / hangzhou 等国际通用的 名称,可视为英文。
注释就是对程序进行解释说明的文字(不会被编译运行)
其目的是为了方便自己或别人后期阅读这部分代码的提示,能够快速的让阅读者了解这部分代码的作用。
当你需要维护一个老项目的代码时,几万甚至几十万行的代码量非常常见,除了相对规范的包结构和文档能把你带到入口处(前后端接口),如何去梳理业务的逻辑就大大的依赖你的技术经验和前人的注释了。
虽然有个梗:“只要我的代码谁也看不懂,我在公司就是不可或缺的”,不过这句话图个乐就得了,如果不养成良好的习惯,以后团队协作和提交前/日后 review 代码就会变得异常折磨。
-
单行注释
// 这行注释
-
多行注释
-
文档注释(JavaDoc 注释)如下:
类注释
方法注释
编写代码时,类注释和方法注释都必须使用 JavaDoc 注释,而不是 // 这种单行注释,类能看到作者以及描述创建时间,方法能不进入代码块的情况下方便的看到方法描述和参数以及返回值。
4. 常量 4.1 定义常量就是在程序执行的过程中,其值不发生改变的量(例如π、重力加速度,光速等)
在 Java 中我们使用 final 关键字来修饰常量
-
eg: final double PI = 3.1415927
注意:虽然常量名也可以用小写,但为了便于识别,通常使用大写字母 表示常量,这也算是大家默认的要求。
4.2 怎么用?一般来说,我们写代码时,是不允许出现魔法值的(即未预先经过定义的值)
例如根据 id 查询用户的昵称和头像时,如果查询不到,则给一个默认值,避免直接返回 null。
// 例如 userInfo 就是查询到的用户信息
if (userInfo == null || StingUtils.isBlank(userInfo.getUserName)){
userInfo.setUserName("用户");
}
像 userInfo.setUserName("用户"); 中的 "用户" 就是魔法值,因为我们并没有事前定义它,所以可以定义一个常量类,其中使用 final 修饰我们想定义的常量。
public class DefaultInfoConstant {
public static final String DEFAULT_PERSON_HEAD_IMAGE_URL = "xxx.png";
public static final String DEFAULT_USER_NAME = "用户";
}
这样就可以这样调用了,以后所有调用了这个常量的部分我们都不需要去操心了,修改这个常量类即可,所有引用它的地方都会跟着变化了。
// 例如 userInfo 就是查询到的用户信息
if (userInfo == null || StingUtils.isBlank(userInfo.getUserName)){
userInfo.setUserName(DefaultInfoConstant.DEFAULT_USER_NAME);
}
5. 变量
5.1 定义
我们刚介绍了什么是常量,那么什么是变量呢,顾名思义,变量就是在某个范围内可以变化的量,其实它就是一个被你所定义的变量,在一个数据类型的约束下,可以在数据类型所允许的范围内进行,被赋值,运算,等操作。
image.png
格式:数据类型 变量名 = 初始化值
注意:可以在一行中声明多个变量,但是我们不推荐这种方式。
尤其真实项目中往往变量名会比较长,逐一声明变量能提高程序的可读性。
// 不推荐 String name, address; // 推荐 String name; String address;5.2 变量类型
-
局部变量
-
实例变量
-
类变量(静态变量)
局部变量就是定义在方法、构造方法、或者语句块中的变量
public class HelloWorld {
public static void main(String[] args) {
// 下一行的 name 会报错
System.out.println(name);
}
public static void testMethod() {
String name = "张三";
}
}
局部变量即只能在一定范围内使用的变量,随着这个方法/语句块的结束,这个变量也就无效了。(生而带来,死而带去 只能活在自己的世界),所以上述代码中,我们在 testMethod 方法中定义了 name 字符串,其值为 "张三",但是这也就意味着这个变量的作用域只在 testMethod 方法中,自然不能在别的地方,例如 main 函数中去调用了。
PS:对于局部变量的理解,刚入门可能也不会太深,等后面几篇我们学习到方法后,再回过头来看这部分内容,就会有一种明了的感觉。
5.2.2 实例变量实例变量:声明在类中,但在方法、构造方法和语句块之外
public class Student {
private String name;
private int age;
public void print(){
System.out.println("print: " + name + ", " + age);
}
}
实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见。例如文中的 name 和 age 就都是实例变量,在同一个类中的 print 方法中是可以直接访问的,同时利用 private 控制了变量的可访问范围。
暂时在学习基础语法知识的时候可以暂时忽略实例变量这部分内容,这部分内容主要被使用在面向对象的部分,但是极其重要。
5.2.3 类变量static 修饰的变量也称作静态变量,静态变量属于类,所以也称为类变量,存储于方法区中的静态区,随着类的加载而加载,消失而消失,可以通过类名调用,也可以通过对象调用。
例如在 Student 类中定义两个 public 修饰的变量 name 和 address,而且其中 name 是用 static 修饰的,即是一个类变量。
public class Student {
public static String name;
public String address;
}
当我们在另一个类中去调用这个变量的时候,只有 name 可以用类名调用。而 address 就必须创建对象后才能调用。(这部分后面的文章会讲到)
public class Demo {
public void testMethod() {
// 可以用类名调用
String name = Student.name;
// 不可以
String address = Student.address;
}
}
6. 数据类型
6.1 定义
Java是一种强类型的语言,针对每一种数据都定义了明确的数据类型(就是将一些值的范围做了约束,从而为不同类型的值在内存中分配不同的内存空间)
注意:在此部分暂时不用深究引用类型,着重认熟悉一下基本数据类型,引用类型在面向对象的部分会详细解释。
我们来看一下八种基本数据类型的详细说明:
| Name | Size* | Rang |
|---|---|---|
| byte | 1byte | 8bit |
| short | 2bytes | 16bit |
| int | 4bytes | 32bit |
| long | 4bytes | 64bit |
| float | 4bytes | 32bit |
| double | 8bytes | 64bit |
| boolean | 只有true和false两个取值。 | |
| char | 2bytes | 存储Unicode码,用单引号赋值。 |
注意:
-
整数默认是 int 类型。
-
声明 long 型常量的时候长整数要加 L 或者 l。
-
一些字体下 1 和 l 容易混淆,所以规范书写,都加大写 L。
如:long l = 66666666666666L; // 否则报错
-
浮点数默认是 double(双精度浮点型)。
声明 float 型(单精度的浮点数)要加 F 或者 f。
double d = 521.1;// double 不需要加字符 float f = 52.1f; // float 必须加f
-
boolean 一般用来进行逻辑运算 - 流程控制中。
-
byte、short 类型被赋值时,其实接收的是一个 int 类型的值,不在范围内即报错。
-
一个中文字符占据两用字节,Java中字符可以存储一个汉字,是因为Java字符采用Unicode编码,每个字符占用两个字节。
-
Java中提供了三个特殊的浮点数值,正无穷大(正数除以 0),负无穷大(负数除以0),NaN(不是一个数字,0 除以 0,负数开根号)。
一般来说,我们在运算的时候,要求参与运算的数值类型必须一致,很多时候就需要进行数据类型的转换。类型的转换大致分为两种:
-
默认转换
-
强制转换
默认转换就是从小类型转换为大类型的自动类型转换。
-
这个大小是按照它们各自代表的数据存储范围来的。
-
排序如下:byte、short、 char、 int、 long、float、double
-
int → long → float → double 这几者可以按顺序转换,而 byte,short, char 相互之间不转换。
举个例子:int 类型的 520 可以被 long 类型的变量接收,然后输出。
public static void main(String[] args) {
int numInt = 520;
long numLong = numInt;
System.out.println(numLong);
}
疑惑:为什么 float(4个字节)在 long(8个字节)后面?
-
它们底层的存储结构不同
-
float 表示的数据范围比long范围要大
long:2^63-1 float:3.410^38 > 210^38 > 28^38 > 22^3^38 = 2*2^144 > 2^63 -1
正例:低精度byte到高精度int 会根据默认转换,自动转换类型
反例:高精度int到低精度byte 可能会损失精度
public class Demo {
public static void main(String[] args) {
byte a = 3;
int b = 4;
byte c = a + b;
System.out.println(c);
}
}
image.png
byte 数据类型是 1个字节、8位
int 数据类型是 4个字节、32位
但是有没有办法能够让我们输出这种运算的结果呢?这就需要我们用到强制类型转换的知识。
格式:目标数据类型 变量 = (目标数据类型)被转换的数据
int i = 128; // 格式如下 byte b = (byte)i;
注意:
-
在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
-
不要随便的去用强制转化,因为它隐含了精度损失的问题。
-
如上述代码:因为 byte 类型是8位,最大值为 127,所以当 int 强制转换为 byte 类型的时候,值 128 就会导致溢出。
来看两个例子:
6.2.2.1 例子:变量相加赋值和常量相加赋值
public static void main(String[] args) {
byte b1 = 3;
byte b2 = 4;
byte b;
// 下面两个赋值有什么区别吗
b = (byte) (b1 + b2);
b = 3 + 4;
System.out.println(b);
}
第一个赋值语句:
-
byte 类型的 b1,b2 相加,自动类型转换为 int 型,int 类型的(b1 + b2) 赋值给 byte 类型的 b,属于大单位转换为小单位 可能造成精度损失。
第二个赋值语句:
-
3 和 4 为常量,编译过程中 先把结果计算出来,然后看是否在 byte 的范围内,如果在就不报错。
总结:
-
变量相加,会首先看类型问题,最终把结果赋值也会考虑类型问题。
-
常量相加,首先做加法,然后看结果是否在赋值的数据类型范围内,如果不是,才报错。
再配合下一个例子,大家就能深刻的理解丢失精度的意义了。
6.2.2.2 例子:强转后丢失精度
public static void main(String[] args) {
byte b = 130;
byte b = (byte) 130;
System.out.println(b);
}
-
当你打出 byte b = 130; 时,编译器应该已经在代码处报红了,因为 byte 的范围是:-128 到 127,所以报错了。
-
它下方的 byte b = (byte) 130; 使用了强制类型转换却不会报错,并且能输出结果 -126。
分析(原反补码将在下面具体介绍)
我们想要知道结果是什么,就应该知道是如何计算的,而我们又知道计算机中数据的运算都是补码进行的。
得到补码,首先要计算出数据的二进制,如下,求出130的二进制 10000010
130 是一个整数 所以补齐4个字节 (一个字节8位) 0000000 00000000 00000000 10000010
接着做截取操作,截成 byte 类型的 10000010,而这个结果是补码,如下表已知补码求原码,最后的结果是 11111110 转换为十进制为 -126
| 值位 | 符号位 | 数值位 |
|---|---|---|
| 补码: | 1 | 0000010 |
| 反码: | 1 | 0000001 |
| 原码 | 1 | 1111110 |
字符是指在计算机中所使用的 字母、数字、汉字、和符号,表示时用单引号包含在内。例如:'5' 和 'R' 和 '和' 均是字符
在内存中,字符数据以ASCII码存储 ,即以整数表示
需要记忆的常见字符 'a' → 97 'A' → 65 '0'→ 48,其余字符依次递推即可
| 值 | 符号 | 值 | 符号 | 值 | 符号 | 值 | 符号 |
|---|---|---|---|---|---|---|---|
| 0 | 空格符 | 42 | * | 62 | > | 123 | { |
| 32 | 空格 | 43 | + | 63 | ? | 124 | | |
| 33 | ! | 44 | , | 64 | @ | 125 | } |
| 34 | " | 45 | - | 65~90 | A~Z | 126 | ~ |
| 35 | # | 46 | . | 91 | [ | 127 | Delete 键 |
| 36 | $ | 47 | / | 92 | |||
| 37 | % | 48~57 | 0~9 | 93 | ] | ||
| 38 | & | 58 | : | 94 | ^ | ||
| 39 | ' | 59 | ; | 95 | - | ||
| 40 | ( | 60 | < | 96 | ` | ||
| 41 | ) | 61 | = | 97~122 | a~z |
有一些特殊的字符叫做转义字符,其格式为通过 + 一些特定的字母
转义 + 字符 = 转移字符 = 转变含义的字符(不再是本来字符的意思)
| 转义字符 | 意义 | ASCII码值(十进制) |
|---|---|---|
| a | 响铃(BEL) | 007 |
| b | 退格(BS) ,将当前位置移到前一列 | 008 |
| f | 换页(FF),将当前位置移到下页开头 | 012 |
| n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
| r | 回车(CR) ,将当前位置移到本行开头 | 013 |
| t | 水平制表(HT) (跳到下一个TAB位置) | 009 |
| v | 垂直制表(VT) | 011 |
| 代表一个反斜线字符''' | 092 | |
| ' | 代表一个单引号(撇号)字符 | 039 |
| " | 代表一个双引号字符 | 034 |
| ? | 代表一个问号 | 063 |


