Java 复习笔记

1. 类型转换

1.1 数据类型

1.1.1 内置数据类型

4 个整数型, 2 个浮点型,1 个字符,1 个布尔

复制代码
1. 整型(有符号)1byte = 8bit
	byte: 8 位 / 1 字节 ,默认 0,表示范围:-128 到 127 (-2⁷ 到 2⁷ - 1),用在大型数组中节约空间,主要代替整数。
	short: 16 位 / 2 字节 ,默认 0,表示范围:-32,768 到 32,767 (-2¹⁵ 到 2¹⁵ - 1)。
	int: 32 位 / 4 字节 ,默认 0,表示范围:-2³¹ 到 2³¹ - 1,大约 ±21亿。
	long: 64 位 / 8 字节 ,默认 0L,表示范围:-2⁶³ 到 2⁶³ - 1

2. 浮点型(符合 IEEE 754 标准),可以精确地表示数字 0,还能区分 正零 (+0.0 或 0.0) 和 负零 (-0.0)。
	
	float: 32 位 / 4 字节 ,单精度,默认0.0f,大约 ±3.4E+38F = ± 3.4 × 10³⁸,存大型浮点数组的时候可节省内存。(有效位数 6-7 位小数)
    double:64 位 / 8 字节,双精度,默认0.0d,取值范围大约 ±1.7E+308,
    	注意:double 的范围关于零点对称------
    			最大的负数和最大的正数对称:~ -1.7 × 10³⁰⁸ 和 ~ +1.7 × 10³⁰⁸
    			最小的负数和最小的正数对称:~ -4.9 × 10⁻³²⁴ 和 ~ +4.9 × 10⁻³²⁴
    	它们要这样获取:
    			最小规格化正数(最小正正规数):常量 Double.MIN_VALUE 表示最小的正数 4.9 × 10⁻³²⁴ 
    			对应的负数叫 "最接近 0 的负规格化数" :- Double.MIN_VALUE = - 4.9 × 10⁻³²⁴
    			最大有限正数:常量 Double.MAX_VALUE = 1.7 × 10³⁰⁸
    			最大有限负数:常量 -Double.MAX_VALUE = -1.7 × 10³⁰⁸
    	注意 .MIN_VALUE 指的是最接近零的那俩;.MAX_VALUE 指的是最外边那俩边界
			 float 也是一样的:
			 最大有限值对称: -3.4 × 10³⁸ (-Float.MAX_VALUE) 到  +3.4× 10³⁸ (Float.MAX_VALUE)
			 最接近零的值对称: -1.4 × 10⁻⁴⁵ (-Float.MIN_VALUE) 到 +1.4 × 10⁻⁴⁵ (Float.MIN_VALUE)
			 特殊值对称:正零 (+0.0f) 和 负零 (-0.0f)、正无穷大 (Float.POSITIVE_INFINITY) 和 负无穷大 (Float.NEGATIVE_INFINITY)
			 
			 他们的最大MAX、最小MIN 都是指跟 0 的距离最大、最小
    			
3. boolean: 1 位(理论上),仅 true、false 两个取值,默认值是 false 。在 JVM 实现层面,因为需要内存对齐和寻址,所以占 1 字节 或 4 字节 。

4. char: 无符号,在 Java 内存中总是占用 2 个字节,取值范围是(0 到 65,535,2^16),可存任何字符。	它本质上是一个 UTF-16 代码单元。
		对大多数常见字符(如英文字母、常用汉字),一个 char 就是一个完整的字符,占用 2 个字节。
		少数扩展字符,如一些 emoji、非常生僻的汉字,需要一个 char 对(两个 char,4字节)来表示。
	    String s = "😊";  // 字符串内部用char数组存储,对于"😊",这个数组长度是2。

为什么 boolean 型规定只占 1 位,但在 JAVA 中,实际却大于 1 位 呢?

由于内存对齐和寻址规则,用 1 字节的空间 换 高速的处理时间,在 JVM 实现层面,boolean 型占 1 字节(局部变量、对象成员、布尔数组) 或 4 字节(栈帧的数据区操作数栈最小 4 字节)

最小可寻址单元:

CPU 的基本内存寻址和操作单位是字节(byte)。直接访问一个比特,在硬件层面非常复杂且效率极低。

具体来讲,可以把内存理解为一个大的字节数组,每个字节有一个唯一的内存地址。CPU 通过地址总线来读写数据,而地址总线指向字节,而非比特。所以 CPU 可以一次读取或写入1 个字节(单字节)、双字节、4 字节等,却无法直接寻址到单个比特。
内存对齐:

为了有最佳性能,CPU 要求数据在内存中的地址与其自身大小对齐。例如 int(32位,4字节)最好放在地址是 4 的倍数的位置上。

一个 boolean 规定只占 1 比特,那么它可能放在任何位置,比如一个字节的中间。

CPU 要想读写这个比特位,要么读整个字节,要么用位操作(如掩码和移位)来读,要想写,就得把改完的整个字节写回内存。整个"读-修改-写"的过程不是原子性的(在多线程环境下会引发问题),且比直接读写一个字节要慢得多。

