1 Java背景知识
1.1 JDK JRE JVM
- JDK(开发工具包)
- JRE(运行环境)运行时类库
- JVM(Java虚拟机)
JDK:(Java Development Kit)
Java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。
JRE:(Java Runtime Environment)
Java运行环境,用于解释执行Java的字节码文件。
JVM: (Java Virtual Machine)
Java虚拟机,是JRE的一部分,负责解释执行字节码文件,是可运行Java字节码文件的虚拟计算机。
区别联系:(问答题会考可能)
JDK包含JRE,JDK和JRE中都包含JVM。JDK除了包含JRE还包含一些常用开发工具和基础类库。
JDK用于开发,JRE用于运行Java程序。
JVM是Java编程语言的核心并且具有平台独立性。
1.2 开发Java程序需要的3个步骤:
- 编写源文件
- 编译源文件生成字节码
- 加载运行字节码
1.3 Java程序运行过程:
1 javac: java源文件->class字节码文件(0,1) 2 java: 运行class文件
1.4 java程序语句执行的顺序
java程序语句执行的顺序包括4种基本控制结构:顺序结构、选择结构、循环结构、异常处理逻辑结构。 如果三个空(那就顺序 选择 循环)
2 编程基础
2.1 Java的基本语法
–方法格式
|
|
–权限修饰符
下表为Java访问控制符的含义和使用情况
| 访问级别 | 类内部 | 本包 | 子类 | 外部包 |
|---|---|---|---|---|
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | × |
| default | √ | √ | × | × |
| private | √ | × | × | × |
default也叫友好型
–注释
// 单行注释 /* 多行注释 / /* 文档注释 */
–关键字
| 关键字 | 含义 |
|---|---|
| private | 私有的 |
| protected | 受保护的 |
| public | 公共的 |
| abstract | 声明抽象 |
| class | 类 |
| extends | 继承、扩展 |
| final | 最终、不可改变 |
| implements | 实现 |
| interface | 接口 |
| native | 本地 |
| new | 新,创建 |
| static | 静态 |
| strictfp | 严格,精准 |
| synchronized | 线程、同步 |
| transient | 短暂 |
| volatile | 易失 |
| 程序控制语句 | 含义 |
|---|---|
| break | 跳出,中断 |
| continue | 继续 |
| return | 返回 |
| do | 运行 |
| while | 循环 |
| if | 如果 |
| else | 否则 |
| for | 循环 |
| 其它关键字 | 含义 |
|---|---|
| instanceof | 实例 |
| switch | 观察 |
| case | 返回观察里的结果 |
| default | 默认 |
| try | 捕获异常 |
| catch | 处理异常 |
| throw | 抛出一个异常对象 |
| throws | 声明一个异常可能被抛出 |
| import | 引入 |
| package | 包 |
| boolean | 布尔型 |
| byte | 字节型 |
| char | 字符型 |
| double | 双精度 |
| float | 浮点 |
| int | 整型 |
| long | 长整型 |
| short | 短整型 |
| null | 空 |
| TRUE | 真 |
| FALSE | 假 |
| super | 父类,超类 |
| this | 本类 |
| void | 无返回值 |
| goto | 跳转 |
| const | 静态 |
| native | 本地 |
–标识符
(你自己定义的一个东西的名字(比如类名,方法名,变量名,接口名,常量名…))
–注意事项定义的时候:
示识符:
由字母、数字、下划线(_)和美元符号($)组成。
不能以数字开头。
不能是Java中的关键字。
2.2 变量 常量
–变量的定义
按所属的数据类型划分:
- 基本数据类型变量
- 引用数据类型变量
按被声明的位置划分:
-
局部变量:方法或语句块内部定义的变量
-
成员变量:方法外部、类的内部定义的变量
基本数据类型
| 类型 | 名称 | 含义 | bit | 字节数 | 值范围 |
|---|---|---|---|---|---|
| 整型 | byte | 字节 | 8 | 1字节 | -128 到 127 |
| 整型 | short | 短整型 | 16 | 2字节 | -32768 到 32767 |
| 整型 | int | 整型 | 32 | 4字节 | -2,147,483,648 到 2,147,483,647 |
| 整型 | long | 长整型 | 64 | 8字节 | -9223372036854775808 到 922337203685477580 |
| 浮点型 | float | 浮点数 | 32 | 4字节 | 有效位数15位 |
| 浮点型 | double | 双精度浮点数 | 64 | 8字节 | 有效位数15位 |
| 字符 | char | 字符 | 16 | 2字节 | Unicode字符集 |
| 布尔型 | boolean | 布尔型 | 1 | true/false |
布尔型(boolean)的字节数在Java中并不是精确定义的,它是一个特殊的类型,用于表示真(true)或假(false)。在Java虚拟机(JVM)中,boolean的存储可能与其他基本类型不同,且其大小可能依赖于JVM的实现。在实际应用中,boolean通常用于逻辑判断,而不是进行数值计算。
引用数据类型
在 Java 中,引用类型(Reference Types)是指那些不是基本数据类型(如 int、char、double 等)的类型。引用类型包括以下几种:
-
类(Class):用户自定义的类,例如
public class A {...}中的A类。 -
接口(Interface):定义了一组方法规范,但不提供实现的类型。
-
数组(Array):存储固定大小的相同类型元素的集合,例如
int[] numbers = new int[10];。 -
枚举(Enum):一种特殊的类类型,其值是固定的常量,例如
enum Day { MONDAY, TUESDAY, WEDNESDAY, ... };。 -
注解(Annotation):一种特殊的接口类型,用于提供元数据,例如
@Deprecated。 -
字符串(String):虽然
String在 Java 中是不可变的,但它是一个引用类型,用于表示字符序列。
–变量的类型转换
boolean 类型不能转换成任何其它数据类型。
自动类型转换
容量小的类型自动转换成容量大的数据类型 byte, short, int -> float -> long -> double byte, short, int 不会互相转换,它们三者在计算时会转换成 int 类型
显式类型转换
容量大的类型转换成容量小的数据类型时,要加上强制转换符(截断转换)
|
|
–变量的作用域
- 成员变量(全局变量 private int i=0;)或静态变量 private static String name=“list”) 在类体内定义的变量称为成员变量,它们作用域是整个类
- 局部变量 在一个方法或方法内代码块中定义的变量称为局部变量
–Java中的常量
(不怎么考)
常量不能被转换,例如常数
–注意事项
|
|
2.3 运算符
算数
|
|
赋值
=
关系
< >= <= == !=
逻辑
! && ||
& | 不怎么用
^ 按位异或运算符,逻辑异或运算符
位运算符(不会考)
~ << >> >>>
条件运算符
condition ? valueIfTrue : valueIfFalse;
condition:一个布尔表达式,其结果为true或false。valueIfTrue:如果condition为true,则这个值会被选择。valueIfFalse:如果condition为false,则这个值会被选择。
|
|
在这个例子中,如果 score 大于或等于90,grade 将被赋值为 "A";否则,它将被赋值为 "B"。
2.4.1 选择语句
|
|
2.4.2 java的循环
|
|
|
|
ElementType:表示集合中元素的数据类型。element:表示当前遍历到的集合元素的变量。collection:表示要遍历的数组或集合。
|
|
2.5 数组
-不允许在前面的括号写元素个数
2.5.1 多维数组初始化3种方式
–动态两种
java的多维数组每一维数可不同
|
|
|
|
–静态一种
|
|
不赋值默认元素为0
一般来说初始化时都默认括号在数组名前,这是Java的风格,当然反过来也一样可行(c语言风格)
2.5.2 数组的常见操作
声明数组:
|
|
数组初始化:
|
|
查看数组长度:
|
|
for each 循环:
|
|
数组拷贝:
|
|
数组排序:
|
|
将int数组转换为字符串:
|
|
2.6 输入输出
输入
|
|
在Java中,Scanner 类的 next() 方法用于从输入流中读取下一个完整的 token。Token 通常是输入中的一个单词,由空白字符(如空格、制表符或换行符)分隔。next() 方法会读取并返回一个字符串,直到遇到下一个空白字符,但不包括这个空白字符。(类比scanf)
|
|
如果需要读取包含空格的字符串,应该使用 nextLine() 而不是 next()。
它将读取输入直到遇到换行符(\n),并将换行符之前的所有内容(包括空格)作为字符串返回。
|
|
在s.next()的基础上,有:
|
|
Scanner 类的 hasNext() 方法用于检查输入流中是否还有更多的输入。这是一个非常有用的功能,尤其是在处理不确定数量的输入时,比如在读取用户输入直到用户决定停止时。
|
|
同理有:hasNextLine() hasNextFloat()等方法检验有无特定类型的输入
这里插入一下字符串的比较,equals()方法
|
|
输出
在Java中,输出数据到控制台或文件可以通过多种方式实现。以下是一些输出方法:
-
System.out.print 和 System.out.println:(常用)
System.out.print:将数据打印到标准输出(通常是控制台),但不换行。System.out.println:将数据打印到标准输出,并在末尾添加一个换行符。
1 2System.out.print("Hello, "); System.out.println("World!"); -
System.out.printf:
- 用于格式化输出,类似于C语言中的
printf函数。可以指定输出格式和宽度等。
1System.out.printf("The value of pi is: %.2f%n", Math.PI); - 用于格式化输出,类似于C语言中的
-
System.out.format:
- 类似于
System.out.printf,但返回String对象而不是打印到控制台。
1String formattedString = System.out.format("The value of pi is: %.2f%n", Math.PI); - 类似于
-
PrintStream:
System.out是一个PrintStream对象,提供了更多的方法来控制输出,如print,println,printf,format等。
-
BufferedWriter:
- 用于将文本写入字符输出流,可以提高写入性能,特别是当写入大量数据时。
1 2 3 4BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); writer.write("Hello, World!"); writer.newLine(); // 写入换行符 writer.flush(); // 清空缓冲区 -
PrintWriter:
- 用于打印格式化表示的字符到控制台或文件。
1 2 3PrintWriter writer = new PrintWriter(System.out, true); writer.println("Hello, World!"); writer.flush(); // 清空缓冲区 -
FileWriter:
- 用于写入字符到文件。
1 2 3FileWriter writer = new FileWriter("output.txt"); writer.write("Hello, World!"); writer.close(); // 关闭文件写入器 -
Files.write (Java 7+):
- 用于将字节数据写入文件,可以指定字符编码。
1 2Path path = Paths.get("output.txt"); Files.write(path, "Hello, World!".getBytes(StandardCharsets.UTF_8)); -
Logger:
- Java的日志记录框架,用于记录应用程序的日志信息。
1 2Logger logger = Logger.getLogger("MyLogger"); logger.info("Hello, World!"); -
StringBuffer 和 StringBuilder:
- 用于在内存中构建字符串,特别是当需要多次修改字符串内容时。
1 2 3StringBuilder sb = new StringBuilder("Hello, "); sb.append("World!"); System.out.println(sb.toString());
选择哪种输出方法取决于你的具体需求,比如是否需要格式化输出、是否需要写入文件、是否需要考虑性能等因素。
2.7.1 类与对象
- 概念
- 三大特征
-
封装 “通过 private、default、protected、public 关键字实现属性或方法的封装,仅对外提供公共访问方式。” “高内聚、低耦合”
封装的好处:
- 实现数据和方法的隐藏
- 实现信息隐藏,允许外部对类有限的访问,开发者可以自由的改变类的内部实现
- 提高了代码的重用性
-
继承
通过 extends。 两个好处:
- 代码重用了。
- 通过继承,实现对现实世界更加准确的建模。
-
多态
多态是指允许不同类的对象对同一消息做出响应,即同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。在Java中多态的实现方式:接口实现,继承父类进行方法重写。同一个类中进行方法重载,父类引用指向子类对象。
2.7.2 类与对象 (重点)
-
关系
-
实例化(对象的创建)
通过 new 关键字创建 比如
|
|
|
|
|
|
若使用无参数构造函数
|
|
若使用带参数构造函数
|
|
类的定义(格式,注意事项)
|
|
2.8 类的继承
Object类
Object类是所有类的父类,里面有很多方法 clone getClass toString equals hashCode notify notifyAll wait finalize
- getClass方法 获取运行时类型,返回值为Class对象
- hashCode方法 返回该对象的哈希码值,是为了提高哈希表的效率(Hashtable)
- equals方法 判断两个对象是否相等,在Object类中equals就是使用==去判断,所以在Object的子类中,如果equals相等的两个对象,hashCode一定相等,实现不同的比较。
- clone方法 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递。我们有时候不希望在方法里修改参数,这就需要在类中重写clone方法。 如果在clone方法中调用super.clone()方法需要实现Cloneable接口,否则会抛出CloneNotSupportedException。 此方法只实现了一个浅层拷贝,对于基本类型字段成功拷贝,但是如果是数组等对象,只做了浅拷贝,也就是只复制了对象的引用,所以需要自己重写clone方法进行深层拷贝。
- toString方法 返回一个String字符串,用于描述当前对象的信息,可以重写该方法返回对自己有用的信息,默认返回的是当前对象的类名+hashCode的16进制数字。
- wait方法 多线程中用到的方法,作用是让当前线程进入等待状态,同时也会释放当前线程所持有的锁。直到其他线程调用此对象的notify()方法或notifyAll()方法,当前线程才会被唤醒。
- notify方法 多线程时用到的方法,唤醒该对象等待的某个线程
- notifyAll方法 多线程时用到的方法,唤醒该对象等待的所有线程
- finalize 对象在被垃圾收集器回收前一定会调用finalize方法,对象被释放前最后的挣扎,因为无法确定该方法什么时候被调用,很少使用。
–类的继承格式
|
|
–继承了之后有父类(非私有private)的属性或方法,可直接调用
|
|
—重写父类方法
子类可以重写父类的同名方法,以根据需求覆盖原方法
|
|
2.9 类的封装
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供getter/setter的方法来对隐藏的信息进行操作和访问。
getter setter
封装的实现步骤:
(1) 将成员属性的可见性设为(private)
(2) 创建getter/setter方法(用于属性的读写)(通过这两种方法对数据进行获取和设定,对象通过调用这两种方法实现对数据的读写)
(3) 在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)
|
|
2.10 构造方法(重点)
–定义
主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
一个类可以有多个构造函数,可根据其参数个数的不同或参数类型的不同来区分它们,即构造函数的重载。
–重载
|
|
2.11 方法的重载 和 重写
–回顾一下方法定义格式:
|
|
重载(Overloading):
发生在同一个类中,当多个方法有相同的名称但参数列表不同(与返回值类型、修饰符无关)时,这些方法就是重载的。
重载的目的是为了提供相同功能但使用不同参数的方法,以提高代码的可读性和灵活性。
示例见下或2.10
|
|
重写(Overriding):
发生在子类和父类之间,当子类有一个与父类方法签名(方法名称和参数列表)完全相同的方法时,子类的方法就重写了父类的方法。
重写的目的是为了提供特定于子类的行为,即子类可以根据自己的需要改变父类方法的行为。
实例见 2.8
重写的注意事项:
- 重写的方法必须要和父类一模一样(包括返回值类型、方法名、参数列表)。
- 重写的方法可以使用
@Override注解来标识。 - 子类中重写的方法的访问权限不能低于父类中方法的访问权限。权限修饰符的顺序是:
private< 默认(什么都不写) <protected<public。
2.12.1 this 关键字
Java 中为解决变量的命名冲突和不确定性问题,引入关键字 this 代表其所在方法的当前对象的引用:
- 构造方法中指该构造器所创建的新对象:
|
|
- 方法中指调用该方法的对象:
|
|
- 在类本身的方法或构造器中引用该类的实例变量(全局变量)和方法:
|
|
–注意
this 只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现 this
–原因:static 方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。
2.12.2 super 关键字
一句话概括:super 关键字主要存在于子类方法中,用于指向子类对象中的父类对象;可以访问父类的属性、函数以及构造函数。
-
当子类和父类存在着同名的成员(包括变量和方法)时,在子类中默认是访问子类的成员,可以通过
super关键字指定访问父类的成员。 -
默认会先调用父类无参的构造方法,可以通过
super关键字指定调用父类的构造方法。
示例
假设我们有一个父类 Animal 和一个子类 Dog,我们可以这样使用 super 关键字:
|
|
在这个例子中,super 关键字用于在子类 Dog 中调用父类 Animal 的构造方法和 makeSound 方法。这展示了如何在子类中访问和使用父类的成员。
2.13.1 static 关键字
–静态变量
|
|
–静态方法
|
|
–静态代码块
|
|
-
被
static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来。 -
被
static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来。
平时要使用类中的变量或者方法都要先new实例化一个类。
2.13.2 final关键字
final:用于声明常量、最终类或最终方法。
–修饰变量
- 基本类型变量使用
final修饰了就不可变了 - 对于引用类型变量被
final修饰了;引用变量引用不可变(就整个引用变量不可变),但是引用对象的内容可以改变。
举例
final修饰数组
|
|
在这个例子中,数组 numbers 被 final 修饰,这意味着数组的引用不能被改变指向另一个数组。但是,数组中的元素可以被修改。
–修饰类
|
|
注意
final 修饰的类,不能被继承()
–修饰方法
final 修饰的方法 不能被重写,但是子类可以用父类中 final 修饰的方法;
|
|
2.14 抽象类
|
|
在这段代码中,Action 类被声明为抽象类,使用 abstract 关键字。这意味着 Action 类不能被实例化,它只能作为其他类的父类。
抽象类可以包含抽象方法和具体方法。
抽象方法也使用 abstract 关键字声明,它们没有方法体,必须在子类中被实现。在这个例子中,doSomething 是一个抽象方法,而 test 是一个具体方法,它提供了一个方法体。
子类继承 Action 类时,必须实现 doSomething 方法,即要重写 doSomething 方法并添加具体的方法体。
2.15 接口
|
|
在 Java 中,接口(interface)是一种特殊的抽象类型,它可以包含抽象方法和常量。接口中的方法默认是 public abstract 的,这意味着它们没有方法体,必须由实现接口的类来提供具体实现。接口中的变量默认是 public static final 的,这意味着它们是常量,并且必须在声明时初始化。
–区别
- 接口要被子类实现,抽象类要被子类继承。
- 接口中变量全为公共静态常量,抽象类中可有普通变量。
- 接口中全为抽象方法的声明,抽象类中可以有具体方法的实现。
- 接口中不可以有构造函数,抽象类中可以有构造函数。
- 一个类可实现多个接口,而抽象类只能被单继承。
- 接口中方法为抽象方法,而抽象类中也可有非抽象方法。
示例
|
|
|
|
|
|