1、JDK与JRE的区别
JDK(java程序开发包): 包括JRE + 工具包
JDK(Java SE Development Kit)Java标准开发工具包。它提供Java程序所需的各种资源和工具,包括Java编译器、Java运行环境。以及常用的Java类库等。
JRE:包括JVM和lib类库
JRE(Java Runtime Environment)Java程序运行环境,用于解释和执行Java的字节码文件。普通用户而只需要安装 JRE来运行 Java 程序。而程序开发者必须安装JDK来编译、调试程序。
JVM:(Java Virtual Mechinal)。Java虚拟机。是实现Java跨平台最核心的一部分。是可运行Java字节码文件的虚拟计算机
区别和联系:
1、JDK 用于开发,JRE 用于运行java程序 ;如果只是运行Java程序,可以只安装JRE,无序安装JDK。
2、JDK包含JRE,JDK 和 JRE 中都包含 JVM。
3、JVM 是 java 编程语言的核心并且具有平台独立性。
2、普通类和抽象类的区别:
- 普通类不能包含抽象方法,抽象类可以包含抽象方法
- 抽象类是不能被实例化的。就是不能够用new调用构造方法创建实例对象。但是普通类可以实例化。
- 如果一个普通类实现一个抽象类,必须实现该抽象类的抽象方法。如果子类没有实现抽象类的抽象方法,那么这个子类也必须定义为抽象类
- 抽象类不能被final关键字修饰
扩展:
接口和抽象类的区别:
从语法上来讲:
抽象类可以有普通成员方法。接口只有public abstract方法。
抽象类中的成员变量可以是任何类型的,但是接口中的变量只能是public static final类型的。
抽象类只能继承一个,接口可以实现多个
从设计上说:
接口是用来对类的行为进行约束。
抽象类是为了代码复用
从本质上说:
接口是对行为的抽象,表达的是like a的关系
抽象类是对类本质的抽取。表达的是 is a的关系
3、final的作用:
修饰类:表示该类不可被继承
修饰方法:表示方法不能被子类覆盖,但是能重载
修饰变量:表示该变量一旦被赋值就不可修改
修饰不同变量的区别:
1、修饰成员变量:
*如果final修饰的是类变量,那么只能在静态代码块中赋值或者在声明该变量的时候指定初始值
*如果final修饰的是成员变量,可以在非静态代码块、声明该变量或者构造器中执行初始值
2、修饰局部变量
*系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化。因此使用final修饰局部变量时,即可以在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初值(仅一次)
3、修饰基本数据和引用数据
* 修饰基本数据时,变量的值不会再改变
* 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是引用的值可变。
4、HashMap和HashTable的区别
*HashMap不是线程安全的,HashTable是线程安全的。因为HashTable内部的方法基本都是synchronized实现的。
*因为线程安全问题,HashMap的性能要比HashTable要好,而且HashTable过于久远,不建议在代码中使用
*HashMap可以使用null作为键,但是HashTable不可以
HashMap的底层实现:
JDK1.8之前HashMap底层是数组+链表结合在一起使用也就是链表散列。HashMap通过Key的hashCode经过扰动函数处理后得到hash值,再通过(n-1)&hash判断当前元素存放的位置。(这里n指的是数组的长度)。如果当前位置存在元素的话,就判断当前元素与要存入元素的hash值以及Key是否相同。如果相同的话就通过拉链法解决冲突。
使用扰动函数可以减少哈希碰撞。
在JDK1.8之后解决哈希冲突时有了较大的变化。当链表长度大于阈值(默认为8)时,将链表转换为红黑树,以减少搜索时间。
5、ArrayList和LinkedList的区别
ArrayList:
*是基于动态数组的,查找快,增删慢。
*存储连续,适合随机访问
LinkedList:
*底层是基于双向链表实现的。可以存储在分散的内存中。
*数据插入和删除效率高。查询效率低
*遍历LinkedList要用iterator而不使用for循环,因为每次for循环都是通过get(i)来获取元素就需要对list进行重新的遍历,性能消耗极大。
6、MySQL的常用函数
一、数字函数
二、字符串函数
三、日期函数
四、MySQL高级函数
具体详情:MySQL常用函数
CONCAT:连接字符串
7、MySQL左连接和内连接的区别
内连接:
关键字:inner join
sql语句:select* from table_left(表名) inner join table_right(表名) on table_left.id = table_right.id
注释说明:结合两张表的记录,返回相关的查询结果,返回的是两个表的交集部分(即阴影部分),见下图
左连接:
关键字:left join
sql语句:select* from table_left(表名) left join table_right(表名) on table_left.id = table_right.id
注释说明:left join 是left outer join 的简写,全称其实是左外连接,属于外连接的一种,左连接查询,左表的信息全部展示出来,右表只会展示符合搜索条件的信息,不足的地方记为NULL
右连接:
关键字:right join
sql语句:select* from table_left(表名) right join table_right(表名) on table_left.id = table_right.id
注释说明:right join 是right outer join 的简写,全称是右外连接,也属于外连接的一种,右连接查询,右表的信息全部展示出来,左表只会展示符合搜索条件的信息,不足的地方记为NULL
全连接:实际上就是把两张表合并,不管有的没的,都先给整上来。
8、进程和线程的区别:
在操作i系统中,一个任务通常就是一个程序,,每一个运行中的程序就是一个进程。当一个程序运行的时候,内部包含了多个顺序执行流,每个顺序执行流就是一个线程。
进程是系统进行资源调度的一个独立单位
线程是CPU进程中实施调度和分派的基本单位。
线程的生命周期,有几种状态?
线程有五种状态:
新建、就绪、运行、阻塞、死亡
1、新建状态(NEW):新创建了一个线程对象
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,等待CPU的调度
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态
5、死亡状态(Dead):线程执行完了或者因为异常退出了run方法,该线程结束生命周期
9、怎么解决死锁
死锁的概念:
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
**产生死锁有四个必要条件。**只要破坏其中一个条件,就可以避免死锁
*互斥条件:一个资源每次只能被一个进程使用
*请求与保持条件:一个进程因为请求的资源阻塞时,又不释放拥有的资源
*不剥夺条件:进程已经获得的资源在没有使用完之前不能被强行剥夺
*循环等待条件:若干进程之间形成一种头尾相连循环等待的资源条件
10、SpringMVC中的RequestMapping的作用
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或者方法上,当用于类上时,表示类中的所有响应请求的方法都是以该地址作为父路径。
方法处: 提供进一步的细分映射信息。 相对于类定义处的 URL。
11、Spring中的IOC和AOP说一下
AOP:
一个系统是由不同的组件组成的,每个组件都负责一块特定的业务,实现自己的核心功能;此外,这些组件可能还会有额外的任务。比如日志、事务管理、安全保障等业务,这些业务常常需要融入到不同组件的核心功能中,会跨越系统的多个组件,这些额外的需求在AOP中被称为横切关注点;
AOP:将程序中的交叉业务逻辑(比如安全、日志、事务等)封装成一个切面,然后注入到目标对象的具体业务逻辑中。AOP可以对某个对象或者某个对象的某些功能进行增强,比如对对象方法的增强,可以在方法的前后添加额外的功能。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来
主要是使用动态代理模式实现。
IOC:
从三个方面来回答:容器概念、控制反转、依赖注入
1️⃣Ioc容器:本质上就是一个map(key-value),里面存放了各种对象:
xml中配置的bean结点
@Repository、@Service、@Controller、@Conponent标注的类
在项目启动的时候会读取配置文件中的的bean结点,扫描以上注解标时的类,根据全限定类名通过反射创建对象存放到map中;
2️⃣ 控制反转:
没有引入IoC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
引入IoC容器之后,对象A与对象B之间失去了直接联系,当对象A运行到需要对象B的时候,IoC容器会主动创建一个对象B注入到对象A需要的地方。
通过前后的对比,不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转这个名称的由来
全部对象的控制权全部上缴给"第三方"IoC容器,所以IoC容器成了整个系统的关键核心,它起到了一种类似“粘合剂的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂,对象与对象之间会彼此失去联系,这就是有人把IoC容器比喻成“粘合剂"的由来。
3️⃣ 依赖注入:
DI是IoC的一种实现方式,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
依赖注入的方式:
1、属性注入(最常用的方式)
1.1. 通过 setter 方法注入Bean 的属性值或依赖的对象
1.2. 使用元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 子节 点指定属性值
2、 构造器注入
2.1 通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用
2.2 构造器注入在 元素里声明属性, 中没有 name 属性