硬件原生支持直接操作一个字节,这个速度是很快的。而操作一个比特。则需要多条 CPU 指令。用 1 字节的空间 换 高速的处理时间,典型的 以空间换时间 的权衡,绝大多数情况下,都是值得的。
  Java 没有明确规定 boolean 在内存中的确切大小,而是将决定权交给了JVM。而 JVM 的设计目标之一是高效执行,因此它遵循了底层硬件的特性。

  • 在 局部变量 或 对象成员 中,将 boolean 型存为 1个字节,是因为将其对齐到字节边界处理起来最简单、最快。
  • 在数组中,JVM 规范明确指出,boolean 数组中的每个元素应被编码为 1个字节。保证每个数组元素都可以被直接寻址
  • 在栈帧的操作数栈中,JVM运行时,数据区的操作数栈最小单位是 4 字节,小于4字节的类型会被转为4字节(int)计算(通过符号扩展或零扩展),计算完再截断存回。

1.1.2 引用数据类型

不直接存对象本身,而是存了一个指向 对象在内存中位置 的 "地址"或"指针"。默认值都是null。就像一个快捷方式或一张写着"文件在哪个柜子、哪个抽屉"的地址卡片。通过卡片能找到真正的文件(对象)。

Java 的引用数据类型主要分为四类:

  • 类引用
java 复制代码
// String, Integer, Scanner等的 new 对象都是引用数据类型
MyClass myObject;
// 使用new在堆上创建一个 MyClass 对象,并将其地址赋给 myObject
myObject = new MyClass();
// 通过引用 'myObject' 来操作对象
myObject.doSomething();
  • 接口引用
java 复制代码
//接口本身不能被实例化,但可以声明一个接口类型的引用变量,指向实现了该接口的类的对象。这是实现多态的关键。
List<String> myList; // 声明一个接口类型的引用
myList = new ArrayList<>(); // 指向一个实现了List接口的ArrayList对象
// 只能调用List接口中定义的方法
myList.add("Hello");
  • 数组引用
java 复制代码
//数组在 Java 中也是对象,因此数组变量也是引用类型。
int[] arr;
// 在堆上创建一个包含5个int的数组对象,并将其地址赋给 'arr'
arr = new int[5];
// 另一种初始化方式,数组内容 {1, 2, 3} 也在堆上
int[] arr2 = {1, 2, 3};

/*
int[] arr1 = new int[]{1,2,3,4};
System.out.println(arr1);//会输出 arr1 的内存地址
// [I@10f87f66 : [ 表示当前空间是个数组元素
				 I 表示元素的数据类型
				 @ 分隔符
				 10f87f66 十六进制内存地址
*/
  • 枚举引用
java 复制代码
enum Day { MONDAY, TUESDAY, WEDNESDAY }
Day today = Day.MONDAY; // 'today' 是一个指向枚举常量 'MONDAY' 的引用

1.1.3 关键特性

  1. 内存分配
  • 栈内存:方法运行时,进入栈内存。 局部变量(包括基本类型变量和引用类型变量)都存在这。方法执行完,栈帧被清除,这些变量自动销毁。
  • 堆内存:用于存储所有对象实例(包括数组),所有 new 出来的内容会在堆内存中开辟空间,每 new 一次,开辟一块,不重复,并产生地址值。由垃圾回收器管理。

内存状态:

  • 方法区:一运行,字节码文件(.class文件)就会加载进方法区,main方法被 JVM 自动调用,进入栈内存执行
  • 本地方法栈: 调用操作系统相关文件
  • 寄存器:CPU 用的
  1. 是否相等
    ==:对于引用类型,比较的是内存地址,是否指向同一个对象。
    .equals():比较的是内容是否逻辑上相等,通常需要重写此方法。
java 复制代码
String s1 = new String("Hello");
String s2 = new String("Hello");

System.out.println(s1 == s2);      // false! 两个不同的对象,地址不同。
System.out.println(s1.equals(s2)); // true! String类重写了equals方法,比较内容。
  1. 特殊值:null
    是引用变量,但不指向任何对象。若用值为 null 的引用来访问方法或字段,会抛出错误 NullPointerException
  2. 参数传递:Java 中只有值传递
      引用类型传递的是引用的副本(即地址的拷贝),而非对象本身。在方法内修改引用所指向对象的状态(如修改成员变量),会影响原始对象。但若使引用参数指向新对象,不会影响原始引用。
java 复制代码
public static void modify(StringBuilder sb) {
    sb.append(" World");    // 1. 修改了指向的对象,原始对象被改变
    sb = new StringBuilder(); // 2. 引用指向新对象,原始引用不受影响
}

public static void main(String[] args) {
    StringBuilder original = new StringBuilder("Hello");
    modify(original);
    System.out.println(original); // 输出: "Hello World"
}
  1. 比较总结

1.2 类型转换

1.2.1 隐式转换

  • 范围小的可以直接赋给范围大的;
  • 小的和大的做运算,小变大,再运算;
  • byte、short、char 运算时,不论是否有更高的数据类型,都会先变 int ,再运算
    如:int(32 bit) < double(64 bit)
