超详细——面试高频

目录

1.基础题

1.1面向对象和面向过程的区别

面向过程

  • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源
  • 缺点: 没有面向对象易维护、易复用、易扩展

面向对象

  • 优点: 易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
  • 缺点: 性能比面向过程低

1.2 Java 语言有哪些特点

  • 简单易学;
  • 面向对象(封装,继承,多态);
  • 平台无关性( Java 虚拟机实现平台无关性);
  • 可靠性;
  • 安全性;
  • 支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);
  • .支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);
  • 编译与解释并存;

1.3 Java 和 C++的区别

  • 都是面向对象的语言,都支持封装、继承和多态
  • Java 不提供指针来直接访问内存,程序内存更加安全
  • Java 的类是单继承的, C++ 支持多重继承;虽然 Java 的类不可以多
    继承,但是接口可以多继承。
  • Java 有自动内存管理机制,不需要程序员手动释放无用内存

1.4 什么是 Java 程序的主类 应用程序和小程序的主类有何不同

一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这
个主类是指包含 main()方法的类。而在 Java 小程序中,这个主类是一个继
承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是 public
类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点。

1.5 Java 应用程序与小程序之间有那些差别

简单说应用程序是从主线程启动(也就是 main() 方法)。 applet 小程序没有
main 方法,主要是嵌在浏览器页面上运行(调用 init()线程或者 run()来启动),嵌入浏览器这点跟 flash 的小游戏类似。

1.6 字符型常量和字符串常量的区别

  • 形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
  • 含义上: 字符常量相当于一个整形值( ASCII 值),可以参加表达式运算 字符串常量代表一个地址值(该字符串在内存中存放位置)
  • 占内存大小 字符常量只占 2 个字节 字符串常量占若干个字节(至少一个字符结束标志) (注意: char 在 Java 中占两个字节)

1.7 基本类型

在这里插入图片描述

1.8 构造器 Constructor 是否可被 override

在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以
Constructor 也就不能被 override(重写) ,但是可以 overload(重载) ,所以
你可以看到一个类中有多个构造函数的情况。

1.9 重载和重写的区别

重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。

1.10 Java 面向对象编程三大特性: 封装 继承 多态

封装
封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码
关于继承如下 3 点请记住:

  1. 子类拥有父类非 private 的属性和方法。
  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
  3. 子类可以用自己的方式实现父类的方法。(以后介绍)。

多态
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发
出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变
量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中
实现的方法,必须在由程序运行期间才能决定。

1.11 String、StringBuffer 和 StringBuilder 的区别

可变性

  • String 类中使用 final 关键字字符数组保存字符串, private final char value[],所以 String 对象是不可变的。
  • StringBuilder 与StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串 char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的

线程安全性

  • String 中的对象是不可变的,也就可以理解为常量,线程安全。
  • StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以
    是线程安全的。 StringBuilder 并没有对方法进行加同步锁,所以是非线程安全
    的。

操作少量的数据 = String
单线程操作字符串缓冲区下操作大量数据 = StringBuilder
多线程操作字符串缓冲区下操作大量数据 = StringBuffer

1.12 自动装箱与拆箱

装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;

1.13在一个静态方法内调用一个非静态成员为什么是非法的

由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非
静态变量,也不可以访问非静态变量成员

1.14 在 Java 中定义一个不做事且没有参数的构造方法的作用

Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定
的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定
义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类
中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没
有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数
的构造方法。

1.15 import java 和 javax 有什么区别

javax 当时只是扩展API 包来使用,但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准 API 的一部分。实际上 java 和 javax 没有区别。

1.16 接口和抽象类的区别是什么

  • 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),抽象类可以有非抽象的方法
  • 接口中的实例变量默认是 final 类型的,而抽象类中则不一定
  • 一个类可以实现多个接口,但最多只能实现一个抽象类
  • 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
  • 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口
    的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范

1.17 成员变量与局部变量的区别有那些

  • 从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰;
  • 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存.
  • 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
  • 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰的成员变量也必须显示地赋值);而局部变量则不会自动赋值。

1.18 创建一个对象用什么运算符?对象实体与对象引用有何不同?

new 运算符, new 创建对象实例(对象实例在堆内存中),对象引用指向对象
实例(对象引用存放在栈内存中)。一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球) ;一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)

1.19 什么是方法的返回值?返回值在类的方法里的作用是什么?

方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前
提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他
的操作!

1.20 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 ?为什么?

主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明
构造方法也会有默认的不带参数的构造方法。

1.21 构造方法有哪些特性

  • 名字与类名相同;
  • 没有返回值,但不能用 void 声明构造函数;
  • 生成类的对象时自动执行,无需调用

1.22 静态方法和实例方法有何不同

  • 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
  1. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制.

1.23 对象的相等与指向他们的引用相等,两者有什么不同?

对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们
指向的内存地址是否相等。

1.24 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?

帮助子类做初始化工作。

1.25 == 与 equals(重要)

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同
一个对象。 (基本数据类型比较的是值,引用数据类型比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个
    对象时,等价于通过“==”比较这两个对象。

  • 情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来
    两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

1.26 hashCode 与 equals(重要)

面试官可能会问你: “你重写过 hashcode 和 equals 么,为什么重写 equals
时必须重写 hashCode 方法? ”

  • hashCode() 的作用是获取哈希码,是确定该对象在哈希表中的索引位置。
  • 你把对象加入 HashSet 时, HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode, HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同, HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。
  • 如果两个对象相等,则 hashcode 一定也是相同的
  • 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  • 两个对象有相同的 hashcode 值,它们也不一定是相等的

1.27 简述线程,程序、进程的基本概念。以及他们之间关系是什么

  • 线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
  • 程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
  • 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。

1.28关于 final 关键字的一些总结

  • 对于一个 final 变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
  • 当用 final 修饰一个类时,表明这个类不能被继承。 final 类中的所有成员方法都会被隐式地指定为 final 方法。
  • 使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的 Java 实现版本中,会将final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。

1.29 Java 中的异常处理

  • Error(错误) :是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM( Java 虚拟机)出现的问题。例如, Java 虚拟机运行错误( Virtual MachineError),当JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时, Java 虚拟机( JVM)一般会选择线程终止。
  • Exception(异常) :是程序本身可以处理的异常。 Exception 类有一个重要的
    子类 RuntimeException。 RuntimeException 异常由 Java 虚拟机抛出。

1.30 Java 序列化中如果有些字段不想进行序列化 怎么办

对于不想进行序列化的变量,使用 transient 关键字修饰。
transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。

1.31 final、finally、finalize区别

  • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
  • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码
  • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用 System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断

1.32 对象的四种引用

  • 强引用:只要引用存在,垃圾回收器永远不会回收
Object obj = new Object();
User user=new User();

只有当 obj 这个引用被释放之后,对象才会被释放掉,这也是我们经常所用到的编码形式。

  • 软引用 非必须引用,内存溢出之前进行回收,可以通过以下代码实现
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();//有时候会返回null

这时候sf是对obj的一个软引用,通过sf.get()方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回null;
软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据

  • 弱引用 第二次垃圾回收时回收,可以通过如下代码实现
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
wf.get();//有时候会返回null
wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾

弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。
弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued 方法返回对象是否被垃圾回收器标记

  • 虚引用 垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永远返回null
pf.isEnQueued();//返回是否从内存中已经删除

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
虚引用主要用于检测对象是否已经从内存中删除

1.33 Java获取反射的三种方法

通过new对象实现反射机制
通过路径实现反射机制
通过类名实现反射机制

public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}

public class Get {
	//获取反射机制三种方式
	public static void main(String[] args) throws ClassNotFoundException {
	//方式一(通过建立对象)
	Student stu = new Student();
	Class classobj1 = stu.getClass();
	System.out.println(classobj1.getName());
	//方式二(所在通过路径-相对路径)
	Class classobj2 = Class.forName("fanshe.Student");
	System.out.println(classobj2.getName());
	//方式三(通过类名)
	Class classobj3 = Student.class;
	System.out.println(classobj3.getName());
}
}

1.34 Java反射机制

Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为 Java 的反射机制

1.35 异常分类以及处理机制

  • Java标准库内建了一些通用的异常,这些类以Throwable为顶层父类。
  • Throwable又派生出Error类和Exception类。
    • 错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
    • 异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。

1.36 solr 的原理?

Solr 是一个全文检索服务器,只需要进行配置就可以实现全文检索服务, Solr 可以独立运行,运行在 Jetty、 Tomcat 等这些 Servlet 容器中, Solr 索引的实现方法很简单,用POST 方法向 Solr 服务器发送一个描述 Field 域名及其内容的 XML 文档, Solr 根据xml 文档添加、删除、更新索引 。 Solr 搜索只需要发送 HTTP GET 请求,然后对 Solr 返回 Xml、 json 等格式的查询结果进行解析,组织页面布局。 Solr 不提供构建 UI 的功能,Solr 提供了一个管理界面,通过管理界面可以查询 Solr 的配置和运行情况。

1.37 Tomcat 怎么优化

  • 去掉对 web.xml 的监视,把 jsp 提前编辑成 Servlet。有富余物理内存的情况,加大 tomcat 使用的 jvm 的内存
  • 利用缓存和压缩
  • 采用集群
  • 优化 tomcat 参数

1.38 Java 中有几种方法可以实现一个线程?用什么关键字修饰同步方法?

  • 继承 Thread 类,重写 run 函数
  • 实现 Runnable 接口,重写 run 函数
  • 实现 Callable 接口,重写 call 函数
    • Callable 是类似于 Runnable 的接口,实现 Callable 接口的类和实现 Runnable 的类都 是可被其它线程执行的任务。

1.39 系统一使用 utf-8,系统二使用 gdk,怎么实现数据传递?

String s=new String(str.getBytes(“iso8859-9),”utf-8);

1.40 什么是值传递和引用传递

值传递是对基本型变量而言的,传递的是该变量的一个副本。改变副本当然不影响原变量。 引用传递一般是对于对象型变量而言的。传递的是该对象地址的一个副本。这个地址空间 保存对象的数据,虽然是副本,但地址是唯一的。好比我拿你家地址的原件或复印件都能 找到你家。所以对改地址进行操作会同样改变原对象。 但传递的并不是原对象本身。所以,如果函数内的对象指向新的地址,并不会改变原对象的地址。 其实一般认为, java 内的传递都是值传递。只是传递的内容不同罢了

1.41 set 为什么不可以有重复?

set 是一个特殊的 Map, value 值都是一个 object, key 值就是 set 的值,当 key 一样时, hash 算法会计算到同一个节点,所以不能重复

1.42 开发单例应用需要注意什么?为什么要用单例?

  • 单例模式 只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等
  • 单例的缺点 就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
  • 单例最大优势就是性能优势。因为每生成一个对象都会产生内存,造成浪费

1.43 float和double的区别是什么?

1.44 char和varchar的区别是什么?

varchar 与 char 的区别: char 是一种固定长度的类型, varchar 则是
一种可变长度的类型
varchar(50)中 50 的涵义 : 最多存放 50 个字节

1.45 写一个 ArrayList 的动态代理类

final List<String> list = new ArrayList<String>();
List<String> proxyInstance =
(List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(),
list.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(list, args);
}
});
proxyInstance.add("你好");
System.out.println(list);

1.46 写一个 ArrayList 的动态代理类

1.47 ZooKeeper、Eureka和Nacos的区别

Zookeeper保证CP

  • 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。

Eureka保证AP

  • Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。

Nacos就是注册中心+配置中心的组合=Eureka+Config+Bus
Nacos:Naming(Na)+Configuration(co)+Service(s)

2.Mysql数据库

2.1 你说的 NoSQL 数据库是什么意思?NoSQL 与 RDBMS 直接有什么区别?为什么要使用和不使用NoSQL 数据库?说一说 NoSQL 数据库的几个优点?

  • NoSQL 是非关系型数据库, NoSQL = Not Only SQL。
  • 关系型数据库采用的结构化的数据, NoSQL 采用的是键值对的方式存储数据。
  • 在处理非结构化/半结构化的大数据时;在水平方向上进行扩展时;随时应动态增加的数据项时可以优先考虑使用 NoSQL 数据库。
  • 在考虑数据库的成熟度;支持;分析和商业智能;管理及专业性等问题时,应优先考虑关系型数据库。

2.2 MySQL 与 MongoDB 之间最基本的差别是什么?

  • MySQL 和 MongoDB 两者都是免费开源的数据库。 MySQL 和 MongoDB 有许多基本差别包括数据的表示(data representation),查询,关系,事务, schema 的设计和定义,标准化(normalization),速度和性能
  • 通过比较 MySQL 和 MongoDB,实际上我们是在比较关系型和非关系型数据库,即数据存储结构不同。

2.3 MongoDB 成为最好 NoSQL 数据库的原因是什么?

  • 面向文件的
  • 高性能
  • 高可用性
  • 易扩展性
  • 丰富的查询语言

2.3 MongoDB 的功能且实用场景

