本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Java基础:熟悉 Java 基础知识,如面向对象、并发编程、异常处理、集合类、Java8新特性等
一、数据类型、运算符、流程控制
1 数据类型
(1)整型
| 类型 | 占用存储空间 | 表数范围 |
|---|---|---|
| byte | 1字节=8bit位 | -128 ~ 127 |
| short | 2字节 | -215 ~215 |
| int | 4字节 | -2^31 ~ 2^31-1 (约21亿) |
| long | 8字节 | -2^63 ~ 2^63-1 |
自动类型转换:容量小的类型自动转换为容量大的数据类型。
(2)浮点型
(3)字符型 char
(4)布尔型 boolean
Java语言表达所操作的boolean值,在编译之后都使用java虚拟机中的 int 数据类型来代替:true 用 1 表示,false 用 0 表示。———《java虚拟机规范 8版》
2 运算符
(1)位运算符
| 运算符 | 运算 | 示例 | 细节 | |||
|---|---|---|---|---|---|---|
| << | 左移 | |||||
| >> | 右移 | |||||
| >>> | 无符号右移 | |||||
| & | 与运算 | 二进制位进行&运算,只有1&1时结果是1,否则是0; | ||||
| 或运算 | 二进制位进行 | 运算,只有0 | 0时结果是0,否则是1; | |||
| 异或运算 | ||||||
| ~ | 取反运算 |
(2)三元运算符
3 流程控制
顺序
分支
switch-case
String season = "summer";
switch (season) {
case "spring":
System.out.println("春暖花开");
break;
case "summer":
System.out.println("夏日炎炎");
break;
case "autumn":
System.out.println("秋高气爽");
break;
case "winter":
System.out.println("冬雪皑皑");
break;
default:
System.out.println("季节输入有误");
break;
}
break 语句用来在执行完一个 case 分支后使程序跳出 switch 语句块。
如果没有 break,程序会顺序执行到 switch 结尾(case 穿越)。
循环
有 while、do…while、for 三种循环语句。
注:JDK1.5提供了 foreach 循环,方便的遍历集合、数组元素。
二、数组
// (1)动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
int[] arr1 = new int[10];
// (2)静态初始化:定义数组的同时就分配空间并赋值
int[] arr = new int[]{1,2,3,4,5};
for each循环
-
处理一个集合中的所有元素
-
很多情况下还是需要使用传统的
for循环,如不希望遍历整个集合,或者在循环内部需要使用下标值。 -
对于打印数组中的所有值:可以使用
Arrays类的toString方法。- Arrays.toString(a)返回一个包含数组元素的字符串,如"[2, 3, 5, 7, 11, 13]"
三、面向对象
1 类 (Class) 和对象(Object)(面向对象的核心概念)
(1)属性
- 常用的权限修饰符有:private、缺省、protected、public
(2)方法
-
方法的重载
overload -
可变个数的形参
-
方法参数的 [值] 传递机制
-
方法的重写
override -
递归方法
(3)构造器(构造方法)
给对象进行初始化(定义对象的初始状态)。
(4)代码块(初始化块)
# 程序中成员变量赋值的执行顺序
声明成员变量的 「默认初始化 」
「显式初始化」、多个初始化块依次被执行(同级别下按先后顺序执行)
「构造器 」再对成员进行初始化操作
通过「”对象.属性”」或”对象.方法”的方式,可多次给属性赋值
2 封装和隐藏 ⭐️
我们程序设计追求“高内聚,低耦合”。
- 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合 :仅对外暴露少量的方法用于使用。
好处🍁
- 隐藏一个类中不需要对外提供的实现细节。改变内部实现不会影响其它代码。
- 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作。
3 this
- 当在方法内需要用到调用该方法的对象时,就用
this。- 我们可以用this来区分属性和局部变量。比如:this.name = name
4 package和import的使用
1. java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
2. java.net----包含执行与网络相关的操作的类和接口。
3. java.io ----包含能提供多种输入/输出功能的类。
4. java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
5. java.text----包含了一些java格式化相关的类
6. java.sql----包含了java进行JDBC数据库编程的相关类/接口
7. java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的多个类。
- 这些类被用来构建和管理应用程序的图形用户界面(GUI)。 B/S C/S
5 继承 ⭐️
可以基于已有的类创建新的类。
-
Java 支持单继承和多层继承,不允许多重继承,但提供了一些类似多重继承的功能。
- 一个子类只能有一个直接父类
- 一个父类可以派生出多个子类(继承层次)
- 所有的类都是
Object类的子类
-
好处
- 减少代码冗余,提高复用性。
- 易扩展,子类更强大。
- 类之间产生关系,多态前提。
7 super(调用父类中的属性/方法/构造器)
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
8 多态
- 父类的引用指向子类的对象。
- 子类可看做是特殊的父类
- Java引用变量有两个类型:编译时类型和运行时类型。
- 编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
- 提高了代码的通用性,常称作接口重用。
9 Object
| NO. | 方法名称 | 类型 | 描述 |
|---|---|---|---|
| 1 | public Object() | 构造 | 构造器 |
| 2 | public boolean equals(Object obj) | 普通 | 对象比较 |
| 3 | public int hashCode() | 普通 | 取得Hash码 |
| 4 | public String toString() | 普通 | 对象打印时调用 |
10 final
final 关键字是最终的意思,可以修饰(方法,变量,类)
- 修饰方法:表明该方法是最终方法,不能被重写。
- 修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次) 。
- 修饰类:表明该类是最终类,不能被继承(不允许扩展) 。
11 包装类
针对八种基本数据类型定义相应的引用类型,即包装类(封装类)。
| 基本数据类型 | 包装类 |
|---|---|
| int(4字节) | Integer |
| byte(1字节) | Byte |
| short(2字节) | Short |
| long(8字节) | Long |
| float(4字节) | Float |
| double(8字节) | Double |
| char(2字节) | Character |
| boolean(未定) | Boolean |
JDK1.5之后,支持自动装箱,自动拆箱。但类型必须匹配。
以 Interger 类为例,装箱自动调用Integer的 valueOf(int) 方法,拆箱自动调用Integer的 intValue() 方法。
12 static 静态
# 堆:new出来的结构:对象、数组
# 栈:局部变量
# 方法区:类的加载信息、静态变量、常量。
13 抽象类与抽象方法 abstract
类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
14 接口 interface
15 内部类
四、异常
-
Throwable 顶级父类
-
Error(Java虚拟机无法解决的严重问题,如 StackOverflowError 和 OOM)
-
Exception(可以使用针对性的代码进行处理)
- RuntimeException(运行时异常,程序员应积极避免)
- 受检异常(编译器要求必须处置的异常)
-
-
异常可分为受检异常与非受检异常(Error 和 RuntimeException类及其子类 )
- RuntimeException是非受检异常的子集
处理机制
- try-catch-finally 捕获异常
- throws 声明抛出异常
return 和 finally的执行顺序 ?
答:
return先执行,将方法停下后执行 finally ,最后再执行 return 将值返回。
五、多线程
六、常用类
七、枚举类与注解
八、Collection 接口系列集合、Map 接口系列集合
Collection
Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法可用于操作 Set 集合、List集合 和 Queue 集合。
| 方法 | 说明 | |
|---|---|---|
| add(Object obj)、addAll(Collection coll) | 添加 | |
| int size() | 获取有效元素的个数 | |
| void clear() | 清空集合 | |
| boolean isEmpty() | 是否是空集合 | |
| boolean contains(Object obj)、boolean containsAll(Collection c) | 是否包含某个元素 | 通过元素的equals方法来判断是否是同一个对象 |
| boolean remove(Object obj) | 删除 | |
| boolean retainAll(Collection c) | 取两个集合的交集 | |
| boolean equals(Object obj) | 集合是否相等 | |
| Object[] toArray() | 转成对象数组 | |
| hashCode() | 获取集合对象的哈希值 | |
| iterator() | 遍历 | 返回迭代器对象,用于集合遍历 |
map
Map与Collection并列存在。用于保存具有映射关系的数据: key-value
常用方法
| 方法 | 说明 | |
|---|---|---|
| Object put(Object key,Object value) | 将指定key-value添加到(或修改)当前map对象中 | |
| void putAll(Map m) | 将m中的所有key-value对存放到当前map中 | |
| Object remove(Object key) | 移除指定key的key-value对,并返回value | |
| void clear() | 清空当前map中的所有数据 | |
| Object get(Object key) | 获取指定key对应的value | |
| boolean containsKey(Object key) | 是否包含指定的key | |
| boolean containsValue(Object value) | 是否包含指定的value | |
| int size() | 返回map中key-value对的个数 | |
| boolean isEmpty() | 判断当前map是否为空 | |
| boolean equals(Object obj) | 判断当前map和参数对象obj是否相等 | |
| Set keySet() | 返回所有key构成的Set集合 | |
| Collection values() | 返回所有value构成的Collection集合 | |
| Set entrySet() | 返回所有key-value对构成的Set集合 |
HashMap源码中的重要常量
| 常量 | 说明 | |
|---|---|---|
| DEFAULT_INITIAL_CAPACITY | HashMap的默认容量,16 ⭐️ | |
| MAXIMUM_CAPACITY | HashMap的最大支持容量,2^30 | |
| DEFAULT_LOAD_FACTOR | HashMap的默认加载因子 0.75f ⭐️ | |
| TREEIFY_THRESHOLD | Bucket中链表长度大于该默认值,转化为红黑树 ⭐️ | |
| UNTREEIFY_THRESHOLD | Bucket中红黑树存储的Node小于该默认值,转化为链表 | |
| MIN_TREEIFY_CAPACITY | 桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。) | |
| table | 存储元素的数组,总是2的n次幂 | |
| entrySet | 存储具体元素的集 | |
| size | HashMap中存储的键值对的数量 | |
| modCount | HashMap扩容和结构改变的次数 | |
| threshold | 扩容的临界值,= 容量 * 填充因子 | |
| loadFactor | 填充因子 |
九、泛型
// 我们使用泛型的上限进行限定
public static void go(ArrayList<? extends Car> cars){
}
// ? extends genericity_limit.Car: ?必须是Car或者其子类 泛型上限
// ? super genericity_limit.Car : ?必须是Car或者其父类 泛型下限
? 可以在 使用泛型 的时候代表一切类型。
E T K V 是在定义泛型的时候使用的。
# 案例:开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。
package genericity_limit;
import java.util.ArrayList;
/**
* @author cat
* @description
* @date 2022/4/11 下午9:00
*/
// https://www.bilibili.com/video/BV1Cv411372m?p=132
// 黑马讲的很不错,理解了泛型的概述和优势、自定义泛型类/泛型方法/泛型接口、泛型通配符以及上下限(4月11日面试考题)
public class GenericDemo {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList<BENZ> benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
// 不符合,狗不应该能够比赛
//ArrayList<genericity_limit.Dog> dogs = new ArrayList<>();
//dogs.add(new genericity_limit.Dog());
//dogs.add(new genericity_limit.Dog());
//dogs.add(new genericity_limit.Dog());
//go(dogs);
}
/**
* 所有车比赛
* @param cars
*/
// 虽然BMW和BENZ都继承了Car, 但是ArrayList<genericity_limit.BMW>和ArrayList<genericity_limit.BENZ>与ArrayList<genericity_limit.Car>没有关系的!
// (1)类有继承关系,但是父子类各自的集合没有关系
//public static void go(ArrayList<genericity_limit.Car> cars){
//}
// (2)使用泛型可以,但是狗不应该能够比赛,所以下面我们使用泛型的上下限
// ? extends genericity_limit.Car: ?必须是Car或者其子类 泛型上限
// ? super genericity_limit.Car : ?必须是Car或者其父类 泛型下限
// 狗不应该可以比赛
public static void go2(ArrayList<?> cars){
}
// 我们使用泛型的上限进行限定
public static void go(ArrayList<? extends Car> cars){
}
}
// -------------------------------------
// 不应该能比赛的狗
class Dog{
}
class BENZ extends Car{
}
class BMW extends Car{
}
class Car{
}
十、IO 流 stream
分类:
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流
Java的IO流共涉及 40 多个类,实际上非常规则,都是从如下4个抽象基类派生的。
| 抽象基类 | 字节流 | 字符流 |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
节点流
缓冲流
对象流
十一、网络编程
十二、反射
十三、Java8 新特性
Lambda表达式(核心1)⭐️
强大的Stream API(核心2)⭐️
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。