Java学习笔记

一、java命令执行过程

第一步:先启动JVM
第二部:JVM启动之后,JVM会去启动“类加载器classloader”
类加载器的作用:用于加载类。本质上类加载器负责去硬盘上找 “类” 对应的 “字节码” 文件
假设是 java HelloWorld ,那么类加载器回去硬盘上搜索:HelloWorld.class 文件。
第三步:类加载器如果在硬盘上找不到对应的字节码文件,会报错
错误:找不到或无法加载对主类
类加载器如果在硬盘上找到了对应的字节码文件,类加载器会将该字节码文件装载到 JVM 当中,JVM 启动 “解释器” 将字节码文件解释成为 “101011101001…” 这中二进制码,操作系统则执行该二进制码文件和硬件交互。

1.1 classpath

问题: 默认情况下,类加载器 classLoader 去哪找对应的字节码文件?
默认情况下,类加载器(classLoader)会从当前路径下找对应的字节码文件。

问题:那么能不能给类加载器指定一个路径,让类加载器去指定的路径下加载字节码文件呢?
答案:当然可以,但是我们需要设置一个环境变量,叫做 classpath

1.1.1 classpath的写法

classpath=A路径;B路径;C路径
路径之间使用 ; 隔开。
注意: 若将classpath配置为 classpath=D:\DEV 后,classloader今后则只会在D:\DEV目录下查找字节码文件。

二、变量

2.1 整数类型

byte \ short \ int \ long \ char
在 Java 中有一条非常重要的结论,必须记住:

在任何情况下,整数型的 “字面量/数据”默认被当作 int 类型处理。 如果希望该“整数型字面量”被当作 long 类型来处理,需要在 “字面量” 后面添加 Ll ,如:1234L

这里需要注意: int类型的取值范围为 [-2147483648, 2147483647] 所以,字面量中不能写在该范围之外的数字,否则编译会报错。

2.2.1 自动类型转换

在 Java 中,小容量的类型可以自动转换大容量的类型,这成为自动类型转换。

  1. public class IntTest01{
  2. public static void main(String[] args) {
  3. // 分析:200这个字面量默认被当作int类型来处理
  4. // b变量是long类型,int类型占4个字节,long类型占8个字节
  5. // 小容量可以自动转换成大容量,这种操作为自动类型转换。
  6. long b = 200;
  7. }
  8. }

2.3 强制类型转换

在 Java 中,大容量的类型要想转换为小容量的类型,需要使用强制类型转换
但是 Java 会给 byteshortchar 类型开后门,只要当整数型字面量没有超 byteshortchar 类型的范围时,允许不加强制类型转换符,直接赋值。

  1. public class IntTest01{
  2. public static void main(String[] args) {
  3. int b = 200L; // 大容量long类型字面值直接复制给小容量int类型的变量,会编译报错
  4. int c = (int)200L; // 使用强制类型转换符进行强转,编译能通过,运行时可能会损失精度。
  5. int d = (int)2147483648; // 这会损失精度
  6. }
  7. }

强制类型转换原理:
比如 long 类型转换为 int 类型,会将前面的四个字节“砍掉”,如下例:

比如整数2147483648L -> (int)2147483648 的过程 二进制: long类型:00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000 转换为int类型后: 10000000 00000000 00000000 00000000,由于首位表示符号位,故其值为: -2147483648

当一个整数赋值给一个 char 类型变量的时候,会自动转换为 char 字符型,最终的结果是一个字符。

  1. public class CharTest03() {
  2. public static void main(String[] args) {
  3. char c1 = 97; // 这里会做强制类型转换
  4. System.out.println(c1); // 'a'
  5. }
  6. }

2.4 整数类型混合运算

结论:bytecharshort 做混合运算的时候,先各自转换成 int 再做运算。

  1. char c1 = 'a';
  2. byte b = 1;
  3. System.out.println(c1 + b); //98

结论:多种数据类型做混合运算的时候,最终的结果是最大容量的对应的类型(char、short、byte除外)。

2.2 浮点型

float4个字节
double8个字节
Java中规定,任何一个浮点型数据字面量默认被当作 double 类型来处理。
如果想让这个浮点型字面量被当作 float 类型来处理,那么请在字面后面添加 fF

