大家好呀,最近很多小伙伴问我一些很基础的问题,看来是基础没有打牢啊,这期我就在代码中带大家回顾Java中的基础知识,可以自己敲一下看看,加深理解。根据这些知识我还整理了一张图,基本上每个知识点都有注释详解。大家有需要的可以找我要。点这里加群领取资料
Java中的类
我们先剖析一个完整的Java程序,它的基本结构是什么:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
因为Java是面向对象的语言,一个程序的基本单位就是class,class是关键字,这里定义的class名字就是Hello:
public class Hello {
}
类名要求: 类名必须以英文字母开头,后接字母,数字和下划线的组合,习惯以大写字母开头。 要注意遵守命名习惯,好的类命名: Hello NoteBook VRPlayer 注意到public是访问修饰符,表示该class是公开的。 不写public,也能正确编译,但是这个类将无法从命令行执行。 在class内部,可以定义若干方法(method):
public class Hello {
public static void main(String[] args) {
}
}
方法定义了一组执行语句,方法内部的代码将会被依次顺序执行。 这里的方法名是main,返回值是void,表示没有任何返回值。 我们注意到public除了可以修饰class外,也可以修饰方法。而关键字static是另一个修饰符,它表示静态方法,后面我们会讲解方法的类型,目前,我们只需要知道,Java入口程序规定的方法必须是静态方法,方法名必须为main,括号内的参数必须是String数组。 方法名也有命名规则,命名和class一样,但是首字母小写: 好的方法命名: main goodMorning playVR 在方法内部,语句才是真正的执行代码。Java的每一行语句必须以分号结束:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
在Java程序中,注释是一种给人阅读的文本,不是程序的一部分,所以编译器会自动忽略注释。
Java中的变量
在Java中,变量分为两种:基本类型的变量和引用类型的变量。 我们先讨论基本类型的变量。 在Java中,变量必须先定义后使用,在定义变量的时候,可以给它一个初始值。例如: int x = 1; 上述语句定义了一个整型int类型的变量,名称为x,初始值为1。 不写初始值,就相当于给它指定了默认值。默认值总是0。 来看一个完整的定义变量,然后打印变量值的例子:
public class Main {
public static void main(String[] args) {
int x = 100;
System.out.println(x);
}
}
运行结果:
100
变量的一个重要特点是可以重新赋值。例如,对变量x,先赋值100,再赋值200,观察两次打印的结果:
public class Main {
public static void main(String[] args) {
int x = 100;
System.out.println(x);
x = 200;
System.out.println(x);
}
}
运行结果:
100 200
注意到第一次定义变量x的时候,需要指定变量类型int,因此使用语句int x = 100;。而第二次重新赋值的时候,变量x已经存在了,不能再重复定义,因此不能指定变量类型int,必须使用语句x = 200;。 变量不但可以重新赋值,还可以赋值给其他变量。让我们来看一个例子:
public class Main {
public static void main(String[] args) {
int n = 100;
System.out.println("n = " + n);
n = 200;
System.out.println("n = " + n);
int x = n;
System.out.println("x = " + x);
x = x + 100;
System.out.println("x = " + x);
System.out.println("n = " + n);
}
}
运行结果:
n = 100 n = 200 x = 200 x = 300 n = 200
Java中的常量
定义变量的时候,如果加上final修饰符,这个变量就变成了常量:
final double PI = 3.14;
double r = 5.0;
double area = PI * r * r;
PI = 300;
常量在定义时进行初始化后就不可再次赋值,再次赋值会导致编译错误。 常量的作用是用有意义的变量名来避免魔术数字(Magic number),例如,不要在代码中到处写3.14,而是定义一个常量。如果将来需要提高计算精度,我们只需要在常量的定义处修改,例如,改成3.1416,而不必在所有地方替换3.14。 根据习惯,常量名通常全部大写。
数据类型
byte,short,int,long四大整型类型
Java只定义了带符号的整型,因此,最高位的bit表示符号位(0表示正数,1表示负数)。各种整型能表示的最大范围如下: byte:-128 ~ 127 short: -32768 ~ 32767 int: -2147483648 ~ 2147483647 long: -9223372036854775808 ~ 9223372036854775807 我们来看定义整型的例子:
public class Main {
public static void main(String[] args) {
int i = 2147483647;
int i2 = -2147483648;
int i3 = 2_000_000_000;
int i4 = 0xff0000;
int i5 = 0b1000000000;
long l = 9000000000000000000L;
}
}
特别注意:同一个数的不同进制的表示是完全相同的,例如15=0xf=0b1111。
float,double两大浮点类型
浮点类型的数就是小数,因为小数用科学计数法表示的时候,小数点是可以“浮动”的,如1234.5可以表示成12.345x102,也可以表示成1.2345x103,所以称为浮点数。 下面是定义浮点数的例子:
float f1 = 3.14f;
float f2 = 3.14e38f;
double d = 1.79e308;
double d2 = -1.79e308;
double d3 = 4.9e-324;
对于float类型,需要加上f后缀。 浮点数可表示的范围非常大,float类型可最大表示3.4x1038,而double类型可最大表示1.79x10308。
字符类型
字符类型char是基本数据类型,它是character的缩写。一个char保存一个Unicode字符:
char c1 = 'A';
char c2 = '中';
因为Java在内存中总是使用Unicode表示字符,所以,一个英文字符和一个中文字符都用一个char类型表示,它们都占用两个字节。要显示一个字符的Unicode编码,只需将char类型直接赋值给int类型即可:
int n1 = 'A';
int n2 = '中';
还可以直接用转义字符\u+Unicode编码来表示一个字符: // 注意是十六进制:
char c3 = '\u0041';
char c4 = '\u4e2d';
字符类型char表示一个字符。Java的char类型除了可表示标准的ASCII外,还可以表示一个Unicode字符:
public class Main {
public static void main(String[] args) {
char a = 'A';
char zh = '中';
System.out.println(a);
System.out.println(zh);
}
}
运行结果:
A 中
注意char类型使用单引号’,且仅有一个字符,要和双引号"的字符串类型区分开。
布尔类型
布尔类型boolean只有true和false两个值,布尔类型总是关系运算的计算结果:
boolean b1 = true;
boolean b2 = false;
boolean isGreater = 5 > 3;
int age = 12;
boolean isAdult = age >= 18;
Java语言对布尔类型的存储并没有做规定,因为理论上存储布尔类型只需要1 bit,但是通常JVM内部会把boolean表示为4字节整数。
整数运算
自增/自减
Java还提供了++运算和–运算,它们可以对一个整数进行加1和减1的操作:
public class Main {
public static void main(String[] args) {
int n = 3300;
n++;
n--;
int y = 100 + (++n);
System.out.println(y);
}
}
运行结果:
3401
位移运算
在计算机中,整数总是以二进制的形式表示。例如,int类型的整数7使用4字节表示的二进制如下: 00000000 0000000 0000000 00000111 可以对整数进行移位运算。对整数7左移1位将得到整数14,左移两位将得到整数28:
int n = 7;
int a = n << 1;
int b = n << 2;
int c = n << 28;
int d = n << 29;
左移29位时,由于最高位变成1,因此结果变成了负数。 类似的,对整数28进行右移,结果如下:
int n = 7;
int a = n >> 1;
int b = n >> 2;
int c = n >> 3;
如果对一个负数进行右移,最高位的1不动,结果仍然是一个负数:
int n = -536870912;
int a = n >> 1;
int b = n >> 2;
int c = n >> 28;
int d = n >> 29;
还有一种不带符号的右移运算,使用>>>,它的特点是符号位跟着动,因此,对一个负数进行>>>右移,它会变成正数,原因是最高位的1变成了0:
int n = -536870912;
int a = n >>> 1;
int b = n >>> 2;
int c = n >>> 29;
int d = n >>> 31;
对byte和short类型进行移位时,会首先转换为int再进行位移。 仔细观察可发现,左移实际上就是不断地×2,右移实际上就是不断地÷2。
位运算
位运算是按位进行与、或、非和异或的运算。 与运算的规则是,必须两个数同时为1,结果才为1:
n = 0 & 0;
n = 0 & 1;
n = 1 & 0;
n = 1 & 1;
或运算的规则是,只要任意一个为1,结果就为1:
n = 0 | 0;
n = 0 | 1;
n = 1 | 0;
n = 1 | 1;
非运算的规则是,0和1互换:
n = ~0;
n = ~1;
异或运算的规则是,如果两个数不同,结果为1,否则为0:
n = 0 ^ 0;
n = 0 ^ 1;
n = 1 ^ 0;
n = 1 ^ 1;
对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:
public class Main {
public static void main(String[] args) {
int i = 167776589;
int n = 167776512;
System.out.println(i & n);
}
}
运行结果:
167776512
上述按位与运算实际上可以看作两个整数表示的IP地址10.0.17.77和10.0.17.0,通过与运算,可以快速判断一个IP是否在给定的网段内。
相关概念
运算优先级
在Java的计算表达式中,运算优先级从高到低依次是:
( ) ! ~ ++ – / % ±<< >> >>> & | += -== /=
记不住也没关系,只需要加括号就可以保证运算的优先级正确。
溢出
要特别注意,整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果: // 运算溢出
public class Main {
public static void main(String[] args) {
int x = 2147483640;
int y = 15;
int sum = x + y;
System.out.println(sum);
}
}
运算结果:
-2147483641
类型转换
在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,short和int计算,结果总是int,原因是short首先自动被转型为int:
public class Main {
public static void main(String[] args) {
short s = 1234;
int i = 123456;
int x = s + i;
short y = s + i;
}
}
运行结果:
Main.java:7: 错误: 不兼容的类型: 从int转换到short可能会有损失 short y = s + i; // 编译错误! ^ 1 个错误 错误: 编译失败
也可以将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用(类型),例如,将int强制转型为short:
int i = 12345;
short s = (short) i;
要注意,超出范围的强制转型会得到错误的结果,原因是转型时,int的两个高位字节直接被扔掉,仅保留了低位的两个字节:
public class Main {
public static void main(String[] args) {
int i1 = 1234567;
short s1 = (short) i1;
System.out.println(s1);
int i2 = 12345678;
short s2 = (short) i2;
System.out.println(s2);
}
}
运行结果:
-10617 24910
因此,强制转型的结果很可能是错的。
浮点数数运算
基本运算和整数运算一样。
相关概念
溢出
整数运算在除数为0时会报错,而浮点数运算在除数为0时,不会报错,但会返回几个特殊值: NaN表示Not a Number Infinity表示无穷大 -Infinity表示负无穷大 例如:
double d1 = 0.0 / 0;
double d2 = 1.0 / 0;
double d3 = -1.0 / 0;
强制转型
可以将浮点数强制转型为整数。在转型时,浮点数的小数部分会被丢掉。如果转型后超过了整型能表示的最大范围,将返回整型的最大值。例如:
int n1 = (int) 12.3;
int n2 = (int) 12.7;
int n2 = (int) -12.7;
int n3 = (int) (12.7 + 0.5);
int n4 = (int) 1.2e20;
如果要进行四舍五入,可以对浮点数加上0.5再强制转型:
public class Main {
public static void main(String[] args) {
double d = 2.6;
int n = (int) (d + 0.5);
System.out.println(n);
}
}
运行结果:
3
类型提升
如果参与运算的两个数其中一个是整型,那么整型可以自动提升到浮点型:
public class Main {
public static void main(String[] args) {
int n = 5;
double d = 1.2 + 24.0 / n;
System.out.println(d);
}
}
运行结果:
6.0
需要特别注意,在一个复杂的四则运算中,两个整数的运算不会出现自动提升的情况。例如:
double d = 1.2 + 24 / 5; // 5.2
计算结果为5.2,原因是编译器计算24 / 5这个子表达式时,按两个整数进行运算,结果仍为整数4。
布尔运算
对于布尔类型boolean,永远只有true和false两个值。 布尔运算是一种关系运算,包括以下几类: (因为符号比较多,与编辑器的一些指令冲突,全用代码块表示了)
比较运算符:>,>=,<,<=,==,!=
与运算 &&
或运算 ||
非运算 !
下面是一些示例:
boolean isGreater = 5 > 3;
int age = 12;
boolean isZero = age == 0;
boolean isNonZero = !isZero;
boolean isAdult = age >= 18;
boolean isTeenager = age >6 && age <18;
关系运算符的优先级从高到低依次是:
!
>,>=,<,<=
==,!=
&&
||
短路运算
布尔运算的一个重要特点是短路运算。如果一个布尔运算的表达式能提前确定结果,则后续的计算不再执行,直接返回结果。 因为false && x的结果总是false,无论x是true还是false,因此,与运算在确定第一个值为false后,不再继续计算,而是直接返回false。 我们考察以下代码:
public class Main {
public static void main(String[] args) {
boolean b = 5 < 3;
boolean result = b && (5 / 0 > 0);
System.out.println(result);
}
}
运行结果:
false
如果没有短路运算,&&后面的表达式会由于除数为0而报错,但实际上该语句并未报错,原因在于与运算是短路运算符,提前计算出了结果false。 如果变量b的值为true,则表达式变为true && (5 / 0 > 0)。因为无法进行短路运算,该表达式必定会由于除数为0而报错,可以自行测试。 类似的,对于||运算,只要能确定第一个值为true,后续计算也不再进行,而是直接返回true: boolean result = true || (5 / 0 > 0); // true
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。 可以的话请给我一个三连支持一下我哟,我们下期再见
领取资料
|