功能

  • 面向集合的存储:适合存储对象及 JSON 形式的数据
  • 动态查询: Mongo 支持丰富的查询表达式。查询指令使用 JSON 形式的标记,可轻易查询文档中内嵌的对象及数组。
  • 完整的索引支持
  • 查询监视

适用场景

  • 网站数据: Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性
  • 缓存:由于性能很高, Mongo 也适合作为信息基础设施的缓存层。

2.4 mysql的内连接、左连接、右链接有什么区别?

2.5 mysql的索引是怎么实现的?

2.6 怎么验证mysql的索引是否满足需求?

2.7 说一下数据库的事务隔离?

2.8 说一下mysql的常用引擎

MyISAM InnoDB MEMORY MERGE
MyISAM

  • 是旧版本mysql的默认引擎,现在默认引擎是InnoDB。MyISAM引擎的主要特点就是快,没有事务处理操作,也不支持外键操作。适合于多读取插入,少更新删除的操作表。
    InnoDB
  • 是新版本mysql的默认引擎,支持事务处理和外键,但是其缺点几就是慢了些。 是由 Oracle 公司开发的 Innobase Oy 事务安全存储引擎。
    MEMORY
  • 数据访问非常快的引擎,存储格式统一放在内存中的一个磁盘文件中
    MERGE
  • 本身是融合的意思,实质是MyISUM表的融合,这些融合的表必须结构完全相同。

2.9 说一下mysql的行锁和表锁

2.10 说一下乐观锁和悲观锁

2.11 mysql的问题排查都有哪些手段?

2.12 数据库的三范式是什么?

第一范式:数据库表的每一个字段都是不可分割的。
第二范式:数据库表中的非主属性只依赖于主键。
第三范式:不存在非主属性对关键字的传递函数依赖关系。

2.13 一张自增表里总共有7条数据,删除了最后2条数据,重启mysql数据库,又插入了一条数据,此时id是几?

2.14 说一下ACID是什么?

2.15 Mysql 服务器默认端口是什么?

Mysql 服务器的默认端口是 3306。

2.16 与 Oracle 相比, Mysql 有什么优势?

Mysql 是开源软件,随时可用,无需付费。
Mysql 是便携式的
带有命令提示符的 GUI。
使用 Mysql 查询浏览器支持管理

2.17 请简洁描述 Mysql 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

SQL 标准定义的四个隔离级别为:
read uncommited :读到未提交数据
read committed:脏读,不可重复读
repeatable read:可重读
serializable :串行事物

2.18 如何获取当前的 Mysql 版本?

SELECT VERSION();用于获取当前 Mysql 的版本

2.19 Mysql 驱动程序是什么?

PHP 驱动程序
JDBC 驱动程序
ODBC 驱动程序
CWRAPPER
PYTHON 驱动程序
PERL 驱动程序
RUBY 驱动程序
CAP11PHP 驱动程序
Ado.net5.mxj

2.20 主键和候选键有什么区别?

表格的每一行都由主键唯一标识,一个表只有一个主键。
主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用。

2.21 如果一个表有一列定义为 TIMESTAMP,将发生什么?

每当行被更改时,时间戳字段将获取当前时间戳。

2.22 列设置为 AUTO INCREMENT 时,如果在表中达到最大值,会发生什么情况?

它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。

2.23 你怎么看到为表格定义的所有索引?

SHOW INDEX FROM

2.24 LIKE 声明中的%和_是什么意思?

%对应于 0 个或更多字符, _只是 LIKE 语句中的一个字符

2.25 列对比运算符是什么?

在 SELECT 语句的列比较中使用=, <>, <=, <, > =, >, <<, >>, <=>, AND, OR 或 LIKE 运算符。

2.26 Mysql 查询是否区分大小写?

不区分

2.27 Mysql 中有哪些不同的表格?

共有 5 种类型的表格:
MyISAM
Heap
Merge
INNODB
ISAM
MyISAM 是 Mysql 的默认存储引擎。

2.28 ISAM 是什么?

ISAM 简称为索引顺序访问方法。它是由 IBM 开发的,用于在磁带等辅助存储系统上存储和检索数据

2.29 InnoDB 是什么?

lnnoDB 是一个由 Oracle 公司开发的 Innobase Oy 事务安全存储引擎。

2.30 如何输入字符为十六进制数字?

如果想输入字符为十六进制数字,可以输入带有单引号的十六进制数字和前缀( X),或者只用( Ox)前缀输入十六进制数字。

2.31 如何显示前 50 行?

SELECT*FROM xxx LIMIT 0,50;

2.32 可以使用多少列创建索引?

任何标准表最多可以创建 16 个索引列

2.33 NOW()和 CURRENT_DATE()有什么区别?

NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒。
CURRENT_DATE()仅显示当前年份,月份和日期。

2.34 MYSQL 数据表在什么情况下容易损坏?

服务器突然断电导致数据文件损坏。
强制关机,没有先关闭 mysql 服务等

2.35 Mysql 中有哪几种锁?

MyISAM 支持表锁, InnoDB 支持表锁和行锁,默认为行锁
表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高

2.36 有哪些数据库优化方面的经验?

  • 用 PreparedStatement, 一般来说比 Statement 性能高:一个 sql发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存
  • 有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就去掉外键。

2.37 请简述常用的索引有哪些种类?

  • 普通索引: 即针对数据库表创建索引
  • 唯一索引: 与普通索引类似,不同的就是: MySQL 数据库索引列的值必须唯一,但允许有空值
  • 主键索引: 它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引
  • 组合索引: 为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。即将数据库表中的多个字段联合起来作为一个组合索引。

2.38 mysql 数据库中索引的工作机制是什么?

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更
新数据库表中数据。索引的实现通常使用 B 树及其变种 B+树

2.39 MySQL 的基础操作命令

mysql -u root -p;
show databases;
show tables;

2.40 MySQL 中 InnoDB 引擎的行锁是通过加在什么上完成(或称实现)的?

InnoDB 行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据, InnoDB 才使用行级锁,否则, InnoDB 将使用表锁!

2.41 MySQL 当记录不存在时 insert,当记录存在时 update,语句怎么写?

INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY
UPDATE c=c+1;

2.42 请简洁描述 MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

read uncommited : 读到未提交数据
read committed: 脏读,不可重复读
repeatable read: 可重读
serializable : 串行事物

2.43 在 MySQL 中 ENUM 的用法是什么?

