一、Java概述
1、Java之父
詹姆斯 · 高斯林 java曾用名Oak
2、Java的三大平台版本:
- J2ME: 小型版 嵌入式开发
- J2SE:标准版 桌面应用开发
- J2EE:企业版 企业应用程序开发
3、Java语言的特点
- 简单性:Java的语法相较于C语言和C语言很接近,但代码量减少,使得大多数程序员很容易学习和使用Java。
- 健壮性:检查机制,程序编译期间检测,报错。
面向对象:是世界上第一个完全面向对象的语言。- 可移植性:基于JVM运行,在对应版本的JVM中都可以运行。
- 多线程:同时执行多个不同功能的代码。
- 分布式:程序功能分割执行,在不同的服务器中。
- 安全性:Java通常被用在网络环境中,因此,Java提供了一个安全机制以防恶意代码的攻击。
- 动态性:初始jdk只安装常用的基础功能,可以通过扩展的形式进行额外功能的添加。
4、jdk、jre、jvm简述(分别介绍、关系介绍)
- JDK:Java开发工具包,提供了编译、运行Java程序所需要的各种工具和标准,包括源代码以及公共jre并且包含开发环境的所有功能。
- JRE:Java运行环境,为Java的运行提供了所需环境,用于解释执行Java的字节码文件。
- JVM:Java虚拟机,是整个java实现跨平台的最核心的部分,保证程序的跨平台性,以及编译执行写好的java程序,是可运行Java字节码文件的虚拟计算机。
- 关系:JDK、JRE和JVM三者是包含关系,使用JDK开发完成的java程序,交给JRE去运行,由JVM保证跨平台性。
5、jdk安装注意事项(自定义安装、安装、jdk8之前版本与之后版本安装)
- 自定义安装:需要单独创建jdk与jre文件夹保存。
- 默认安装:只需要记住安装路径。
- JDK8版本之前安装会分别安装jdk与jre需要分别存储,JDK内部有专用JRE、 需要专用JRE才能运行JDK中包含的工具;而后边下载的JRE是公共JRE,这个JRE可由其他Java应用程序使用。
- 之后由于安装了公共的JRE,所以在安装成功后无需配置 就可以直接执行java的运行命令。
6、环境变量配置(配置哪些环境变量,有哪些不用配置,配置项作用)
配置三个变量
- Class Path:在jdk1.5版本之后默认进行配置无需配置。 //用于设置编译Java文件工具以及编译文件位置
- Path:添加固定变量%JAVA_HOME%\bin; //用于使计算机在任意位置都可以识别java编译指令
- JAVA_HOME:变量名固定为:JAVA_HOME;变量值为安装jdk的目录。 //标志jdk安装路径,为第三方需要使用jdk的软件提供支持
二、Java基础语法
1、第一个java程序(书写注意事项,编译运行过程)
public class HelloWorld{
public static void main(String [] args){
System.out.println("Hello!");
}
}
- JAVAC:将以.java结尾的源文件编译为以.class结尾的二进制字节码文件。
- JAVA:运行指定的类
2、注释(功能、分类、特点)
注释是对代码的解释和说明的文字
分类:
- 单行注释:以//开始 注释本行内容
- 多行注释:以/开始 注释到/结束中的多行内容
- 文本注释:以/*开始 注释到/结束中的多行内容,不同的是可以使用@author等注解进行额外内容的书写。
3、标识符(规则、规范(类、包、常量))
标识符是用户编程时使用的名字,用于给类、方法、变量、常量等命名。
组成规则
- 以字母、数字、下划线_、美元符号$组成
- 不能以数字开头
- 不能以关键字命名(可以使用组合命名)
- 严格区分大小写
- 同一{}内不允许出现同名标识符。
命名规范
- 见名知意: 标识符命名与实际功能关联
- 驼峰命名法: 如果标识符由多个单词组成除首单词外其他单词首字母大写userName,passWord
类: 要求满足基本规范的前提下首字母大写。
包: 通常以倒置的域名进行命名,全部由小写字母组成多个包之间使用.分隔。com.公司名.项目名.部门名.功能名
变量名和方法:
- 一个单词: 全部小写 value get()
- 多个单词: 从第二个单词的首字母开始,每一个单词都要大写 maxValue getValue() (小驼峰)
自定义常量:
- 一个单词: 全部大写 MAX VALUE
- 多个单词: 全部大写 中间用 _ 隔开 MAX_VALUE
4、常量与变量
- 常量: 在程序运行过程中,其值不可以发生改变的量。
- 变量: 在程序运行过程中可以改变的量。
5、数据类型(两大类、四类八种、所占字节数、位数取值范围)
两大类:
- 基本数据类型: 整数类型(byte、short、int、long),浮点类(float、double),字符型(char),布尔型(boolean)。
- 引用类型: 类、数组、接口
6、类型转换(自动转换、强制转换 )
- 自动转换: 数据类型小向数据类型大的转换
- 强制转换: 数据类型大向数据类型小的转换由于是强制转换可能造成数据的溢出,所以需要使用特定语法进行强制类型转换要转换的小的类型:变量=(要转换的小的类型)大的类型变量;
(byte、short、char)——> int——> long——> float——> double 从左到右自动转换
7、运算符(分类)
- 算数运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 位运算符: 是计算机底层进行数值计算的方式,先将数据转换为二进制之后进行位运算
- 三目运算符: 数据类型 变量名=布尔表达式?值1:值2 //三目运算符会返回结果,所以一般使用变量接收。
8、&与&& 的区别
- 1.&——位运算符、逻辑运算符
&作为逻辑运算符时,&左右两端条件式有一个为假就会不成立,但是两端都会运行,比如(1+2)=4 &(1+2)=3;1+2=4即使为假也会去判断1+2=3是否成立。- 2.&&——逻辑运算符
&&也叫做短路运算符,因为只要左端条件式为假直接不成立,不会去判断右端条件式。- 3.相同点:
&与&&都是与运算,当等式两边结果都为true时返回true,等式两边存在fasle时返回false。只要有一端为假,则语句不成立
9、哪句是编译失败的呢?为什么呢?
byte b1=3,b2=4,b;
b=b1+b2;
b=3+4;
b=b1+b2;会编译失败
在进行赋值时虽然默认为int类型 但是如果数值在存储范围内不会出错
进行如果进行运算的是变量会获取对应地址存储的数据类型,进行运算后结果根据运算的类型进行转换,之后在进行赋值
10、++ --放在变量前后的区别
++ --放在前面先执行自加或自减然后执行程序,
++ --放在后面先执行程序,在对数值进行自加或自减。
11、顺序流程控制语句(概念)
顺序流程控制语句 就是java程序默认的执行顺序,java程序从上至下从左至右逐条运行。类默认执行main方法
12、选择流程控制语句(分类、语法)
选择流程控制语句 也称为分支流程控制语句,可以在代码书写时定义多个分支,在执行过程中根据条件表达式返回的结果,进行分支的执行。
- 按语法:
if…else
switch…case
- 按分支个数:
单分支、双分支、多分支
13、switch与if的区别
- switch表达式的结果只能byte short char int String(1.74以后) 枚举(1.5以后)
- if表达式可以为结果,也可以是表达式
- switch常用于caes值有限个且较少的时候,if可以用于根据范围执行不同语句
14、switch不书写break导致的问题
程序一直执行
15、if分支语句与三目运算符的区别
- if分支语句是使用if关键字的特殊流程控制语句语法,三目运算符本质是运算符
- 三目运算符会将结果返回,if语句不需要返回值
- 在java源码中大量使用了三目运算符
- 三目运算符书写的功能都可以使用if语句完成,但是反之可能要书写额外代码
- 三目运算符运算结束后只能返回一个数据,if语句可以在代码块中对多个数据赋值
- 三目运算符与if语句不成立的条件与代码块都不会执行
- 三目运算符执行效率相比较if可能较低(如果三目运算符与if语句的结果都为常量时,三目运算符的效率高)
16、while循环与do…while循环的区别
- 1、执行流程不同
while先执行条件表达式,do…while先执行循环体- 2、循环体执行次数不同
while循环可能一次都不执行,do…while至少执行一次- 3、使用场景不同
while是先判断后执行,do…while是先执行后判断。当第一次条件不成立时,while不会执行!而do-while无论是否成立都至少会执行一次!
17、while循环与for循环的区别:
- 1、语法不同
使用不同的关键字实现循环功能- 2、初始化变量作用域不同
while循环创建的初始化变量在循环结束后也可以使用)- 3、内存占用区别
for循环内创建的变量在for循环结束后就会回收 => 初始化与方法体中变量- 4、使用场景不同
- (1)如果在循环结束后仍然需要使用初始化变量使用while
- (2)如果进行有限次数的循环使用for(存在固定次数)
18、break、continue、return
break
: 跳出当前循环(结束当前循环),结束循环 , 会结束当前循环继续执行后续代码continue
: 跳过本次循环,进入下次循环 , 跳过当前循环后续应该执行代码,进入下一次循环,循环结束后执行后续代码return
: 方法级别的结束 , 结束当前方法(main方法) 当前方法后续代码不会运行 , return后不能书写代码
19、 外循环执行一次,内循环执行一圈
01、打印长方形
for(int i=1;i<=3;i++){
for(int j=1;j<=5;j++){
System.out.print("*");
}
System.out.println();
}
02、 打印直角边在左下的直角三角形
for(int i = 1; i <= 5; i++){
for(int j = 1; j <= i; j++){
System.out.print("*");
}
System.out.println();
}
03、 打印直角边在左上的直角三角形
for(int i = 5; i >= 1; i--){
for(int j = i; j >= 1; j--){
System.out.print("*");
}
System.out.println();
}
04、 打印直角边在右下的直角三角形
for(int i = 1; i <= 5; i++){
for(int j = 5; j >= 1; j--){
if(i < j){
System.out.print(" ");
}else{
System.out.print("*");
}
}
System.out.println();
}
05、 打印直角边在右上的直角三角形
for(int i = 1; i <= 5; i++){
for(int j = 1; j <= 5; j++){
if(i > j){
System.out.print(" ");
}else{
System.out.print("*");
}
}
System.out.println();
}
06、 打印正等腰三角形
for(int i = 1; i <= 5;i++){
//控制前面空格
for(int j = 1; j <= 5 - i; j++){
System.out.print(" ");
}
//控制每行的*
for(int k = 1; k <= 2 * i - 1;k++){
System.out.print("*");
}
System.out.println();
}
for(int i = 1; i <= 3; i++){
for(int j = 1; j <= 5; j++){
//扣去左上角和右上角,用空格代替
if(j <= 3 - i || j >= 3 + i){
System.out.print(" ");
}else{
System.out.print("*");
}
}
System.out.println();
}
07、 打印倒等腰三角形
for(int i = 5; i >= 1; i--) {
System.out.println();
//根据5-i的值确定前面空格的数量
for (int n = 1; n <= 5 - i; n++) {
System.out.print(" ");
}
//根据公式2*i-1确定打印*的个数
for (int j = 1; j <= 2*i-1; j++) {
System.out.print("*");
}
}
20、数组(概念、分类、特点、创建)
数组: 用于存储具有相同数据类型的容器。
- 分类:
一维数组、多维数组
- 特点:
- 存储数据类型统一
- 可以存储任意数据类型
- 存储长度在创建时已经固定
- 存储类型固定
- 创建:
- 动态创建
int[] arr = new int[3];
- 静态创建
int[] arr = {1, 2, 3};
- 动态创建
21、内存分配
- 栈: 保存的是运行过程中声明的变量,其中保存的是栈的名与数据地址 堆的回收时间根据回收算法决定(不用就回收)
- 堆: 堆中保存的是运行过程中创建的对象(所有new出来的内容) 栈的回收时间根据回收算法决定(不用就回收)
- 常量池: 保存运行过程中创建的常量(只要是在代码中出现的常量) 常量池数据在整个程序运行结束后回收
22、冒泡排序算法
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
int []arr = {8,7,2,9,3,5,4,6,1};
//从小到大排序
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length - 1 - i; j++){
if(arr[j] > arr[j + 1]){
int temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
//从大到小排序
for(int i = 0; i < arr0.length - 1; i++){
for(int j = 0; j < arr0.length - 1 - i; j++){
if(arr0[j] < arr0[j + 1]){
int temp = arr0[j];
arr0[j] = arr0[j + 1];
arr0[j + 1] = temp;
}
}
}
23、选择排序算法
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
int []arr = {8,7,2,9,3,5,4,6,1};
//从小到大排序
for(int i = 0; i < arr.length - 1; i++){
int minIndex = i;
for(int j = i + 1; j < arr.length; j++){
if(arr[minIndex] > arr[j]){
minIndex = j;
}
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
//从小到大排序
for(int i = 0; i < arr.length - 1; i++){
int maxIndex = i;
for(int j = i + 1; j < arr.length; j++){
if(arr[maxIndex] < arr[j]){
maxIndex = j;
}
}
int temp = arr[i];
arr[i] = arr[maxIndex];
arr[maxIndex] = temp;
}
24、方法的定义(组成,组成部分功能)
方法:又称之为函数,将一行或多行代码进行封装,提供统一的方法名,通过方法名以及参数进行使用;
- 修饰符:public static固定写法;用于修饰当前方法定义当前方法使用权限。
- 返回值类型: 用于定义方法执行结束后返回数据的类型,如果方法无需返回数据则使用void。
- 方法名: 用于定义方法的名称 ,符合标识符命名规范
- 参数列表: 用于声明方法执行时需要使用的数据,可以有零到无穷个。
- 方法体:用于定义方法执行时实际执行的代码
25、方法的重载(概念、特点、参数不同的三种情况)
概念: 在同一个类中,方法名相同参数列表不同我们称发生了方法的重载或两方法互为重载。
- 特点:
- 参数个数不同 ==> 两个方法 方法名相同 参数列表个数不同
- 参数数据类型不同 ==> 两个方法 方法名相同 参数列表个数相同 参数类型不同
- 参数顺序不同 ==> 两个方法 方法名相同 参数列表个数相同 参数类型相同(个数类型两个以上) 参数数据类型的顺序不同
仅有返回类型不同是不足以区分两个重载的方法。
26、形参与实参
- 形参: 声明方法时参数列表声明的变量
- 实参: 调用方法时实际传入的数据变量
27、override重写与overload重载的区别
overload: 方法重载
- 在一个类,方法名相同参数列表不同称发生了方法的重载,或多个方法互为重载
- 仅有返回类型不同是不足以区分两个重载的方法。
- 参数列表不同:
- 1.参数个数不同 ==> 两个方法 方法名相同 参数列表个数不同
- 2.参数数据类型不同 ==> 两个方法 方法名相同 参数列表个数相同 参数类型不同
- 3.参数顺序不同 ==> 两个方法 方法名相同 参数列表个数相同 参数类型相同(个数类型两个以上) 参数数据类型的顺序不同
override: 方法重写
- 发生继承过程中,子类重写继承父类方法,称之为重写。
overload和override的区别:
- ①发生位置不同: 重载一般发生在同一类中,重写发生在继承中
- ②书写语法不同: 重载只需要方法名与参数列表就可以发生,重写返回值、方法名、参数列表必须与父类相同
三、JavaOOP
1、面向对象编程思想(概念、优点)
面向对象编程思想: 是一种程序设计思想,是在计算机程序设计过程中,参照现实中的事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。
- 优点:
- 更符合我们的思想
- 将复杂的事情简单化
- 将我们从执行者变为了指挥者
- 三大特征:
- 封装、继承、多态
2、类的概念(类与对象的关系)
类:是一组相关属性和行为的集合。
- 类与对象的关系
- 1、类是大量对象共性的抽象
- 2、对象是类的具体表现
- 3、类是创建对象的模板
3、对象的概念
对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为 。
4、成员变量和局部变量的区别
在类中的位置不同
- 成员变量:类中,方法外
- 局部变量:方法中或者方法声明上(形式参数)
作用范围不一样
- 成员变量:类中
- 局部变量:方法中
初始化值的不同
- 成员变量:有默认值
- 局部变量:没有默认值。必须先定义,赋值,最后使用
在内存中的位置不同
- 成员变量:堆内存
- 局部变量:栈内存
生命周期不同
- 成员变量:随着对象的创建而存在,随着对象的消失而消失
- 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
5、面向对象-封装(概念)
- 对类隐藏内部执行代码与数据细节,提供公开简单方式进行使用。
- 方法的封装就是将多行代码封装成方法,使用方法名进行标识使用;
- 类的封装就是将属性与方法封装成类,为指定的类创建对象提供属性和行为。
- 现在的封装指的最多地是对属性的封装,使用private关键字对属性进行修饰使其只对当前类可见,提供公开的方法进行访问,大大地提高了系统的安全性。
6、访问权限修饰符
用于修饰类、成员变量、方法的关键字,用于设置其使用范围(可见性)
public
公共的空格
默认,如果没有书写访问权限修饰符,系统会默认添加protected
受保护的private
私有的,只有当前类的方法才能够访问
7、this关键字
this代表所在类的当前对象的引用(地址值),即对象自己的引用。
this
中保存的是调用对象的内存地址。- 方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
8、this关键字与super关键字(指代对象、调用构造方法)
- this代表所在类的当前对象的引用(地址值),即对象自己的引用。
- super调用的是指代对象的父类
- this: 当前类中方法声明的形参与成员变量相同时,使用this关键字标识成员变量
- super: 在继承过程中子类属性方法与父类属性方法相同时,使用super关键字标识父类属性与方法
- this与super都可以调用构造方法
this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法
9、构造方法(作用、书写、重载、构造方法的特点)
构造方法 又称之为构造函数、构造器,在使用new关键字创建对象时,由jvm调用根据传入的参数创建对象并对属性进行赋值。
- 作用:
创建对象并进行初始化赋值。
- 重载:
构造方法重载,一般指的是参数个数不同
- 特点:
- 构造方法没有返回值
- 构造方法的方法名就是类名
- 所有的类都有构造方法,如果在代码书写中没有显式定义构造方法,那么在编译时jvm会自动添加一个无参构造方法
- 如果类中书写了任意构造方法,那么不会在提供无参构造方法
10、面向对象-继承(概念)
继承就是子类继承父类非私有的属性和方法,使得子类对象具有与父类相同的属性、相同的方法。子类可以直接访问父类中的非私有的属性和方法。继承描述的是事物之间的所属关系。
- 特点:
- Java中的继承是单继承(一个子类只能拥有一个父类,但是一个父类可以拥有多个子类)
- 继承关键字书写在子类
- 子类可以继承父类非私有的属性与方法
- 子类可以书写额外的属性与方法
- 类与类之间产生了关系,是多态的前提。
11、方法重写(概念、要求、@Override)
方法重写: 在继承过程中,子类继承父类方法,父类方法不满足子类需求,子类重写父类方法方法体,实现方法的重载。
- 重写要求:
修饰符访问范围大于或等于父类 返回值不能修改 方法名不能修改 参数列表不能修改 方法体根据需求修改。
- @Override:
重写注解,无特殊功能,用于标识重写的方法,被该注解标识的方法必须满足方法重写的语法规则 。
12、抽象类(概念、注意事项)
在类的书写过程中如果存在由于类的定义无法实现的方法时,将方法定义为抽象方法,同时将类定义为抽象类。
- 抽象的注意事项:
- 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类
13、接口(概念、特点、使用、总结)
接口,是Java语言中一种引用类型,是方法的集合, 接口的内部主要就是封装了方法(功能),包含抽象方法 (JDK7及以前) , 默认方法和静态方法(JDK8)私有方法(JDK9)。 可以理解为大量抽象方法的抽象。
- 特点:
①成员变量: 接口中的成员变量只能是静态常量
②成员方法: 接口中书写的方法只能是抽象方法,
③构造方法: 没有构造方法,因为接口主要是扩展功能的,而没有具体存在
- 使用:
接口是不能创建对象,必须有实现类才能使用,类实现接口用
implements
表示 。
- 总结:
①接口中只有常量和抽象方法
②接口是没有静态代码块和构造方法的。
③一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。 单继承多实现。 public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { // 覆盖重写所有抽象方法}
④如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
⑤接口的实现类必须重写接口中的所有的抽象方法,要么该类是一个抽象类
14、抽象类与接口的区别
- 语法区别: 抽象类使用abstract关键字修饰class 接口使用interface关键字创建
- 成员变量区别: 抽象类可以书写任意变量,接口中只能书写静态常量
- 成员方法区别: 抽象类中既可以书写实现方法也可以书写抽象方法,接口中只能拥有抽象方法
- 修饰符区别: 抽象类中修饰符与类的修饰符默认书写一致,接口中方法修饰符默认为public abstract
- 构造方法区别: 抽象类中可以书写构造方法,由子类调用进行赋值,接口中不能书写构造方法
- 关系区别: 类与类之间只存在单继承关系,类与接口存在多实现关系,接口与接口可以多继承
- 设计理念区别: 抽象类为了继承而来,让子类强制重写父类中的抽象方法,接口是对行为抽象,主要是行为的集合。
15、面向对象-多态(概念、发生条件、书写、转型)
多态: 一个父类不同的子类形态,根据不同的形态决定代码的调用与执行。
发生条件(完整性): ①子类继承父类或实现类实现接口、②方法重写、③向上转型(声明父类变量保存子类对象)。
- 书写:
- 普通类多态的格式
父类 对象 = new 子类();- 抽象类多态的格式
抽象类 对象名 = new 抽象类子类();- 接口多态的格式
接口 对象名 = new 接口实现类();
- 多态的转型:
向上转型: 声明父类变量,保存子类对象,类似于java的自动类型转换
向下转型:- 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
- 声明子类变量,保存父类声明对象变量,类似于java的强制类型转换,需要书写额外语法
- 向下转型成功的前提(曾经发生过向上转型并且与转型类型相同)
16、内部类(同级类、成员内部类、局部内部类、匿名内部类)
概念: 在一个类的内部书写另一个类
同级类: 严格意义来讲不算内部类,只不过是在同一个.java中定义多个类;
成员内部类: 在一个类类体中定义另一个类,将定义类的当做是类的成员;
局部内部类: 在一个类的方法中定义一个类;
匿名内部类: 创建具有实现方法的无名称的类;//匿名内部类必须继承一个父类或者实现一个父接口。
17、final关键字
- final关键字代表最终的,用于修饰类、方法、变量。
- 被final修饰的类无法被继承,被final修饰的方法,可以被继承不能被重写,被final修饰的变量称之为自定义常量,只能被赋值一次。
- 如果修饰的局部变量,可以只声明不赋值,但是在使用时必须进行赋值且只能读取,不可修改。
- 如果修饰的是全局变量,在声明时必须赋值,因为如果不进行赋值在进行创建对象时可能会使用默认值赋值,导致属性无意义。
- 如果修饰的是引用数据类型,变量保存的是地址,地址不能修改,但是对象属性的地址可以修改。
- 被final修饰的变量,标识符一般使用大写字母进行命名,多个单词组成使用_连接。
18、static关键字
static: 静态的,类的,用于修饰成员变量以及成员方法
被static修饰的成员变量称之为类变量或静态变量,被static修饰的方法称之为类方法或静态方法
- 注意事项:
- 静态方法可以直接访问类变量和静态方法。
- 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。
- 静态方法中,不能使用this关键字。
静态代码块: 就是一个可执行的代码块,在类第一次被使用时执行,且只执行一次,常用与对静态的属性进行初始化赋值
19、访问修饰符的访问范围
public | protected | default(空的) | private | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一包中(子类与无关类) | √ | √ | √ | |
不同包的子类 | √ | √ | ||
不同包中的无关类 | √ |
- 在四大权限中,public是最大的权限,private是最小的权限;
- 在编写代码时,如果没有特殊的考虑,建议以下使用方式;
- 成员变量使用 private ,隐藏细节。
- 构造方法使用 public ,方便创建对象。
- 成员方法使用 public ,方便调用方法
20、详述面向对象三大特性
1、封装
- 概念:
- 对类隐藏内部执行代码与数据细节,提供公开简单方式进行使用。
- 分类:
- 方法的封装就是将多行代码封装成方法,使用方法名进行标识使用;
- 类的封装就是将属性与方法封装成类,为指定的类创建对象提供属性和行为。
- 现在的封装指的最多地是对属性的封装,使用private关键字对属性进行修饰使其只对当前类可见,提供公开的方法进行访问,大大地提高了系统的安全性。
2、继承
- 概念:
子类继承父类非私有的属性和方法,使得子类对象具有与父类相同的属性、相同的方法。- 作用:
继承描述的是事物之间的所属关系,实现了代码的复用。3、多态
- 概念:
一个父类不同的子类形态,根据不同的形态决定代码的调用与执行。- 发生条件:
①子类继承父类或实现类实现接口②方法重写③向上转型(声明父类变量保存子类对象)。
四、工具类
1、Scanner类
2、Random类
3、Object类(概念、常用方法)
Object类: 是所有类的父类,也叫做基类(超类),所有类都直接或间接继承于Object类,一个类如果没有显式继承任何一个类,那么默认继承Object类。
- 常用方法:
finalize()
方法: 回收方法
hashCode()
方法: 返回对象的哈希码值
equals()
方法: 用于判断指定对象与当前对象是否相等
toString()
方法 : 返回该对象的字符串
4、final finally finalize()区别
final: java中的关键字,修饰符。
- A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
- B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
- 1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
- 2)被声明final的方法只能使用,不能重载。
finally: java的一种异常处理机制。
- finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
finalize: Java中的一个方法名。
- Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
- finalize()方法是回收方法,当GC发现对于当前对象没有引用自动调用进行回收,每个对象只能调用一次finalize方法
5、hash值相同的两个对象值一定相同吗
不一定,但是java中规定,如果两个对象值相同,那么hash值一定也相同
System.out.println(“Aa”.hashCode()); // 2112
System.out.println(“BB”.hashCode()); // 2112
6、为什么重写equals()方法必须重写hashCode()方法
java中规定,如果两个对象值相同,那么hash值一定也相同
如果equals方法返回true那么两个对象的hash值一定相同
反之不一定成立
7、equals()与==的区别
- equals()是Object提供的方法,== 是比较运算符
- == 常用与比较基本数据类型中数值类型值是否相等,比较引用数据类型时,比较的是两个对象是否为同一个对象(物理地址是否相同)
- equals()是Object类提供的方法源码中使用的就是 == ,一般子类会重写equals()方法进行内容的比较
- == 既能比较基本数据类型也能比较引用数据类型,equals()只能比较引用类型(参数为Object,只能使用多态传入任意对象类型)
8、String类(本质、构造方法、常用方法)
String中保存的是字符串常量
- String的本质是
- JDK8之前是char[] 数组
- JDK8之后是byte[] 数组
- 构造方法:
String()
构造方法:空字符串String(byte[] arr)
构造方法: 通过使用指定的 byte 数组,构造一个新的 StringString(char[] arr)
构造方法: 使用指定的char数组,创建字符串String(String str)
构造方法: 使用指定的字符串常量创建字符串String(char[] arr,int startIndex,int endIndex)
构造方法: 使用指定char数组指定索引长度的内容创建字符串
- 常用方法:
length()
方法: 用于返回当前字符串中字符个数(返回底层数组长度)charAt(int index)
方法: 用于获取当前字符串中指定索引对应的字符concat(String str)
方法: 由于字符串是常量不可以修改,所以字符串String提供的方法会返回一个新字符串contains(String str)
方法: 判断指定字符串在当前字符串中是否存在startsWith(String str)
方法: 判断当前字符串是否以指定字符串开头或结尾endsWith(String str)
方法: 判断当前字符串是否以指定字符串开头或结尾getBytes()
方法: 用于获取当前字符串所代表的字节数组indexOf(String str)
方法: 用于获取指定字符串在当前字符串中第一次或最后一次出现的索引lastIndexOf(String str)
方法: 用于获取指定字符串在当前字符串中第一次或最后一次出现的索引replace(String str,String str)
方法: 将当前字符串中指定字符串替换为另一个字符串split(String str)
方法: 使用指定分隔符分割字符串为字符串数组substring(int index)
方法: 返回当前字符串指定索引后的字符串toCharArray()
方法: 将当前字符串创建新的char数组返回toUpperCase()
方法: 将当前字符串中字母转换为大写/小写创建新的字符串返回toLowerCase()
方法: 将当前字符串中字母转换为大写/小写创建新的字符串返回
9、StringBuffer类
StringBuffer类:是一个带有缓冲区的,线程安全的可变字符序列,是API提供用于操作字符串的工具类。
- 构造方法:
StringBuffer()
构造方法:创建一个空的字符串StringBuffer(int length)
构造方法:根据参数创建指定字符大小的空字符串。StringBuffer(String str)
构造方法: 根据参数创建指定字符长度的缓冲区并存储指定字符(初始长度+字符串长度)。
- 常用方法:
append()
方法: 在原字符串后继续添加其他字符串delete()
方法:删除指定索引中间字符串,保留其他字符串insert()
方法: 将指定字符串插入当前字符串指定索引位置replace()
方法: 将指定索引范围替换为指定字符串reverse()
方法: 将字符串反转subString()
方法: 返回该对象的字符串
10、StringBuilder类
StringBuilder类是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder对象中的内容是可变的
- 构造方法:
StringBuilder()
方法: 创建一个空白可变字符串对象,不含有任何内容StringBuilder(String str)
方法: 根据字符串的内容,来创建可变字符串对象
- 常用方法:
append(Object obj)
方法: 添加数据,并返回对象本身reverse()
方法: 返回相反的字符序列toString()
方法: 将StringBuilder转换为String
StringBuilder
和String
相互转换
toString()
方法:通过 toString() 就可以实现把 StringBuilder 转换为 StringStringBuilder(String s)
方法:通过构造方法就可以实现把 String 转换为 StringBuilder
11、String、StringBuffer、StringBuilder区别
存储不同:
- String:存储的是字符串常量,不允许修改
- StringBuffer、StringBuilder是具有缓冲区,允许修改
返回时是否修改自身:
- String方法会返回一个新的字符串
- StringBuffer、StringBuilder基本会返回自己修改后的本身
工作效率:
- String:线程安全 占用资源
- StringBuffer:线程安全 效率低
- StringBuilder:线程不安全 效率高
使用场景:
- ①用于声明字符串并不进行频繁修改时使用String,否则应该使用StringBuffer、StringBuilder
- ②如果涉及到线程安全使用StringBuffer,只考虑效率使用StringBuilder
12、Math类
所有方法均为静态方法
- Math.PI : 常量,圆周率
abs(double num)
方法: 取绝对值ceil(double num)
方法: 向上取整floor(double num)
方法: 向下取整round(double num)
方法: 四舍五入max(int a, int b)
方法: 求最大值min(int a, int b)
方法: 求最小值pow(double a, double b)
方法: 求a的b次幂random()
方法: 随机数,随机的范围[0,1)
13、Array类
所有方法均为静态方法
- 常用方法:
toString(int[] a)
方法: 返回指定数组内容的字符串表示形式。sort(int[] a)
方法: 对指定的int型数组按数字升序进行排序。copyOf(Object[] obj,int length)
方法: 数组拷贝
14、System类
java.lang.System
类中提供了大量的 静态方法,可以获取与系统相关的信息或系统级操作
- 常用方法:
currentTimeMillis()
方法: 返回以毫秒为单位的当前时间。arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
方法: 将数组中指定的数据拷贝到另一个数组中。exit(int status)
方法: l 用来结束正在运行的Java程序。参数传入一个数字即可。通常传入0记为正常状态,其他为异常状态
15、包装类
基本类型 | 对应的包装类(位于java.lang包中) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
装箱: 从基本类型转换为对应的包装类对象。
拆箱: 从包装类对象转换为对应的基本类型。
16、什么是包装类,什么是自动拆装箱
java中对于基本数据类型提供的对应引用类型类,byte—>Byte,short—>Short,int—>Integer,long—>Long,float—>Float,double—>Double,char—>Character,boolean—>Boolean
自动拆装箱就是在代码运行时,基本数据类型与对应包装类对象互相自动转换的过程
17、BigInteger类
BigInteger类:最大整数类型
- 构造方法:
BigInteger(String val)
方法: 将字符串的数组封装成BigInteger对象
- 常用方法:
add(BigInteger val)
方法: 两个BigInteger进行相加,并返回BigIntegersubtract(BigInteger val)
方法: 两个BigInteger进行相减,并返回BigIntegermultiply(BigInteger val)
方法: 两个BigInteger进行相乘 ,并返回BigIntegerdivide(BigInteger val)
方法: 两个BigInteger进行相除,并返回BigInteger
18、BigDecimal类
BigDecimal类:最小浮点类
- 构造方法:
BigDecimal(String val)
方法: 将String类型的数组封装为BigDecimal对象
常用方法:
add(BigDecimal augend)
方法: 浮点类型数据相加操作subtract(BigDecimal subtrahend)
方法: 浮点类型数据相减操作multiply(BigDecimal multiplicand)
方法: 浮点类型数据相乘操作divide(BigDecimal divisor)
方法: 浮点类型数据相除操作divide(BigDecimal divisor,int scale,int roundingMode)
方法: 浮点类型数据相除操作,按照指定的模式,保留几位小数
ROUND_HALF_UP
与ROUND_FLOOR
区别:
ROUND_HALF_UP
:保留小数位后一位如果满足5,就进一ROUND_FLOOR
:保留小数位后一位不管满足5还是不满足5直接舍去掉
19、Date类
java.util.Date
类 表示特定的瞬间,精确到毫秒。
- 构造方法:
Date()
方法: 分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)Date(long date)
方法: 分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,
即1970年1月1日00:00:00 GMT)以来的指定毫秒数。
- 常用方法:
getTime()
方法: 用于获取当前时间至1970年1月1日00:00:00 GMT所过毫秒数
20、SimpleDateFormat日期格式化类
SimpleDateFormat日期格式化类: 是日期/时间格式化子类的抽象类,通过这个类可以完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。
- 构造方法:
SimpleDateFormat(String atr)
方法:
- 常用方法:
- 格式化
String format(Date)
方法: 将日期对象使用当前格式进行格式化返回字符串- 解析
Date parse(String)
方法: 将指定字符串使用当前格式解析为Date对象
21、Calendar日历类
java.util.Calendar
是日历类 , 该类将所有可能用到的时间信息封装为静态成员变量
创建:Calendar c=Calendar.getInstance();
getInstance()
方法: 使用默认时区和语言环境获得一个日历
- 常用方法:
get(int)
方法 : 通过传入指定的静态常量对应的值,获取对应数据set()
方法 : 设置了不同的重载方法。set()
方法 :修改当前日历对象代表的日期set(field, value)
方法:为指定属性赋值set(year, month, date)
方法:设置年月日set(year, month, date, hourOfDay, minute)
方法:同时设置年月日小时与分钟set(year, month, date, hourOfDay, minute, second)
方法:同时设置年月日时分秒
add(field, amount)
方法 : 添加方法,为指定属性进行数据的添加
22、异常(概念、分类、处理)
异常 :指的是在程序书写与运行过程中,由于非语法产出的非正常情况,最终会导致JVM的非正常停止。
- 分类:
- 运行时异常: 也叫非受检异常,runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)
- 非运行时异常: 也叫受检异常、编译异常,checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
- 异常的处理:
向上抛出处理:
throws
自行处理:try...catch
23、处理异常两种方式的区别
- 抛出异常使用 throws 关键字,自行处理 try…catch
- 抛出异常时调用方处理,自行处理自己书写处理代码进行处理
- 抛出异常书写在方法上,标识当期方法可能出现的异常,自行处理使用try将可能出现的异常代码包裹对于出现的异常使用catch进行匹配处理
- 抛出异常会导致程序的停止运行,自行处理可能不会停止
24、 finally关键字
finally不能单独使用。必须配合着try…catch使用
书写在try...catch
之后,无论代码是否发生异常都会执行
25、return
执行后finally
代码块是否还会执行
执行,finally代码块一定会执行无论是否在处理中使用return结束当前方法,也会在方法结束之前执行,除非在catch中调用System.exit(0)退出系统的执行
26、自定义异常
自定义异常类只需要创建类继承
Exception
或者RuntimeException
就可以创建对应的受检异常以及运行时异常
在发生符合异常的代码位置,使用
throw
关键字 抛出一个新的异常对象
27、throw 与throws的区别
- throw用在方法体内,根的是异常对象名;throws用在方法声明后面,跟的是异常类名
- throw表示抛出异常,由方法体内的语句处理;throws表示抛出异常,由该方法的调用者来处理
- throw执行throw约定抛出了某种异常;throws表示出现异常的一种可能性,并不一定会发生这些异常
五、集合
集合:集合是java中提供的一种容器,可以用来存储多个数据,并且可以存储任意类型的数据!
- 分类: 单列集合
java.util.Collection
、双列集合java.util.Map
- Collection集合:
java.util.List
、java.util.Set
List
的特点是元素有序、元素可重复。List
接口的主要实现类有java.util.ArrayList
和java.util.LinkedList
Set
的特点是元素无序,而且不可重复。Set
接口的主要实现类有java.util.HashSet
和java.util.LinkedHashSet
。
1、Collection集合
- 常用方法:
add(E e)
方法:把给定的对象添加到当前集合中 。remove(E e)
方法:把给定的对象在当前集合中删除。contains(E e)
方法:判断当前集合中是否包含给定的对象。isEmpty()
方法:判断当前集合是否为空。size()
方法:返回集合中元素的个数。toArray()
方法:把集合中的元素,存储到数组中。clear()
方法:清空集合中所有的元素。
2、迭代器
创建: Iterator it = coll.iterator();
- 常用方法:
next()
方法:返回迭代的下一个元素。hasNext()
方法:如果仍有元素可以迭代,则返回 true。
//使用迭代器 遍历 每个集合对象都有自己的迭代器
Iterator<String> it = coll.iterator();
// 泛型指的是 迭代出 元素的数据类型
while(it.hasNext()){ //判断是否有迭代元素
String s = it.next();//获取迭代出的元素
System.out.println(s);
}
3、增强for
for(元素的数据类型 变量 : Collection集合or数组){
//写操作代码
}
4、for循环与增强for循环的区别
1、语法不同:
- for循环语法中书写初始值、判断条件、迭代语句
- 增强for循环中书写保存每次取出数据的变量声明以及遍历的数据
2、执行流程不同
- for循环按照初始值、判断条件、迭代语句、循环体语句、判断语句 …执行
- 增强for循环依次取出遍历容器中的数据赋值给临时变量之后使用
3、功能不同
- for循环进行容器操作时,使用的是容器提供的方式进行获取并且可以进行修改
- 增强for循环每次使用临时变量保存,不会修改容器中的数据
4、使用场景不同
- for循环可以在执行时根据条件进行终止与操作
- 增强for循环只能从头到尾遍历所有数据
5、List集合
特点:元素存取有序、带有索引、集合中可以有重复的元素
- 1、数据有序->存入位置与取出顺序相同
- 2、拥有索引->可以通过索引精确获取对应数据
- 3、数据重复->不同索引存储的数据可以相同
- 常用方法:
add(int index, E element)
方法:将指定的元素,添加到该集合中的指定位置上。get(int index)
方法:返回集合中指定位置的元素·。remove(int index)
方法:移除列表中指定位置的元素, 返回的是被移除的元素。set(int index, E element)
方法:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
6、ArrayList
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
- 常用方法:
add(int index, E element)
方法:将指定的元素,添加到该集合中的指定位置上。get(int index)
方法:返回集合中指定位置的元素·。remove(int index)
方法:移除列表中指定位置的元素, 返回的是被移除的元素。set(int index, E element)
方法:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。add(E e)
方法:将指定的元素添加到此列表的尾部
7、LinkedList
java.util.LinkedList
集合数据存储的结构是双向链表结构。方便元素添加、删除的集合,查找修改慢。
- 常用方法:
addFirst(E e)
方法:将指定元素插入此列表的开头。addLast(E e)
方法:将指定元素添加到此列表的结尾。getFirst()
方法:返回此列表的第一个元素。getLast()
方法:返回此列表的最后一个元素。removeFirst()
方法:移除并返回此列表的第一个元素。removeLast()
方法:移除并返回此列表的最后一个元素。pop()
方法:从此列表所表示的堆栈处弹出一个元素。push(E e)
方法:将元素推入此列表所表示的堆栈。isEmpty()
方法:如果列表不包含元素,则返回true。
8、ArrayList与LinkedList的区别
ArrayList: 底层使用数组形式对数据进行存储
- 查询修改快:数组可以直接通过索引获取对应位置数据
- 添加删除慢: 在对首位或中间数据进行添加与删除操作时,需要将之后的数据向后或向前移动,随着数据的增大移动的次数也会增大,导致执行的效率降低
LinkedList: 底层使用双向链表形式对数据进行存储
- 查询修改慢:底层使用双向链表形式对数据进行存储,每一块只保存当前数据以及前后块地址,在进行查找时,如果查找的是非首末位块,需要依次向后查找
- 添加删除快:链表每块保存数据添加与删除时只影响前后块位置的修改
9、在实际开发过程中经常使用ArrayList进行数据的存储
1、在数据量一定的情况下对ArrayList首位添加删除效率仍然比LinkedList对末位前一位的查找效率高
2、在实际开发中添加数据一般都是直接添加至末位,更多的时候是对数据的查找与修改
10、Set集合
Set集合: 继承自
Collection
接口,与Collection
接口中的方法基本一致,并没有对Collection
接口进行功能上的扩充,只是比Collection
接口更加严格。
- 特点:
- Set集合中的元素不可重复
- Set集合没有索引
11、HashSet
HashSet:
java.util.HashSet
是Set
接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)
- 特点:
- HashSet集合中的元素不可重复
- HashSet集合没有索引
- HashSet集合是无序的(存储元素的顺序与取出元素顺序可能不一致)
HashSet集合存储数据的结构:
- JDK的版本不同,HashSet集合的数据结构有所不同:
-
JDK8之前:数组+链表
-
JDK8之后:数组+链表+红黑树
-
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
12、LinkedHashSet
java.util.LinkedHashSet
,是链表和哈希表组合的一个数据存储结构
特点:
-
LinkedHashSet集合中的元素不可重复
-
LinkedHashSet集合没有索引
-
LinkedHashSet集合是有序的(存储元素的顺序与取出元素顺序一致)
13、Map集合
java.util.Map
接口,提供了专门的集合类用来存放这种对象关系的对象
- 常用方法:
put(K key, V value)
方法:把指定的键与指定的值添加到Map集合中。remove(Object key)
方法:把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。get(Object key)
方法:根据指定的键,在Map集合中获取对应的值。containsKey(Object key)
方法:判断集合中是否包含指定的键。keySet()
方法:获取Map集合中所有的键,存储到Set集合中。Set<Map.Entry<K,V>> entrySet()
方法:获取到Map集合中所有的键值对对象的集合(Set集合)。
14、Map集合的遍历
keySet()
方法:
通过元素中的键,获取键所对应的值
- 常用方法:
keyset()
方法:获取Map中所有的键get(K key)
方法:根据键,获取键所对应的值
//创建Map集合对象
HashMap<String, String> map = new HashMap<String,String>();
//添加元素到集合
map.put("胡歌", "霍建华");
map.put("郭德纲", "于谦");
map.put("薛之谦", "大张伟");
//获取所有的键 获取键集
Set<String> keys = map.keySet();
// 遍历键集 得到 每一个键
for (String key : keys) {
//key 就是键
//获取对应值
String value = map.get(key);
System.out.println(key+"的CP是:"+value);
}
entrySet()
方法:
Entry:
Map
中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map
中是一一对应关系,这一对对象又称做Map
中的一个Entry(项)
。Entry
将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map
集合时,就可以从每一个键值对(Entry
)对象中获取对应的键与对应的值。
- 获取Entry:
public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
- 常用方法:
getKey()
方法:获取Entry对象中的键。getValue()
方法:获取Entry对象中的值。
15、Map与Collection集合区别:
-
Collection集合
单列集合,一次只能添加一个元素 有的是有索引,有的没有索引 有的集合可以存储重复的元素,有的则不可以 有的元素是无序的,有的是有序的
-
Map集合
Map集合是双列集合,由Key和Value组成 Key是不允许重复的,Value是允许重复 Key允许存null值的,但是只能存储唯一的一个
16、LinkedHashMap
特点:
- 有序的,而且key不允许重复
- 数据结构: 哈希表 + 链表
17、HashMap和Hashtable的区别
- HashMap是HashTable的替代
- HashMap线程不安全,HashTable线程安全
- HashMap的key可以使用null作为key;HashTable的key不允许为null作为key
18、Arraylist 与Vector 区别
- 同步性:Vector 是线程安全的(同步),而ArrayList 是线程序不安全的;
- 数据增长:当需要增长时,Vector 默认增长一倍,而ArrayList 却是一半。
19、List、Map、Set 三个接口,存取元素时,各有什么特点?
- List:以特定次序来持有元素,可有重复元素。
- Set:无法拥有重复元素,内部排序。
- Map:保存key-value 值,value 可多值,但Key值唯一。
六、泛型
1、什么是泛型
用于声明时无法确定类型的替代,在使用时必须传入对应的类型进行转换,会自动将声明时类所有使用泛型的位置替换为指定的类型。
- 书写与使用
泛型通常使用大写的单个字母定义,如果定义多个泛型使用
,
分隔,使用<>
包裹
2、什么是不确定参数
在定义方法时,无法确定方法的参数有多少个,只能确定参数的类型,这个时候可以使用不确定参数进行书写,在调用方法时可以无限填入参数,会自动根据填入的参数创建数组在方法中使用。
- 书写
String... arr
3、简述递归的思想以及书写形式
在方法中不断调用本身,从而实现相应需求的过程称之为递归
书写
- 1、明确每次执行的功能
- 2、定义递归条件与边界
- 3、调用自身方法
4、简述什么叫设计模式
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
5、单例模式
一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。
6、工厂模式
工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
7、线程与进程的区别
根本区别
- 进程是操作系统资源分配的基本单位。
- 线程是程序执行流的最小单元,是处理器任务调度和执行的基本单位。
内存分配不同
- 同一进程的线程共享本进程的地址空间和资源。
- 进程之间的地址空间和资源是相互独立的。
包含关系
- 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程
影响不同
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响。
- 一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
资源开销
- 每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销。
- 线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
执行过程
- 每个独立的进程有程序运行的入口、顺序执行序列和程序出口。
- 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
8、创建多线程的方式
1、继承Thread类重写run方法
2、实现runnable接口重写run方法
3、使用callable与futrue接口创建线程
4、线程池创建
9、线程的生命周期
线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身;Java 中的线程有四种状态分别是:运行、就绪、挂起、结束。
10、start方法与run方法的区别
书写的不同
- run方法是线程执行时执行的具体方法
- start方法是线程启动执行时的方法无需书写
线程生命周期转换不同
- start方法是将线程由初始态转换为就绪态
- run方法是将线程由就绪态转换为运行态
调用方不同
- start方法由我们调用启动线程执行
- run由计算机为线程分配运行资源之后自动调用
使用不同
- start方法直接调用使用启动线程
- run方法直接调用不会启动线程而是直接运行
11、wait()与 sleep()的区别
- wait与sleep都可以使线程由运行态转化为阻塞态
- wait由Object类提供所有的锁对象都可以使用,sleep由Thread类提供
- wait方法会让当前获取对象锁的线程进入阻塞状态(必须获取锁对象)
- sleep方法就是让当前线程进入阻塞状态
- wait方法必须使用notify进行唤醒获取锁对象资源后继续执行
- sleep方法在休眠时间到达后自动进入就绪态
- wait方法执行后当前线程会释放锁对象
- sleep方法不会释放锁对象
12、线程同步的方式
同步代码块
使用synchronized关键字将代码块中的代码进行同步,当多个线程执行相同代码时,会进行阻塞(等待其他线程执行结束后再执行)同步方法
使用synchronized关键字修饰方法,当多个线程调用该方法时,同一时间只允许一个线程执行。Lock锁
在对应任务类创建锁对象,通过加锁lock()与释放锁方法unlock()对中间执行的代码进行能同步。
13、线程通信的原理
在线程同步的基础上调用方法使线程按照指定的顺序执行
14、死锁的原理
两个线程或多个线程相互持有对方所需要的资源,导致线程都处于等待状态,无法往下执行,导致死锁。
15、简述synchronized 和Lock 的异同?
主要相同点:
- Lock 能完成synchronized 所实现的所有功能。
主要不同点:- Lock 有比synchronized 更精确的线程语义和更好的性能。
- synchronized 会自动释放锁,而Lock 一定要求程序员手工释放,并且必须在finally 从句中释放。
16、TCP协议与UDP协议的区别
本质区别
- TCP传输控制协议
- UDP数据报协议
连接区别
- TCP是通过三次握手后建立连接之后的数据传输
- UDP无需连接直接发送数据
安全区别
- TCP保证数据的准确性
- UDP在传输过程中造成数据的丢失
数据传输的区别
- TCP在连接中使用IO流的形式进行数据传输
- UDP将数据分成等大的数据块进行传输
数据量的区别
- TCP在安全的连接中无需考虑大小
- UDP如果数据过大,数据包增大,丢失的概率也增大
使用场景不同
- TCP用于安全通信与数据的安全传输,数据的上传
- UDP用于数据的发送,适用于直播,视频
17、接口的默认方法与接口的静态方法的区别
默认方法:
- 使用 default 修饰,不可省略。
- Java8 允许在接口中增加默认方法,默认方法在实现类中可以不去实现它。
- 如果接口中有默认方法,实现类将默认继承这个默认方法,当然如果有需要的话可以在实现类中覆盖抽象方法
- 默认方法的使用方式:用实现类的实例来直接点出这个默认方法。而当被覆盖后,接口中的默认方法调用为:接口名.super.默认方法。
静态方法:
- 使用 static 修饰,供接口直接调用。
- 只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。
- 静态方法属于接口本身,不被实现类所继承。
18、创建对象时类的加载顺序
先加载父类,执行父类静态代码块,父类静态变量与方法,父类成员变量与方法,创建父类对象
加载子类,执行子类静态代码块,子类静态变量与方法,子类成员变量与方法,创建子类对象
19、常用类加载器有哪些
BootstrapClassLoader
- 引导类加载器, 用来加载 Java 的核心库,是用原生代码来实现的,
- 并不继承自 java.lang.ClassLoader。它负责将jre/lib下面的核心类库.
PlatformClassLoader
- 平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
SystemClassLoader
- 它也被称为应用程序类加载器(ApplicationClassLoader) ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
UserClassLoader
- 自定义类加载器
20、XML解析方式以及其优缺点
sax解析
- sax:Simple API for XML。边读取边解析,采用的是事件回调的方式,书写好用于处理响应事件的方法,进行解析,当进行读取事触发相应事件执行对应方法
- 优点
- 进行解析是无需加载全部文档,可以边读取边解析
- 基于事件回调进行响应的解析,只有触发相应事件时才会回调相应方法
- 可以解析数据量大于内存的数据
- 缺点
- 需要自己维护响应事件的回调方法,随文档的复杂度难度递增
- 单向解析,不会进行反向查询,只能从头解析
dom解析
- dom:domDocument Object Model。dom解析方式基于数据的节点层次结构进行解析,dom解析方式类可以理解为内嵌了处理器,在进行加载时使用已经提供的方式进行数据的解析,并以一定的层次结构进行保存,提供相应的方法可以直接进行数据的获取
- 优点
- 底层以数据节点的形式进行存储数据,提供相应的方法快速获取
- 可以对某一标签直接进行访问
- 缺点
- 需要加载整个文件,消耗内存,不能处理大于内存的数据
- 无论是否需要都会加载整个数据
jdom解析
- jdom:Java-based Document Object Model。基于java规范开发的dom方式解析xml数据,主要是基于javaAPI与集合修改了原本的nodeList存储节点的形式,与dom原有的API。
- 优点:
- 将数据存储使用集合的形式存储
- 简化API的使用
- 缺点:
- 没有良好的灵活性
- 性能较差
dom4j解析
- DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,为解决jdom简化API导致的灵活性问题,dom4j在其基础上添加了大量的API功能代码。
- 优点:
- 提供了大量的API应用于各种形式的使用
- 缺点:
- API太过繁琐,如果只是进行简单的解析,不需要使用
21、事务的四大特征
原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
持久性:当事务提交或回滚后,数据库会持久化的保存数据。
隔离性:多个事务之间。相互独立。
一致性:事务操作前后,数据总量不变
22、SQL优化
数据库结构优化
- 创建数据库时使用数据库三范式进行表结构的创建
- 创建表时对于表的字段类型进行优化
- 在字段类型设置时不要使用null 可能使索引失效
sql语句优化
- 添加索引
- 在查询时减少不必要字段的查询(*)
- 减少null 与not null 的使用 因为会导致索引失效
- 减少in 与not in 的使用 因为会导致索引失效
- 减少like 的使用 因为可能会导致索引失效
- 减少or 的使用 因为可能会导致索引失效
- 尽量使用连接查询替代子查询
- 在进行连接查询时,尽量将条件书写在on中(数据的连接可以理解为数据的准备阶段,在准备阶直接将数据进行过滤,减少where条件的书写)
- 减少在where字句中条件的书写
- 减少排序ordery的使用
- 在进行查询添加等操作时,书写的数据类型最好与字段的类型相匹配