程序跑起来后运行结果却有BUG?
0X01 前言
对于有些编程经验的小伙伴来说,当他学过一门编程语言后,再去学习其他语言时,都会感觉这和某某语言很相似,貌似感觉都会,于是针对初期的基础知识学习也就会眼高手低,那么其实这些编程语言的基础语法知识到底有多重要呢?通过后期大量的写各种代码和实战写项目,就会发现其实有时候的BUG就是那些学习基础知识的盲区导致的,由于程序可用正常跑起来,但运行结果却始终不对,这种问题一般也很难发现。先看两段代码体会体会!
0X02 你的代码
- 代码一
class Student{
private int id;
private String name;
private int age;
void print(){
System.out.println(this.id + '\n' + this.name + '\n' + this.age);
}
public static void main(String [] arg){
Student xm = new Student();
xm.id = 10086;
xm.name = "小明";
xm.age = 18;
xm.print();
}
}
上面代码执行后结果是什么呢?
预期结果:
10086
小明
18
实际结果:
10096小明
18
- 代码二
class TestBug {
public static void main(String[] args) {
String a = "Hello";
// \u000d a="world";
System.out.println(a);
// \u000a a="hello world!";
System.out.println(a);
}
}
上面的代码运行结果是什么呢?注释真的不会执行吗?
预期结果:
Hello
Hello
实际结果:
world
hello world!
0X03 BUG分析
通过观察代码一的执行结果可以发现,在打印语句处出现了两个问题:
- 学生id打印结果不正确,应该为10086却加了10打印出来了10096
- 学生id打印后换行符未能正常打印,直接打印出来了学生姓名
说到这里,你应该能够知道问题出现在了哪。
Java语法基础知识恶补
在Java语言中,数据类型分为基本数据类型和引用数据类型。其中基本数据类型又可以分为数值型、字符型和布尔型。
数值型包括:整数类型(byte、short、int、long);浮点类型(float、double);其中Java的整型常量默认为 int 型,Java 的浮点型常量默认为double型。
字符型(char)数据用来表示通常意义上“字符”(2字节),字符型常量的三种表现形式:
- 字符常量是用单引号(‘ ’)括起来的单个字符,涵盖世界上所有书面语的字符。例如:char c1 = 'a'; char c2 = '中'; char c3 = '9';
- Java中还允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。例如:char c3 = ‘\n’; // ‘\n’表示换行符
- 直接使用 Unicode 值来表示字符型常量:‘\uXXXX’。其中,XXXX代表一个十六进制整数。例如:\u000a 表示 \n。
char类型是可以进行运算的。因为它都对应有Unicode码。
boolean 类型适于逻辑运算,一般用于程序流程控制,只允许取值true和false,无null。
不可以0或非 0 的整数替代false和true,这点和C语言不同。
基本数据类型转换
自动类型转换:容量小的类型自动转换为容量大的数据类型。
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。
byte,short,char之间不会相互转换,他们三者在计算时首先转换为int类型。
当把任何基本类型的值和字符串值进行连接运算时(+),基本类型的值将自动转化为字符串类型。
强制类型转换:自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符 (),但可能造成精度降低或溢出,格外要注意。
所以,上面的打印语句中,在执行this.id + '\n'
时,因为id为int型,转移字符'\n'为char类型,在进行+运算时会自动转换为int类型与之相加。通过下面强制类型转换我们可以发现转移字符'\n'转换为int类型后为10.
class TestBug {
public static void main(String[] args) {
char c = '\n';
System.out.println((int)c);
}
}
//10
于是执行打印语句时,就会把10086与10相加得到的值10096,再和字符串姓名相连接打印出来。
通常,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型。
如:String a = “43”; int i = Integer.parseInt(a);
boolean类型不可以转换为其它的数据类型。
通过观察代码二的执行结果可以发现,注释中的Hello World被打印了。
众所周知,在计算机内部,所有数据都使用二进制表示。那么如何简便的将现实世界常用的字符在计算机中表示呢?于是就有了各种编码。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码。ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
这种编码涵盖的字符太有限了,因为是美国人规定的,所以只有他们常用的英文字母和一些特殊字符。但是对于不同国家语言很显然就不适用了,于是就出现了各种各样的编码。
世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。
后来有了Unicode这种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,使用 Unicode 没有乱码的问题。
在Java中,JVM内部,所有的字符都是用Unicode编码的。
于是在处理上面代码二时,注释中的\u000a正好对应字符‘\n’,\u000d正好对应字符‘\r’,于是jvm就会执行相应操作。代码就变成了:
class TestBug {
public static void main(String[] args) {
String a = "Hello";
//
a="world";
System.out.println(a);
//
a="hello world!";
System.out.println(a);
}
}
所以,Java的编译器不仅会去编译代码,也会去解析Unicode字符。
0X04 总结
通过上面两个小示例,大家应该也能体会到学习编程语言的基础语法知识的重要性,其实通过日常写的代码,不难发现用到的不就是这些简单的基础知识吗,比如三大控制结构,字符处理,字符串处理等等。正所谓"树高千尺,营养还在根部",正是这个道理吧!
0X05 微信关注