回炉重造之Java基础语法
前言
这篇文章主要记录Java回炉重造的基础阶段的学习。
Java基础语法
基本数据类型
java主要分为基本数据类型和引用数据类型,其中基本数据类型分为数值型(整数和浮点数)、字符型、布尔型,引用数据类型分为类、接口、数组
| 基本数据类型 | 占用的字节数 | 数据范围 |
|---|---|---|
| byte | 1 | -128 ~ 127 |
| short | 2 | -32768 ~ 32767 |
| int | 4 | -2147483648 ~ 2147483647 |
| long | 8 | -2^63 ~ 2^63-1 |
| float | 4 | -3.403E38 ~ 3.403E38 |
| double | 8 | -1.798e308 ~ 1.798E308 |
| char | 2 | - |
整型
Java中整型默认为int型,声明long型常量需要在后面加上”l”或者”L”,变量一般声明为int型,除非不足才用long以节省资源。
1 | int n1 = 1;//四个字节 正确的 |
浮点数
由于二进制转换的问题,计算机中的浮点数均为近似数,Java中的浮点数默认是double,声明float变量的时候后面要加上”f”或者”F”,浮点数的常量通常用十进制如5.12 .512 512.0f或者科学计数法如5.12e2 5.12E-1 分别代表5.1210^2 和5.1210^-2,通常来说应该使用double以此来保留精度。
1 | double m = 2.1234567851;//正确 |
字符类型
字符类型可以存放的是单个字符,char类型占用两个字节这样可以存中文,多个字符使用String类型。char的本质是一个编码的整数。
1 | char c1 = 'a';//正确的 存单个字符 |
布尔类型
布尔类型只有true和false,没有null,boolean类型适合用于逻辑运算。注意Java和C语言不一样,不可以用0和非0数来表示true和false。编译阶段就会报错。
自动类型转换
Java可以对数据类型进行自动转换,精度小的类型自动转换为精度大的类型,转换规则有两种方式:
char -> int -> long -> float -> double
byte -> short -> int -> long -> float -> double
注意:(byte short)与char 不能自动转换,但是三者之间可以计算,计算之前会自动转换成int类型。boolean不参与运算。所有数据类型参与运算时,会把结果提升为所有数据类型中精度最大的。
1 | float d = 1 + 1.1;//直接报错 右边是double类型 左边是float |
强制类型转换
自动类型转换的逆过程,将精度大的类型转换成精度小的类型,使用时候要加上强制转换符(),但可能会造成精度降低或溢出,格外注意!
1 | int n1 = (int)1.9;//正确 但是输出的结果是1 精度丢失 |
String和基本数据类型转换
String转成基本数据类型时,必须确保能正确转换,例如”hello”就不能转成int类型,否则会抛出异常。
1 | int n1 = 100; |
运算符
运算符主要包含算数运算符、赋值运算符、关系(比较)运算符、逻辑运算符、位运算符、三元运算符。
算术运算符
算数运算符包含+、-、*、/、%、++、–。
1 | System.out.println(10 / 4); //左右都是整数 结果是2 不是2.5 |
关系运算符
关系运算符的结果都是boolean类型,主要用在循环或者判断条件中。> < != ==
逻辑运算符
逻辑运算符用于连接多个条件,结果也是boolean类型。短路于&&,短路或||,取反!,逻辑于&,逻辑或|,^异或
| a | b | a&b | a&&b | a|b | a||b | !a | a^b |
|---|---|---|---|---|---|---|---|
| true | true | true | true | true | true | false | false |
| true | false | false | false | true | true | false | true |
| false | true | false | false | true | true | true | true |
| false | false | false | false | false | false | true | false |
1 | //&& 和 & 的区别: |
赋值运算符
赋值运算符分为基本赋值运算符(=)以及复合赋值运算符: +=、-=、*=、/=、%=等。赋值运算符顺序是从右往左,左边只能是变量,右边可以是变量、表达式、常量值。
1 | byte b = 3; //复合赋值运算符会进行自动类型转换 |
三元运算符
基本语法:条件表达式 ? 表达式1 : 表达式2,如果条件表达式为true,则运算后的结果为表达式1,否则为表达式2。表达式1和表达式2要为可以赋给接受变量的类型或者可以自动转换
1 | int a = 3; int b = 4; |
运算优先级
忘了的时候再查表,但是记住从右往左运算的只有单目运算符和赋值运算符。
标识符
Java中对各种变量、方法和类等明明时使用的字符序列称为标识符。标识符的基本规则:
- 由26个英文字母大小写,0-9,_或$组成
- 数字不可以开头,例如int 3ab;是错误写法
- 不可以用关键字和保留字,但能包含关键字和保留字
- Java中严格区分大小写,长度没有限制
- 标识符不可以包含空格
标识符规范
包名:多单词组成时所有字母都小写:com.hsp.com
类名、接口名:多单词组成时,所有单词的首字母大写:TankShotGame
变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:tankShotGame
常量名:所有字母都大写。多单词时每个单词用下划线链接:TAX_RATE
关键字和保留字
关键字是被Java赋予了特殊的含义,用作专门用途的字符串,所有关键字都是小写单词,比较多,在idea中会变色提示。保留字是当前的Java版本还没有使用,但以后的版本可能会用,依然无法作为标识符。
进制
对于整数,有四种的表示方式:
- 二进制:0,1,满2进1,以0b或0B开头
- 十进制:0-9,满10进1
- 八进制:0-7,满8进1
- 十六进制:0-9及A(10)-F(15),满16进1,以0x或0X开头,注意此处的A-F不区分大小写
进制转换
第一组:
二进制转十进制
规则:从最低位(最右边)开始,将每个位上的数提取出来,乘以2的(位数-1)次方,然后再求和。
案例:把0b1011转成十进制
0b1011 = 1* 2^(1-1) + 1 * 2^(2-1) + 0 * 2^(3-1) + 1 * 2^(4-1) = 11 (十进制数)八进制转十进制
规则:从最低位(最右边)开始,将每个位上的数提取出来,乘以8的(位数-1)次方,然后再求和。
案例:把0234转换成10进制数 注意0开头表示8进制数
0234 = 4 * 8^0 + 3 * 8^1 + 2 * 8^2 = 4 + 24 + 128 = 156十六进制转十进制
规则:从最低位(最右边)开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后再求和。
案例:0x23A转换成十进制数
0x23A = 10 * 16^0 + 3 * 16^1 + 2 * 16^2 = 10 + 48 + 512 = 570
第二组:
十进制转二进制
规则:将该数不断除以2,直到商为0为止,然后将每步得到的余数倒序输出,就是对应的二进制
案例:把34转成二进制
34 / 2 = 17-0 17 / 2 = 8-1 8 / 2 = 4-0 4 / 2 = 2-0 2 / 2 = 1 -0 => OB00100010 (倒序输出但整数4字节存储 不满1字节的前面补0)十进制转八进制
规则:将该数不断除以8,直到商为0为止,然后将每步得到的余数倒序输出,就是对应的八进制十进制转十六进制
规则:将该数不断除以16,直到商为0为止,然后将每步得到的余数倒序输出,就是对应的十六进制
第三组:
二进制转八进制
规则:从地位开始,将二进制数每三位一组,转成对应的八进制数即可。
案例:把0b11010101 => 101(5) 010(2) 11(3) => 0325二进制转十六进制
规则:从地位开始,将二进制数每四位一组,转成对应的十六进制数即可。
案例:把0b11010101 => 0101(5) 1101(D) => 0xD5
第四组:
八进制转二进制
规则:将八进制数每一位,转成对应的一个3位的二进制数即可
案例:0237转成二进制数
0237 = 7(111) 3 (011) 2(010) = 0b10011111(8bit直接不要前面的0)十六进制转二进制
规则:将十六进制数每一位,转成对应的一个4位的二进制数即可
案例:0x23B转成二进制数
0x23B = B(1011) 3(0011) 2(0010) = 0b001000111011
原码 反码 补码(重难点)
- 二进制的最高位是符号位:0表示正数,1表示负数(口诀:0->0 1-> -)
- 正数的原码、反码、补码都一样(三码合一)
- 负数的反码 = 它的原码符号位不变,其他位取反(0->1,1->0)
- 负数的补码 = 它的反码+1,负数的反码 = 负数的补码-1
- 0的反码、补码都是0
- java没有无符号数,换言之,java中的数都是有符号的
- 在计算机运算的时候,都是以补码的方式来运算的 (这样可以把正数和负数统一起来)
- 当我们看运算结果的时候,要看他的原码 (重点)
位运算符
Java中有7个运算符,它们的运算规则是:
按位与 & : 两位全是1,结果为1,否则为0
按位或 | : 两位有一个为1,结果为1,否则为0
按位异或^ :两位为0,一个为1,结果为1,否则为0
按位取反~ :0->1,1->0
例如:2&3
首先得到2的补码 => 2是正数只需要原码 00000000 00000000 00000000 00000010
同理得到3的补码 => 3 00000000 00000000 00000000 00000011
运算后的补码为00000000 00000000 00000000 00000010 由于是正数这也是补码,转成十进制是2,同理,负数与正数的区别是在最高位为1
案例:22操作得到运算补码 11111111 11111111 11111111 11111101
1.得到2的补码 00000000 00000000 00000000 00000010
2.
3.运算后的反码(补码-1) 11111111 11111111 11111111 11111100
4.运算后的原码(最高位不变) 10000000 00000000 00000000 00000011
5.~2 = -3
算术左移、右移、逻辑右移 >>、<<、>>>
算术右移>>:低位溢出,符号位不变,并用符号位补溢出的高位
算数左移<<:符号位不变,低位补0
逻辑右移>>>:低位溢出,高位补0
特别说明是没有<<<这个符号
案例:
1 | int a = 1 >>2;// => 00000001 => 00000000 (01被扔掉) 本质是 1 / 2 / 2 =0 |
控制结构
控制结构分为顺序控制、分支控制(if,else,switch)、循环控制(for,while,dowhile,多重循环)、break、continue、return
顺序控制
程序从上到下逐行的执行,中间没有任何判断和跳转。即执行语句1->执行语句2->执行语句n
1 | int num1 =12; |
分支控制
分支控制是让程序有选择的执行,分支控制有三种:单分支、双分支、多分支,分支之间可以嵌套,嵌套尽可能不要超过三层。
1 | //单分支: |
循环控制
for循环控制:循环条件是返回一个布尔值的表达式,for循环中的初始化和迭代可以写到循环体内,但两边的分号不可省略。
1 | for(循环变量初始化;循环条件;循环变量迭代){ |
while和dowhile循环:while和for循环一样也有四要素,只是位置不同
1 | while(循环条件){ |
break细节:当break出现在多层嵌套语句的时候,可以用标签来指明要终止的是那一层的语句块,建议最好别用标签来结束。break不带标签会自动退出最近的一层label
1 | label1: |
continue细节:
continue和label搭配使用的时候也是默认结束最近的这一次label,如果没有label就是当前大括号最近的循环层。
数组
数组可以存放多个同一类型的数据,数组也是一种数据结构,是引用类型。数组是解决多个相同类型变量产生的数量自定义的问题。
数组的定义方式有三种:
1 | //动态初始化1 |
数组的注意事项
- 数组是多个相同类型的组合,如果不同数据类型之间必须要可以自动转换 例如从int到double 但不能把double放到int数组中。
- 数组的元素可以放任何数据类型,包括基本类型和引用类型,但不能混用
- 数组创建后如果没有赋值,是带有默认值的,int,short,byte,long都为0,float,double是0.0,chart是\u0000,boolean是false,String是null
- 数组的下标从0开始,其自带了length属性表示长度。
- 数组下标必须在合理范围使用否则会报越界异常
- 数组属于引用类型,数组型数据是对象(Object)
数组赋值机制
基本数据类型是采用的值拷贝的方式,当一个变量赋值给另一个变量的时候,两个变量之间并不存在直接关联关系,第二个变量的变化不会影响第一个变量,但数组的赋值方式是引用传达,其赋值的是一个地址,因此会影响到原数组,基本原理是JVM当中栈和堆的使用。
1 | int n1 = 10; |
数组扩容
数组定义的时候是直接固定了大小的,因此希望可以实现动态的数组扩容。思路:创建一个新数组长度是原数组的长度+1,数据拷贝后最后一个数据放到数组尾部。(后期用集合实现自动扩容)
1 | int[] arr = {1,2,3}; |
二维数组
很多时候我们需要用到二维数组,例如一维数组代表一行的话,二维数组可以代表N行N列的矩阵,二维数组的创建方式和一维数组类似,二维数组可以看作一维数组,这个一维数组的每一个元素都是另一种一维数组,例如2行3列的二维数组创建的时候首先在栈当中开辟2个地址,然后这两个地址分别指向另外2个长度为3的堆内存的地址。
1 | int[][] arr = {{0,0,0},{1,1,1},{2,2,2}}; |