ENUM 是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用。
Create table size(name ENUM('Smail,‘Medium’,‘Large’);

2.44 列的字符串类型可以是什么?

  • SET
  • BLOB:BLOB 是一个二进制对象,可以容纳可变数量的数据。
  • ENUM
    • ENUM 是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用。
    • Create table size(name ENUM('Smail,‘Medium’,‘Large’);
  • CHAR
  • TEXT:TEXT 是对于排序和比较不区分大小写的 BLOB。
  • VARCHAR

2.45 通用 SQL 函数?

数学函数

  • Abs( num)求绝对值
  • floor( num)向下取整
  • ceil( num)向上取整

字符串函数

  • insert (s1,index,length,s2) 替换函数
    • S1 表示被替换的字符串
    • s2 表示将要替换的字符串
    • Index 表示被替换的位置, 从 1 开始
    • Lebgth 表示被替换的长度
  • upper( str), ucase( str)将字母改为大写
  • lower( str), lcase( str)将字母改为小写
  • left( str, length)返回 str 字符串的前 length 个字符
  • right( str, length)返回 str 字符串的后 length 个字符
  • reverse( str)将 str 字符串倒序输出

日期函数

  • curdate()、 current_date( ) 获取当前日期
  • curtime()、 current_time( ) 获取当前日期
  • now()获取当前日期和时间
  • datediff( d1、 d2) d1 和 d2 之间的天数差
  • adddate( date, num)返回 date 日期开始,之后 num 天的日期
  • subdate( date, num)返回 date 日期开始,之前 num 天的日期
    聚合函数
  • Count(字段)根据某个字段统计总记录数(当前数据库保存到多少条数据)
  • sum(字段)计算某个字段的数值总和
  • avg(字段)计算某个字段的数值的平均值
  • Max(字段)、 min(字段)求某个字段最大或最小值

2.46 mysql数据优化

优化数据类型

  • 避免使用 NULL, NULL 需要特殊处理, 大多数时候应该使用 NOT
    NULL,或者使用一个特殊的值,如 0, -1 作为默认值。
  • 仅可能使用更小的字段, MySQL 从磁盘读取数据后是存储到内存中
    的,然后使用 cpu 周期和磁盘 I/O 读取它,这意味着越小的数据类
    型占用的空间越小.

小心字符集转换

  • 客户端或应用程序使用的字符集可能和表本身的字符集不一样,这需要MySQL 在运行过程中隐含地进行转换,此外,要确定字符集如 UTF-8 是否支持多字节字符,因此它们需要更多的存储空间。

优化 UNION

  • 在跨多个不同的数据库时使用 UNION 是一个有效的优化方法,UNION 从两个互不关联的表中返回数据,这就意味着不会出现重复的行,同时也必须对数据进行排序,我们知道排序是非常耗费资源的,特别是对大表的排序。
  • UNION ALL 可以大大加快速度,如果你已经知道你的数据不会包括重复行,或者你不在乎是否会出现重复的行,在这两种情况下使用UNION ALL 更适合。

2.48 Mysql如何创建索引

2.49 Mysql优化

  1. select 指定查询字段,不要全查出来,节省内存

  2. 使用批量插入语句节省交互

  3. limit的基数比较大时,使用 between,between 限定比 limit 快,但是between也有缺陷,如果id中间有断行或是中间部分id不读取的情况,数据会少

select * from t where 1 limit 100000,10
优化为
select * from t where id between 100000 and 100010
  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  2. 应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。

  3. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  4. 避免频繁创建和删除临时表,以减少系统表资源的消耗

  5. 使用 JOIN 时,应该用小结果集驱动大结果集,同时把复杂的 JOIN 查询拆分成多个query,因为 JOIN 多个表,可能导致更多的锁定和堵塞

  6. 使用 LIKE 时,避免使用 %%

  7. 不要做无谓的排序操作,而应尽可能在索引中完成排序

  8. 索引优化-选择索引列:创建索引简单,但是在哪些列上创建索引则需要好好思考。

  9. 最左前缀原则-联合索引(name,age,phoneNum) ,B+树是按照从左到右的顺序来建立搜索树的。如(‘张三’,18,‘18668247652’)来检索数据的时候,B+树会优先匹配name来确定搜索方向,name匹配成功再依次匹配age、phoneNum,最后检索到最终的数据。

  10. 不能使用索引说明:mysql会按照联合索引从左往右进行匹配,直到遇到范围查询,如:>,<,between,like等就停止匹配,a = 1 and b =2 and c > 3 and d = 4,如果建立(a,b,c,d)顺序的索引,d是不会使用索引的。但如果联合索引是(a,b,d,c)的话,则a b d c都可以使用到索引,只是最终c是一个范围值。

  11. 一般情况下不建议使用like操作,如果非使用不可的话,需要注意:like '%abd%'不会使用索引,而like ‘aaa%’可以使用索引。这也是前面的最左前缀原则的一个使用场景

  12. 当 SQL 包含一对多表查询时,避免在 SELECT 子句中使用 DISTINCT,一般用 EXIST 替换,EXISTS查询更为迅速,因为 RDBMS 核心模块将在子查询的条件一旦满足后,立刻返回结果

(低效):
1. SELECT DISTINCT USER_ID,BILL_ID FROM USER_TAB1 D,USER_TAB2 E
2. WHERE D.USER_ID= E.USER_ID;
(高效):
1. SELECT USER_ID,BILL_ID FROM USER_TAB1 D WHERE EXISTS(SELECT 1
2. FROM USER_TAB2 E WHERE E.USER_ID= D.USER_ID);
  1. 只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT所释放的资源而减少

  2. 用>=替代>

高效:
SELECT * FROM TEMP WHERE ID >=4;
低效:
SELECT * FROM TEMP WHERE ID >3;
区别:前者 DBMS 将直接跳到第一个 ID 等于 4 的记录而后者将首先定位到 ID=3
的记录并且向前扫
描到第一个 ID 大于 3 的记录
  1. 避免在索引列上使用计算,WHERE 子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。
低效:
SELECTFROM TEMP WHERE SAL * 12 > 25000;
高效:
SELECTFROM TEMP WHERE SAL > 25000/12;

2.50 sql语句面试题

基本表结构:
student(sno,sname,sage,ssex)学生表
course(cno,cname,tno) 课程表
sc(sno,cno,score) 成绩表
teacher(tno,tname) 教师表

  1. 查询课程1的成绩比课程2的成绩高的所有学生的学号
select a.sno from
(select sno,score from sc where cno=1) a,
(select sno,score from sc where cno=2) b
where a.score>b.score and a.sno=b.sno

  1. 查询平均成绩大于60分的同学的学号和平均成绩
select a.sno as "学号", avg(a.score) as "平均成绩" 
from
(select sno,score from sc) a 
group by sno having avg(a.score)>60

  1. 查询所有同学的学号、姓名、选课数、总成绩
select a.sno as 学号, b.sname as 姓名,
count(a.cno) as 选课数, sum(a.score) as 总成绩
from sc a, student b
where a.sno = b.sno
group by a.sno, b.sname

  1. 查询姓“张”的老师的个数
selectcount(distinct(tname)) from teacher where tname like '张%‘
或者:
select tname as "姓名", count(distinct(tname)) as "人数" 
from teacher 
where tname like'%'
group by tname

  1. 查询没学过“张三”老师课的同学的学号、姓名
select student.sno,student.sname from student
where sno not in (select distinct(sc.sno) from sc,course,teacher
where sc.cno=course.cno and teacher.tno=course.tno and teacher.tname='张三')

  1. 查询同时学过课程1和课程2的同学的学号、姓名
select sno, sname from student
where sno in (select sno from sc where sc.cno = 1)
and sno in (select sno from sc where sc.cno = 2)
或者:
selectc.sno, c.sname from
(select sno from sc where sc.cno = 1) a,
(select sno from sc where sc.cno = 2) b,
student c
where a.sno = b.sno and a.sno = c.sno
或者:
select student.sno,student.sname from student,sc where student.sno=sc.sno and sc.cno=1
and exists( select * from sc as sc_2 where sc_2.sno=sc.sno and sc_2.cno=2)

  1. 查询学过“李四”老师所教所有课程的所有同学的学号、姓名
select a.sno, a.sname from student a, sc b
where a.sno = b.sno and b.cno in
(select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四')
或者:
select a.sno, a.sname from student a, sc b,
(select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四') e
where a.sno = b.sno and b.cno = e.cno

  1. 查询课程编号1的成绩比课程编号2的成绩高的所有同学的学号、姓名
select a.sno, a.sname from student a,
(select sno, score from sc where cno = 1) b,
(select sno, score from sc where cno = 2) c
where b.score > c.score and b.sno = c.sno and a.sno = b.sno

  1. 查询所有课程成绩小于60分的同学的学号、姓名
select sno,sname from student
where sno not in (select distinct sno from sc where score > 60)

  1. 查询至少有一门课程与学号为1的同学所学课程相同的同学的学号和姓名
select distinct a.sno, a.sname
from student a, sc b
where a.sno <> 1 and a.sno=b.sno and
b.cno in (select cno from sc where sno = 1)
或者:
select s.sno,s.sname 
from student s,
(select sc.sno 
from sc
where sc.cno in (select sc1.cno from sc sc1 where sc1.sno=1)and sc.sno<>1
group by sc.sno)r1
where r1.sno=s.sno

  1. 把“sc”表中“王五”所教课的成绩都更改为此课程的平均成绩
update sc set score = (select avg(sc_2.score) from sc sc_2 wheresc_2.cno=sc.cno)
from course,teacher where course.cno=sc.cno and course.tno=teacher.tno andteacher.tname='王五'

  1. 查询和编号为2的同学学习的课程完全相同的其他同学学号和姓名
这一题分两步查:
1select sno
from sc
where sno <> 2
group by sno
having sum(cno) = (select sum(cno) from sc where sno = 2)
2select b.sno, b.sname
from sc a, student b
where b.sno <> 2 and a.sno = b.sno
group by b.sno, b.sname
having sum(cno) = (select sum(cno) from sc where sno = 2)

  1. 删除学习“王五”老师课的sc表记录
delete sc from course, teacher
where course.cno = sc.cno and course.tno = teacher.tno and tname = '王五'

  1. 向sc表中插入一些记录,这些记录要求符合以下条件:将没有课程3成绩同学的该成绩补齐, 其成绩取所有学生的课程2的平均成绩
insert sc select sno, 3, (select avg(score) from sc where cno = 2)
from student
where sno not in (select sno from sc where cno = 3)

  1. 按平平均分从高到低显示所有学生的如下统计报表:-- 学号,企业管理,马克思,UML,数据库,物理,课程数,平均分
select sno as 学号
,max(case when cno = 1 then score end) AS 企业管理
,max(case when cno = 2 then score end) AS 马克思
,max(case when cno = 3 then score end) AS UML
,max(case when cno = 4 then score end) AS 数据库
,max(case when cno = 5 then score end) AS 物理
,count(cno) AS 课程数
,avg(score) AS 平均分
FROM sc
GROUP by sno
ORDER by avg(score) DESC

  1. 查询各科成绩最高分和最低分:以如下形式显示:课程号,最高分,最低分
select cno as 课程号, max(score) as 最高分, min(score) 最低分
from sc group by cno

select  course.cno as '课程号'
,MAX(score) as '最高分'
,MIN(score) as '最低分'
from sc,course
where sc.cno=course.cno
group by course.cno

  1. 按各科平均成绩从低到高和及格率的百分数从高到低顺序
SELECT t.cno AS 课程号,
max(course.cname)AS 课程名,
isnull(AVG(score),0) AS 平均成绩,
100 * SUM(CASE WHEN isnull(score,0)>=60 THEN 1 ELSE 0 END)/count(1) AS 及格率
FROM sc t, course
where t.cno = course.cno
GROUP BY t.cno
ORDER BY 及格率 desc

  1. 查询如下课程平均成绩和及格率的百分数(用"1行"显示): 企业管理(001),马克思(002),UML (003),数据库(004)
select 
avg(case when cno = 1 then score end) as 平均分1,
avg(case when cno = 2 then score end) as 平均分2,
avg(case when cno = 3 then score end) as 平均分3,
avg(case when cno = 4 then score end) as 平均分4,
100 * sum(case when cno = 1 and score > 60 then 1 else 0 end) / sum(casewhen cno = 1 then 1 else 0 end) as 及格率1,
100 * sum(case when cno = 2 and score > 60 then 1 else 0 end) / sum(casewhen cno = 2 then 1 else 0 end) as 及格率2,
100 * sum(case when cno = 3 and score > 60 then 1 else 0 end) / sum(casewhen cno = 3 then 1 else 0 end) as 及格率3,
100 * sum(case when cno = 4 and score > 60 then 1 else 0 end) / sum(casewhen cno = 4 then 1 else 0 end) as 及格率4
from sc

  1. 查询不同老师所教不同课程平均分, 从高到低显示
select max(c.tname) as 教师, max(b.cname) 课程, avg(a.score) 平均分
from sc a, course b, teacher c
where a.cno = b.cno and b.tno = c.tno
group by a.cno
order by 平均分 desc
或者:
select r.tname as '教师',r.rname as '课程' , AVG(score) as '平均分'
from sc,
(select  t.tname,c.cno as rcso,c.cname as rname
from teacher t ,course c
where t.tno=c.tno)r
where sc.cno=r.rcso
group by sc.cno,r.tname,r.rname 
order by AVG(score) desc

  1. 查询如下课程成绩均在第3名到第6名之间的学生的成绩:
    – [学生ID],[学生姓名],企业管理,马克思,UML,数据库,平均成绩
select top 6 max(a.sno) 学号, max(b.sname) 姓名,
max(case when cno = 1 then score end) as 企业管理,
max(case when cno = 2 then score end) as 马克思,
max(case when cno = 3 then score end) as UML,
max(case when cno = 4 then score end) as 数据库,
avg(score) as 平均分
from sc a, student b
where a.sno not in 

(select top 2 sno from sc where cno = 1 order by score desc)
  and a.sno not in (select top 2 sno from sc where cno = 2 order by scoredesc)
  and a.sno not in (select top 2 sno from sc where cno = 3 order by scoredesc)
  and a.sno not in (select top 2 sno from sc where cno = 4 order by scoredesc)
  and a.sno = b.sno
group by a.sno

2.51 mysql的语句优化,使用profiling工具

MySQL提供的一个时间记录工具,可以详细的记录每一条sql语句在执行的过程中,每一步花费的具体时间,时间级别达到微秒级别。默认是关闭的。
1.查看配置
在这里插入图片描述
2.开启配置
在这里插入图片描述

3.测试后
在这里插入图片描述

4.详细分析:可以详细分析这条sql语句在MySQL执行过程中,每一步花费的时间。
show proflies 可以查看所有被profile记录的sql语句
show profile for query ID 具体分析某条sql语句
在这里插入图片描述

2.52 Mysql悲观锁和乐观锁的区别,怎么实现

悲观锁

  • 当事务在操作数据时把这部分数据进行锁定,直到操作完毕后再解锁,其他事务操作才可操作该部分数据。这将防止其他进程读取或修改表中的数据。
  • 大多数情况下依靠数据库的锁机制实现
    一般使用 select …for update 对所选择的数据进行加锁处理,例如select * from account where name=”Max” for update, 这条sql 语句锁定了account 表中所有符合检索条件(name=”Max”)的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。
    乐观锁
  • 如果有人在你之前更新了,你的更新应当是被拒绝的,可以让用户重新操作。
  • 实现:大多数基于数据版本(Version)记录机制实现
    具体可通过给表加一个版本号或时间戳字段实现,当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断当前版本信息与第一次取出来的版本值大小,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,拒绝更新,让用户重新操作。

2.53 mysql不用内连接怎么多表查询数据

3. 集合

3.1 Java集合框架的基础接口有哪些?

Collection为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java平台不提供这个接口任何直接的实现。

  • Set是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。
  • List是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List更像长度动态变换的数组。
  • Map是一个将key映射到value的对象.一个Map不能包含重复的key:每个key最多只能映射一个value。
  • 一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。

3.1 Arraylist与LinkedList区别

  • ArrayList是数组的数据结构,LinkedList是链表的数据结构
  • 随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于索引(index)的数据结构,可以直接映射到
  • 插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。
    LinkedList比ArrayList开销更大,因为LinkedList的节点除了存储数据,还需要存储引用。

3.2 HashMap原理,java8做了什么改变

  • HashMap是以键值对存储数据的集合容器
  • HashMap是非线性安全的。
  • HashMap底层数据结构:数组+(链表、红黑树),jdk8之前是用数组+链表的方式实现,jdk8引进了红黑树
  • Hashmap数组的默认初始长度是16,key和value都允许null的存在
  • HashMap通过put和get方法存储和获取。
  • HashMap的put方法,首先计算key的hashcode值,定位到对应的数组索引,然后再在该索引的单向链表上进行循环遍历,用equals比较key是否存在,如果存在则用新的value覆盖原值,如果没有则向后追加。
  • jdk8中put方法:先判断Hashmap是否为空,为空就扩容,不为空计算出key的hash值i,然后看table[i]是否为空,为空就直接插入,不为空判断当前位置的key和table[i]是否相同,相同就覆盖,不相同就查看table[i]是否是红黑树节点,如果是的话就用红黑树直接插入键值对,如果不是开始遍历链表插入,如果遇到重复值就覆盖,否则直接插入,如果链表长度大于8,转为红黑树结构,执行完成后看size是否大于阈值threshold,大于就扩容,否则直接结束。
    Hashmap解决hash冲突,使用的是链地址法,即数组+链表的形式来解决。put执行首先判断table[i]位置,如果为空就直接插入,不为空判断和当前值是否相等,相等就覆盖,如果不相等的话,判断是否是红黑树节点,如果不是,就从table[i]位置开始遍历链表,相等覆盖,不相等插入。
  • HashMap的扩容机制,Hashmap的扩容中主要进行两步,第一步把数组长度变为原来的两倍,第二部把旧数组的元素重新计算hash插入到新数组中,jdk8时,不用重新计算hash,只用看看原来的hash值新增的一位是零还是1,如果是1这个元素在新数组中的位置,是原数组的位置加原数组长度,如果是零就插入到原数组中。扩容过程第二部一个非常重要的方法是transfer方法,采用头插法,把旧数组的元素插入到新数组中。

3.2 List 和 Set,Map 的区别

  • List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null。
  • Set 不能存放重复元素,无序的,只允许一个null
  • Map 保存键值对映射,映射关系可以一对一、多对一
  • List 有基于数组、链表实现两种方式
  • Set、Map 容器有基于哈希存储和红黑树两种方式实现
  • Set 基于 Map 实现,Set 里的元素值就是 Map的键值

3.3 poll()方法和 remove()方法的区别

Queue队列中,poll() 和 remove() 都是从队列中取出一个元素,在队列元素为空的情况下,remove() 方法会抛出异常,poll() 方法只会返回 null

3.4 写一段代码在遍历 ArrayList 时移除一个元素

因为foreach删除会导致快速失败问题,fori顺序遍历会导致重复元素没删除

第一种遍历,倒叙遍历删除
for(int i=list.size()-1;
 i>;;;-1; i--){
if(list.get(i).equals("jay")){ 
 list.remove(list.get(i))}}


第二种,迭代器删除
Iterator itr = list.iterator()while(itr.hasNext()) { 
 if(itr.next().equals("jay") { 
itr.remove()}}

3.5 Java中怎么打印数组

public class Test { public static void main(String[] args) { 
String[] jayArray = {"jay", "boy"}System.out.println(jayArray)}}//output[Ljava.lang.String;
@1540e19d

打印数组可以用流的方式Strem.of().foreach(),如下:
public class Test { 
public static void main(String[] args) { 
String[] jayArray = {"jay", "boy"}Stream.of(jayArray).forEach(System.out::println)}}//outputjayboy

打印数组,最优雅的方式可以用这个APi,Arrays.toString()
public class Test { 
public static void main(String[] args) { 
String[] jayArray = {"jay", "boy"}System.out.println(Arrays.toString(jayArray))}}
//output[jay, boy]

3.6 TreeMap底层

TreeMap实现了SotredMap接口,它是有序的集合。
TreeMap底层数据结构是一个红黑树,每个key-value都作为一个红黑树的节点

3.7 HashMap 的扩容过程

第一步把数组长度变为原来的两倍,
第二步把旧数组的元素重新计算hash插入到新数组中。
jdk8时,不用重新计算hash,只用看看原来的hash值新增的一位是零还是1,如果是1这个元素在新数组中的位置,是原数组的位置加原数组长度,如果是零就插入到原数组中。扩容过程第二步一个非常重要的方法是transfer方法,采用头插法,把旧数组的元素插入到新数组中。

3.8 HashMap 是线程安全的吗,为什么不是线程安全的?死循环问题?

不是线性安全的。
并发的情况下,扩容可能导致死循环问题。

3.9 哪些集合类是线程安全的?哪些不安全?

线性安全的

  • Vector:比Arraylist多了个同步化机制。
  • Hashtable:比Hashmap多了个线程安全。
  • ConcurrentHashMap:是一种高效但是线程安全的集合。
  • Stack:栈,也是线程安全的,继承于Vector

线性不安全的

  • Hashmap
  • Arraylist
  • LinkedList
  • HashSet
  • TreeSet
  • TreeMap

3.10 ArrayList 和 Vector 的区别是什么?

  • Vector是线程安全的,ArrayList不是线程安全的。
  • Vector只要是关键性的操作,方法前面都加了synchronized关键字,来保证线程的安全性。

3.11 如何决定使用 HashMap 还是TreeMap?

这个点,主要考察HashMap和TreeMap的区别。
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按key的升序排序,也可以指定排序的比较器。当用Iterator遍历TreeMap时,得到的记录是排过序的。

3.12 如何实现数组和 List之间的转换

数组转换成为List:调用Arrays的asList()方法

//string数组转成List<String>
String[] string = {"a", "b", "c", "d"};
List<String> Lstring = Arrays.asList(string);

List转换成为数组:调用ArrayList的toArray()方法

List<String> Lstring = new ArrayList<String>();
String[] string = (String[])Lstring .toArray();

3.13 迭代器 Iterator 是什么?怎么用,有什么特点

Iterator:它是遍历集合的工具,即我们通常通过Iterator迭代器来遍历集合。我们说Collection依赖于Iterator,是因为Collection的实现类都要实现iterator()函数,返回一个Iterator对象。ListIterator是专门为遍历List而存在的
Iterator 的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

List<String> list = new ArrayList<>();
Iterator<String> it = list. iterator();
while(it. hasNext()){
  String obj = it. next();
  System. out. println(obj);
}

//remove() 方法将迭代器新返回的元素删除

3.14 Iterator 和 ListIterator 有什么区别

  • Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
  • Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
  • ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
  • ListIterator 可以使用set()方法替换它访问过的最后一个元素.
  • ListIterator 可以使用add()方法在next()方法返回的元素之前或previous()方法返回的元素之后插入一个元素.

3.15 什么是Java优先级队列(Priority Queue)

优先队列PriorityQueue是Queue接口的实现,可以对其中元素进行排序
优先队列中元素默认排列顺序是升序排列
但对于自己定义的类来说,需要自己定义比较器

  • 基于优先级堆
  • 不允许null值
//测试优先级队列自动排序
	public static List<Integer> insertSort(){
		List<Integer> list = new ArrayList<Integer>();
		Queue<Integer> queue = new PriorityQueue<Integer>(7);
		Random random = new Random();
		for(int i=0;i<7;i++){
			queue.add(new Integer(random.nextInt(100))); 
		}
		for(int i=0;i<queue.size();i++){
			list.add(queue.poll());
		}
		return list;
	}

	public static void main(String[] args) {
		System.out.println(Arrays.toString(insertSort().toArray()));
	}

peek()//返回队首元素
poll()//返回队首元素,队首元素出队列
add()//添加元素
size()//返回队列元素个数
isEmpty()//判断队列是否为空,为空返回true,不空返回false

3.16 阻塞队列的实现,ArrayBlockingQueue的底层实现

ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列,继承自AbstractBlockingQueue,间接的实现了Queue接口和Collection接口。底层以数组的形式保存数据(实际上可看作一个循环数组)。常用的操作包括 add ,offer,put,remove,poll,take,peek。

3.17 Java 中的 LinkedList是单向链表还是双向链表

双向链表,列表中的每个节点都包含了对前一个和后一个元素的引用

3.18 HashMap 的长度为什么是2的幂次方,以及其他常量定义的含义

为了能让HashMap存取高效,数据分配均匀

3.19 当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?

在作为参数传递之前,使用Collections.unmodifiableCollection(Collection c)方法创建一个只读集合,这将确保改变集合的任何操作都会抛出UnsupportedOperationException。

3.20 Array 和 ArrayList 有何区别?

定义一个 Array 时,必须指定数组的数据类型及数组长度,即数组中存放的元素个数固定并且类型相同。
ArrayList 是动态数组,长度动态可变,会自动扩容。不使用泛型的时候,可以添加不同类型元素。

3.21 为什么HashMap中String、Integer这样的包装类适合作为key?

String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,它们都是final修饰的类,不可变性,保证key的不可更改性,不会存在获取hash值不同的情况

3.22 讲讲红黑树的特点

  • 每个节点或者是黑色,或者是红色。
  • 根节点是黑色。
  • 每个叶子节点(NIL)是黑色。[注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
  • 如果一个节点是红色的,则它的子节点必须是黑色的。
  • 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

3.23 Java集合类框架的最佳实践有哪些

  • 根据应用需要正确选择要使用的集合类型对性能非常重要,比如:假如知道元素的大小是固定的,那么选用Array类型而不是ArrayList类型更为合适。
  • 有些集合类型允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以指定初始容量来避免重新计算hash值或者扩容等。
  • 为了类型安全、可读性和健壮性等原因总是要使用泛型。同时,使用泛型还可以避免运行时的ClassCastException。
  • 使用JDK提供的不变类(immutable class)作为Map的键可以避免为我们自己的类实现hashCode()和equals()方法。
  • 编程的时候接口优于实现
  • 底层的集合实际上是空的情况下,返回为长度是0的集合或数组而不是null。

3.24 HashSet和TreeSet有什么区别

  • Hashset 的底层是由哈希表实现的,Treeset 底层是由红黑树实现的。
  • HashSet中的元素没有顺序,TreeSet保存的元素有顺序性(实现Comparable接口)
  • HashSet的add(),remove(),contains()方法的时间复杂度是O(1);
  • TreeSet中,add(),remove(),contains()方法的时间复杂度是O(logn)

3.25 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()?

元素重复与否是使用equals()方法进行判断的,这个可以跟面试官说说==和equals()的区别,hashcode()和equals

3.26 说出ArrayList,LinkedList的存储性能和特性

这道面试题,跟ArrayList,LinkedList,就是换汤不换药的

3.27 ArrayList集合加入1万条数据,应该怎么提高效率

我们调用ArrayList的指定容量的构造器方法ArrayList(int size) 就可以实现不扩容,就提高了性能。

3.28 我们如何对一组对象进行排序?

 如果我们需要对一个对象数组进行排序,我们可以使用Arrays.sort()方法。
 如果我们需要排序一个对象列表,我们可以使用Collection.sort()方法。
两个类都有用于自然排序(使用Comparable)或基于标准的排序(使用Comparator)的重载方法sort()Collections内部使用数组排序方法,所有它们两者都有相同的性能,只是Collections需要花时间将列表转换为数组。

package com.example.Test;

/**
 * @author Administrator
 *
 */
public class TestObj implements Comparable<TestObj> {
    public int id;
    
    public String name;
    
    public int age;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "TestObj [id=" + id + ", name=" + name + ", age=" + age + "]";
    }
    @Override
    public int compareTo(TestObj o) {
        // TODO Auto-generated method stub
        return String.valueOf(this.getAge()).compareTo(String.valueOf(o.getAge()));
    }
}

然后调用Collections.sort(list)进行排序

@Test
     public void testListSort() {
         List<TestObj> list = new ArrayList<>();
         
         TestObj obj1 = new TestObj();
         obj1.setId(1);
         obj1.setName("张三");
         obj1.setAge(16);
         
         TestObj obj2 = new TestObj();
         obj2.setId(2);
         obj2.setName("李四");
         obj2.setAge(20);
         
         TestObj obj3 = new TestObj();
         obj3.setId(3);
         obj3.setName("王五");
         obj3.setAge(12);
         
         TestObj obj4 = new TestObj();
         obj4.setId(4);
         obj4.setName("赵六");
         obj4.setAge(24);
         
         list.add(obj1);
         list.add(obj2);
         list.add(obj3);
         list.add(obj4);
         
         Collections.sort(list);
         for (TestObj testObj : list) {
            System.out.println(testObj.toString());
        }
     }

 

输出结果

TestObj [id=3, name=王五, age=12]
TestObj [id=1, name=张三, age=16]
TestObj [id=2, name=李四, age=20]
TestObj [id=4, name=赵六, age=24]

3.29 ArrayList 和 HashMap 的默认大小是多数

在 Java 7 中,ArrayList 的默认大小是 10 个元素,HashMap 的默认大小是16个元素(必须是2的幂)。

3.30 HashMap是怎么解决哈希冲突的

Hashmap解决hash冲突,使用的是链地址法,即数组+链表的形式来解决。put执行首先判断table[i]位置,如果为空就直接插入,不为空判断和当前值是否相等,相等就覆盖,如果不相等的话,判断是否是红黑树节点,如果不是,就从table[i]位置开始遍历链表,相等覆盖,不相等插入

3.31 集合框架中的泛型有什么优点?

泛型允许我们为集合提供一个可以容纳的对象类型。
因此,如果你添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现ClassCastException,因为你将会在编译时得到报错信息。
泛型也使得代码整洁,我们不需要使用显式转换和instanceOf操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。

3.32 Enumeration和Iterator接口的区别?

  • Enumeration的速度是Iterator的两倍,也使用更少的内存。Enumeration是非常基础的,也满足了基础的需要。
  • 但是,与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。
  • 迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。

3.32 Iterater和ListIterator之间有什么区别?

  • 我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。
  • Iterator只可以向前遍历,而LIstIterator可以双向遍历。
  • ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

3.33 collection和collections有什么区别

Collection是集合类的上级接口,继承与他有关的接口主要有List和Set
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作

3.34 List 的三个子类的特点

ArrayList 底层结构是数组,底层查询快,增删慢。
LinkedList 底层结构是链表型的,增删快,查询慢。
voctor 底层结构是数组 线程安全的,增删慢,查询慢。

3.35 HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?

不是线程安全的;
如果有两个线程A和B,都进行插入数据,刚好这两条不同的数据经过哈希计算后得到的哈希码是一样的,且该位置还没有其他的数据。所以这两个线程都会进入我在上面标记为1的代码中。假设一种情况,线程A通过if判断,该位置没有哈希冲突,进入了if语句,还没有进行数据插入,这时候 CPU 就把资源让给了线程B,线程A停在了if语句里面,线程B判断该位置没有哈希冲突(线程A的数据还没插入),也进入了if语句,线程B执行完后,轮到线程A执行,现在线程A直接在该位置插入而不用再判断。这时候,你会发现线程A把线程B插入的数据给覆盖了。发生了线程不安全情况。本来在HashMap 中,发生哈希冲突是可以用链表法或者红黑树来解决的,但是在多线程中,可能就直接给覆盖了

4.JVM(java虚拟机)

链接: https://blog.csdn.net/qq_44859586/article/details/120344194

5.线程

5.1 什么是线程?

线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中.是进程中的实际运作单位。
是一段可运行的线程

5.2 线程和进程有什么区别?

进程是一个可运行的完整程序代码,一个进程可以有很多线程.每条线程并行执行不同的任务。

5.3 实现线程的方法:

继承Thread 实现Runnable 实现Callable类

5.4 Java 关键字volatile 与 synchronized 作用与区别?

5.5 有哪些不同的线程生命周期

线程的5个状态:创建就绪运行阻塞终止
当我们在Java程序中新建一个线程时.它的状态是New。当我们调用线程的start()方法时.状态被改变为Runnable。线程调度器会为Runnable线程池中的线程分配CPU时间并且讲它们的状态改变为Running。其他的线程状态还有Waiting.Blocked 和Dead

5.6 你对线程优先级的理解是什么?

每一个线程都是有优先级的.一般来说.高优先级的线程在运行时会具有优先权.但这依赖于线程调度的实现.。
我们可以定义线程的优先级.但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10).1代表最低优先级.10代表最高优先级。
priority():线程的优先级,越大优先级越高

5.7 什么是线程安全?Vector是一个线程安全类吗

有多个线程在同时运行.而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的.而且其他的变量的值也和预期的是一样的.就是线程安全的。
Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。

5.8 Java中如何停止一个线程

以前版本有stop()这些,由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了。
当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程.你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程

5.9 什么是ThreadLocal

ThreadLocal用于创建线程的本地变量.我们知道一个对象的所有线程会共享它的全局变量.所以这些变量不是线程安全的.我们可以使用同步技术。但是当我们不想使用同步的时候.我们可以选择ThreadLocal变量。

5.10 ThreadLocal可以用来共享数据吗

不可以
ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本
ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏

5.11 什么是线程饿死.什么是活锁?

当所有线程阻塞.或者由于需要的资源无效而不能处理.不存在非阻塞线程使资源可用。JavaAPI中线程活锁可能发生在以下情形:

  • 当所有线程在程序中执行Object.wait(0).参数为0的wait方法。程序将发生活锁直到在相应的对象上有线程调用Object.notify()或者Object.notifyAll()。
  • 当所有线程卡在无限循环中。

5.12 什么是Java Timer类?如何创建一个有特定时间间隔的任务?

  • java.util.Timer是一个工具类.可以用于安排一个线程在未来的某个特定时间执行。Timer类可以用安排一次性任务或者周期任务。
  • java.util.TimerTask是一个实现了Runnable接口的抽象类.我们需要去继承这个类来创建我们自己的定时任务并使用Timer去安排它的执行。

5.13 Java中的同步集合与并发集合有什么区别?

  • 同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合.不过并发集合的可扩展性更高。
  • 在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用.阻碍了系统的扩展性。
  • Java5介绍了并发集合像ConcurrentHashMap.不仅提供线程安全还用锁分离和 内部分区等现代技术提高了可扩展性。

5.14 同步方法和同步块.哪个是更好的选择?

同步块是更好的选择.因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。
同步方法会锁住整个对象.哪怕这个类中有多个不相关联的同步块.这通常会导致他们停止执行并需要等待获得这个对象上的锁。

5.15 什么是线程池? 为什么要使用它?

创建线程要花费昂贵的资源和时间.如果任务来了才创建线程那么响应时间会变长.而且一个进程能创建的线程数有限。
为了避免这些问题.在程序启动的时候就创建若干线程来响应处理.它们被称为线程池.里面的线程叫工作线程。
从JDK1.5开始.Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池.每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。

5.16 多线程中的忙循环是什么?

忙循环就是程序员用循环让一个线程等待.不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制.而忙循环不会放弃CPU.它就是在运行一个空循环。这么做的目的是为了保留CPU缓存。

5.17 启动一个线程用run还是start

启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

5.18 有三个线程T1,T2,T3,怎么确保它们按顺序执行?

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成

5.19 怎么检测一个线程是否拥有锁?

在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。

5.20 如何在两个线程间共享数据?

你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构,用wait和notify方法实现了生产者消费者模型。

5.21 什么地方用了多线程

一般的java web 方面开发的话几乎用不到多线程!只有用户量极大的时候才用,或者进行并发测试的时候

5.22 Excutors可以产生哪些线程池

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。ThreadPoolExecutor是Executors类的底层实现。

5.23 Java 中多线程同步是什么?

即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态

5.24 用户线程和守护线程有什么区别

守护线程:是个服务线程,准确地来说就是服务其他的线程
守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
默认情况下启动的线程是用户线程,通过setDaemon(true)将线程设置成守护线程

5.25 如何暂停一条线程?

两种方式暂停一条线程,一个是采取 Thread 类的 sleep()方法,一个是在同步代码中使用 wait()方法.

5.26 线程的调度和时间分片?

  • java 虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用 CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用 CPU。处于运行状态的线程会一直运行,直至它不得不放弃 CPU。
  • 线程的调度不是跨平台的,它不仅仅取决于 java 虚拟机,还依赖于操作系统。在某些操作系统中,只要运行中的线程没有遇到阻塞,就不会放弃 CPU;在某些操作系统中,即使线程没有遇到阻塞,也会运行一段时间后放弃 CPU,给其它线程运行的机会。
  • java 的线程调度是不分时的,同时启动多个线程后,不能保证各个线程轮流获得均等的.

5.27 Synchronized 用 过 吗 , 其 原 理 是 什 么 ?

Synchronized 是 由 JVM 实 现 的 一 种 实 现 互 斥 同 步 的 一 种 方 式 , 如 果你 查 看 被 Synchronized 修 饰 过 的 程 序 块 编 译 后 的 字 节 码 , 会 发 现 ,被 Synchronized 修 饰 过 的 程 序 块 , 在 编 译 前 后 被 编 译 器 生 成 了monitorenter 和 monitorexit 两 个 字 节 码 指 令
这 两 个 指 令 是 什 么 意 思 呢
在 虚 拟 机 执 行 到 monitorenter 指 令 时 , 首 先 要 尝 试 获 取 对 象 的 锁 :如 果 这 个 对 象 没 有 锁 定 , 或 者 当 前 线 程 已 经 拥 有 了 这 个 对 象 的 锁 , 把 锁的 计 数 器 +1; 当 执 行 monitorexit 指 令 时 将 锁 计 数 器 -1; 当 计 数 器为 0 时 , 锁 就 被 释 放 了 。如 果 获 取 对 象 失 败 了 , 那 当 前 线 程 就 要 阻 塞 等 待 , 直 到 对 象 锁 被 另 外 一个 线 程 释 放 为 止 。
Java 中 Synchronize 通 过 在 对 象 头 设 置 标 记 , 达 到 了 获 取 锁 和 释 放锁 的 目 的 。

5.28 你 刚 才 提 到 获 取 对 象 的 锁 , 这 个 “ 锁 ” 到 底 是 什 么 ? 如 何 确 定对 象 的 锁 ?

“ 锁 ” 的 本 质 其 实 是 monitorenter 和 monitorexit 字 节 码 指 令 的 一个 Reference 类 型 的 参 数 , 即 要 锁 定 和 解 锁 的 对 象 。 我 们 知 道 , 使 用Synchronized 可 以 修 饰 不 同 的 对 象 , 因此 , 对 应 的 对 象 锁 可 以 这 么 确定 。

  • 如 果 Synchronized 明 确 指 定 了 锁 对 象 , 比 如 Synchronized( 变 量名 ) 、 Synchronized(this) 等 , 说 明 加 解 锁 对 象 为 该 对 象 。
  • 如 果 没 有 明 确 指 定 :
    • 若 Synchronized 修 饰 的 方 法 为 非 静 态 方 法 , 表 示 此 方 法 对 应 的 对 象 为锁 对 象
    • 若 Synchronized 修 饰 的 方 法 为 静 态 方 法 , 则 表 示 此 方 法 对 应 的 类 对 象为 锁 对 象

注 意 , 当 一 个 对 象 被 锁 住 时 , 对 象 里 面 所 有 用 Synchronized 修 饰 的方 法 都 将 产 生 堵 塞 , 而 对 象 里 非 Synchronized 修 饰 的 方 法 可 正 常 被调 用 , 不 受 锁 影 响

5.29 什 么 是 可 重 入 性 , 为 什 么 说 Synchronized 是 可 重 入 锁 ?

可 重 入 性 是 锁 的 一 个 基 本 要 求 , 是 为 了 解 决 自 己 锁 死 自 己 的 情 况 。比 如 下 面 的 伪 代 码 , 一 个 类 中 的 同 步 方 法 调 用 另 一 个 同 步 方 法 , 假 如Synchronized 不 支 持 重 入 , 进 入 method2 方 法 时 当 前 线 程 获 得 锁 ,method2 方 法 里 面 执 行 method1 时 当 前 线 程 又 要 去 尝 试 获 取 锁 , 这时 如 果 不 支 持 重 入 , 它 就 要 等 释 放 , 把 自 己 阻 塞 , 导 致 自 己锁 死 自 己 。

5.30 为 什 么 说 Synchronized 是 非 公 平 锁 ?

非 公 平 主 要 表 现 在 获 取 锁 的 行 为 上 , 并 非 是 按 照 申 请 锁 的 时 间 前 后 给 等待 线 程 分 配 锁 的 , 每 当 锁 被 释 放 后 , 任 何 一 个 线 程 都 有 机 会 竞 争 到 锁 ,这 样 做 的 目 的 是 为 了 提 高 执 行 性 能 , 缺 点 是 可 能 会 产 生 线 程 饥 饿 现 象 。

5.31 什 么 是 锁 消 除 和 锁 粗 化

锁 消 除 : 指 虚 拟 机 即 时 编 译 器 在 运 行 时 , 对 一 些 代 码 上 要 求 同 步 , 但 被检 测 到 不可 能 存 在 共 享 数 据 竞 争 的 锁 进 行 消 除 。
锁 粗 化 : 原 则 上 , 同 步 块 的 作 用 范 围 要 尽 量 小 。 但 是 如 果 一 系 列 的 连 续操 作 都 对 同 一 个 对 象 反 复 加 锁 和 解 锁 , 甚 至 加 锁 操 作 在 循 环 体 内 , 频 繁地 进 行 互 斥 同 步 操 作 也 会 导 致 不 必 要 的 性 能 损 耗 。锁 粗 化 就 是 增 大 锁 的 作 用 域 。

5.32 为 什 么 说 Synchronized 是 一 个 悲 观 锁 ?

不 管 是 否 会 产 生 竞 争 , 任 何 的 数 据 操 作 都 必 须 要 加 锁 、 用 户 态 核 心 态 转
换 、 维 护 锁 计 数 器 和 检 查 是 否 有 被 阻 塞 的 线 程 需 要 被 唤 醒 等 操 作 。

5.33 乐 观 锁 的 实 现 原 理又 是 什 么 ?

先 进 行 操 作 , 如 果 没 有 其 他 线 程 征 用 数 据 , 那 操 作 就 成 功 了 ;如 果 共 享 数 据 有 征 用 , 产 生 了 冲 突 , 那 就 再 进 行 其 他 的 补 偿 措 施 。 这 种乐 观 的 并 发 策 略 的 许 多 实 现 不 需 要 线 程 挂 起 , 所 以 被 称 为 非 阻 塞 同 步 。
乐 观 锁 的 核 心 算 法 是 CAS( Compareand Swap, 比 较 并 交 换 )

5.34 CAS是什么(比 较 并 交 换)

它 涉及 到 三 个 操 作 数 : 内 存 值 、 预 期 值 、 新 值 。 当 且 仅 当 预 期 值 和 内 存 值 相
等 时 才 将 内 存 值 修 改 为 新 值。
这 样 处 理 的 逻 辑 是 , 首 先 检 查 某 块 内 存 的 值 是 否 跟 之 前 我 读 取 时 的 一样 , 如 不 一 样 则 表 示 期 间 此 内 存 值 已 经 被 别 的 线 程 更 改 过 , 舍 弃 本 次 操作 , 否 则 说 明 期 间 没 有 其 他 线 程 对 此 内 存 值 操 作 , 可 以 把 新 值 设 置 给 此块 内 存 。
CAS 具 有 原 子 性 , 它 的 原 子 性 由 CPU 硬 件 指 令 实 现 保 证 , 即 使 用JNI 调 用 Native 方 法 调 用 由 C++ 编 写 的 硬 件 级 别 指 令 。

5.35 乐 观 锁 一 定 就 是 好 的 吗 ?

乐 观 锁 避 免 了 悲 观 锁 独 占 对 象 的 现 象 , 同 时 也 提 高 了 并 发 性 能 , 但 它 也有 缺 点 :

  • 乐 观 锁 只 能 保 证 一 个 共 享 变 量 的 原 子 操 作 。 如 果 多 一 个 或 几 个 变 量 , 乐观 锁 将 变 得 力 不 从 心 , 但 互 斥 锁 能 轻 易 解 决 , 不 管 对 象 数 量 多 少 及 对 象颗 粒 度 大 小 。
  • 长 时 间 自 旋(while) 可 能 导 致 开 销 大 。 假 如 CAS 长 时 间 不 成 功 而 一 直 自 旋 , 会给 CPU 带 来 很 大 的 开 销。
  • ABA 问 题 。 CAS 的 核 心 思 想 是 通 过 比 对 内 存 值 与 预 期 值 是 否 一 样 而 判断 内 存 值 是 否 被 改 过 , 但 这 个 判 断 逻 辑 不 严 谨 , 假 如 内 存 值 原 来 是 A,后 来 被 一 条 线 程 改 为 B, 最 后 又 被 改 成 了 A, 则 CAS 认 为 此 内 存 值 并没 有 发 生 改 变 , 但 实 际 上 是 有 被 其 他 线 程 改 过 的 , 这 种 情 况 对 依 赖 过 程值 的 情 景 的 运 算 结 果 影 响 很 大 。 解 决 的 思 路 是 引 入 版 本 号 , 每 次 变 量 更新 都 把 版 本 号 加 一 。

5.36 跟 Synchronized 相 比 , 可 重 入 锁 ReentrantLock 其 实 现原 理 有 什 么 不 同 ?

Synchronized 是 一 种 JVM原 生 的 锁 实 现 方 式 , 而 ReentrantLock 以 及 所 有 的 基 于 Lock 接 口 的实 现 类 , 都 是 通 过 用 一 个 volitile 修 饰 的 int 型 变 量 , 并 保 证 每 个 线程 都 能 拥 有 对 该 int 的 可 见 性 和 原 子 修 改 , 其 本 质 是 基 于 所 谓 的 AQS框 架 。

5.37 那 么 请 谈 谈 AQS 框 架 是 怎 么 回 事 儿 ?

AQS( AbstractQueuedSynchronizer 类 ) 是 一 个 用 来 构 建 锁 和 同 步 器的 框 架 , 各 种 Lock包 中 的 锁 ,都 是 基 于 AQS 来 构 建 。

5.38 ReentrantLock 是 如 何 实 现 可 重 入 性 的 ?其 实 就 是

加 锁 的 时 候 通 过 CAS 算 法 , 将 线 程 对 象 放 到 一 个 双 向 链 表 中 , 每 次 获取 锁 的 时 候 , 看 下 当 前 维 护 的 那 个 线 程 ID 和 当 前 请 求 的 线 程 ID 是 否一 样 , 一 样 就 可 重 入 了 。

5.39 除 了 ReetrantLock, 你 还 接 触 过 JUC 中 的 哪 些 并 发 工 具 ?

通 常 所 说 的 并 发 包 ( JUC) 也 就 是 java.util.concurrent 及 其 子 包 , 集中 了 Java 并 发 的 各 种 基 础 工 具 类

5.40 Java 中 的 线 程 池 是 如 何 实 现 的 ?

控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

5.41 创 建 线 程 池 的 几 个 核 心 构 造 参 数 ?

  • corePoolSize: 线 程 池 的 核 心 线 程 数 。
  • maximumPoolSize: 线 程 池 允 许 的 最 大 线 程 数 。
  • keepAliveTime: 超 过 核 心 线 程 数 时 闲 置 线 程 的 存 活 时 间 。
  • workQueue: 任 务 执 行 前 保 存 任 务 的 队 列 , 保 存 由 execute 方 法 提 交的 Runnable 任 务

5.42 线 程 池 中 的 线 程 是 怎 么 创 建 的 ? 是 一 开 始 就 随 着 线 程 池 的 启 动创 建 好 的 吗 ?

显 然 不 是 的 。 线 程 池 默 认 初 始 化 后 不 启 动 Worker, 等 待 有 请 求 时 才 启
动 。
每 当 我 们 调 用 execute() 方 法 添 加 一 个 任 务 时 , 线 程 池 会 做 如 下 判
断 :

  • 如 果 正 在 运 行 的 线 程 数 量 小 于 corePoolSize, 那 么 马 上 创 建 线 程 运 行这 个 任 务 ;
  • 如 果 正 在 运 行 的 线 程 数 量 大 于 或 等 于 corePoolSize, 那 么 将 这 个 任 务放 入 队 列 ;
  • 如 果 这 时 候 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 小 于maximumPoolSize, 那 么 还 是 要 创 建 非 核 心 线 程 立 刻 运 行 这 个 任 务 ;
  • 如 果 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 大 于 或 等 于maximumPoolSize, 那 么 线 程 池 会 抛 出 异 常RejectExecutionException。当 一 个 线 程 完 成 任 务 时 , 它 会 从 队 列 中 取 下 一 个 任 务 来 执 行 。
  • 当 一 个线 程 无 事 可 做 , 超 过 一 定 的 时 间 ( keepAliveTime) 时 , 线 程 池 会 判断 。
  • 如 果 当 前 运 行 的 线 程 数 大 于 corePoolSize, 那 么 这 个 线 程 就 被 停 掉 。所 以 线 程 池 的 所 有 任 务 完 成 后 , 它 最 终 会 收 缩 到 corePoolSize 的 大小 。

5.43 如 何 在 Java 线 程 池 中 提 交 线 程 ?

线 程 池 最 常 用 的 提 交 任 务 的 方 法 有 两 种 :

  • execute(): ExecutorService.execute 方 法 接 收 一 个 Runable 实例 , 它 用 来 执 行 一 个 任 务 * submit(): ExecutorService.submit() 方 法 返 回 的 是 Future 对象 。 可 以 用 isDone() 来 查 询 Future 是 否 已 经 完 成 , 当 任 务 完 成 时 ,它 具 有 一 个 结 果 , 可 以 调 用 get() 来 获 取 结 果 。 也 可 以 不 用 isDone()进 行 检 查 就 直 接 调 用 get(), 在 这 种 情 况 下 , get() 将 阻 塞 , 直 至 结 果准 备 就 绪

5.44 什 么 是 Java 的 内 存 模 型

Java 的 内 存 模 型 (java memory model)在 虚 拟 机 中 将变 量 存 储 到 内 存 和 从 内 存 中 取 出 。JMM规定了内存主要划分为主内存和工作内存两种,主内存对应的是Java堆中的对象实例部分,工作内存对应的是栈中的部分区域

5.45 请 谈 谈 volatile 有 什 么 特 点

关 键 字 volatile 是 Java 虚 拟 机 提 供 的 最 轻 量 级 的 同 步 机 制 。 当 一 个变 量 被 定 义 成 volatile 之 后 , 具 备 三种 特 性 :

  • 保 证 此 变 量 对 所 有 线 程 的 可 见 性 。 当 一 条 线 程 修 改 了 这 个 变 量 的 值 , 新值 对 于 其 他 线 程 是 可 以 立 即 得 知 的 。 而 普 通 变 量 做 不 到 这 一 点
  • 非原子性
  • 禁 止 指 令 重 排 序 优 化 。 普 通 变 量 仅 仅 能 保 证 在 该 方 法 执 行 过 程 中 , 得 到正 确 结 果 , 但 是 不 保 证 程 序 代 码 的 执 行 顺 序

5.46 既 然 volatile 能 够 保 证 线 程 间 的 变 量 可 见 性 , 是 不 是 就 意 味着 基 于 volatile 变 量 的 运 算 就 是 并 发 安 全 的 ?

显 然 不 是 的 。 基 于 volatile 变 量 的 运 算 在 并 发 下 不 一 定 是 安 全 的 。volatile 变 量 在 各 个 线 程 的 工 作 内 存 , 不 存 在 一 致 性 问 题 ( 各 个 线 程 的工 作 内 存 中 volatile 变 量 , 每 次 使 用 前 都 要 刷 新 到 主 内 存 ) 。

5.47 请 对 比 下 volatile 对 比 Synchronized 的 异 同 。

  • Synchronized 既 能 保 证 可 见 性 , 又 能 保 证 原 子 性 , 而 volatile 只 能保 证 可 见 性 , 无 法 保 证 原 子 性 。

5.48 ThreadLocal 和 Synchonized 的区别

  • ThreadLocal 和 Synchonized 都 用 于 解 决 多 线 程 并 发 访 问 , 防 止 任 务在 共 享 资 源 上 产 生 冲 突 。 但 是 ThreadLocal 与 Synchronized 有 本 质的 区 别 。
  • Synchronized 用 于 实 现 同 步 机 制 , 是 利 用 锁 的 机 制 使 变 量 或 代 码 块 在某 一 时 该 只 能 被 一 个 线 程 访 问 , 是 一 种 “ 以 时 间 换 空 间 ” 的 方 式 。而 ThreadLocal 为 每 一 个 线 程 都 提 供 了 变 量 的 副 本 , 使 得 每 个 线 程 在某 一 时 间 访 问 到 的 并 不 是 同 一 个 对 象 , 根 除 了 对 变 量 的 共 享 , 是 一 种“ 以 空 间 换 时 间 ” 的 方 式 。

5.49 请 谈 谈 ThreadLocal 是 怎 么 解 决 并 发 安 全 的 ?

ThreadLocal 为 每 一 个 线 程 维 护 变 量 的 副 本 , 把 共 享 数 据 的 可 见 范 围 限制 在 同 一 个 线 程 之 内 , 其 实 现 原 理 是 , 在 ThreadLocal 类 中 有 一 个Map, 用 于 存 储 每 一 个 线 程 的 变 量 的 副 本

5.50 很 多 人 都 说 要 慎 用 ThreadLocal, 谈 谈 你 的 理 解 , 使 用ThreadLocal 需 要 注 意 些 什 么 ?

使 用 ThreadLocal 要 注 意 remove!

5.51 线程基本方法

start():新启动一个线程,这时此线程处于就绪(可运行)状态
run():普通的方法调用,这时此线程处于运行状态

join():线程的让步,让其他线程先走
sleep():线程的睡眠,让线程进入阻塞状态,不会释放锁
wait():让线程进入等待状态,同时也会让当前线程释放它所持有的锁。与notify()/notifyAll()使用(必须在同步代码块执行synchronized)
notify()/notifyAll():唤醒当前对象上等待的线程
interrupt():线程的中断,让线程终止
setDaemon():后台线程(守护线程)当java线程结束后,让线程在后台完成运行
priority():线程的优先级,越大优先级越高
yield():线程的礼让,当前线程会尽量让出CPU资源来给其他线程执行,进入就绪状态

5.52 死锁的四个必要条件

互斥条件:某资源仅为一个进程所占有,其他进程请求该资源,则请求进程只能等待。
请求和保持条件:进程已经获得了至少一个资源,又对其他资源发出请求,而其他资源被其他线程占有,则该进程的请求被阻塞,自己的资源也一直拿着。
不可剥夺条件:进程已获得的资源在未使用完毕之前,不可被其他进程强行剥夺,只能由自己释放。
环路等待条件:链中每一个进程的资源同时被链中下一个进程所请求。
------预防死锁的方式就是打破四个必要条件中的任意一个即可。

5.53 为什么要使用线程池?直接new个线程不是很舒服?

如果用new的话,当这个方法被调用频繁时就会创建很多线程,就会消耗系统资源且降低了稳定性
线程池的好处:

  • 降低资源消耗。通过重复利用已创建的线程,降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 增加线程的可管理型。使用线程池可以进行统一分配,调优和监控。

5.54 只要有并发,一定要加锁

5.55 synchronized 和 Lock 的区别

synchronized:直接在方法或类写一个关键词public synchronized void test(){} --》与wait()和notify()、notifyAll()配合 等待 唤醒
Lock: Lock lock=new ReentrantLock(); Condition condition=lock.newCondition();或实现接口,lock.lock();开启,lock.unlock();在finally释放锁–》与condition.await()、condition.signal();配合 等待 唤醒
Condition:Lock的一个监视器方法,可以精准的通知和唤醒线程 Condition condition2=lock.newCondition(); condition2.signal(); 唤醒线程

  • Lock 是一个接口,是个java类;synchronized 是 Java 中的关键字,synchronized 是内置的语言实现;
  • Lock 在发生异常时,如果没有主动通过 unLock() 去释放锁,很可能会造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;
    synchronized 不需要手动获取锁和释放锁,在发生异常时,会自动释放锁,因此不会导致死锁现象发生;
  • Lock 的使用更加灵活,可以有响应中断、有超时时间等,判断锁的状态;
    而 synchronized 却不行,使用 synchronized 时,等待的线程会一直等待下去,直到获取到锁;
  • 在性能上,随着近些年 synchronized 的不断优化,Lock 和 synchronized 在性能上已经没有很明显的差距了,所以性能不应该成为我们选择两者的主要原因。
    官方推荐尽量使用 synchronized,除非 synchronized 无法满足需求时,则可以使用 Lock。
  • synchronized的锁可重入、不可中断、非公平(其他线程可插入优先),而Lock锁可重入、可判断、可公平(两者皆可)
  • Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题

5.55 何谓悲观锁与乐观锁

  • 悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁( 共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。 Java 中 synchronized 和ReentrantLock 等独占锁就是悲观锁思想的实现。
  • 乐观锁总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。 乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于 write_condition 机制,其实都是提供的乐观锁。在 Java 中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。

6.设计模式

6.1 什么是设计模式?你是否在你的代码里面使用过任何设计模式?

设计模式是世界上各种各样程序员用来解决特定设计问题的尝试和测试的方法。设计模式
是代码可用性的延伸

6.2 请列举出在 JDK 中几个常用的设计模式

单例模式( Singleton pattern)
工厂模式( Factory pattern)
观察者模式( Observer pattern)被用于 Swing 和很多的事件监听中
装饰器设计模式( Decoratordesign pattern)被用于多个 Java IO 类中

6.3 Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

单例模式重点在于在整个系统上共享一些创建时较耗资源的对象。整个应用中只维护一个特定类实例,它被所有组件共同使用。 Java.lang.Runtime 是单例模式的经典例子。从 Java5 开始你可以使用枚举( enum)来实现线程安全的单例

6.4 在 Java 中,什么叫观察者设计模式( observer design pattern)?

观察者模式是基于对象的状态变化和观察者的通讯,以便他们作出相应的操作。简单的例子就是一个天气系统,当天气变化时必须在展示给公众的视图中进行反映。这个视图对象是一个主体,而不同的视图是观察者。

6.5 使用工厂模式最主要的好处是什么?在哪里使用?

工厂模式的最大好处是增加了创建对象时的封装层次。如果你使用工厂来创建对象,之后你可以使用更高级和更高性能的实现来替换原始的产品实现或类,这不需要在调用层做任何修改。

6.6 举一个用 Java 实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次

装饰模式增加强了单个对象的能力。 Java IO 到处都使用了装饰模式,典型例子就是Buffered 系列类如 BufferedReader 和 BufferedWriter,它们增强了 Reader 和 Writer 对象,以实现提升性能的 Buffer 层次的读取和写入。

6.7 在 Java 中,为什么不允许从静态方法中访问非静态变量?

Java 中不能从静态上下文访问非静态数据只是因为非静态变量是跟具体的对象实例关联的,而静态的却没有和任何实例关联。

6.8 设计一个 ATM 机,请说出你的设计思路?

比如设计金融系统来说,必须知道它们应该在任何情况下都能够正常工作。不管是断电还是其他情况, ATM 应该保持正确的状态(事务) , 想想 加锁( locking)、事务( transaction)、错误条件( error condition)、边界条件( boundary condition) 等等。尽管你不能想到具体的设计,但如果你可以指出非功能性需求,提出一些问题,想到关于边界条件,这些都会是很好的

7.JavaWeb

7.1 说下原生 jdbc 操作数据库流程

第一步:Class.forName()加载数据库连接驱动;
第二步:DriverManager.getConnection()获取数据连接对象;
第三步:根据 SQL 获取 sql 会话对象,有 2 种方式 Statement、PreparedStatement ;
第四步:执行 SQL 处理结果集,执行 SQL 前如果有参数值就设置参数值 setXXX();
第五步:关闭结果集、关闭会话、关闭连接。

7.2 什么要使用 PreparedStatement?

  • PreparedStatement 接口继承 Statement, PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。
  • 作 为 Statement 的 子 类 , PreparedStatement 继 承 了 Statement 的 所 有 功 能 。 三 种 方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数
  • 代码的可读性和可维护性.Statement 需要不断地拼接,而 PreparedStatement 不会。
  • PreparedStatement 尽最大可能提高性能.DB 有缓存机制,相同的预编译语句再次被调用不会再次需要编译。
  • 最重要的一点是极大地提高了安全性.Statement 容易被 SQL 注入,而 PreparedStatementc 传入的内容不会和 sql 语句发生任何匹配关系。

7.3 说说事务的概念,在JDBC编程中处理事务的步骤。

  • 事务是作为单个逻辑工作单元执行的一系列操作。
  • 一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务

事务处理步骤:

  • conn.setAutoComit(false);设置提交方式为手工提交
  • conn.commit()提交事务
  • 出现异常,回滚 conn.rollback();

7.4 关系数据库中连接池的机制是什么?

前提:为数据库连接建立一个缓冲池。
1:从连接池获取或创建可用连接
2:使用完毕之后,把连接返回给连接池
3:在系统关闭前,断开所有连接并释放连接占用的系统资源
4:能够处理无效连接,限制连接池中的连接总数不低于或者不超过某个限定值。

7.5 数据库连接池的原理。为什么要使用连接池?

数据库连接是一件费时的操作,数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发,测试及性能调整提供依据。

  • 连接池可以使多个操作共享一个连接。使用连接池是为了提高对数据库连接资源的管理

7.6 Http 的长连接和短连接

HTTP 协议有 HTTP/1.0 版本和 HTTP/1.1 版本。

  • HTTP1.1 默认保持长连接(HTTP persistent connection,也翻译为持久连接),数据传输完成了保持 TCP 连接不断开(不发 RST 包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接。
  • 在 HTTP/1.0 中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。从 HTTP/1.1 起,默认使用的是长连接,用以保持连接特性。

7.7 Http 常见的状态码有哪些?

200 OK //客户端请求成功
301 Moved Permanently(永久移除),请求的 URL 已移走。Response 中应该包含一个 Location URL, 说明资源现在所处的位置
302 found 重定向
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的 URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

7.8 GET 和 POST 的区别?

从表面现像上面看 GET 和 POST 的区别:

  1. GET 请求的数据会附在 URL 之后(就是把数据放置在 HTTP 协议头中),以?分割 URL 和传输数据,参数之间以&相连,如:login.action?name=zhagnsan&password=123456。POST 把提交的数据则放置在是 HTTP 包的包体中。
  2. POST 的安全性要比 GET 的安全性高。通过 GET 提交数据,用户名和密码将明文出现在 URL 上,因为(登录页面有可能被浏览器缓存,(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用 GET 提交数据还可能会造成 Cross-site request forgery 攻击。
    Get 是向服务器发索取数据的一种请求,而 Post 是向服务器提交数据的一种请求,在 FORM(表单)中,Method默认为"GET",实质上,GET 和 POST 只是发送机制不同,并不是一个取一个发!

7.9 Http 中重定向和请求转发的区别?

本质区别:转发是服务器行为,重定向是客户端行为。
重定向特点:两次请求,浏览器地址发生变化,可以访问自己 web 之外的资源,传输的数据会丢失。
请求转发特点:一次强求,浏览器地址不变,访问的是自己本身的 web 资源,传输的数据不会丢失。

7.10 Http与Https协议的区别

HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。
简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

7.11 Cookie 和 Session 的区别?

Cookie 是 web 服务器发送给浏览器的一块信息,浏览器会在本地一个文件中给每个 web 服务器存储 cookie。
以后浏览器再给特定的 web 服务器发送请求时,同时会发送所有为该服务器存储的cookie。
Session 是存储在 web 服务器端的一块信息。session 对象存储特定用户会话所需的属性及配置信息。 当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。

  • 无论客户端做怎样的设置,session 都能够正常工作。当客户端禁用 cookie 时将无法使用 cookie。
  • 在存储的数据量方面:session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象。

7.12 在单点登录中,如果 cookie 被禁用了怎么办?

单点登录的原理是后端生成一个 session ID,然后设置到 cookie,后面的所有请求浏览器都会带上 cookie,然后服务端从 cookie 里获取 session ID,再查询到用户信息。所以,保持登录的关键不是 cookie,而是通过cookie 保存和传输的 session ID,其本质是能获取用户信息的数据。

7.13 什么是 jsp,什么是 Servlet?jsp 和 Servlet 有什么区别?

jsp 本质上就是一个 Servlet,它是 Servlet 的一种特殊形式(由 SUN 公司推出),每个 jsp 页面都是一个 servlet实例。
Servlet 是由 Java 提供用于开发 web 服务器应用程序的一个组件,运行在服务端,由 servlet 容器管理,用来生成动态内容。一个 servlet 实例是实现了特殊接口 Servlet 的 Java 类,所有自定义的 servlet 均必须实现 Servlet 接口。

  • jsp 是 html 页面中内嵌的 Java 代码,侧重页面显示;
  • Servlet 是 html 代码和 Java 代码分离,侧重逻辑控制,mvc 设计思想中 jsp 位于视图层,servlet 位于控制层

7.14 jsp 有哪些域对象和内置对象及他们的作用

四大域对象

  • pageContext page 域-指当前页面,在当前 jsp 页面有效,跳到其它页面失效
  • request request 域-指一次请求范围内有效,从 http 请求到服务器处理结束,返回响应的整个过程。在这个过程中使用 forward(请求转发)方式跳转多个 jsp,在这些页面里你都可以使用这个变量
  • session session 域-指当前会话有效范围,浏览器从打开到关闭过程中,转发、重定向均可以使用
  • application context 域-指只能在同一个 web 中使用,服务器未关闭或者重启,数据就有效

九大内置对象

  • request对象:javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息
  • response对象:response 代表的是对客户端的响应
  • session对象:服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。
  • application对象:application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。
  • out 对象:out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。
  • pageContext 对象:pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。
  • config 对象:config 对象的主要作用是取得服务器的配置信息。
  • page 对象:page 对象代表JSP本身,只有在JSP页面内才是合法的。
  • exception 对象:exception 对象的作用是显示异常信息,只有在包含 isErrorPage=“true” 的页面中才可以被使用

7.15 什么是 xml,使用 xml 的优缺点,xml 的解析器有哪几种,分别有什么区别?

xml 是一种可扩展性标记语言,支持自定义标签(使用前必须预定义)使用 DTD 和 XML Schema 标准化 XML 结构。
优点:用于配置文件,格式统一,符合标准;用于在互不兼容的系统间交互数据,共享数据方便;
缺点:xml 文件格式复杂,数据传输占流量,服务端和客户端解析 xml 文件占用大量资源且不易维护

Xml 常用解析器有 2 种,分别是:DOM 和 SAX;
主要区别在于它们解析 xml 文档的方式不同。使用 DOM 解析,xml 文档以 DOM
树形结构加载入内存,而 SAX 采用的是事件模型

7.16 Servlet生命周期

Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的

7.17 tomcat容器是如何创建servlet类实例?用到了什么原理?

当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析,并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过反射的方式实例化。(有时候也是在第一次请求时实例化)
在servlet注册时加上1如果为正数,则在一开始就实例化,如果不写或为负数,则第一次请求实例化。

7.18 谈谈你对 ajax 的认识?

Ajax 是一种创建交互式网页应用的的网页开发技术
Ajax 的最大特点:
可以实现局部刷新,在不更新整个页面的前提下维护数据,提升用户体验度。

7.19 跨域两种解决方案

CORS:CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

8.Spring

8.1 谈谈你对Spring的理解

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架),Spring 框架是一个分层架构,由 7 个定义良好的模块组成。

  • 核心容器(spring Core):核心容器提供 Spring 框架的基本功能。实现了工厂模式(某一接口的具体实现类的选择控制权从调用类中移除,转而交给第三方决定,即借由Spring的Bean配置来实现控制)的工厂类BeanFactory 。 BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
    Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文 包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
    Spring AOP: Spring 框架集成了面向切面编程。通过使用 Spring AOP,不用依赖组件,就可以 将声明性事务管理集成到应用程序中。
    Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。例如打开和关闭连接。
    Spring ORM(对象关系映射):用于实体类映射数据库字段,遵从 Spring DAO 异常层次结构。
    Spring Web 模块:为基于 Web 的应用程序提 供了上下文。
    Spring MVC 框架:MVC 框架是构建 Web 应用程序的 MVC 实现。通过策略接口, MVC 框架变成为高度可配置的。

8.2 ApplicationContext通常的实现是什么

FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。

8.3 什么是Spring的依赖注入?有哪些方法进行依赖注入

Bean对象依赖于容器创建,注入Bean对象所依赖的资源 , 这一切是由容器来设置和装配。
构造器注入、set注入、注解注入

8.4 Spring 的常用注解

<context:annotation-config/> 开启注解

Bean的自动装配:spring会在应用上下文中为某个bean寻找其依赖的bean

  • 在xml中显式配置(构造器注入、set注入)
  • 在java中显式配置(@Configuration+@bean)
  • 隐式的bean发现机制和自动装配(组件扫描(component scanning)和自动装配(autowiring))

8.4.1 Bean的自动装配注解

@Autowired:按类型自动转配的,不支持id匹配。

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
  • @Qualifier不能单独使用。

@Resource:先按该属性进行byName方式查找装配;其次再进行默认的byName方式进行装配;都不成功,则报异常。

@Component+@Value:属性注入,相当于配置文件中
@Component的衍生注解

  • @Controller:web层 连接层
  • @Service: service层 业务层
  • @Repository: dao层 接口 写上这些注解,就相当于将这个类交给Spring管理装配了!

@Configuration+@bean:全注解

8.5 什么是Spring beans

Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中 的形式定义

8.6 解释Spring支持的几种bean的作用域?

<bean id="user2" class="com.node.pojo.User"  scope="singleton"/>

singleton(单例) : bean在每个Spring ioc 容器中只有一个实例。
prototype(多例):一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的 Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

8.7 解释Spring框架中bean的生命周期

  1. Bean容器找到Spring配置文件中Bean的定义;

  2. Bean容器利用java 反射机制实例化Bean;

  3. Bean容器为实例化的Bean设置属性值;

  4. 如果Bean实现了BeanNameAware接口,则执行setBeanName方法;

  5. 如果Bean实现了BeanClassLoaderAware接口,则执行setBeanClassLoader方法;

  6. 如果Bean实现了BeanFactoryAware接口,则执行setBeanFactory方法;

  7. 如果Bean实现了ApplicationContextAware接口,则执行setApplicationContext方法;

  8. 如果加载了BeanPostProcessor相关实现类,则执行postProcessBeforeInitialization方法;

  9. 如果Bean实现了InitializingBean接口,则执行afterPropertiesSet方法;

  10. 如果Bean定义初始化方法(PostConstruct注解或者配置的init-method),则执行定义的初始化方法;

  11. 如果加载了BeanPostProcessor相关实现类,则执行postProcessAfterInitialization方法;

  12. 当要销毁这个Bean时,如果Bean实现了DisposableBean接口,则执行destroy方法。

  13. 当要销毁这个Bean时,如果自定义了销毁方法(PreDestroy注解或者配置destroy-method),则执行定义的销毁方法。

8.8 在Spring中如何注入一个java集合?

类型用于注入一列值,允许有相同的值。
类型用于注入一组值,不允许有相同的值。
类型用于注入一组键值对,键和值都可以为任意类型。
类型用于注入一组键值对,键和值都只能为String类型

8.9 Spring 配置文件有什么作用?

Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。

8.10 什么是 Spring IOC 容器?

对象由Spring IOC容器来创建 , 管理 , 装配 ,通过依赖注入(DI),装配、配置和管理这些对象的整个生命周期。

8.11 IOC 的优点是什么?

把应用的代码量降到最低。它使应用容易测试,也是为了解耦这个目的

8.12 Spring 支持的 ORM 框架有哪些?

Hibernate、MyBatis、JPA (Java Persistence API)

8.13 Aop在Spring中的作用

它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或维护性。

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要 关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。
    在这里插入图片描述
    在这里插入图片描述

8.14 在 Spring AOP 中,关注点和横切关注的区别是什么?

  • 关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
  • 横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。

8.15 Spring 的通知是什么?有哪几种类型?

通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。

  • before:前置通知,在一个方法执行前被调用。
  • after: 在方法执行之后调用的通知,无论方法执行是否成功
  • after-returning: 仅当方法成功完成后执行的通知。
  • after-throwing: 在方法抛出异常退出时执行的通知。
  • around: 在方法执行之前和之后调用的通知。

8.16 什么是织入?什么是织入应用的不同点?

织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。织入可以在编译时,加载时,或运行时完成。

8.17 写一个 ArrayList 的动态代理类

final List<String> list = new ArrayList<String>();
List<String> proxyInstance =
(List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(),
list.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(list, args);
}
});
proxyInstance.add("你好");
System.out.println(list);


8.18 动静态代理的区别,什么场景使用

静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
Spring AOP核心就是动态代理
Spring AOP的动态代理有两种:一是JDK的接口动态代理;另一个是cglib动态代理(通过修改字节码来实现代理)。

动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象。

抽象角色 : 一般使用接口或者抽象类来实现
真实角色 : 被代理的角色 (房东)
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 . (中介)
客户 : 使用代理角色来进行一些操作 .(房客)

9.Mybatis

9.1 什么是Mybatis

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
  • 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO为数据库中的记录。
  • 数据持久化:将有用的数据以某种技术保存起来,之后可以再次取出来用

9.2 Mybatis 中#和$的区别?

  • #相当于对数据加上双引号当成字符串,$相当于直接显示数据
  • #方式能够很大程度防止 sql 注入
  • $方式一般用于传入数据库对象,例如传入表名
  • 一般能用#的就别用$

9.3 Mybatis 的编程步骤是什么样的

  • 创建 SqlSessionFactory
  • 通过 SqlSessionFactory 创建 SqlSession
  • 通过 sqlsession 执行数据库操作
  • 调用 session.commit()提交事务
  • 调用 session.close()关闭会话

9.4 JDBC 编程有哪些不足之处,MyBatis 是如何解决这些问题的?

  • 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。mysql在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
  • Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。mysql将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
  • 向 sql 语句传参数麻烦, Mybatis 自动将 java 对象映射至 sql 语句
  • 对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,Mybatis 自动将 sql 执行结果映射至 java 对象

9.5 使用 MyBatis 的 mapper 接口调用时有哪些要求?

  • Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同
  • Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同
  • Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同
  • Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。

9.6 Mybatis 中一级缓存与二级缓存?

  • 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或close 之后,该 Session 中的所有 Cache 就将清空。
  • 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源。

9.7 Mybatis 是如何进行分页的?分页插件的原理是什么?

Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用
Mybatis 的分页插件——pageHelper

9.8 为什么说 Mybatis 是半自动 ORM 映射工具

Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。全自动可以根据对象关系模型直接获取

9.9 MyBatis 与 Hibernate 有哪些不同?

  • Mybatis不完全是一个 ORM 框架,因为 MyBatis 需要程序员自己编写 Sql 语句,不过 mybatis 可以通过 XML 或注解方式灵活配置要运行的 sql 语句。
  • Mybatis 学习门槛低,简单易学,程序员直接编写原生态 sql,可严格控制 sql 执行性
    能,灵活度高

9.10 什么是 MyBatis 的接口绑定,有什么好处?

接口映射就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑定,我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可以有更加灵活的选择和设置

9.11 接口绑定有几种实现方式,分别是怎么实现的?

  • 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上@Select@Update 等注解里面包含 Sql 语句来绑定
  • 另外一种就是通过 xml 里面写 SQL 来绑定,在这种情况下,要指定 xml 映射文件里面的 namespace 必须为接口的全路径名

9.12 MyBatis 实现一对一、对多有几种方式?具体怎么操作的?

两种:

  • 使用使用resultType进行等值查询
  • 使用使用resultMap进行级联查询

9.17 MyBatis 里面的动态 Sql 是怎么设定的?用什么语法?

MyBatis 里面的动态 Sql 一般是通过 if 节点来实现,通过 OGNL 语法来实现,但是如果要写的完整,必须配合 where,trim 节点,where 节点是判断包含节点有内容就插入 where,否则不插入,trim 节点是用来判断如果动态语句是以 and 或 or 开始,那么会自动把这个 and 或者 or取掉。

9.18 MyBatis 是如何将 sql 执行结果转换为目标对象并返回的?有哪些映射形式?

方式一、 标签使用 resultType 参数,传递 Java 类,sql 中 select 的字段名保持与 Java 类属性名称一致

方式二、使用 标签,定义数据库列名和对象属性名之间的映射关系

方式三、使用注解 select 的字段名保持与接口方法返回的 Java 类或集合的元素类的属性名称一致

9.19 Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?

在这里插入图片描述

9.20 Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问, B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面

虽然 Mybatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方, Mybatis 都可以正确识别。原理是, Mybatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到,尚不存在,此时, Mybatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕, Mybatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时, B 标签已经存在, A 标签也就可以正常解析完成了

9.21 Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件, id 是否可以重复?

不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。

9.22 Mybatis 中如何执行批处理

使用 BatchExecutor 执行器完成批处理

9.23 Mybatis 中如何指定使用哪一种 Executor 执行器?

在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数

9.24 Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?

SimpleExecutor、 ReuseExecutor、BatchExecutor。

  • SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
  • ReuseExecutor:执行 update 或 select,以 sql 作为key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map
  • BatchExecutor:完成批处理。

9.25 resultType resultMap 的区别

  • 类的名字和数据库相同时,可以直接设置 resultType 参数为 Pojo 类
  • 若不同,需要设置 resultMap 将结果名字和 Pojo 名字进行转换

10.SpringMVC

10.1 简介

是基于Java实现MVC的轻量级Web框架
特点:

  • 轻量级,简单易学
  • 高效 , 基于请求响应的MVC框架
  • 约定优于配置
  • 可以任意使用各种视图技术,而不仅仅局限于 JSP

10.1SpringMVC 的工作原理

在这里插入图片描述

  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,
    • DispatcherServlet接收请求并拦截请求。
    • 我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
    • 如上url拆分成三部分:
    • http://localhost:8080服务器域名
    • SpringMVC部署在服务器上的web站点
    • hello表示控制器
  • 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。调用适配哪一个方法哪一controller
  • Handler让具体的Controller执行。
  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 视图解析器将解析的逻辑视图名传给DispatcherServlet。
  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  • 最终视图呈现给用户。

10.2 SpringMVC 工作执行流程

  • 客户端发送请求到 DispatcherServlet
  • DispatcherServlet 查询 handlerMapping 找到处理请求的 Controller
  • Controller 调用业务逻辑后,返回 ModelAndView
  • DispatcherServlet 查询 ModelAndView,找到指定视图
  • 视图将结果返回到客户端

10.3 SpringMVC 常用注解都有哪些?

@requestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所
有响应请求的方法都是以该地址作为父路径。
@RequestBody 注解实现接收 http 请求的 json 数据,将 json 数据转换为 java 对象。
@ResponseBody 注解实现将 controller 方法返回对象转化为 json 响应给客户

10.4 如何开启注解处理器和适配器?

我们在项目中一般会在 springmvc.xml 中通过开启 mvc:annotation-driven
来实现注解处理器和适配器的开启。

10.5 如何解决 get 和 post 乱码问题

解决 post 请求乱码:

  • 我们可以在 web.xml 里边配置一个 CharacterEncodingFilter 过滤器。 设置为 utf-8
    解决 get 请求的乱码
  • 修改 tomcat 配置文件添加编码与工程编码一致。
  • 另外一种方法对参数进行重新编码
String userName=NewString(Request.getParameter(“userName”).getBytes(“ISO8859-1),“utf-8);

10.6 SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决?

是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决
方案是在控制器里面不能写字段。

10.7 SpingMvc 中的控制器的注解一般用那个,有没有别的注解可以替代?

一般用@Conntroller 注解,表示是表现层,不能用用别的注解代替。

10.8 怎么样把某个请求映射到特定的方法上面?

直接在方法上面加上注解@RequestMapping,并且在这个注解里面写上要拦截的路径

10.9 如果在拦截请求中,我想拦截 get 方式提交的方法,怎么配置?

可以在@RequestMapping 注解里面加上 method=RequestMethod.GET

10.10 怎么样在方法里面得到 Request,或者 Session?

直接在方法的形参中声明RequestBody,SpringMvc 就自动把 request 对象传入

10.11 我想在拦截的方法里面得到从前台传入的参数,怎么得到?

直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样

10.12如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?

直接在方法中声明这个对象,SpringMvc 就自动会把属性赋值到这个对象里面。

10.13 SpringMvc 中函数的返回值是什么?

SpringMvc 中函数的返回值是什么?

10.14 SpringMVC 怎么样设定重定向和转发的?

在返回值前面加"forward:“就可以让结果转发,譬如"forward:user.do?name=method4” 在
返回值前面加"redirect:"就可以让返回值重定向,譬如"redirect:http://www.baidu.com

10.15 springmvc的重定向与转发的区别

  • 请求重定向和请求转发都是web开发中资源跳转的方式。
  • 请求转发是服务器内部的跳转
    • 地址栏不发生变化
    • 只有一个请求响应
    • 可以通过request域传递数据
  • 请求重定向是浏览器自动发起对跳转目标的请求
    • 地址栏会发生变化
    • 两次请求响应
    • 无法通过request域传递对象

10.16 SpringMvc 用什么对象从后台向前台传递数据的?

通过 ModelMap 对象,可以在这个对象里面用 put 方法,把对象加到里面,前台就可以通过 el 表达式拿到

10.17 SpringMvc 中有个类把视图和数据都合并的一起的,叫什么?

ModelAndView

10.18 怎么样把 ModelMap 里面的数据放入 Session 里面?

可以在类上面加上@SessionAttributes 注解,里面包含的字符串就是要放入 session 里面
的 key

10.19 SpringMvc 怎么和 AJAX 相互调用的?

通过 Jackson 框架就可以把 Java 里面的对象直接转化成 Js 可以识别的 Json 对象

  • 加入 Jackson.jar
  • 在配置文件中配置 json 的映射
  • 在接受 Ajax 方法里面可以直接返回 Object,List 等,但方法前面要加上@ResponseBody
    注解

10.20 当一个方法向 AJAX 返回特殊对象,譬如 Object,List 等,需要做什么处理?

要加上@ResponseBody 注解

10.21 SpringMvc 里面拦截器是怎么写的

有两种写法,一种是实现接口,另外一种是继承适配器类,然后在 SpringMvc 的配置文件中配置拦截器即可

<!-- 配置 SpringMvc 的拦截器 -->
<mvc:interceptors>
	<!-- 配置一个拦截器的 Bean 就可以了 默认是对所有请求都拦截 -->
	<bean id="myInterceptor" class="com.et.action.MyHandlerInterceptor"></bean>
	<!-- 只针对部分请求拦截 -->
	<mvc:interceptor>
		<mvc:mapping path="/modelMap.do" />
		<bean class="com.et.action.MyHandlerInterceptorAdapter" />
	</mvc:interceptor>
</mvc:interceptors>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CV工程湿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值