jsp与servlet的区别与联系
jsp和servlet的区别、共同点、各自应用的范围?
JSP是Servlet技术的扩展,本质上就是Servlet的简易方式。JSP编译后是“类servlet”。
Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。
JSP侧重于视图,Servlet主要用于控制逻辑。在struts框架中,JSP位于MVC设计模式的视图层,而Servlet位于控制层。
Java基础常见笔试题总结:https://blog.csdn.net/qq_16633405/article/details/79211002
1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
谈谈你对Java的理解
平台无关性、面向对象、GC、类库、语言特性、异常处理
java虚拟机是执行字节码文件(.class)的虚拟机进程。java源程序(.java)被编译器编译成字节码文件(.class)。然后字节码文件,将由java虚拟机,解释成机器码(不同平台的机器码不同),利用机器码操作硬件和操作系统。
因为不同的平台装有不同的JVM,它们能够将相同的.class文件,解释成不同平台所需要的机器码。正是因为有JVM的存在,java被称为平台无关的编程语言。
2.“static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
重写的前提是必须要继承,private修饰不支持继承(因为私有方法不能被子类访问, 所以不能重写。只有public 和ptotected方法可以被重写),因此被私有的方法不能重写。
3.是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。因为静态的成员属于类,随着类的加载而加载到静态方法区内存,当类加载时,此时不一定有实例创建,没有实例,就不可以访问非静态的成员。
4.Java支持的数据类型有哪些?什么是自动拆装箱?
基本数据类型:
整数值型:byte,short,int,long,
字符型:char
浮点类型:float,double
布尔型:boolean
首先知道String是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。引用类型包括类、接口、数组等。String类还是final修饰的。
而包装类就属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型后,就可以new对象,从而调用包装类中封装好的方法进行基本类型之间的转换或者toString(当然用类名直接调用也可以,便于一眼看出该方法是静态的),还有就是如果集合中想存放基本类型,泛型的限定类型只能是对应的包装类型。
自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把int转化成Integer,double转化成Double,等等。反之就是自动拆箱。
自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。原始类型byte, short, char, int, long, float, double 和 boolean 对应的封装类为Byte, Short, Character, Integer, Long, Float, Double, Boolean。
Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
java 自动装箱与拆箱的实现原理:https://www.jianshu.com/p/0ce2279c5691
public class IntegerTest {
public static void main(String[] args) {
Integer a = 1;
Integer b = 1;
Integer c = 500;
Integer d = 500;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
}
}
执行结果:
true
false
true
Process finished with exit code 0
5.Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载O verloading是一个类中多态性的一种表现。
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被”屏蔽”了。
如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
6.Java支持多继承么?
不支持,Java不支持多继承。每个类都只能继承一个类,但是可以实现多个接口。
7.接口和抽象类的区别是什么?
Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:
• 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
• 类可以实现很多个接口,但是只能继承一个抽象类
• 类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,子类可以不实现抽象类声明的所有方法,当然,在这种情况下,该子类只能是抽象类。
• 抽象类可以在不提供接口方法实现的情况下实现接口。
• Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
• Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
• 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
也可以参考JDK8中抽象类和接口的区别
抽象类要被子类继承,接口要被类实现。
8.什么是值传递和引用传递?
值传递是对基本变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
引用传递一般是对于对象型变量而言,传递的是该对象地址的一个副本,并不是原对象本身。
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。
首先,不要纠结于 Pass By Value 和 Pass By Reference 的字面上的意义,否则很容易陷入所谓的“一切传引用其实本质上是传值”这种并不能解决问题无意义论战中。
更何况,要想知道Java到底是传值还是传引用,起码你要先知道传值和传引用的准确含义吧?可是如果你已经知道了这两个名字的准确含义,那么你自己就能判断Java到底是传值还是传引用。
这就好像用大学的名词来解释高中的题目,对于初学者根本没有任何意义。
一:搞清楚 基本类型 和 引用类型的不同之处
int num = 10;
String str = "hello";
如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。
二:搞清楚赋值运算符(=)的作用
num = 20;
str = "java";
对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。
如上图所示,"hello" 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
三:调用方法时发生了什么?参数传递基本上就是赋值操作。
第一个例子:基本类型
void foo(int value) {
value = 100;
}
foo(num); // num 没有被改变
第二个例子:没有提供改变自身方法的引用类型
void foo(String text) {
text = "windows";
}
foo(str); // str 也没有被改变
第三个例子:提供了改变自身方法的引用类型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。
第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。
重点理解为什么,第三个例子和第四个例子结果不同?
下面是第三个例子的图解:
builder.append("4")之后
下面是第四个例子的图解:
builder = new StringBuilder("ipad"); 之后(地址指向不同地方)
https://www.nowcoder.com/questionTerminal/b296e9e1c40542ec8677c1e452b6b576
9.创建线程有几种不同的方式?你喜欢哪一种?为什么?
①继承Thread类(真正意义上的线程类),是Runnable接口的实现。
②实现Runnable接口,并重写里面的run方法。
③使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。
- 继承于Thread类的线程类,可以直接调用start方法启动线程(使用static也可以实现资源共享).一个线程(对象)只能够执行一次start(),而且不能通过Thread实现类对象的run()去启动一个线程。
- 实现Runnable接口的类需要再次用Thread类包装后才能调用start方法。(三个Thread对象包装一个类对象,就实现了资源共享)。
- 线程的使用的话,注意锁和同步的使用。(多线程访问共享资源容易出现线程安全问题)
一般情况下,常见的是第二种。
* Runnable接口有如下好处:
Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
Thread
package nizhipeng.RunnableandThread.compare;
public class Threadtest extends Thread {
private int ticket = 5;
@Override
public void run() {
while(true){
System.out.println(Thread.currentThread().getName()+"-->" + ticket--);
if(ticket < 0){
break;
}
}
}
public static void main(String[] args) {
Threadtest t1 = new Threadtest();
t1.setName("窗口一");
t1.start();
Threadtest t2 = new Threadtest();
t2.setName("窗口二");
t2.start();
}
}
输出结果:
窗口二-->5
窗口一-->5
窗口二-->4
窗口一-->4
窗口二-->3
窗口一-->3
窗口二-->2
窗口二-->1
窗口二-->0
窗口一-->2
窗口一-->1
窗口一-->0
Process finished with exit code 0
重复卖票,不能数据共享。
Runnable
package nizhipeng.RunnableandThread.compare;
public class Runnabletest implements Runnable{
private int ticket = 5;
@Override
public void run() {
while(true){
System.out.println(Thread.currentThread().getName()+"-->" + ticket--);
if(ticket < 0){
break;
}
}
}
public static void main(String[] args) {
Runnabletest m = new Runnabletest();
new Thread(m, "窗口一").start();
new Thread(m, "窗口二").start(); // 资源共享
}
}
输出结果:
窗口二-->4
窗口一-->5
窗口二-->3
窗口一-->2
窗口二-->1
窗口一-->0
Process finished with exit code 0
可以实现数据共享,不会重复卖票。
但是顺序是乱的。
如何使顺序有序呢?
线程执行的时候,一个个执行不就有序了。即线程1在执行的时候,其他线程阻塞不要执行。
加synchronize。
@Override
public synchronized void run() {
while(true){
System.out.println(Thread.currentThread().getName()+"-->" + ticket--);
if(ticket < 0){
break;
}
}
}
https://www.jianshu.com/p/9c9a11092f26
https://www.cnblogs.com/luxd/p/9812069.html
总结:
实现Runnable接口比继承Thread类所具有的优势: 1. 适合多个相同的程序代码的线程去共享同一个资源。 2. 可以避免java中的单继承的局限性。 3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。 4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
10.同步方法和同步代码块的区别是什么?
为何要使用同步?
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),
将会导致数据不准确,相互之间产生冲突。
相同点:
- 同步方法就是在方法前加关键字synchronized,然后被同步的方法一次只能有一个线程进入,其他线程等待。
- 同步代码块则是在方法内部使用大括号使得一个代码块得到同步。同步代码块会有一个同步的“目标”,使得同步块更加灵活一些(同步代码块可以通过“目标”决定需要锁定的对象)。一般情况下,如果此“目标”为this,那么同步方法和同步代码块没有太大的区别。
不同点:
- 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁。很明显,同步方法锁的范围比较大。
- 而同步代码块范围要小点。一般同步的范围越大,性能就越差。所以一般需要加锁进行同步的时候,范围越小越好,这样性能更好。
11.什么是死锁(deadlock)?
两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。
死锁 :是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去
package nizhipeng.RunnableandThread.Synchronized;
import java.util.Date;
public class LockTest {
public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static void main(String[] args) {
LockA la = new LockA();
new Thread(la).start();
LockB lb = new LockB();
new Thread(lb).start();
}
}
class LockA implements Runnable{
public void run() {
try {
System.out.println(new Date().toString() + " LockA 开始执行");
while(true){
synchronized (LockTest.obj1) {
System.out.println(new Date().toString() + " LockA 锁住 obj1");
Thread.sleep(3000); // 此处等待是给B能锁住机会
synchronized (LockTest.obj2) {
System.out.println(new Date().toString() + " LockA 锁住 obj2");
Thread.sleep(60 * 1000); // 为测试,占用了就不放
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class LockB implements Runnable{
public void run() {
try {
System.out.println(new Date().toString() + " LockB 开始执行");
while(true){
synchronized (LockTest.obj2) {
System.out.println(new Date().toString() + " LockB 锁住 obj2");
Thread.sleep(3000); // 此处等待是给A能锁住机会
synchronized (LockTest.obj1) {
System.out.println(new Date().toString() + " LockB 锁住 obj1");
Thread.sleep(60 * 1000); // 为测试,占用了就不放
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
Sun Jul 28 00:02:19 CST 2019 LockA 开始执行
Sun Jul 28 00:02:19 CST 2019 LockB 开始执行
Sun Jul 28 00:02:20 CST 2019 LockB 锁住 obj2
Sun Jul 28 00:02:20 CST 2019 LockA 锁住 obj1
12.如何确保N个线程可以访问N个资源同时又不导致死锁?
使用多线程的时候,一种非常简单的避免死锁的方式就是:指定获取锁的顺序,并强制线程按照指定的顺序获取锁。因此,如果所有的线程都是以同样的顺序加锁和释放锁,就不会出现死锁了。
13.Java集合类框架的基本接口有哪些?
Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类里面最基本的接口有:
• Collection:代表一组对象,每一个对象都是它的子元素。
• Set:不包含重复元素的Collection。
• List:有顺序的collection,并且可以包含重复元素。
• Map:可以把键(key)映射到值(value)的对象,键不能重复。
总共有两大接口:Collection 和Map ,一个元素集合,一个是键值对集合; Collection
中的集合称为单列集合,Map
中的集合称为双列集合。其中List和Set接口继承了Collection接口,一个是有序元素集合,一个是无序元素集合; 而ArrayList和 LinkedList 实现了List接口,HashSet实现了Set接口,这几个都比较常用; HashMap 和HashTable实现了Map接口,并且HashTable是线程安全的,但是HashMap性能更好。
collection与collections不一样。
14.什么是迭代器(Iterator)?
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
迭代器本质是一种设计模式,为了解决不同集合类提供统一的遍历操作接口(给不同的集合提供统一的遍历操作接口)。
15.Iterator和ListIterator的区别是什么?
下面列出了他们的区别:
• Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
• Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
• ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
https://jingyan.baidu.com/article/93f9803f5a38a4e0e56f5569.html
16.Java中的HashMap的工作原理是什么?
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算法决定集合元素的存储位置,这样可以保证能快速存、取集合元素;对于 HashMap 而言,系统 key-value 当成一个整体进行处理,系统总是根据 Hash 算法来计算 key-value 的存储位置,这样可以保证能快速存、取 Map 的 key-value 对。
参考:https://zhuanlan.zhihu.com/p/77899892
17.实现一个拷贝文件的工具类使用字节流还是字符流?
我们拷贝的文件不确定只包含字符流,有可能有字节流(图片、音乐、视频等流媒体文件不是字符),为了考虑到通用性,要使用字节流。
18.讲一下线程的几种实现方式?
实现方式:
1.通过继承Thread类实现一个线程
2.通过实现Runnable接口实现
继承拓展性不强,java只支持单继承,如果一个类继承Thread就不能继承其他的类了。
怎么启动?
Thread thread = new Thread(继承了Thread的对象/实现了Runnable的对象)
启动线程使用start方法,而启动了以后执行的是run方法。
怎么区分线程?在一个系统中有很多线程,每个线程都会打印日志,我想区分是哪个线程打印的怎么办?
thread.setName("设置一个线程名称"); 这是一种规范,在创建线程完成后,都需要设置名称。
=================================================================================
1、为什么用HashMap?
- HashMap 是一个散列桶(数组和链表),它存储的内容是键值对 key-value 映射
- HashMap 采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改
- HashMap 是非 synchronized,所以 HashMap 很快
- HashMap 可以接受 null 键和值,而 Hashtable 则不能(原因就是 equlas() 方法需要对象,因为 HashMap 是后出的 API 经过处理才可以)
2、HashMap 的工作原理是什么?
HashMap 是基于 hashing 的原理
我们使用 put(key, value) 存储对象到 HashMap 中,使用 get(key) 从 HashMap 中获取对象。当我们给 put() 方法传递键和值时,我们先对键调用 hashCode() 方法,计算并返回的 hashCode 是用于找到 Map 数组的 bucket 位置来储存 Node 对象。
这里关键点在于指出,HashMap 是在 bucket 中储存键对象和值对象,作为Map.Node 。
以下是 HashMap 初始化
简化的模拟数据结构:
以下是具体的 put 过程(JDK1.8)
- 对 Key 求 Hash 值,然后再计算下标
- 如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的 Hash 值相同,需要放到同一个 bucket 中)
- 如果碰撞了,以链表的方式链接到后面
- 如果链表长度超过阀值(TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表
- 如果节点已经存在(即key已经存在)就替换旧值
- 如果桶(数组)满了(容量16*加载因子0.75,意味着bucket填满75%,则需要扩容),就需要 resize(桶扩容2倍后重排)
(多线程环境下,调整大小会存在条件竞争,容易死锁)
以下是具体 get 过程
考虑特殊情况:如果两个键的 hashcode 相同,你如何获取值对象?
当我们调用 get() 方法,HashMap 会使用键对象的 hashcode 找到 bucket 位置,找到 bucket位置之后,会调用 keys.equals() 方法去找到链表中正确的节点,最终找到要找的值对象。
3、有什么方法可以减少碰撞?
扰动函数可以减少碰撞
- 原理是如果两个不相等的对象返回不同的 hashcode 的话,那么碰撞的几率就会小些。这就意味着存链表结构减小,这样取值的话就不会频繁调用 equal 方法,从而提高 HashMap 的性能(扰动即 Hash 方法内部的算法实现,目的是让不同对象返回不同hashcode)。
- 使用不可变的、声明作 final 对象,并且采用合适的 equals() 和 hashCode() 方法,将会减少碰撞的发生。
==============================================================
17.HashMap和Hashtable有什么区别?
HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:
- HashMap允许键和值是null,而Hashtable不允许键或者值是null。
- HashTable的方法,都是synchronized同步的,所以,HashTable是同步的,安全的。而HashMap中,所有的方法,均没有加锁,就是不提供数据访问保护,有可能出现多个线程先后更改数据,造成所得到的数据是脏数据。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
- Hashtable和HashMap之间一个更显著的区别是,由于线程安全性和同步性,如果在单线程环境中使用,Hashtable比HashMap慢得多。因此,如果不需要同步,并且HashMap仅由一个线程使用,那么它的性能将优于Java中的Hashtable。
o 一般认为Hashtable是一个遗留的类。
synchronizedMap使hashMap线程安全:
ConccurentHashMap(不允许插入null键值)
- 1.5分段锁
- 1.8后只锁 红黑树或链表的首节点
18.数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?
下面列出了Array和ArrayList的不同点:
• Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
• Array大小是固定的,ArrayList的大小是动态变化的。
• ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
19.怎么防止前端重复提交?
1.提交按钮后屏蔽提交按键(前端的js控制)
2.前端生成唯一的id,后端通过唯一索引
3.利用Session防止表单重复提交
20.String,Stringbuffer,StringBuilder的区别。
存储空间:
String 是被 final 修饰的(final char[]),他的长度是不可变的,每次对String的操作都会生成新的String对象,效率低耗费大量内存空间,从而引起GC。StringBuffer和StringBuilder都是可变。
执行效率:
三者在执行速度方面的比较:StringBuilder > StringBuffer > String
应用场景
- 如果要操作少量的数据用 = String
- 单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
- 多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
StringBuffer和StringBuilder区别
是否线程安全:
StringBuilder 的方法不是线程安全的(不能同步访问),StringBuffer是线程安全的。只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
应用场景:
然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
21.反射的原理,反射创建类实例的三种方式是什么。
JAVA反射机制是在运行状态中。对于任意一个类,都能找到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象的功能称为java语言的反射机制。
将类的各个组成部分封装为Java对象,这就是反射机制
获取Class对象的方式:
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
* 多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着。
* 多用于对象的获取字节码的方式
代码举例:
执行结果:
Hello Robot
================输出类的实例===================
Class name is com.interview.javabasic.reflect.Robot
================throwHello=====================
getHello result is Hello Bob
================sayHi======================
Welcome null
=============sayHi name 为 Alice=====================
Welcome Alice
null
D:\IdeaProjects\itcast\javaoffer\out\production\javaoffer
Process finished with exit code 0
- 反射中,Class.forName和ClassLoader区别 。
- Class.forName得到的class是已经初始化完成的(以上三步都完成)
- Classloader.loadClass得到的class是还没有链接的(只完成了第一步加载)
所以这就是为什么在jdbc进行数据库操作的时候要用Class.forName进行驱动的加载。
看一下com.mysql.jdbc.Driver的源码,其中有一段静态代码块:
https://www.zhihu.com/collection/179772357?page=1
- 描述动态代理的几种实现方式,分别说出相应的优缺点。
- 动态代理与cglib实现的区别。
- 为什么CGlib方式可以对接口实现代理。
- final的用途。
- 写出三种单例模式实现 。
- 如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有何优劣。
- 请结合OO设计理念,谈谈访问修饰符public、private、protected、default在应用设计中的作用。
- 深拷贝和浅拷贝区别。
- 数组和链表数据结构描述,各自的时间复杂度。
- error和exception的区别,CheckedException,RuntimeException的区别。
- 请列出5个运行时异常。
- 在自己的代码中,如果创建一个java.lang.String类,这个类是否可以被类加载器加载?为什么。
- 什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。
- java8的新特性。
- 点击这里有一套java架构面试专题及答案
TCP与HTTP
- http1.0和http1.1有什么区别。
- HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法。
- HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
GET 和 POST
在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST。
- GET - 从指定的资源请求数据。
- POST - 向指定的资源提交要被处理的数据。
GET:查询字符串(名称/值对)是在 GET 请求的 URL 中发送的
POST:查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的
Get 是用来从服务器上获得数据,而 Post 是用来向服务器上传递数据。
Get 是不安全的,因为在传输过程,数据被放在请求的 URL 中
- TCP三次握手和四次挥手的流程,为什么断开连接要4次,如果握手只有两次,会出现什么。
- TIME_WAIT和CLOSE_WAIT的区别。
- 说说你知道的几种HTTP响应码,比如200, 302, 404。
- 当你用浏览器打开一个链接(如:http://www.javastack.cn)的时候,计算机做了哪些工作步骤。
- TCP/IP如何保证可靠性,说说TCP头的结构。
- 如何避免浏览器缓存。
- 如何理解HTTP协议的无状态性。
- 简述Http请求get和post的区别以及数据包格式。
- HTTP有哪些method
- 简述HTTP请求的报文格式。
- HTTP的长连接是什么意思。
- HTTPS的加密方式是什么,讲讲整个加密解密流程。
- Http和https的三次握手有什么区别。
- 什么是分块传送。
- Session和cookie的区别。
数据库知识
- 数据库隔离级别有哪些,各自的含义是什么,MYSQL默认的隔离级别是是什么。
- 什么是幻读。
- MYSQL有哪些存储引擎,各自优缺点。
- 高并发下,如何做到安全的修改同一行数据。
- 乐观锁和悲观锁是什么,INNODB的标准行级锁有哪2种,解释其含义。
- SQL优化的一般步骤是什么,怎么看执行计划,如何理解其中各个字段的含义。
- 数据库会死锁吗,举一个死锁的例子,mysql怎么解决死锁。
- MYsql的索引原理,索引的类型有哪些,如何创建合理的索引,索引如何优化。
- 聚集索引和非聚集索引的区别。
- select for update 是什么含义,会锁表还是锁行或是其他。
- 为什么要用Btree实现,它是怎么分裂的,什么时候分裂,为什么是平衡的。
- 数据库的ACID是什么。
- 某个表有近千万数据,CRUD比较慢,如何优化。
- Mysql怎么优化table scan的。
- 如何写sql能够有效的使用到复合索引。
- mysql中in 和exists 区别。
- 数据库自增主键可能的问题。
- MVCC的含义,如何实现的。
- 你做过的项目里遇到分库分表了吗,怎么做的,有用到中间件么,比如sharding jdbc等,他
- 们的原理知道么。
- MYSQL的主从延迟怎么解决。
操作系统
Linux系统下你关注过哪些内核参数,说说你知道的。Linux下IO模型有几种,各自的含义是什么。epoll和poll有什么区别。平时用到哪些Linux命令。用一行命令查看文件的最后五行。用一行命令输出正在运行的java进程。进程和线程的区别。
作者:享学课堂 Java架构
链接:https://zhuanlan.zhihu.com/p/66941420
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
多线程
- 多线程的几种实现方式,什么是线程安全。
- volatile的原理,作用,能代替锁么。
- 画一个线程的生命周期状态图。
- sleep和wait的区别。
- sleep和sleep(0)的区别。
- Lock与Synchronized的区别 。
- synchronized的原理是什么,一般用在什么地方(比如加在静态方法和非静态方法的区别,静
- 态方法和非静态方法同时执行的时候会有影响吗),解释以下名词:重排序,自旋锁,偏向锁,轻
- 量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。
- 用过哪些原子类,他们的原理是什么。
- JUC下研究过哪些并发工具,讲讲原理。
- 用过线程池吗,如果用过,请说明原理,并说说newCache和newFixed有什么区别,构造函
- 数的各个参数的含义是什么,比如coreSize,maxsize等。
- 线程池的关闭方式有几种,各自的区别是什么。
- 假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有10个线程同
- 时调用它,如何做到。
- spring的controller是单例还是多例,怎么保证并发的安全。
- 用三个线程按顺序循环打印abc三个字母,比如abcabcabc。
- ThreadLocal用过么,用途是什么,原理是什么,用的时候要注意什么。
- 如果让你实现一个并发安全的链表,你会怎么做。
- 有哪些无锁数据结构,他们实现的原理是什么。
- 讲讲java同步机制的wait和notify。
- CAS机制是什么,如何解决ABA问题。
- 多线程如果线程挂住了怎么办。
- countdowlatch和cyclicbarrier的内部原理和用法,以及相互之间的差别(比如
- countdownlatch的await方法和是怎么实现的)。
- 对AbstractQueuedSynchronizer了解多少,讲讲加锁和解锁的流程,独占锁和公平所
- 加锁有什么不同。
- 使用synchronized修饰静态方法和非静态方法有什么区别。
- 简述ConcurrentLinkedQueue和LinkedBlockingQueue的用处和不同之处。
- 导致线程死锁的原因?怎么解除线程死锁。
- 非常多个线程(可能是不同机器),相互之间需要等待协调,才能完成某种工作,问怎么设计这种协调方案。
- 用过读写锁吗,原理是什么,一般在什么场景下用。
- 开启多个线程,如果保证顺序执行,有哪几种实现方式,或者如何保证多个线程都执行完
- 再拿到结果。
- 延迟队列的实现方式,delayQueue和时间轮算法的异同。
深入理解Session和Cookie的区别:https://zhuanlan.zhihu.com/p/68132320
作者:EnjoyMoving
链接:https://www.zhihu.com/question/29800631/answer/109486025
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
J2SE基础:
1. 八种基本数据类型的大小,以及他们的封装类。
https://www.runoob.com/java/java-basic-datatypes.html
2. Switch能否用string做参数?
3. equals与==的区别。
4. Object有哪些公用方法?
5. Java的四种引用,强弱软虚,用到的场景。
6. Hashcode的作用。
7. ArrayList、LinkedList、Vector的区别。
8. String、StringBuffer与StringBuilder的区别。
9. Map、Set、List、Queue、Stack的特点与用法。
10. HashMap和HashTable的区别。
11. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
12. TreeMap、HashMap、LindedHashMap的区别。
13. Collection包结构,与Collections的区别。
14. try catch finally,try里有return,finally还执行么?
15. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
16. Java面向对象的三个特征与含义。
17. Override和Overload的含义去区别。
18. Interface与abstract类的区别。
19. Static class 与non static class的区别。
20. java多态的实现原理。
21. 实现多线程的两种方法:Thread与Runable。
22. 线程同步的方法:sychronized、lock、reentrantLock等。
23. 锁的等级:方法锁、对象锁、类锁。
24. 写出生产者消费者模式。
25. ThreadLocal的设计理念与作用。
26. ThreadPool用法与优势。
27. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
28. wait()和sleep()的区别。
29. foreach与正常for循环效率对比。
30. Java IO与NIO。
31. 反射的作用于原理。
32. 泛型常用特点,List<String>能否转为List<Object>。
33. 解析XML的几种方式的原理与特点:DOM、SAX、PULL。
34. Java与C++对比。
35. Java1.7与1.8新特性。
36. 设计模式:单例、工厂、适配器、责任链、观察者等等。
37. JNI的使用。
学习java应该如何理解反射?:https://www.zhihu.com/question/24304289
支付宝一面(基础面)
1.介绍一下自己。
2.项目参与的核心设计有哪些
3.ArrayList和LinkedList底层
4.HashMap及线程安全的ConcurrentHashMap,以及各自优劣势
5.Java如何实现线程安全
6.Synchronized和Lock哪个更好?
7.HashMap中的get()方法是如何实现的?
8.HashMap可以用在哪些场景?
9.JVM,垃圾回收机制,内存划分等
10.SQL优化,常用的索引?
11.还有什么问题需要问的。
作者:程序人生a
链接:https://zhuanlan.zhihu.com/p/66798659
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
一、Java 基础
1.JDK 和 JRE 有什么区别?
- JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
- JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。
2.== 和 equals 的区别是什么?
== 解读
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用是否相同;
代码示例:
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。
equals 解读
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。
首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:
class Cat {
public Cat(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false
输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
原来 equals 本质上就是 ==。
那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:
String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true
同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。
总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不对,两个对象的 hashCode()相同,equals()不一定 true。
String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));
执行的结果:
str1:1179395 | str2:1179395
false
代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
4.final 在 java 中有什么作用?
- final 修饰的类叫最终类,该类不能被继承。
- final 修饰的方法不能被重写。
- final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
5.java 中的 Math.round(-1.5) 等于多少?
等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
6.String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,String是final修饰的java类,是引用类型。
7.java 中操作字符串都有哪些类?它们之间有什么区别?
String、StringBuffer、StringBuilder。
8.String str="i"与 String str=new String("i")一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。
9.String 类的常用方法都有那些?
- indexOf():返回指定字符的索引。
- charAt():返回指定索引处的字符。
- replace():字符串替换。
- trim():去除字符串两端空白。
- split():分割字符串,返回一个分割后的字符串数组。
- getBytes():返回字符串的 byte 类型数组。
- length():返回字符串长度。
- toLowerCase():将字符串转成小写字母。
- toUpperCase():将字符串转成大写字符。
- substring():截取字符串。
- equals():字符串比较。
10.抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法。
示例代码:
abstract class Cat {
public static void sayHi() {
System.out.println("hi~");
}
}
11.普通类和抽象类有哪些区别?
- 普通类不能包含抽象方法,抽象类可以包含抽象方法。
- 抽象类不能直接实例化,普通类可以直接实例化。
12.抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类。
13.接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
14.java 中 IO 流分为几种?
- 按功能来分:输入流(input)、输出流(output)。
- 按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据
16.Files的常用方法都有哪些?
- Files.exists():检测文件路径是否存在。
- Files.createFile():创建文件。
- Files.createDirectory():创建文件夹。
- Files.delete():删除一个文件或目录。
- Files.copy():复制文件。
- Files.move():移动文件。
- Files.size():查看文件个数。
- Files.read():读取文件。
- Files.write():写入文件。
二、容器
17.java 容器都有哪些?
常用容器的图录:
18.Collection 和 Collections 有什么区别?
1、java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。List,Set,Queue接口都继承Collection。
2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
20.List、Set、Map 之间的区别是什么?
Map是一个接口不能实例化,HashMap是Map的一个实现
21.HashMap 和 Hashtable 有什么区别?还有ConcurrentHashMap。
相同点:都可以使用存储key-value的数据。
区别:
HashMap可以把null作为key或者value,而HashTable不允许。
HashMap是线程不安全的,效率较高,而HashTable是线程安全的,效率较低。
想要线程安全又想效率高:
(jdk1.5)使用ConcurrentHashMap,通过把整个Map分为N个Segment,可以提相同的线程安全,但是效率提升倍,默认16倍。
22.说一下 HashMap 的实现原理?
当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根据hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)
23.说一下 HashSet 的实现原理?
- HashSet底层由HashMap实现
- HashSet的值存放于HashMap的key上
- HashMap的value统一为PRESENT
24.ArrayList 和 LinkedList 的区别是什么?
ArrayList 和 LinkedList 都实现了 List 接口
ArrayList 是基于索引的数据接口,它的底层是数组,API都做了一层对数组底层访问的封装。它可以以O(1)时间复杂度对元素进行随机访问。
LinkedList 的底层数据结构是双向循环链表,不支持随机访问。查找某个元素的时间复杂度是O(n)。
理论上来说在做新增和删除操作add和remove时,LinedList比较占优势,因为ArrayList要移动数据。
LinkedList 比 ArrayList 更占内存,因为 LinkedList 为每一个节点存储了两个引用,一个指向前一个元素,一 个指向下一个元素。
ArrayList底层使用的是数组,LinkedList使用的是链表。
数组具有索引,查询特定的元素特别快,而插入、删除、修改比较慢。(数组在内存中是一块连续的内存,如果要插入或删除是需要移动内存的)
链表不需要内存是连续的,查询时需要从头部开始一个一个的找,所以查询效率低。插入时不需要改变内存,所以插入或者删除的效率高。
ArrayList使用在查询比较多,但是插入和删除比较少的情况。
LinkedList使用在查询比较少而插入和删除比较多的情况。
25.如何实现数组和 List 之间的转换?
- List转换成为数组:调用ArrayList的toArray方法。
- 数组转换成为List:调用Arrays的asList方法。
26.哪些集合类是线程安全的?
- vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
- statck:堆栈类,先进后出。
- hashtable:就比hashmap多了个线程安全。
- enumeration:枚举,相当于迭代器。
27.迭代器 Iterator 是什么?
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。
迭代器本质是一种设计模式,为了解决不同集合类提供统一的遍历操作接口(给不同的集合提供统一的遍历操作接口)。
28.Iterator 怎么使用?有什么特点?
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
29.Iterator 和 ListIterator 有什么区别?
- Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
- Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
- ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
30.Java中的集合
Java中的集合分为两种为value(Collection),key-value(Map)
存储值分为List和set
- List是有序的,可以重复的
- Set是无序的,不可以重复的,根据equals和hashcode判断,也就是说如果一个对象要存储在Set中,必须重写equals和hashCode方法。
存储key-value的为map
31.ArrayList和LinkedList的区别?
ArrayList底层使用的是数组,LinkedList使用的是链表。
数组具有索引,查询特定的元素特别快,而插入、删除、修改比较慢。(数组在内存中是一块连续的内存,如果要插入或删除是需要移动内存的)
链表不需要内存是连续的,查询时需要从头部开始一个一个的找,所以查询效率低。插入时不需要改变内存,所以插入或者删除的效率高。
ArrayList使用在查询比较多,但是插入和删除比较少的情况。
LinkedList使用在查询比较少而插入和删除比较多的情况。
32.forward和redirect的区别?
1.forward是服务器端的转向而redirect是客户端的跳转。
2.使用forward浏览器的地址不会发生改变,而redirect会发生改变。
3.forward是一次请求中完成,redirect是重新发起请求。
4.forward是在服务器端完成,而不用客户端重新发起请求。
三、多线程
35.并行和并发有什么区别?
https://cloud.tencent.com/developer/article/1424249
并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其实是通过CPU时间片技术,并发完成的。
并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
36.线程和进程的区别?
简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。
37.守护线程是什么?
守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程。
38.创建线程有哪几种方式?
①. 继承Thread类创建线程类
- 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
- 创建Thread子类的实例,即创建了线程对象。
- 调用线程对象的start()方法来启动该线程。
②. 通过Runnable接口创建线程类
- 定义义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
- 创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
- 调用线程对象的start()方法来启动该线程。
③. 通过Callable和Future创建线程
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
使用FutureTask对象作为Thread对象的target创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
39.说一下 runnable 和 callable 有什么区别?
有点深的问题了,也看出一个Java程序员学习知识的广度。
Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;
Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
40.线程有哪些状态?
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
- 创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
- 就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
- 运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
- 阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
- 死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪
41.sleep() 和 wait() 有什么区别?
sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。因为sleep() 是static静态的方法,他不能改变对象的锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的锁没有被释放,其他线程依然无法访问这个对象。
wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。
42.notify()和 notifyAll()有什么区别?
notify():
唤醒一个处于等待状态的线程,
注意的是在调用此方法的时候,
并不能确切的唤醒某一个等待状态的线程,
而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll():
唤醒所有处入等待状态的线程;
并可以理解为把他们排进一个队列;
只不过只有头部的线程获得了锁,才能运行;
注意!!并不是给所有唤醒线程一个对象的锁,而是让它们竞争,
当其中一个线程运行完就开始运行下一个已经被唤醒的线程,因为锁已经转移了。
(这个时候是否运行已经不是因为等待状态,而是处于runnning队列中)
43.ThreadLocal 是什么?有哪些使用场景?
线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。
44.说一下 synchronized 底层实现原理?
synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
- 普通同步方法,锁是当前实例对象
- 静态同步方法,锁是当前类的class对象
- 同步方法块,锁是括号里面的对象
45.synchronized 和 volatile 的区别是什么?
- volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
- volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
- volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
- volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
四、反射
什么是 java 序列化?什么情况下需要序列化?
简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
什么情况下需要序列化:
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
五、对象拷贝
深拷贝和浅拷贝区别是什么?
- 浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(例:assign())
- 深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝(例:JSON.parse()和JSON.stringify(),但是此方法无法复制函数类型)
六、异常
74.throw 和 throws 的区别?
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理(放在方法上)。
而throw则是指抛出的一个具体的异常类型(写在方法的内部),抛出指定异常,异常内容自己填写。
75.final、finally、finalize 有什么区别?
- final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
- finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
- finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。
76.try-catch-finally 中哪个部分可以省略?
try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。
77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
finally会执行,在 return 前执行。(catch 中的 return 会等 finally 中的代码执行完之后)
78.常见的异常类有哪些?
- NullPointerException:当应用程序试图访问空对象时,则抛出该异常。
- SQLException:提供关于数据库访问错误或其他错误信息的异常。
- IndexOutOfBoundsException:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
- NumberFormatException:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
- FileNotFoundException:当试图打开指定路径名表示的文件失败时,抛出此异常。
- IOException:当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
- ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常。
- ArrayStoreException:试图将错误类型的对象存储到一个对象数组时抛出的异常。
- IllegalArgumentException:抛出的异常表明向方法传递了一个不合法或不正确的参数。
- ArithmeticException:当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
- NegativeArraySizeException:如果应用程序试图创建大小为负的数组,则抛出该异常。
- NoSuchMethodException:无法找到某一特定方法时,抛出该异常。
- SecurityException:由安全管理器抛出的异常,指示存在安全侵犯。
- UnsupportedOperationException:当不支持请求的操作时,抛出该异常。
- RuntimeExceptionRuntimeException:是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
1. static 和 final 的用法
static 的作用从三个方面来谈,分别是静态变量、静态方法、静态类。
静态变量:声明为 static 的静态变量实质上就是全局变量,当声明一个对象时,并不产生static 变量的拷贝,而是该类所有实例变量共用同一个 static 变量。也就是说这个静态变量只加载一次,只分配一块储存空间。
静态方法: 声明为static的静态方法有以下几个特点:
- (1)静态方法只能调用静态方法;
- (2)静态方法只能访问静态数据;
- (3)静态方法不能以任何方式引用this或super;
静态类:通常一个普通类不允许声明为静态,只有一个内部类才可以(main方法就是一个典型),这时这个声明的静态类可以直接作为一个普通类来使用,而不需要实例一个外部类。
final 的作用从变量、方法、类三个方面来理解:
- final修饰的变量的值不能被修改,是一个常量;
- final修饰的方法不能被重写;
- final修饰的类不能被继承;
2. 抽象类和接口的区别,类可以继承多个类吗,接口可以继承多个接口吗,类可以实现多个接口吗?
抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
抽象类要被子类继承,接口要被类实现。
接口只能做方法声明,抽象类中可以做方法声明,也可以做方法实现
接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。
抽象类里可以没有抽象方法 。
如果一个类里有抽象方法,那么这个类只能是抽象类 。
抽象方法要被实现,所以不能是静态的,也不能是私有的。
接口可继承接口,并可多继承接口,但类只能单根继承。
3. this和super的功能和用法
this :
- (1) 能访问除构造方法以外所有的属性、方法,通过this.来调用方法和属性
- (2) 不可以在静态方法中使用
- (3) 在构造方法中使用this(参数列表) 调用本类的其它构造方法,必须放在构造方法的第一句。
super :访问父类的方法和属性
- (1) 访问父类的方法和属性;
- (2) 在构造方法中通过 super(参数列表) 来调用父类的构造方法,必须放在子类构造方法里的第一行。
4. final, finally, finalize 的区别?
final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承。将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量在初始化以后的引用中只能读取不可修改。被声明为 final 的方法也同样只能使用,不能在子类中被重写。
finally:通常放在try…catch的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
5. Error 和 Exception 有什么区别?
Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;
Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
第一,谈谈final, finally, finalize的区别。
最常被问到。final修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。
Finally在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
finalize方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现。
第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。
Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)。Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。
注: 静态内部类(Inner Class)意味着
1 创建一个static内部类的对象,不需要一个外部类对象
2 不能从一个static内部类的一个对象访问一个外部类对象
第四,&和&&的区别。
这个问得很少。&是位运算符。&&是布尔逻辑运算符
第五,HashMap和Hashtable的区别。
常问。都属于Map接口的类,实现了将惟一键映射到特定的值上。
HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。
Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。
第六,Collection 和 Collections的区别。
你千万别说一个是单数一个是复数。
Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。
Collection是个java.util下的接口,它是各种集合结构的父接口。
第八,GC是什么? 为什么要有GC?
基础。GC是垃圾收集器。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:
System.gc()
Runtime.getRuntime().gc()
第九,String s = new String("xyz");创建了几个String Object?
两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s
第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math.round(11.5)返回(long)12,Math.round(-11.5)返回(long)-11;
short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
short s1 = 1; s1 = s1 + 1;有错,s1是short型,s1+1是int型,不能显式转化为short型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确
第十二,sleep() 和 wait() 有什么区别?
搞线程的最爱。sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非
(a)“醒来”的线程具有更高的优先级
(b)正在运行的线程因为其它原因而阻塞。
wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
第十三,Java有没有goto?
Goto?java中的保留字,现在没有在java中使用。
很十三的问题,如果哪个面试的问到这个问题,我劝你还是别进这家公司。
第十四,数组有没有length()这个方法? String有没有length()这个方法?
数组没有length()这个方法,有length的属性。
String有有length()这个方法。
第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
常问。方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。
- 如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
- 如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。
equals()和==方法决定引用值是否指向同一对象
equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
第十七,给我一个你最常见到的runtime exception.
ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException,
IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFORMatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException
如果你这个答不出来,面试的人会认为你没有实际编程经验。
第十八,error和exception有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
第十九,List, Set, Map是否继承自Collection接口?
List,Set是
Map不是
第二十,abstract class和interface有什么区别?
常问。声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。
第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
都不能
第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。
第二十三,启动一个线程是用run()还是start()?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
第二十四,构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。
第二十五,是否可以继承String类?
String类是final类故不可以继承 (final char[])
第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
可以,但是其它线程不可以进入此对象的这个synchronized方法
第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
会执行,在return前执行
第二十八,编程题: 用最有效率的方法算出2乘以8等於几?
有C背景的程序员特别喜欢问这种问题。2 << 3
第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,有相同的hash code。
第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜! 关注我,私信回复我“架构资料”
获取免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构视频学习资料以及电子书资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!
常见MySQL面试问题如下https://zhuanlan.zhihu.com/p/72020303:
问题1:char、varchar的区别是什么?
varchar是变长而char的长度是固定的。如果你的内容是固定大小的,你会得到更好的性能。
问题2: TRUNCATE和DELETE的区别是什么?
DELETE命令从一个表中删除某一行,或多行,TRUNCATE命令永久地从表中删除每一行。
问题3:什么是触发器,MySQL中都有哪些触发器?
触发器是指一段代码,当触发某个事件时,自动执行这些代码。在MySQL数据库中有如下六种触发器:1.Before Insert2.After Insert3.Before Update4.After Update5.Before Delete6.After Delete
问题4:FLOAT和DOUBLE的区别是什么?
- FLOAT类型数据可以存储至多8位十进制数,并在内存中占4字节。
- DOUBLE类型数据可以存储至多18位十进制数,并在内存中占8字节。
问题5:如何在MySQL种获取当前日期?
问题6:如何查询第n高的工资?
问题7:请写出下面MySQL数据类型表达的意义(int(0)、char(16)、varchar(16)、datetime、text)
int(0)表示数据是INT类型,长度是0、char(16)表示固定长度字符串,长度为16、varchar(16)表示可变长度字符串,长度为16、datetime表示时间类型、text表示字符串类型,能存储大字符串,最多存储65535字节数据)
问题8:请说明InnoDB和MyISAM的区别
1、InnoDB支持事务,MyISAM不支持;2、InnoDB数据存储在共享表空间,MyISAM数据存储在文件中;3、InnoDB支持行级锁,MyISAM只支持表锁;4、InnoDB支持崩溃后的恢复,MyISAM不支持;5、InnoDB支持外键,MyISAM不支持;6、InnoDB不支持全文索引,MyISAM支持全文索引;
问题9:innodb引擎的特性
1、插入缓冲(insert buffer)2、二次写(double write)3、自适应哈希索引(ahi)4、预读(read ahead)
问题10:请列举3个以上表引擎
InnoDB、MyISAM、Memory
问题11:请说明varchar和text的区别
1、varchar可指定字符数,text不能指定,内部存储varchar是存入的实际字符数+1个字节(n<=255)或2个字节(n>255),text是实际字符数+2个字节。2、text类型不能有默认值。3、varchar可直接创建索引,text创建索引要指定前多少个字符。varchar查询速度快于text,在都创建索引的情况下,text的索引几乎不起作用。4、查询text需要创建临时表。
问题12:varchar(50)中50的含义
最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)。
问题13:int(20)中20的含义
是指显示字符的长度,不影响内部存储,只是当定义了ZEROFILL时,前面补多少个 0
问题14:简单描述MySQL中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响?
一个表只能有一个主键索引,但是可以有多个唯一索引。1.主键索引一定是唯一索引,唯一索引不是主键索引。2.主键可以与外键构成参照完整性约束,防止数据不一致。3.联合索引:将多个列组合在一起创建索引,可以覆盖多个列。(也叫复合索引,组合索引)4.外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致性、完整性、和实现级联操作(基本不用)。5.全文索引:MySQL自带的全文索引只能用于MyISAM,并且只能对英文进行全文检索 (基本不用)
问题15:创建MySQL联合索引应该注意什么?
需遵循前缀原则
问题16:列值为NULL时,查询是否会用到索引?
在MySQL里NULL值的列也是走索引的。当然,如果计划对列进行索引,就要尽量避免把它设置为可空,MySQL难以优化引用了可空列的查询,它会使索引、索引统计和值更加复杂。
问题17:以下语句是否会应用索引:SELECT FROM users WHERE YEAR(adddate) < 2019;*
不会,因为只要列涉及到运算,MySQL就不会使用索引。
问题18:MyISAM索引实现?
MyISAM存储引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。MyISAM的索引方式也叫做非聚簇索引的,之所以这么称呼是为了与InnoDB的聚簇索引区分。
问题19:MyISAM索引与InnoDB索引的区别?
1.InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。2.InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。3.MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。4.InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。
问题20:有A(id,sex,par,c1,c2),B(id,age,c1,c2)两张表,其中A.id与B.id关联,现在要求写出一条SQL语句,将B中age>50的记录的c1,c2更新到A表中同一记录中的c1,c2字段中
问题21 :MySQL的关联查询语句你会那些?
六种关联查询1.交叉连接(CROSS JOIN)2.内连接(INNER JOIN)3.外连接(LEFT JOIN/RIGHT JOIN)4.联合查询(UNION与UNION ALL)5.全连接(FULL JOIN)6.交叉连接(CROSS JOIN)
内连接分为三类
1.等值连接:ON A.id=B.id2.不等值连接:ON A.id > B.id3.自连接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid
外连接(LEFT JOIN/RIGHT JOIN)
1.左外连接:LEFT OUTER JOIN, 以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN2.右外连接:RIGHT OUTER JOIN, 以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN
联合查询(UNION与UNION ALL)
1.就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并2.如果使用UNION ALL,不会合并重复的记录行3.效率 UNION 高于 UNION ALL
全连接(FULL JOIN)
1.MySQL不支持全连接2.可以使用LEFT JOIN 和UNION和RIGHT JOIN联合使用
嵌套查询
用一条SQL语句得结果作为另外一条SQL语句得条件,效率不好把握
解题方法
根据考题要搞清楚表的结果和多表之间的关系,根据想要的结果思考使用那种关联方式,通常把要查询的列先写出来,然后分析这些列都属于哪些表,才考虑使用关联查询
问题22:UNION与UNION ALL的区别?
1.如果使用UNION ALL,不会合并重复的记录行2.效率 UNION 高于 UNION ALL
问题23:一个6亿的表a,一个3亿的表b,通过外键tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录。
1.如果A表TID是自增长,并且是连续的,B表的ID为索引
2.如果A表的TID不是连续的,那么就需要使用覆盖索引.TID要么是主键,要么是辅助索引,B表ID也需要有索引。
问题24:拷贝表( 拷贝数据, 源表名:a 目标表名:b)
问题25:Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 查询没学过“叶平”老师课的同学的学号、姓名
问题26:随机取出10条数据
问题27:请简述项目中优化SQL语句执行效率的方法,从哪些方面,SQL语句性能如何分析?
考点分析:
这道题主要考察的是查找分析SQL语句查询速度慢的方法
延伸考点:
1.优化查询过程中的数据访问2.优化长难的查询语句3.优化特定类型的查询语句
如何查找查询速度慢的原因
记录慢查询日志,分析查询日志,不要直接打开慢查询日志进行分析,这样比较浪费时间和精力,可以使用pt-query-digest工具进行分析
使用show profile
使用show status
show status会返回一些计数器,show global status会查看所有服务器级别的所有计数有时根据这些计数,可以推测出哪些操作代价较高或者消耗时间多
show processlist
观察是否有大量线程处于不正常的状态或特征
最常问的MySQL面试题五——每个开发人员都应该知道
使用explain
分析单条SQL语句
优化查询过程中的数据访问
1.访问数据太多导致查询性能下降2.确定应用程序是否在检索大量超过需要的数据,可能是太多行或列3.确认MySQL服务器是否在分析大量不必要的数据行4.避免犯如下SQL语句错误5.查询不需要的数据。解决办法:使用limit解决6.多表关联返回全部列。解决办法:指定列名7.总是返回全部列。解决办法:避免使用SELECT *8.重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存9.是否在扫描额外的记录。解决办法:10.使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,可以通过如下技巧去优化:11.使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果。12.改变数据库和表的结构,修改数据表范式13.重写SQL语句,让优化器可以以更优的方式执行查询。
优化长难的查询语句
1.一个复杂查询还是多个简单查询2.MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多3.使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的。4.切分查询5.将一个大的查询分为多个小的相同的查询6.一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销。7.分解关联查询,让缓存的效率更高。8.执行单个查询可以减少锁的竞争。9.在应用层做关联更容易对数据库进行拆分。10.查询效率会有大幅提升。11.较少冗余记录的查询。
优化特定类型的查询语句
1.count(*)会忽略所有的列,直接统计所有列数,不要使用count(列名)2.MyISAM中,没有任何where条件的count(*)非常快。3.当有where条件时,MyISAM的count统计不一定比其它引擎快。4.可以使用explain查询近似值,用近似值替代count(*)5.增加汇总表6.使用缓存
优化关联查询
1.确定ON或者USING子句中是否有索引。2.确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。
优化子查询
1.用关联查询替代2.优化GROUP BY和DISTINCT3.这两种查询据可以使用索引来优化,是最有效的优化方法4.关联查询中,使用标识列分组的效率更高5.如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。6.WITH ROLLUP超级聚合,可以挪到应用程序处理
优化LIMIT分页
1.LIMIT偏移量大的时候,查询效率较低2.可以记录上次查询的最大ID,下次查询时直接根据该ID来查询
优化UNION查询
UNION ALL的效率高于UNION
优化WHERE子句
解题方法对于此类考题,先说明如何定位低效SQL语句,然后根据SQL语句可能低效的原因做排查,先从索引着手,如果索引没有问题,考虑以上几个方面,数据访问的问题,长难查询句的问题还是一些特定类型优化的问题,逐一回答。
问题28:SQL语句优化的一些方法?
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
http://5.in 和 not in 也要慎用,否则会导致全表扫描,如:
6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索。
7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。