个人笔记总结,以便复习使用,仅供参考.
文章目录
📢一.第一章 基础
JAVASE基础 一[了解Java语言,Java配置运行环境]
1.1 java如何实现跨平台
Java语言的特点:开源;跨平台性;交互式特性;多线程机制;动态内存管理;面向对象;安全性;
它的跨平台体现在一次编译,到处运行;
运行机制:
创建.java文件(源代码)----->编译器----->.class文件(字节码)------>不同平台的JVM------>翻译------>指令----->平台运行
JVM:(Java Virtual Machine):Java虚拟机
它是用于计算设备的规范,它是虚构出来的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的,因为有了不同的JVM,所以同一个Java程序在三个不同的操作系统中都可以执行。 即跨平台性
,也称为移植性
,这个实现的前提是不同的JVM.
- Java虚拟机可以理解成一个翻译器。
- 对于不同的运行平台,有不同的虚拟机。
- Java 虚拟机机制屏蔽了底层运行平台的差别,实现“一次编译,随处运行”
1.2 JDK,JRE,JVM的关系
JDK,JRE,JVM三者关系概括如下:
jdk是JAVA程序开发时用的开发工具包,其内部也有JRE运行环境JRE
。
JRE是JAVA程序运行时需要的运行环境。
JDK、JRE内部都包含JAVA虚拟机JVM.
JVM:
JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分
,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
JRE:JRE是java runtime environment(java运行环境)的缩写。仅有JVM还不能让class文件执行,因为在解释class时JVM需要调用解释所需要的类库lib。
JDK:JDK是java development kit(java开发工具包)的缩写。
JDK的安装目录中有6个文件夹:
一个src类库源码压缩包、和其他几个声明文件。真正在运行java时起作用仅有这四个文件夹:bin、include、lib、jre。
JDK包含JRE,而JRE包含JVM。
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
📢二.第二章 基础语法
JavaSE基础三 (java运算符,控制台输入,条件语句,循环介绍)
2.1 什么是注释,关键字?
Java语言有3种方式的注释;
单行注释
:/ / 用于单行注释, 快捷键ctrl+/
多行注释
:/* * /用于多行注释,快捷键ctrl+shift+/
文本注释
:
/**
文档注释,用于为类,方法(函数),属性 功能进行说明,可在调用时提
示
*/
文本注释,在IDEA中使用的话;类或方法或属性上打个/**
然后回车换行即可自动生成
2.2 标识符的命名规则
Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符。
-
命名由英文字母大小写,0-9 ,_或 $ 组成
;注意不能以数字开头,不能是关键字和保留字,不能有空格。 -
包名
:多单词组成时所有字母都小写:xxxyyyzzz -
类名、接口名
:多单词组成时,所有单词的首字母大写:XxxYyyZzz -
变量名、方法名
:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz -
常量名
:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
2.3 java数据类型分为哪几种?
数据类型分为基本数据类型
和引用数据类型
;
- 基本数据类型:【数值型: [整数型(byte、int,short,long) ;浮点型(float、double)] 】,
【字符型(char)】 【布尔型(boolean)】, - 引用数据类型:【类(class)】【接口(interface)】【数组( [ ] )】
2.4 基本数据类型有哪些?
八大基本数据类型:
【数值型: [整数型(byte、int,short,long) ;浮点型(float、double)] 】,
【字符型(char)】
【布尔型(boolean)】
整数型
Java语言的整型常量默认为int型,声明long型常量可以后加‘ l ’或‘ L ’ ,如:
int i1 = 600; //正确 long l1 = 8888888888L; //必须加l或L否则会出错
浮点型
Java 浮点类型有两种表示形式
十进制数形式,例如: 3.14 314.0
科学记数法形式,如 3.14e2 3.14E2
Java 浮点型常量默认为 double 型,如要声明一个常量为 float 型,则需在数字后面加 f 或 F 。
例如:double d = 12345.6; //正确 float f = 12.3f; //必须加f否则会出错。
浮点数不可用于比较,因为它本身就具有误差.
布尔型
boolean 类型适于逻辑运算,一般用于程序流程控制 。
boolean 类型数据只允许取值 true 或 false 。
不可以0或非 0 的整数替代false和true,这点和C语言不同。
字符型
char 型数据用来表示一个单个字符.;char占2字节;用单引号括起来。
char c1 =‘a’; char c2 =‘一’;
它可涵盖世界上所有书面语的字符。
2.5 常用运算符有哪些?
作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量。
算术运算符:+,-,*,/,%,++,- -。
字符串连接运算符:+
关系(比较)运算符: >,<,>=,<=,==,!=
逻辑运算符: !,& , | , &&,||,^
赋值运算符: =,+ =,- =, * =,/ =
条件运算符:(条件表达式)? 表达式1:表达式2
位运算符: <<, >>, >>>,&,|,^,~
注意后++
不是安全的,并发时会出现问题;
2.6 && , & , || , |的区别
“&”和“&&”的区别:
单&时 逻辑与
,左边无论真假,右边都进行运算;
双&时 短路与
,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
“|”和“||”的区别:,
单 | 时 逻辑或
,左边无论真假,右边都进行运算
双 || 时 短路或
:当左边为真,右边就不参与运算。
异或( ^ ):当左右都为true时,结果为false。
2.7 位运算符了解吗,有哪些?
2.8 if和switch的区别,使用场景
if条件结构是根据条件判断之后再做处理;
switch语句:多分支选择语句,根据表达式的值,来执行多个操作中的一个。
switch (表达式){
case value1: 语句序列1;
[break];
case valueN: 语句序列N;
[break];
[default : 缺省语句;]
}
- 表达式可以是byte、short、int、char、枚举类型。JDK 7以后,可以使用String类
型; - case语句后面只能使用常量表达式;并且后面的值不能重复;
- 某个case分支如果没有提供break语句,则继续执行下一个case后的语句;
- 当表达式的值与任一case子句中的值都不匹配时,将执行default后面的语句;如果没有default子句,则程序直接跳出switch语句。
使用场景区别
- 对于区间判断,对结果为boolean类型判断,可使用
if语句
; - 若判断的具体数值不多,而且判断条件表达式符合byte、 short 、int、 char,String。两个语句都可以使用,建议使用swtich语句[效率高]。
2.9 while,do while的区别?
while: 先判断逻辑表达式的值。若为true(符合条件).则执行其后面的语句,然后再次判断条件并反复执行,直到条件不成立为止;
do while: 先执行语句,再判断逻辑表达式的值,若为true(符合条件),再执行语句,否则结束循环。
2.10 什么时候使用while ? 什么时候使用for?
已知循环次数时,建议使用for循环;
未知循环次数时,使用while循环;
2.11 break,continue的用法,return的作用 ?
-
break;终止循环,只能终止一层。
如果需要从多层循环跳出,则需要使用标签,定义一个标志位,如flag,然后在需要跳出的地方,用break flag就行了 -
continue;只是终止当前这次循环,之后会进入到下一次循环。
-
return: 于从当前执行的方法中退出, 返回到调用该方法的语句处继续执行。
- 格式1(将表达式的值返回):
return 表达式;
- 格式2(不返回任何值,当方法说明中用void声明无返回值时使用, 也可省略):
return;
- 在递归时return是非常重要的,返回到调用处.
- 格式1(将表达式的值返回):
📢三.第三章 数组
JavaSE基础四–(循环嵌套,关于方法基础,数组基础,冒泡排序)
JavaSE基础四–(|选择排序|,|插入排序|,|二维数组|)
3.1 说说你对数组的认识?
- 数组是
相同数据类型元素的集合
。 本身是引用数据类型
,即对象。- 可以存储基本数据类型,也可以存储引用数据类型。
- 创建数组有两种方式;
- 动态创建–>在创建时就给定数组的长度,里面是默认的值。
- 整数默认值: 0
- 浮点数默认值: 0.0
- char默认值: 空格
- 引用类型默认值: null
- 布尔型默认值:false
- 静态创建–>在创建时就为数组赋值。
- 动态创建–>在创建时就给定数组的长度,里面是默认的值。
3.2 什么是索引,索引的特点?
- 数组里面的索引可以看做是指针;索引由0开始;
- 索引的最大值和数组长度始终相差 1;比如数组长度为10;第一个元素的索引就是0,最后一个元素的索引就是9;
- 索引的数据类型是整型。
3.3 数组的优缺点?
1、按照索引查询元素速度快,只要在索引范围内,随意访问。
2、可以存储大量数据。
3、按照索引遍历数组方便。
缺点:
1、根据内容查找元素时速度慢。
2、数组的空间必须是连续的,这就造成数组在内存中分配空间时必须找到一块连续的内存空间。
2、数组的长度在给定后,不能改变。
3、定义了一种类型的数组,它就只能存储这种类型的数据。
4、在数组中增加、删除元素效率慢。
5、无法判断其中实际存在有多少元素,length属性只是得到数组array的容量
注意Array数组类和Arrays工具类是有区别的;
Array类:import java.lang.reflect.Array;
Arrays类:import java.util.Arrays;
操作数组类,提供常用的静态方法;
可以这么看:Array是图书,那么Arrays就是图书管理员,可以对图书进行各种管理操作。
3.4 数组的使用场景
- 对于已知的简单数据操作;可以选择直接使用数组。
- 多维数组解决问题时,建议使用数组。
- ArrayList等容器类无法存储基本类型,那么对于int、long,char…这些基本类型就只能存储他们对应包装类,而在自动装箱和自动拆箱中会带来性能消耗。假设在关注性能的场景下,需要存储基本类型时,建议使用数组。
📢四.第四章 面向对象
JavaSE基础五----【面向对象(1)面向对象介绍,类与对象,方法重载】
JavaSE基础五----【面向对象(2)–对象与引用;Java是值传递 ; static关键字; 代码块;包;访问权限修饰符;封装; this关键字】
JavaSE基础五----【面向对象(3) ||继承||方法重写||类之间关系::关联,依赖||抽象类||接口||多态||向上,向下转型||final关键字||】
4.1 对面向对象语言的理解?
首先说一下面向过程语言和面向对象语言的区别:
比如说洗衣服这件事;
按照面向过程的思路,分为三步骤,人打开洗衣机,将衣服放进去,开启洗衣机;
按照面向对象的思路,分为三个类:人,洗衣机,衣服;人类中定义开启洗衣机,放置衣服,以及关闭洗衣机的方法; 洗衣机类,定义洗衣机运行,洗衣机停止运行的方法;
面向过程语言:
([POP]:procedure oriented programming)
- 分析出解决问题所需要的步骤,然后把步骤一步一步实现。
- 面向过程直接关注流程。
面向对象语言:
([OOP]:object oriented programming)
- 不关心具体做什么;关心的是谁去做这件事。
- 以分类的方式进行思考和解决问题。
- 面向对象先对整体关系作出分类,然后根据不同的类深入细节的处理。
- 面向对象关注于从宏观上把握事物之间的关系,在具体到如何实现某个细节时,仍然采用面向过
程的思维方式。
4.2 面向对象语言三大特征?
封装继承和多态;
封装
:
就是类将某些属性和实现细节封装起来,仅向外界提供一个公共的访问方法,外界通过调用公共方法来获取到类的某些信息;
比如说单例模式中,就是一个类把自己的构造方法隐藏起来;这个类仅存在一个对象实例,且该类对外界只提供一个可以获取对象的方法,
比如之前在学习mybatis时,自定义封装了获取sqlSessionFactory对象
的工具类;这也是封装的一种体现;
/**
* @author by CSDN@小智RE0
* @date 2021-10-25 20:21
* 简易工具类;
*/
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory=null;
static {
Reader reader = null;
try {
//读取资源配置文件;
reader = Resources.getResourceAsReader("mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
//获取sqlSessionFactory对象;
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
//获取sqlSession;
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
继承
:
由一个类派生出子类,在子类中可以调用到父类的属性/方法;也可以通过自己重写实现父类的方法来扩展新功能;
比如说儿子可以继承使用父亲的东西,但是父亲无法访问儿子的个人物品;
/**
* @author by 信计1801 李智青 学号:1809064012
*/
//父类;
class ClassFa {
public String faStr = "父亲";
private void methodFaPri(){
System.out.println("我是父类定义的私有方法");
}
public void methodFa(){
System.out.println(faStr);
System.out.println("我是父类定义的public方法");
}
}
//子类
public class ClassSon extends ClassFa{
public String sonStr;
@Override
public void methodFa() {
//可调用父类的方法;
super.methodFa();
//可访问父类的属性;
System.out.println("这是我父亲的属性之一:"+faStr);
//可自己修改具体实现;
System.out.println("我是子类重写后加的功能");
}
//子类可以写自己的新方法;
public void methodSon(){
System.out.println("我是子类的新方法");
}
}
- Object类是所有类的基类(父类);
- 类与类之间的继承,接口与接口之间也可继承;
- Java类中仅有单继承,接口支持多继承;
- 虽然说类不能多继承,但是由继承的传递性,也可看到类似多继承的效果;A类继承B类,B类继承C类,C类继承D类;那么A类也就是可用到D类的属性和方法;
多态
:
在继承/实现关系的基础上,子类重写了父类的方法,而父类的引用指向子类对象,就是多态机制;
比如学习集合知识的时候,通常使用父类List
引用指向子类的对象;这就是多态的体现;
/**
* @author by 信计1801 李智青 学号:1809064012
*/
public class Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
}
}
比如在学习JavaEE部分的时候;自定义Servlet继承HttpServlet时,重写使用它的doGet()方法
,以及doPost
方法;
而根据请求实际要调用哪个方法由HttpServlet类
的service()
判断;
4.3 继承的优点,何时使用继承?
使用继承,可以提高代码的重用性和可扩展性,
若类/接口之间具有属于关系(is a)时使用继承;
比如宠物狗类和猫类在具有一些相似的方法时,可以考虑创建出一个上层的宠物类;定义方法;让猫类和狗类去继承宠物类;
4.4 多态的优缺点?
优点:可提高代码的重用性;
缺点:父类引用无法直接访问子类特有成员
4.5 什么是构造方法
构造方法
:与类名相同,且没有返回值,且不需要使用void修饰;
- 可以对构造方法进行重载;
- 每个类都有构造方法。若没有显式地为类定义构造方法,这个类默认存在一个无参构造方法;
- 若在Java类中定义了一个构造方法后,那个默认的无参构造方法就会失效。
- 构造方法用于创建对象,当然也可以在此过程中为对象初始化赋值.
- 在调用子类构造器之前,会先调用父类构造器,
- 当子类构造器中没有使用"super(参数或无参数)"指定调用父类构造器时,是默认调用父类的无参构造器,
- 如果父类中包含有参构造器,却没有无参构造器,则在子类构造器中一定要使用“super(参数)”指定调用父类的有参构造器,不然就会报错。
4.6 什么是方法重写 ,重载,使用场景?
方法重载
:
- 在同一个类中,方法名称必须相同;
参数列表必须不同
; - 方法的返回值可以相同,也可以不相同;与访问权限修饰符无关.
- 使用方法重载可以提高方法的扩展性.
方法重写
:
遵循两同两小一大原则
- 在继承关系中,方法名,参数列表,均相同;
- 子类声明的异常小于等于父类的异常类型,
- 子类的访问权限大于等于父类的访问权限;
- 注意子类的返回值类型要小于等于父类的返回值类型
使用场景:重载主要用于在一个类中,某一部分方法的具体实现细节差不多,只是要传递输入不同的参数类型;
比如在经典的String类型
中,就有不同的valueOf(...参数列表)
方法,就是方法重载的体现;
方法重写:就是比较常用的了,通常建议定义上层接口,然后下至分发不同的实现类,因为在jdk8以后,接口中也可以写非抽象的方法:静态方法和默认方法
;子类必须实现接口中的抽象方法,但是静态方法/默认方法可以根据需要进行实现.
比如集合中的Collection
接口,它就有较多的实现类/接口,子类可以使用上层父级的方法,或者扩展自己的新方法实现.
4.7 访问权限修饰符有哪些,作用?
方法权限修饰符有四种:public(公共的),private(私有),protected(受保护的),default(默认的);
- 对于外部类而言,只能有两种控制级别:
public
与default
;
在类,方法,局部变量/成员变量中可使用的一些修饰符(图源:牛客题目讨论区)
4.8 java中包的作用?
Java中使用的包可以避免类重名的问题;可以控制访问权限,可以根据不同的功能来管理类;
- 一级包,常用于命名项目的类型/公司业务类性(com);
- 二级包,用于命名醒目开发的公司(例如sun);
- 三级包,用于命名项目的名称(例如cms管理系统);
- 四级包,命名醒目的分化模块名称;
4.9 static关键字的用法?
使用static关键字,可以修饰方法,成员变量,代码块,内部类;
- 被static修饰的成员会伴随类加载而初始化;
- 被static修饰后,就可以被所有对象共享;静态属性在内存中只有一个;
- 由于被static修饰的静态方法会先加载,所以只能在静态方法中访问使用静态属性;
4.10 this,super关键字?
- this关键字用于调用本类自己的属性/方法,而super关键字用于调用父类的公共属性/方法;
- 注意this关键字要放在非静态方法中使用;
- super关键字用于继承关系中;
4.11 什么是抽象类,接口, 说说区别,以及为什么要使用抽象类,为什么要使用接口?
抽象类
:
首先来说说抽象方法,抽象方法呢,它只是声明方法,而不进行具体的实现(没有方法体);需要使用abstract
关键字修饰;
- 注意,我们使用的抽象方法不能用
private
,static
,synchronized
,native
进行修饰, - 由于抽象方法要被继承,要是能用
private(私有权限访问符)
修饰的话,它就不能被子类继承使用了; - 如果说一个方法被static修饰,它就可以用类名直接调用服务方法的具体实现了,但是抽象方法并没有具体的实现;
- 如果一个方法被synchronized修饰;会为方法加锁;但抽象方法没有具体实现;
- 由于native修饰的方法会被交给本地操作系统,若一块出现了;你这是要把实现交到操作系统手里还是实现子类手里呢
被abstract修饰的类就是抽象类;在抽象类中不一定要有抽象方法;但是定义了抽象方法的类必须声明为抽象类
;
注意抽象类不能用final关键字修饰,因为被final关键字修饰的类将不能被继承;
接口
: 是一个隐式抽象的抽象类;默认被 abstract
修饰 的interface 接口;
接口的属性默认使用public
修饰;
接口的方法默认使用public abstract
修饰;
在java8后,接口中支持定义静态方法和默认方法;
4.12 final关键字作用?
final
表示最终的;
final
关键字修饰类时,该类不可被继承;
final
关键字修饰方法时, 该方法不可被重写;
final
关键字修饰的变量,作为常量,定义常量时就应赋予初始化值,或在构造方法中进行初始化;
当final
修饰方法参数时,不能再方法中更改参数值;
finally
是异常处理时的关键字,常配合try,catch进行异常处理;作为异常处理的出口;
无论是否触发捕获异常,都会执行finally代码块中的内容;
当时学习网络编程链接的时候,就用到了finally代码块来执行关闭方法close()
,保证了链接安全关闭;
当时学习初步web开发流程时,刚开始学的时候没用到线程池;然后就需要频繁地打开关闭与数据库的链接,所以就在finally代码块中执行关闭链接的方法;
finalize
:垃圾回收时使用的方法;finalize() 方法允许在子类中被重写,用于在对象被回收时进行资源释放。在垃圾回收该对象之前,总会隐式地调用该方法;注意它仅能调用一次;
且finalize()
方法的执行时间不是确定的,只有发生GC垃圾回收时,才会触发;
虚拟机中的对象有三种存活状态,可达状态的(可触及的)
,可复活状态的
; 不可触及状态的
;
其中可达的就是从根结点触发,可以搜索到达的对象;
可复活的:当这个对象进行回收的时候,它在finalize()
方法中又被引用了,那么他就复活了;
但是注意若这个对象在回收时,执行finalize()
方法的过程中并没有被引用,那么该对象就是不可触及状态;且不会再有机会起死回生了. (finalize()
方法仅能执行一次)
📢五.第五章 常用类以及API
JavaSE基础六----<常用类(1)>【API||基本数据类型包装类||自动拆箱装箱||Object类||String类||StringBuffer类】
5.1 什么是基本类型包装类?
就是8种基本数据类型对应的引用包装数据类型;
本来Object是所有类的超类,但基本数据类型无法联系起来,
那么对这些基本数据类型做出引用类型的包装类,也就能很好地结合对象使用;
Byte,Short,Integer,Long
, 这四种类型都默认存在[-128,127]
的缓冲区;
Character
默认存在[0,127]
范围的缓冲区;
5.2 Object类中都有哪些方法?
常见的hashCode()
方法,用于计算当前对象的地址哈希值;
getClass()
方法,反射时使用;返回当前的运行时对象Class对象;
equals()
方法,用于比较对象的内存地址是否相同;
clone()
方法,用于对象克隆;
toString()
方法,用于输出当前类地址信息的字符串;
notify()
方法:唤醒一个等待线程;notifyAll()
唤醒所有的等待线程;
wait()
方法,让当前线程进入等待状态,注意会释放锁;
finalize()
方法,GC垃圾回收对象时触发,且仅执行一次.
5.3 String类定义的字符串特点?
字符串是由多个字符组成的一串数据(字符序列)的字符串常量,java中所有字符串都是String类的实例;
一旦定义就是不可变的,因为底层存储使用final
修饰的char类型数组;
在创建字符串对象时就已经为value[]
指定值;
5.4 创建字符串对象的方式有几种,有什么区别?
两种方式:
- String str = new String(“str”);
直接在堆中创建对象;
- String str = “str”;
首先在栈中创建引用变量,然后在字符串常量池中查找字符串对象,若没有则就在常量池中创建;
第二次使用时,若在常量池中找到了该字符串直接引用即可;
5.5 String,StringBuffer,StringBuilder的区别?
-
String类型:不可变类型的字符串;底层是
final char [ ] value
;因为数组一旦创建长度不可变;被final修饰的引用一旦指向某个对象之后,不可在指向其它对象; -
StringBuffer类型;StringBuilder可变类型的字符串;
底层是char [ ] value
;且都是继承自AbstractStringBuilder类
;适用于频繁操作字符串的场景; -
但是
StringBuffer类
支持线程安全;
StringBuffer和StringBuilder的初始化容量都是16;
调用数组工具类方法扩容
关于StringBuffer的length() 方法 和capacity()方法
5.6 String类常用的方法有哪些?
char charAt(int index)
用于查询到字符串的指定索引位置的字符;int compareTo(String anotherString)
比较两个字符串的大小;String concat(String str)
将指定的字符串串拼接到当前字符串的后面;boolean contains(CharSequence s)
判断是否包含指定的char值boolean startsWith(String prefix)
判断当前字符串是否以指定的前缀字符串开头;boolean endsWith(String suffix)
判断当前字符串是否以指定的后缀字符串结尾;boolean equals(Object anObject)
判断两个字符串的内容是否相同;byte[] getBytes(String charsetName)
将指定的字符串转换为字节数组表示;int indexOf(String ch)
计算指定的字符第一次出现的索引位置;String toString()
输出字符串;int lastIndexOf(String str)
计算指定字符串最后一次出现的位置;String replace(char oldChar, char newChar)
用指定的新字符替换旧字符后,返回替换后的字符串;String toLowerCase()
将当前字符串的字母转换为小写字母表示;String toUpperCase()
将当前那字符串的字母转换为大写字母表示;String trim()
清除当前字符串前后的空格;static String valueOf(int i)
将指定类型的参数转换为字符串类型;String substring(int beginIndex, int endIndex)
截取指定区间(左闭右开)的字符串;char[] toCharArray()
字符串转换为字符数组;String[] split(String regex)
按指定正则分隔字符串为数组;
5.7 == 和 equals的区别?
==
基本类型比较的是数值;
引用类型比较的是两个对象的内存地址;
equals()
方法
若没有重写equals()方法
,比较的是两个对象的内存地址是否相同;
若重写equals()
方法,则比较的是两个对象的内容;
一般来说,重写
equals()
方法伴随着重写hashCode()
方法;
对于那些需要比较哈希值的场景;
比如说要将这个自定义的对象存入到hashMap中,由于不可重复性,就需要同时重写equals方法和hashCode方法,保障不重复;
六.第六章 异常
JavaSE基础七----<异常>【常见的异常,异常处理机制,自定义异常】
6.1 什么是异常
异常:就是Java语言定义的,程序执行时的不正常状态就是异常;
由Throwable类
下至的两种异常;Error 错误
;Exception 异常
;
Error
错误是虚拟机都无法解决的程序运行错误;虽不可处理,但是可以尽量避免,比如说提前优化内存空间;注意Error错误不能再程序运行过程中被妥善处理,此时系统会记录错误且安全终止,退出当前进程。
Exception 异常
是程序本身可以处理的异常;分为运行时异常和检查期异常;
6.2 什么是运行时异常,编译期(检查)异常
运行时异常(RuntimeException),编译期异常(Checked Exception),就是一个是在程序运行时才会出现的异常,一个是在编写程序时就出现的异常;
运行期异常
:·比如常见的ArrayIndexOutOfBoundsException
数组越界;NullPointerException
空指针…
常见的IOException , SQLException
就是编译期的异常,所以在使用IO操作,或者链接SQL相关时,在调用编写时就会报出错误,要求我们强制进行异常处理.
6.3 异常处理try catch finally的作用,使用方式
一般来说,异常要么不处理:让系统自己抛出;要么就用try+catch+finally直接组合捕获处理异常;
要么用throw在方法中抛出异常对象,或是在方法处throws声明异常
try,catch,finally通常配合使用;
在try{}代码块中捕获异常;在catch{}
代码块中进行异常处理;
无论异常是否被处理,finally{}代码块中的代码都会被执行;若有return返回值时,先执行finally代码块中的语句;注意若在finally代码块出现之前执行了 System.exit() 方法,那么就不会执行finally代码块中的内容;
6.4 throw throws区别
throw用于在异常处理时抛出异常对象
;
throws用于在方法名末尾声明异常;也就是说告诉调用处这个方法中有异常;
如果是声明的是运行期异常,在方法调用处可处理,也可不处理;
如果声明的是编译期异常,在方法调用处,要么声明给调用它的上一级;要么try catch处理;
区别:
- 位置不同,throws作用在方法上,声明的是异常类;而throw作用在方法内,抛出的是异常对象;
- 功能不同;throws用于声明方法在运行过程可能出现的异常,便于调用处可以预先定义不同的处理方式;而throw用于抛出封装异常信息的对象,
七.第七章 集合
JavaSE基础八----<集合(1)>【泛型、集合体系、Collection接口中的方法,可变长度的参数】
JavaSE基础八----<集合(2)>【List接口及其实现类,List接口的迭代】
JavaSE基础八----<集合(3)>【Set接口及其实现类,Set接口的迭代方式】
JavaSE基础八----<集合(4)>【Map接口及其实现类 Collections类】
7.1 为什么提供不同的集合类
刚开始学习Java的时候,接触的第一种容器就是数组了,但是数组由于自身的限制;比如指定长度就不能改变,且一种类型的数组只能存储一种类型的数据…
这样一来就可以考虑是不是该用新的容器了,它的容量可以自扩容;甚至可以存储不同类型的数据;而且具有不同的结构,灵活高效…
那么,这些可以动态增长长度的容器—集合就来了;
7.2 List,Set,Map集合各自的特点
List集合 是重复的,有序的单列集合;三个实现类ArrayList
,LinkedList
,Vector
;
Set集合:不可重复的单列集合;适用于存储无序的(元素的添加顺序)、值不相等的元素;这里所说的对象是否相等其实基于对象的HashCode值是否相同。
Map集合:不可重复的双列集合;
7.3 List集合实现类有哪些,各自特点
ArrayList:基于数组实现,查询快、增删慢,线程不安全;在创建时可以不指定数组的长度;默认初始化长度为10,扩容速度为1.5倍;缺点是元素必须连续存储,若想插入元素,移动元素比较麻烦,所以说ArrayList适用于查询和遍历操作多的场景
LinkedList:基于双向链表实现,增删快,查询慢,线程不安全。若要进行插入/元素时,仅需改变节点的指向,比较方便;在LinkList
中还定义了操作链表头/尾部的方法。
void addFirst(E e) 在该列表开头插入指定的元素。
void addLast(E e) 将指定的元素追加到此列表的末尾。
E peekFirst() 检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
…
Vector:也是基于数组实现,增删慢,查询快,但是线程安全。 默认长度为10;扩容速度为2倍;
在同一时刻仅允许一个线程对Vector进行写操作,保证在多线程环境下的数据稳定,由于需要频繁加锁、释放锁,它的读写效率实际上比ArrayList差一点呢。
它用到的锁粒度过大,是可重入锁,非公平锁,独占锁,
7.4 ArrayList初始容量,扩容机制
ArrayList
的初始容量为10;
无参构造方法;在初步创建时,内部其实仅是个空数组;
添加第一个元素后,默认创建容量为10的数组;
当使用有参构造方法时,创建就产生指定长度的数组;
在add()方法中,当元素装满数组后,会进行扩容为原来的1.5倍;
看这个add方法;首先会进行数组长度的检测;这里size+1为检测是否还能存入一个新元素进去;
若目前的预算容量minCapacity
比数组的长度还大,就得考虑调用grow()方法
进行扩容了;
grow方法
private void grow(int minCapacity) {
// overflow-conscious code
//数组的目前长度;
int oldCapacity = elementData.length;
//预算扩容1.5倍后的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判断传入的(size+1预算minCapacity)的长度是否合适;
if (newCapacity - minCapacity < 0)
//若合适则就将数组长度定义为预算的1.5倍长度
newCapacity = minCapacity;
//这里还需判断是否大于数组的最大长度定义:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//若1.5倍的预算已超出定义的数组最大长度;
//则根据minCapacity(之前size+1)的长度决定用多少长度的。
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//采用数组复制方式扩容;将原来的内容复制到新的容量数组;再给数组elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
超出数组最大长度时调用的hugeCapacity方法;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
7.5 HashMap存储数据的特点
HashMap
是以数组加链表的形式存储数据,线程不安全;
首先基于键的HashCode值唯一标识数据,且同时基于key的hash值对数据进行存取
;所以他可以快速查询数据;key和value是允许为null的;
数组的每个元素都作为一个单项链表,而在链表的每个元素都是一个Entry(包含key,value,hash值以及指向下一元素的next)
默认容量为16,也是可以扩容的,负载因子为0.75,扩容大小为原来的两倍;也就是当容量到达3/4时就开始扩容,
为减少链表在遍历时的开销,在Java8时HahMap的存储结构有了一点小变化;
数据存储方式变为数组+链表+红黑树
;当链表的元素超过8个时,HashMap将链表结构转换为红黑树;
7.6 HashMap如何保证键不重复
HashMap中采用了 hashCode()
方法与equals()
方法双重检查法,保障键不重复;
拉链法存储
当哈希值相同内容不同时,就会产生哈希冲突;
7.8 Collection和Collections的区别
Collection:
作为集合接口;提供对集合对象进行基本操作的基本通用方法;
Collections:
集合工具类;定义了一些静态方法,不可被实例化;
八.第八章 IO流
JavaSE基础九----<IO流 (2)>【流的体系和分类,字节流,字节缓冲流】
JavaSE基础九----<IO流 (3)>【字符流,字符缓冲流】
JavaSE基础九—<IO流 (4)>【print打印流,对象输入输出流,对象序列化,transient关键字】
8.1 File类的作用
File类只能操作文件的属性,而不能操作其中的具体内容数据;
比如说新建文件夹,删除指定文件。
8.2 流可以分为哪些种类
流的分类;按照方向可分为输入流、输出流;
按照数据单位可分 字节流、字符流;
按照功能可分 节点流、缓冲流
8.3 字符流可以读取图片,音频等文件吗?
注意 字节流
可以读写二进制文件,主要处理音频、图片、歌曲、字节流,处理单元
为1个字节。
而字符流
主要处理字符或字符串,字符流处理单元为1个字符。
8.5 什么是对象序列化,对象反序列化,什么时候用?
对象序列化:将对象转换为字节序列存储文件,该对象需要实现Serializable接口
,
对象反序列化就是 读取字节序列存储文件转换为 对象的过程;
比如说需要持久性地将Java对象存储为文件形式,或者
注意:被transient修饰的属性,不会被序列化.
静态属性也不会被序列化.
九.第九章线程
JavaSE基础(十 一 )—<线程(1)>【线程概述,创建线程,以及线程的方法,优先级,状态,用户线程,守护线程】
JavaSE基础(十 一 )–<线程(2)>【线程同步,死锁,Lock锁,线程通信,生产消费问题,新增的线程创建方式】
9.1 什么是线程,进程, 他们之间的关系
首先一个进程就是正在执行中的程序,含有内存和资源以及存放线程,而一个进程又可以细分为一个/多个线程组成;线程是进程的最小执行单元;
9.2 java如何创建线程
创建线程有4种方式;
(1)继承Thread类;首先这个Thread类也是实现了Runnable接口的;
通过继承Thread线程类;重写其中的run方法;然后创建自定义类的对象;调用线程启动方法start()
;
/**
* @author by 信计1801 李智青 学号:1809064012
*/
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"自定义的线程执行体。。。");
}
public static void main(String[] args) {
MyThread m1 = new MyThread();
MyThread m2 = new MyThread();
m1.start();
m2.start();
}
}
//Thread-0自定义的线程执行体。。。
//Thread-1自定义的线程执行体。。。
(2)实现Runnable接口;
由于在Java的规则中,类只能单继承,那么如果当一个类已经继承了一个其他父类的时候,它没办法通过继承Thread类
的方式创建线程了,那么可通过实现接口的方式;比如Runnable接口;
创建自定义的线程对象之后,注意还不能直接启动,需要将创建的自定义对象放入到创建的Thread类对象中
,然后再使用Thread类
的启动方法;
可以看到在Runnable接口中仅有run方法;
/**
* @author by 信计1801 李智青 学号:1809064012
*/
public class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在执行---");
}
public static void main(String[] args) {
MyThread2 m1 = new MyThread2();
MyThread2 m2 = new MyThread2();
Thread thread0 = new Thread(m1,"线程1");
Thread thread1 = new Thread(m2,"线程2");
thread0.start();
thread1.start();
}
}
(3)实现Callable接口;
使用实现Callable的方式,可以获得一个返回值;
比如说需要在主线程中开启多个子线程并发执行任务,那么可以考虑统计返回的结果。
注意实现的Callable接口后,需重写它的call()方法,
/**
* @author by 信计1801 李智青 学号:1809064012
*/
//这里会根据指定的Callable接口方式指定返回值的类型;
public class MyThread3 implements Callable<String> {
private String threadName;
public MyThread3(String threadName) {
this.threadName = threadName;
}
@Override
public String call() throws Exception {
return "当前执行线程为--"+threadName;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池;
ExecutorService e = Executors.newFixedThreadPool(10);
//任务列表;
List<Future> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Callable callable = new MyThread3(i+" ");
//提交线程;
Future future = e.submit(callable);
System.out.println("当前提交线程"+i);
list.add(future);
}
//关闭线程池;
e.shutdownNow();
for (Future future : list) {
System.out.println("线程执行的返回结果"+future.get().toString());
}
}
}
当前提交线程0
当前提交线程1
当前提交线程2
当前提交线程3
当前提交线程4
当前提交线程5
当前提交线程6
当前提交线程7
当前提交线程8
当前提交线程9
线程执行的返回结果当前执行线程为--0
线程执行的返回结果当前执行线程为--1
线程执行的返回结果当前执行线程为--2
线程执行的返回结果当前执行线程为--3
线程执行的返回结果当前执行线程为--4
线程执行的返回结果当前执行线程为--5
线程执行的返回结果当前执行线程为--6
线程执行的返回结果当前执行线程为--7
线程执行的返回结果当前执行线程为--8
线程执行的返回结果当前执行线程为--9
(4)使用线程池;由于线程的频繁创建–使用–销毁,是比较消耗内存资源的,那么可考虑将线程装入线程池中,使用线程时获取即可;无需销毁线程;
重点知识学习(8.4)–[线程池 , ThreadLocal]
9.3 线程的状态有哪些
线程主要5个状态:
线程新生状态–线程就绪状态–线程运行状态–线程休眠阻塞状态–线程死亡状态;
首先,当前线程被new出来的时候就在新生状态
了;
当线程调用start()
方法后启动了线程就处于就绪状态
,随时等待CPU资源可用;
当线程获得CPU资源的执行权就可以到运行状态了
,注意在运行状态的线程:由于调用了yield()方法
或者失去CPU资源时会被遣送回就绪状态
, 或者由于线程休眠、线程等待、线程阻塞 而进入到阻塞状态
;进入阻塞状态
的线程在结束阻塞后,就会重新进入到就绪状态
,参与抢占CPU资源;
注意,当在运行状态
的线程:正常执行结束,或者出现Error错误/Exception异常时,或被执行了线程的强制停止方法stop()
时,线程会进入到死亡销毁状态
。
9.4 如何让线程从运行状态转换到阻塞状态
一般来说,阻塞状态可分为三种:
- 等待阻塞:当在运行状态的线程执行了wait()等待父,就会进入到等待任务队列中;
- 同步阻塞:当运行状态的线程尝试获取同步锁时,此时会被JVM放入到锁池中;
- 其他阻塞:运行状态线程执行了线程休眠方法sleep() 【当前线程休眠】/ 线程阻塞方法【当前线程快速执行,其他线程阻塞】/出现IO请求时,线程进入到阻塞状态,直至sleep()休眠时间到期,join()当前线程终止或超时,IO请求处理结束时,线程才回到就绪态;
9.5 线程何时会出现线程安全问题
线程安全问题主要是在多线程情况下,同一时间内多个线程抢占使用同一个资源时产生,也就是多线程并发时出现。
9.6 如何解决线程安全问题
在之前解决的线程安全问题时,主要是加锁,常用Synchronized 隐式加锁,或使用ReentarntLook显示加锁,
Synchronized 是隐式锁,可用于修饰方法或代码块作为同步方法/同步代码块,使用Synchronized 锁住的是当前类的对象/当前类Class对象/指定对象;
Synchronized是悲观锁,可重入锁,非公平锁,独占锁;
悲观锁与乐观锁的区别;乐观锁主要采用CAS(比较交换机制)、不断比较和更新交换数据,但悲观锁会认为线程的每次更新操作都是线程不安全的、需要加锁。
可重入锁:外层方法获取到锁之后,在内层的调用方法中也能获取到这把锁;
非公平锁:线程释放锁资源后,线程们一拥而上获取锁,而不是规矩的排队等待获取锁;
独占式锁:当前的锁被一个线程使用时,其他线程不能来使用。
ReentarntLook作为显示锁,可用来修饰代码块;在使用时需要手动加锁,手动释放锁。是可重入锁,公平锁/非公平锁(可设置), 独占锁。
9.7 sleep() 和 wait()的区别
sleep()
:是Thread线程类中的方法;使得当前线程进入休眠阻塞状态,不会释放锁;在休眠时间结束后自己回到就绪状态;
wait()
:是Object基类中的方法,使得当前线程进入等待阻塞状态,会释放当前锁资源,
十.第10章网络编程
JavaSE基础十—<网络编程>【网络编程概述||通讯要素:IP和端口号,网络通信协议||关于InetAddress类||实现TCP通信||实现UDP通信】
10.1 网络模型 OSI七层模型和TCP/IP四层模型
网络模型OSI七层模型
七层模型,主要包括物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
物理层
定义 物理设备标准,主要用于传输比特流;在发送端将0,1码转换为电流强弱传输,到达目标之后再根据电流强弱转换为0,1码,即数据模型转换、模数转换。
数据链路层
:主要是对数据包MAC地址解析封装处理,该层数据以帧
存储,设备有网卡,网桥,交换机。
网络层
:用于对数据包中的IP地址及逆行封装解析处理。数据包
存储。设备:交换机,路由器,防火墙。
传输层
:定义传输数据的协议和端口号。主要对数据分段、传输、重组。常用协议TCP/UDP。
TCP传输控制协议:传输稳定,数据量小,但是效率低。
UDP用户数据包协议:传输不稳定,数据量大。
会话层
:在传输层基础上, 建立网络连接,管理会话资源。设备之间识别可用IP/MAC/主机名。
表示层
:对于接受的数据进行解释,解密/加密,压缩/解压缩 处理。将计算机识别内容转换为开发者可识别内容 --》(图片/音频/文字)。
应用层
:基于网络构建具体应用于访问网络的服务接口,比如FTP文件上传下载服务,HTTP服务…
TCP/IP四层模型
TCP/IP协议是指整个TCP/IP协议簇;分为网络接口层、网络层、传输层、应用层。
网络接口层
:定义主机之间的网络连接协议。
网络层
:用于数据的传输、路由、地址解析。保障主机将数据发送到网络上的目标,主使用IP、ARP地址解析协议。
传输层
:将发送端–接收端的对等实体基于会话进行通信。定义了端到端的TCP/UDP协议。
应用层
:定义具体应用层协议。FTP(文本传输协议),HTTP(超文本传输协议)…
10.2 网络通信基本要素有哪些
网络通信基本要素:IP、端口号、网络通信协议。
IP:可以精准定位到互联网上的机器;
端口号:可用来标识正在计算机上运行的程序。
通信协议:计算机在网络中进行通信时,规定的协议标准制度,例如通信速率、控制方式…
10.3 TCP,UDP通信协议的区别
TCP控制传输协议
:面向连接使用,在发送数据前需建立连接。传输速度慢,会将数据包按顺序排列;重量级连接,需进行三次握手、四次挥手。数据连接可靠,用到SYN\SYN-ACK\ACK协议。
UDP用户数据包协议
:无需建立连接,传输速度较快,不可靠,无法保障可将数据送达。里面的数据包没有固定的顺序,相互独立。
10.4 解释TCP三次握手,四次挥手
三次握手
- 首先客户端向服务端发出SYN(同步序号)报文;且进入同步已发送状态;
- 服务端收到后,打开客户端连接,回应SYN报文;以及ACK(确认字符);进入SYN-RECV(同步已接收状态);
- 客户端收到SYN报文后,回应ACK报文,进入连接状态; – 服务器进入连接状态。
四次挥手:
- 当客户端打出断开请求时,携带
FIN
(终止标志位)表示当前客户端的数据已经发送好了,需要关闭网络链路操作,请求服务器确认, 然后客户端进入最终等待状态1(FIN-WAIT
); - 服务器收到消息后,又想客户端发出携带 ACK报文确认消息,表示已收到客户端的断开请求。服务器随之到达关闭等待状态(CLOSE-WAIT)/半关闭状态;而客户端收到回复时就会进入到再次的最终等待状态2;
- 服务器关闭连接之前还需要向客户端发出数据,包括终止标志位FIN 和 ACK确认报文;请求客户端确认关闭连接,服务器进入
LAST-ACK
最终的确认状态; - 客户端收到FIN消息,发出ACK确认报文,表示会断开连接。注意客户端此时位于
TIME-WAITING
计时等待状态,设置的超时时间结束后才到关闭状态。