java 复制代码
int a = 10;
double b = a; // 系统自动将 a 提升为 10.0 
//打印 b 会输出 10.0 

double c = 12.3;
double d = a + c; // a 先变 double 

byte e = 3;
byte f = 4;
byte g = e + f; //报错,因为 e、f 运算前先变 int,算完还是 int,要强转后才能赋给 byte
byte g = (byte)(e + f); //正确
byte h = 3 + 4; //正确,在这里3、4是常量,JAVA有常量优化机制,算完若不在 byte 范围内才会报错,若在范围内,则编译通过。

long i = 123; // 123 默认是 int, 赋给 long, 小给大,自动转了,正确
long j = 123456789123456789; //错了,默认 int,自动转,但是超过 int 范围了,它转不明白,会报错:整数太大
long k = 123456789123456789L; //这样 OK

范围从小到大如下:

long(8 字节):-2⁶³ 到 2⁶³ - 1

float (4 字节): -3.4 × 10³⁸ 到 3.4 × 10³⁸

2⁶³ - 1 远小于 3.4 × 10³⁸

1.2.2 强制转换

大范围的赋给小范围的,要强转(溢出或损失精度),浮点数强转到整数,小数全舍

java 复制代码
int a = 10;
byte b = (byte)a;

1.3 计组补充知识

1.3.1 原码补码

计算机中的数据,均以 2 进制补码形式运算,忘了就回去翻书翻课件!
计算机的运算器中只有加法器,所以减法要转换成加法来计算。
左高位为符号位,0 正 1 负

这里用人家的图,你快速回顾一下咋求原码!!大神 up 主页在这:计算机知识星球


正数的原、反、补码均是原码本身。所以求这些东西,先看正负数!

负数原码求反码:符号位不变,其他取反

负数求补码,在反码基础上 + 1

复制代码
 // 写的不大规范,重在理解逻辑
 -21D = [ 10010101 B]原 = [ 11101010 B]反 = [ 11101011 B]补

2. 其他基础语法

2.1 键盘输入/输出 和 Random

java 复制代码
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();

System.out.println(i);
java 复制代码
import java.util.Random;
Random r = new Random();
int num = r.nextInt(10); //[0,10),注意不含 10

2.2 运算符

复制代码
 % 取余
 / 除法(若为整数除法,则结果取整)
 & 按位与:全 1 为 1,其余为 0
 | 按位或:全 0 为 0,其余为 1
 ^ 按位异或:同 0 异 1
 〜 按位取反
 << 按位左移,并在右侧补0。  A << 2 按位左移2位 
 >>  按位右移(有符号右移):高位补符号位(正数补0,负数补1)
 >>> 无符号右移:高位一律补0,结果总是非负数。
 如果上面这些右边带一个 = ,如 a %= b :a = a%b, 都是左跟右算了,再赋给左

 条件运算符(三元运算符):主要是决定哪个值应该赋值给变量。
 int b = (a == 1) ?  10 : 20 
 // 若 a == 1成立,则 b = 10 ;':'左边成立; 若表达式为 false,则 b = 20; ':'右边成立; 

 instanceof 检查该对象是否是一个特定类型(类类型或接口类型)。
	String name = "James";
	boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真
	
	Vehicle a = new Car();
  	boolean result =  a instanceof Car;

2.3 跳转控制语句

  • continue : 在循环内部,基于条件控制使用,跳过当前循环体内容的执行,继续下一次的执行
  • break : 在循环内部或switch中,基于条件控制使用,结束整个循环

3. 面向对象编程

3.1 访问修饰符

定义类、方法或变量时,要注意。

  • 不写访问修饰符:同一包可见,使用对象:类、接口、变量、方法;
  • public:所有类可见,使用对象:类、接口、变量、方法;
  • private:最严格!同一类可见,使用对象:变量、方法。不能修饰类(外部类);
  • protected:同一包内 类和所有子类 可见。使用对象:变量、方法。不能修饰类(外部类)。

非访问修饰符:

  • static:修饰类方法和类变量;
  • final:修饰类、方法和变量。final 修饰的类不能被继承,方法不能被继承类重新定义,修饰的变量为常量,不可修改。

先到这,后面再补

相关推荐
Yang-Never5 小时前
Kotlin协程 -> Job.join() 完整流程图与核心源码分析
android·开发语言·kotlin·android studio
AD钙奶-lalala6 小时前
Mac OS上搭建 http server
java
TomCode先生7 小时前
c#动态树形表达式详解
开发语言·c#
高-老师8 小时前
基于R语言的物种气候生态位动态量化与分布特征模拟
开发语言·r语言·物种气候
大翻哥哥8 小时前
Python 2025:量化金融与智能交易的新纪元
开发语言·python·金融
weixin_437830949 小时前
使用冰狐智能辅助实现图形列表自动点击:OCR与HID技术详解
开发语言·javascript·ocr
汇能感知9 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun9 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
鹿鹿学长9 小时前
2025年全国大学生数学建模竞赛(C题) 建模解析|婴儿染色体数学建模|小鹿学长带队指引全代码文章与思路
c语言·开发语言·数学建模