2.3 布尔型

在Java语言中,boolean类型只有两个值 truefalse
不像 c 或 c++ 中的 0 或 1 也能表示布尔类型。

2.4 八种基本数据类型转换规则

1、八种基本数据类型,除了 boolean 类型不能转换外,其余七种都可以互相转换;
2、如果整数型字面量没有超出 byte \ short \ int \ char 的取值范围,则可以直接赋值给这4 种类型;
3、小容量向大容量转换称为自动类型转换,容量从小到大的排序为:
byte < short = char < int < long < float < double,其中 shortchar 都占两个字节,但 char 可以表示更大的正整数。
4、大容量转换为小容量,称为强制类型转换,编写时必须加强制类型转换符号,但运行时可能出现精度损失;
5、byte \ short \ char 在做混合运算时,先各自转换成 int 类型再做运算;
6、多种数据类型混合运算时,先各自转换成容量最大的那一种,再做运算。

三、运算符

3.1 逻辑运算符

& 逻辑与
| 逻辑或
! 取反
&& 短路与
|| 短路或
&&、|| 和 &、| 在运算结果上没有任何区别,完全相同。
短路现象
&& 带来的短路现象:当左边表达式为 false 时,右边表达式不会执行;
|| 带来的锻炼现象:当左边表达式为 true 时,右边表达式不会执行。

  1. int x = 10;
  2. int y = 11;
  3. boolean flag1 = x > y & x > y++; // flag1为false,但y++执行了
  4. System.out.println(y); // 12
  1. int x = 10;
  2. int y = 11;
  3. boolean flag2 = x > y && x > y++; // flag2为false,且y++未执行,出现了短路现象。
  4. System.out.println(y); // 11

3.2 扩展赋值运算符

问题:x +=1x = x + 1 本质上是一样的吗?
答案:不一样!

  1. byte x = 100;
  2. x = x + 1; // 编译器报错,编译器检测到x+1是int类型,int类型无法直接赋值给byte类型。
  1. byte x = 100;
  2. x += 1; // 可以,x = 101。
  3. // 实际上:x += 1 ===> x = (byte)(x + 1)

很重要的语法机制:使用扩展运算符的时候,计算过程中永远都不会改变结果类型!

四、面向对象

4.1 对象的JVM内存结构

JAVA学习笔记 - 图1

4.2 对象与引用

对象:对象时通过 new 出来的,在堆内存中存储。
引用:但凡是变量,并且该变量中保存了内存地址指向了堆内存当中的对象,都是引用。

五、异常

5.1 异常概述

1、什么是异常,Java提供异常处理机制有啥用?

异常是指:在程序执行过程中,出现了不正常的情况 Java语言提供了异常处理机制,若程序在执行过程中出现了不正常的情况, Java会把异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加健壮。

5.2 异常继承结构图

image.png

5.3 编译时异常与运行时异常

编译时异常和运行时异常,都是发生在程序的运行阶段,编译阶段是不会发生的。
编译时异常必须在编译(编写程序)阶段预先处理,如果不处理,会导致编译器报错。
编译时异常也称为受检异常
运行时异常也称为未受检异常

5.4 异常处理

Java中对异常的处理包括两种方式:

  • 第一种方式:在方法声明时使用 trows 关键字,抛给上一级。
  • 第二种方式:使用 try ... catch 语句对异常进行捕捉。

上报和捕捉怎么选择?
如果希望调用者处理,选择**上报方式,其余情况使用捕捉**。

六、集合框架

5.1 主要集合概述

所有的集合类和集合的接口,都在 java.util.* 包下面。
集合有两大接口:
java.util.Collectionjava.util.Map
java集合框架.png

5.1 List

List 接口继承于 Collection,定义了一个有序集合(ordered collection)。可以采用两种方式访问元素:

  • 使用迭代器访问(顺序访问);
  • 使用整数索引访问(随机访问);

List 接口定义了多种随机访问的方法

  1. void add(int index, E element);
  2. void remove(int index);
  3. E get(int index);
  4. E set(int index, E element);

5.1.1 ArrayList

ArrayList底层采用了数组这种数据结构,并且封装了一个动态再分配的对象数组。