1. 语法结构
1. 包声明:必须在文件顶部
2. 导入语句:导入用到的其他类
3. 类定义:定义class类,主类的类名要和文件名一致,大驼峰命名
4. main方法:程序入口
package com.example.demo; // 包声明 import java.util.Scanner; // 导入 public class HelloWorld { // 类名 // 程序入口 public static void main(String[] args) { System.out.println("Hello World!"); } }2. 命名规范
基本规范:
- 只能包含数字,字母,下划线_,美元符$
- 不能以数字开头
- 不能使用Java中的关键字(如 class,void,int...)
- 严格区分大小写
- 需要做到在命名类、对象或变量时,能够望文生义(尽量采用英文命名)
大驼峰命名:指每个单词的首字母都大写(例如:StudentInfo,StudentMangager...),通常用于类的命名
小驼峰命名:指第一个单词首字符小写,后续单词首字符大写(例如:studentName,studentId...),通常用于给变量命名
定义常量命名:全部字母都大写,多个单词之间用下划线_分隔(例如:MAX_VALUE,MIN_VALUE...)
包名命名:全部为小写字母,一半是用公司域名倒写(com.example.demo)
3. Java的八大基本类型
基本类型是Java中最基础的数据类型,它直接存储在栈内存中,操作速度快
- 整型:
- byte:
- 占用字节:1字节(Byte) = 8位(bit)
- 默认值:0
- 取值范围:-128 ~ 127
- 对应包装类:Byte
- short:
- 占用字节:2字节
- 默认值:0
- 取值范围:-32768 ~ 32767
- 对应包装类:Short
- int:
- 占用字节:4字节
- 默认值:0
- 取值范围:-2^31 ~ 2^31-1
- 对应包装类:Integer
- long:
- 占用字节:8字节
- 默认值:0L(数值后必须加 “ L ”)
- 取值范围:-2^63 ~ 2^63-1
- 对应包装类:Long
- byte:
- 浮点型:
- float(单精度):
- 占用字节:4字节
- 默认值:0.0f (数值后必须加 " F " 或 " f ")
- 对应包装类:Float
- double(双精度):
- 占用字节:8字节
- 默认值:0.0d(后缀d可省略)
- 对应包装类:Double
- float(单精度):
- 字符型:
- char:
- 占用字节:2字节
- 默认值:'\u0000' (Unicode转义空字符)
- 取值范围:0 ~ 65535
- 对应包装类:Character
- char:
- 布尔型:
- boolean:
- 占用字节:1字节
- 默认值:false
- 取值范围:true 和 false
- 对应包装类:Boolean
- boolean:
1. 为什么在Java中char是2个字节?
在Java中采用Unicode(UTF-16)编码,char是一个无符号整数,2字节也就是16位,能够表示范围:0~65535,在当时这个范围足以所有字符;后期Unicode扩展,对超出这个范围的字符采用两个char组合来表示
2. 为什么用char来表示字符而不是short?
Unicode编码是从0开始的,所有字符码点都是非负整数,char 类型就是无符号整数,所有都是正数,表示范围是0~65535,而short 类型最高位是符号位,用来表示正负,表示的范围就是-32767~32766,有一半为负数用不上的浪费了,且Unicode中的字符码点要大于32767,所以设计出char来专门表示字符
4. 包装类
基本数据类型对应的引用类型,就是把基本类型包装成对象,而对象默认值都是null
| 基本类型 | 包装类 | 示例 |
|---|---|---|
| byte | Byte | Byte b = 10 |
| short | Short | Short s = 100 |
| int | Integer | Integer i = 5 |
| long | Long | Long l = 100L |
| float | Float | Float f = 3.14f |
| double | Double | Double d = 3.14 |
| char | Character | Character c = ' A ' |
| boolean | Boolean | Boolean b = true |
装箱拆箱方法:
自动装箱是 Java 编译器自动将基本类型转换为对应的包装类型,本质是调用valueOf()方法(例如 Integer a = 100; 等价于 Integer a = Integer.valueOf(100)),而拆箱则是包装类型转换成对应基本类型,本质是调用xxxValue()方法(例如 int b = a; 等价于 int b = a.intValue())
| 基本类型 | 装箱方法 | 拆箱方法 |
|---|---|---|
| int | Integer.valueOf( int i ) | Integer.intValue() |
| byte | Byte.valueOf( byte b ) | Byte.byteValue() |
| short | Short.valueOf( short s ) | Short.shortValue() |
| long | Long.valueOf( long l ) | Long.longValue() |
| float | Float.valueOf( float f ) | Float.floatValue() |
| double | Double.valueOf( double d ) | Double.doubleValue() |
| char | Character.valueOf( char c ) | Character.charValue() |
| boolean | Boolean,valueOf( boolean b ) | Boolean.booleanValue() |
注:
- 包装类都是由final来修饰的,不能被继承,且一旦创建,值不能被修改
- 为了线程安全、缓存机制有效、以及一致性。不可变对象可以被安全地在多个线程间共享,且可以作 HashMap 的 key。
- 包装类对象是在堆中存储,而引用是在栈中
Byte、Short、Integer、Long、Float、Double 继承自 Number 类,Character 和 Boolean 直接继承 Object
1. 为什么需要包装类?
在使用集合或泛型时,参数类型必须是对象类型,且包装类支持null,内置了很多工具方法
2. 缓存机制
提高性能,节省内存。频繁使用的数值被预先创建并复用。Byte,Short,Integer,Long缓存范围为-128~127,Character为0~127,Boolean的true和false都被缓存,而Float,Double浮点数是没有缓存的;
创建一个缓存范围内的对象实际上是从缓存中取的同一对象,超出缓存范围的则是新建对象:
// Integer 缓存范围:-128 ~ 127 Integer a = 100; Integer b = 100; System.out.println(a == b); // true(从缓存取,同一个对象) Integer c = 200; Integer d = 200; System.out.println(c == d); // false(超出缓存,新建对象) System.out.println(c.equals(d)); // true(用 equals 比较内容) Integer a = Integer.valueOf(100); // 从缓存取 Integer b = new Integer(100); // 强制创建新对象 System.out.println(a == b); // false3. 浮点数取值范围没有缓存
因为浮点数取值范围太大,缓存所有值不现实,且浮点数使用频率不如整数高
4.Integer a = null; int b = a;
抛出NullPointerException。因为拆箱时调用 a.intValue(),而 a 为 null。
5.修饰符
修饰符是 Java 中用于修饰类、方法、变量、构造方法等的关键字,用来控制其访问范围、行为特性或继承关系。
访问修饰符:
- public:公开访问,任何地方都可访问
- protected:受保护,允许同一个类,同一个包及不同包的子类访问
- default:默认(无修饰符),只允许同一个类和同一个包下访问
- private:私有的,仅当前类可访问
非访问修饰符:
- static:静态的,被修饰的东西表示是属于类的而非实例
- final:不可变,表示不可被修改、继承、重写
- abstract:抽象的,不可被实例化
- synchronized:修饰线程,表示加锁保证线程安全
- volatile:表示显示可见性,保证代码程序按照顺序执行
1. final、finally、finalize() 的区别?
- final:修饰符,不可改变
- finally:异常处理的最终执行块
- finalize():垃圾回收前调用
2. synchronized 和 volatile 的区别?
- volatile:保证可见性,不保证原子性,不能修饰类和方法
- synchronized:保证可见性和原子性,性能较低
3. static的作用:修饰变量,方法,类,代码块
- 静态变量:属于类的,所有对象共用一份,在类加载时进行初始化,JDK8 之前在方法区,JDK8+ 在堆中的 Class 对象里,可通过 类名.变量名进行访问,也可以通过对象引用访问
- 静态方法:不需要创建对象,可直接通过 类名.方法名进行调用,没有隐式对象不能使用 this 和 super,只能访问静态成员(静态变量或其他静态方法)或通过对象引用来访问实例
- 静态代码块:在类加载时自动执行且只执行这一次,多个静态代码块按照声明顺序进行执行,是在构造方法之前执行,常用于加载驱动或初始化变量
- 静态内部类:独立于外部类,不能使用外部类引用,不用依赖于外部类创建,只能访问到外部类的静态成员,不能直接去访问外部类的实例成员
class Parent { static { System.out.println("Parent 静态代码块 1"); } { System.out.println("Parent 构造代码块"); } static { System.out.println("Parent 静态代码块 2"); } public Parent() { System.out.println("Parent 构造方法"); } } class Child extends Parent { static { System.out.println("Child 静态代码块 1"); } { System.out.println("Child 构造代码块"); } static { System.out.println("Child 静态代码块 2"); } public Child() { System.out.println("Child 构造方法"); } } public class Test { static { System.out.println("Test 静态代码块"); } public static void main(String[] args) { System.out.println("=== main 开始 ==="); new Child(); System.out.println("=== 第一次 new 结束 ==="); new Child(); System.out.println("=== main 结束 ==="); } }Test 静态代码块 === main 开始 === Parent 静态代码块 1 Parent 静态代码块 2 Child 静态代码块 1 Child 静态代码块 2 Parent 构造代码块 Parent 构造方法 Child 构造代码块 Child 构造方法 === 第一次 new 结束 === Parent 构造代码块 Parent 构造方法 Child 构造代码块 Child 构造方法 === main 结束 ===4. static修饰的方法为什么不能使用 this 和 super
static方法属于类,不属于对象;而this和super必须依附于具体的对象实例,即 this 指向堆内存中当前对象实例,super 指向父类实例的内存空间;静态方法被调用时,可能根本没有对象存在。
5. final修饰符作用:修饰变量,方法,类
- 修饰变量:该变量不可再进行赋值,值不可改变,即为常量
- 修饰方法:不能被子类重写,方法可重载
- 修饰类:不能被继承
ps:
重载通常是同一个类中,方法名相同,参数列表不同(参数个数,类型...),与返回值无关
重写是指在子类中,重写实现父类的同一方法,方法名和参数列表必须相同,返回值类型相同或者是父类返回值的子类,抛出的异常不能比父类多
6.运算符
- 算术运算符:用于数值运算
| 运算符 | 作用 | 示例 |
|---|---|---|
| + | 加法运算,字符串拼接 | 1+1 = 2,"a"+"b" = "ab" |
| - | 减法运算 | 2-1 = 1 |
| * | 乘法运算 | 9*9 = 81 |
| / | 除法运算(整型会舍弃小数部分) | (int)5/2 = 2 |
| % | 取余/取模(余数) | 5%2 = 1 |
| ++ | 自增(+1) | i++ = i+1 |
| -- | 自减(-1) | i-- = i-1 |
注:
1. 自增和自减有前后缀之分,当使用 i++ 时,表示先使用的是 i 原先的值,后再继续 +1 操作,而++i 则是先 +1 再使用,同样 -- 也是一样的
2. 整型在除以0或对0去余时会直接抛出异常ArithmeticException;而浮点数则不会抛出异常,结果显示为 Infinity 无穷大 或 NaN非数字
- 关系运算符:比较值之间的关系,结果为boolean型(Ture/False)
| 运算符 | 作用 | 示例 |
|---|---|---|
| == | 等于 | a == b |
| != | 不等于 | a != b |
| > | 大于 | a > b |
| < | 小于 | a < b |
| >= | 大于等于 | a >= b |
| <= | 小于等于 | a <= b |
注:在比较引用类型时(例如String)== 号只比较他们的内存地址而不是具体的值,比较具体的值应使用 .equals() 方法
- 逻辑运算符:用于条件判断,返回boolean
| 运算符 | 作用 | 示例 |
|---|---|---|
| & | 逻辑并(条件同时成立时Ture) | 条件1 & 条件2 |
| | | 逻辑或(有一个条件成立时Ture) | 条件1 | 条件2 |
| && | 短路并(条件1不成立,直接False不计算条件2) | 条件1 && 条件2 |
| || | 短路或(条件1成立,直接Ture不计算条件2) | 条件1 || 条件2 |
| ! | 逻辑非(取反,条件成立则为False,不成立Ture) | ! 条件1 |
| ^ | 逻辑异或(两边不同返回Ture,相同返回False) | ture^false |
注:利用 &&,|| 短路特性可以提高效率并避免潜在的空指针异常
- 赋值运算符:
| 运算符 | 作用 | 示例 |
|---|---|---|
| = | 直接赋值 | a = 1 |
| += | 加后赋值 | a += 1 等价于 a = a + 1 |
| -= | 减后赋值 | a -= 1 等价于 a = a - 1 |
| *= | 乘后赋值 | a *= 1 等价于 a = a * 1 |
| /= | 除后赋值 | a /= 1 等价于 a = a / 1 |
| %= | 取余赋值 | a %= 1 等价于 a = a % 1 |
| 其它运算... | 同理 | .... |
注:
在 Java 中,所有小于 int 的整数类型(byte、short、char)在进行算术运算时,都会自动提升为 int 类型,然后才进行计算,复合赋值运算符有隐式强转,例如:byte a = 1,在进行 a = a+2 的运算时,数字2是 int 型的,而运算中的 a 会从byte 升为 int,最后 int 型的结果又赋值给byte a,就可能出现精度丢失问题,所以这里如果是 a = a + 2,编译器就会报错需要进行强制类型转换,也就是 a = ( byte ) ( a + 2 ) 才可以通过编译,而使用 a += 2时,则会进行隐式强转,不会编译报错
拓展:
- 位运算符:操作整数的二进制位(操作数必须是整数类型)
| 运算符 | 作用 | 示例 |
|---|---|---|
| & | 位与运算(同1则1,不同则0) | 0b0101 & 0b0011 = 0b0001 |
| | | 位或运算(有1则1,无1则0) | 0b0101 | 0b011 = 0b0111 |
| ^ | 异或运算(不同为1,相同为0) | 0b0101 ^ 0b0011 = 0b0110 |
| ~ | 取反运算(补码) | ~0b0101 = 0b1010 |
| << | 左移(低位补0) | 5 << 1 (移位数n)相当于乘以 2ⁿ |
| >> | 右移(高位补符号位,正数1负数0) | -5 >> 1保留符号地除以 2ⁿ |
| >>> | 无符号右移(高位补0) | -5 >>> 1把负数当成大正数来移位 |
- 三元运算符:条件 ? 表达式1 : 表达式2,如果条件为true,取表达式1的值,否则取表达式2的值。例如:int max = (a > b) ? a : b;
- instanceof 类型比较:String s = "Hello"; boolean result = s instanceof String;
- 运算符优先级:可采用()来提高运算优先等级,明确运算顺序
- (最高)++,--,!,~
- *,/,%
- +,-
- <<,>>,>>>
- <,>,<=,>=,instanceof
- ==,!=
- &
- ^
- |
- &&
- ||
- ?:
- 赋值运算
括号 > 单目 > 算术 > 位移 > 关系 > 相等 > 位运算 > 逻辑 > 三元 > 赋值
补充:
1. 整数做除法运算时,如果想保留小数,可以将一个操作数转换成浮点型
例如:(double)a / b
2. == 号通常用于基本数据类型比较,在比较引用类型时,默认比较的是他们的地址
3. 不借助第三个变量来实现两个数值交换:
int a = 10; int b = 20; //1.算术运算加减法 a = a + b; // a = 30, b = 20 b = a - b; // b = 30 - 20 = 10, a = 30 a = a - b; // a = 30 - 10 = 20, b = 10 //2.异或运算 a = a ^ b; // a = 10 ^ 20, b = 20 b = a ^ b; // b = (10 ^ 20) ^ 20 = 10, a = 10 ^ 20 a = a ^ b; // a = (10 ^ 20) ^ 10 = 20, b = 10 //3.赋值表达式 //3.1 b = a + (a = b) * 0; //3.2 a = a + b - (b = a); //3.3 a = (a ^ b) ^ (b = a); //3.4 b = (a ^ b) ^ (b = a);
前不久我的一个朋友发信息给我,他说他最近很难过,他的发小Q,走了,自s的,把自己关在卫生间里,燃了很多木炭,一氧化碳中毒,是Q的妹妹发现的...
Q和他的爷爷奶奶一起生活,那时候Q的爷爷联系我那个朋友,说他们联系不上Q了,很担心他不知道去哪里,我那个朋友和Q的其他共同朋友也同样联系不上,后来我朋友收到消息,Q已经走了... 据我那个朋友所说,Q患有抑郁症,已经有好几年了,Q比我们大几岁,大学毕业后就一直在家没有出去工作,他得抑郁症好像是由于高中时候的一段感情经历,他们本来分手了,后来大学又有了联系,但具体什么样我那个朋友也不清楚,因为那时候Q的精神状态就不太对劲了,这些也没有和他或是其他朋友讲过,大概就是那种断崖式的吧,我也不太懂...
只是觉得很可惜吧,二十几岁啊,这是多么美好的年纪啊,从学校走向社会,能自己挣钱养活自己过自己的生活,又没有结婚房贷车贷的困扰,这是人生中真正属于自己的几年时光...
希望大家不管遇到什么困难,都要努力克服他,战胜他;解决问题可比解决自己要强的多,永远不要轻视生命,永远不要想着放弃。
非常推荐大家去读一本书《钢铁是怎么练成的》,或者是看00年拍的电视剧版,你也能成为自己的保尔柯察金