题目整理
Java基础进阶阶段
基础概念类
1.JDK1.8新特性?
2.面向对象和面向过程的区别?
3.什么是值传递和引用传递?
4.什么是不可变对象?
5.讲讲类的实例化顺序?
6.java 创建对象的几种方式
7.Java访问修饰符的作用域
8.switch中能否使用string作为参数?
9.switch中能否作用在byte,long上?
10.什么是自动拆装箱?
11.如何正确的退出多层嵌套循环?
继承
1.Java支持多继承么?
2.父类的静态方法能否被子类重写?
3.继承的好处和坏处?
接口抽象类
1.接口的意义?
2.抽象类的意义?
3.抽 象 的 (abstract) 方 法 是 否 可 同 时 是 静 态 的 (static), 是 否 可 同 时 是 本 地 方 法(native)?
4.抽象类和接口区别?
5.Java中接口可不可以继承一般类,为什么?
6.重载与重写区别?
7.final有哪些用法?
多态
1.多态的好处和弊端?
2.代码中如何实现多态?
3.Java 中实现多态的机制是什么?
内部类Lambda
1.内部类的作用?
2.一个java文件内部可以有类?(非内部类)
3.Lambda的使用前提是什么?
4.Lambda与匿名内部类区别?
static关键字
1.是否可以在static环境中访问非static变量?
2.static都有哪些用法?
3.静态变量和实例变量的区别?
4.static特点?
数据类型
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4请问s5==s2返回什么?
2.3*0.1==0.3返回值是什么?
3.基本数据类型的默认值?基本数据类型所占的字节以及封装他们的类?
4.String属于那个类,以及常用的方法?
5.String, StringBuffer和StringBuilder区别?
异常类
1.error和exception有什么区别?
2.运行时异常和一般异常有何不同?
3.Java中异常处理机制的原理?
4.你平时在项目中是怎样对异常进行处理的?
5.throw和throws有什么区别?
6.异常处理的时候,finally代码块的重要性是什么?
7.请列出 5 个运行时异常?
8.try catch finally,try里有return,finally还执行么?
集合
1、List、Map、Set三个接口,存取元素时,各有什么特点?
2、ArrayList和LinkedList的底层实现原理?他们为什么线程不安全?在多线程并发操作下,我们应该用什么替代?
3、HashMap和HashTable有什么区别?其底层实现是什么?CurrentHashMap的锁机制又是如何?如果想将一个Map变为有序的,该如何实现?
4.什么是迭代器(Iterator)?
5.Arraylist 与 LinkedList 区别?
6.Arraylist 与 LinkedList 应用场景?
7.Collection 和 Collections的区别?
8.为何Map接口不继承Collection接口?
9.当两个对象的hashcode相同会发生什么?
10.HashMap和Hashtable有什么区别?
11.List 和 Set 区别?
12.Set和List对比?
13.当两个对象的hashcode相同会发生什么?
14.如果两个键的hashcode相同,你如何获取值对象?
15.有没有可能两个不相等的对象有相同的hashcode?
16.HashMap、LinkedHashMap、TreeMap的区别?
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
18.==和 equals hashCode 的区别?
19.自然排序Comparble和比较器排序Comparator的异同点?
泛型
1.为什么使用泛型?
2.泛型用在什么地方?
3.如何使用泛型类?
树
1.什么是二叉树?
2.什么是二叉查找树?
3.什么是平衡二叉树?
序列化
1.什么是 Java 序列化?
2.如何实现 Java 序列化?
3.Java 序列话中,如果有些字段不想进行序列化怎么办?
4.对象操作流是字符流还是字节流?
5.如何在读写文件时指定字符集?
6.字符缓冲流特有方法?
7.为什么使用对象流?
多线程
1.什么是线程?
2.线程和进程有什么区别?
3.如何在Java中实现线程?
4.用Runnable还是Thread?
5.Thread 类中的start() 和 run() 方法有什么区别?
6.Java中Runnable和Callable有什么不同?
7.Java内存模型是什么?
8.Java中的volatile 变量是什么?
9.什么是线程安全?Vector是一个线程安全类吗?
10.Java中如何停止一个线程?
11.Java中notify 和 notifyAll有什么区别?
12. 什么是线程池? 为什么要使用它?
13.如何写代码来解决生产者消费者问题?
14.Java多线程中的死锁?
15.Java中synchronized 和 ReentrantLock 有什么不同?
16.详谈Synchronized?
17.在Java中Lock接口与synchronized块的区别是什么?
18.synchronized 的原理是什么?有什么不足?
19.关于成员变量和局部变量?
20. 如果你提交任务时,线程池队列已满。会时发会生什么?
21.volatile关键字的作用是?
22.守护线程和非守护线程有什么区别?
23.线程的生命周期?
24.wait和sleep,notify()锁方面区别?
25.什么情况下会出现线程安全问题?
26.Java中规定了线程有哪几种状态?
27.什么是原子性?
28.Java中哪些操作是原子操作?
29.什么是CAS算法?
30.synchronized和CAS的区别?
31.并发容器Hashtable和ConcurrentHashMap特点?
反射
1.Java反射机制的作用?
2.什么是反射机制?
3.哪里用到反射机制?
4.反射机制的优缺点?
5.反射中,Class.forName 和 ClassLoader 区别
6.什么是双亲委派模型?
7.为什么要有双亲委派模型?
8.怎么利用反射使用私有成员?
网络通信
1.什么是三次握手?
2.什么是四次挥手?
3.TCP通信注意事项?
web阶段
jsp相关
1.jsp内置对象和EL内置对象的区别与联系?
2.说一下 jsp 的 4 种作用域?
3.ServletContext 与application的异同?
4.jsp 有哪些内置对象?作用分别是什么?
概念相关
1.post和get区别?
2.简单阐述相对路径和绝对路径?
3.Cookie和session的区别?
4.servlet四大域对象的区别?
5.什么是活化与钝化?
6.EL内置对象有哪些?
7.如果有大量的网站访问量。那么会产生很多的session,该怎么解决?
8.页面传递对象的方法?
9.session 和 application的区别?
servlet相关
1.解释一下什么是servlet?
2.servlet的生命周期?
3.servlet生命周期方法有哪些?
4.servlet过滤器的作用?
5.servlet监听器的作用?
6.web.xml中组件的加载顺序?
7.如何确保servlet在应用启动之后被加载到内存?
8.HttpServlet为什么声明为抽象类?
9.redirect(重定向)和forward(请求转发)区别?
10.sevlet中的属性域有哪些?
11.Servlet是否线程安全?
12.如何创建线程安全的servlet?(SingleThreadModel方法不算)
13.是否有必要重写service方法?
14.servlet包装类有什么用?
15.在servlet中能否产生类似死锁情况?
16.Servlet API中forward()与redirect()的区别?
17.ServletContext对象和ServletConfig对象的区别?
18.PrintWriter和ServletOutPutStream类有什么区别?
19.在一个servlet能否同时获取PrintWriter和ServletOutputStream对象?
20.Request对象的主要方法有哪些?
21.jsp和servlet的异同点以及联系是什么?
数据库阶段
索引相关
1.什么是索引?
2.索引是个什么样的数据结构呢?
3.在建立索引的时候,都有哪些需要考虑的因素呢?
4.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?
5.区别B树,B-,B+,B*?
6.MySQL优化策略?
7.key和index的区别?
8.怎么验证 mysql 的索引是否满足需求?
事务相关
1.ACID是什么?可以详细说一下吗?
2.同时有多个事务在进行会怎么样呢?
3.怎么解决这些问题呢?MySQL的事务隔离级别了解吗?
4.Innodb使用的是哪种隔离级别呢?
5.对MySQL的锁了解吗?
6.MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了?
7.行级锁定的优点缺点?
8.说一下 mysql 的行锁和表锁?
表设计相关
1. 为什么要尽量设定一个主键?
2.主键使用自增ID还是UUID?
3. 字段为什么要求定义为not null?
4.varchar(10)和int(10)代表什么含义?
5.建表策略?
存储引擎相关
1. MySQL支持哪些存储引擎?
2.InnoDB和MyISAM有什么区别?
3.什么是存储过程?有哪些优缺点?
4.说一说三个范式?
答案整理
Java基础进阶阶段
基础概念类
1.JDK1.8新特性?
提供lambda表达式极大地减少了代码的冗余; 在接口中可以使用default和static关键字来修饰接口中的普通方法; 提供新的API LocalDate | LocalTime | LocalDateTime
- Java.util.Date和SimpleDateFormatter线程上都不安全,而LocalDate和LocalTime和 String一样都是不可改变类,线程上比较安全,还不能修改;
- Java.util.Date月份从0开始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出错了;
2.面向对象和面向过程的区别?
面向过程
- 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源。比如,单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发,性能是最重要的因素。
- 缺点:没有面向对象易维护、易复用、易扩展。
面向对象
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。
- 缺点:性能比面向过程低。
3.什么是值传递和引用传递?
- 值传递,是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
- 引用传递,一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。
一般认为,Java 内的传递都是值传递,Java 中实例对象的传递是引用传递。
4.什么是不可变对象
- 不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。
5.讲讲类的实例化顺序?
初始化顺序如下:
- 父类静态变量
- 父类静态代码块
- 子类静态变量、
- 子类静态代码块
- 父类非静态变量(父类实例成员变量)
- 父类构造函数
- 子类非静态变量(子类实例成员变量)
- 子类构造函数
6.java 创建对象的几种方式
- 采用new
- 通过反射
- 采用clone
- 通过序列化机制
前2者都需要显式地调用构造方法。造成耦合性最高的恰好是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用
7.Java访问修饰符的作用域
作用域 当前类 同包 子类 其它
- public Y Y Y Y
- protected Y Y Y N
- default Y Y N N
- private Y N N N
8.switch中能否使用string作为参数?
- 在jdk1.7之前,switch只能支持byte,short,char,int或者其他对应的封装类以及Enum类型.jdk1.7之后开始支持String
9.switch中能否作用在byte,long上?
- 可以用在byte上,不能用在long上
10.什么是自动拆装箱?
- 自动装箱和拆箱,就是基本类型和引用类型之间的转换。
- 把基本数据类型转换成包装类的过程就是打包装,为装箱。
- 把包装类转换成基本数据类型的过程就是拆包装,为拆箱。
11.如何正确的退出多层嵌套循环?
使用标号和break;
继承
-
Java支持多继承么?
[li]Java类中不支持多继承,但是可以多实现,所以接口的扩展性比较好,实际开发中尽量避免继承的使用
[/li]
父类的静态方法能否被子类重写
- [li]不能。重写只适用于实例方法,不能用于静态方法,而子类当中含有和父类相同签名的静态方法,我们一般称之为隐藏。
[/li]
继承的好处和坏处
- [li]好处:子类能自动继承父类的对象 2、创建子类的对象时,无须创建父类的对象
[/li]
- 破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性。
接口抽象类
1.接口的意义
- 规范,扩展,回调。
2.抽象类的意义
- 为其他子类提供一个公共的类型
- 封装子类中重复定义的内容
- 定义抽象方法,子类虽然有不同的实现,但是定义时一致的
3.抽 象 的 (abstract) 方 法 是 否 可 同 时 是 静 态 的 (static), 是 否 可 同 时 是 本 地 方 法(native)
- abstract关键字不能同时与static或private或final同时修饰一个方法;
4.抽象类和接口区别?
-
语法区别:
[ul]
抽象类可以有构造方法,接口不能有构造方法
-
抽象类中可以有普通成员变量,接口中没有普通成员变量;
-
抽象类中可以有非抽象的方法,接口中的方法都必须是抽象的;
-
抽象类中的方法可以是public,protected类型,接口中的方法只能是public类型的,切 默认为public abstract类型;
-
抽象类中可以有静态方法,接口中不能有静态方法;
-
抽象类中的静态变量访问类型可以是任意的,但接口中的静态变量只能是public static final 类型。
-
.一个类可以实现多个接口,但一个类只能继承一个抽象类;
应用区别:
接口更多是在系统架构方面发挥作用,主要用于定义模块之间的通信契约;而抽象类在代码方法 发挥作用,可以使用代码块的重用;
[/ul]
5.Java中接口可不可以继承一般类,为什么?
不可以因为接口中只能出现3种成员:
-
公共的静态常量
-
公共的抽象方法
-
静态内部类
而一个类中,就算什么都不写,也必须带一个构造方法,在extends时就会被子类继承,如果是接口也会 继承这个构造方法,很明显构造方法不在上面三项之列 而如果类中有一般的方法和成员变量,也会被子类全部继承,这些更不能出现在接口中了,所以接口是绝 对不可能继承一个类的
6.重载与重写区别
override(重写)
- 方法名、参数、返回值相同。
- 子类方法不能缩小父类方法的访问权限。
- 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
- 存在于父类和子类之间。
- 被final修饰的方法,不能被重写。
overload(重载)
- 参数类型、个数、顺序至少有一个不相同。
- 不能重载只有返回值不同的方法名。
- 存在于父类和子类、同类中。
7.final有哪些用法?
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。
注:修饰变量, final 数据类型 变量名=数据值; 如果该变量是基本数据类型,则值不能修改,如果该变量是引用数据类型,则地址值不能改(既只能new一次);
- 被final修饰的方法,JVM会尝试将其内联,以提高运行效率
- 被final修饰的常量,在编译阶段会存入常量池中。
回答出编译器对final域要遵守的两个重排序规则更好:
- 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
- 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
多态
1.多态的好处和弊端
许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。即父类型的引用指向子类型的对象。
- 优点:可替换性:多态对已存在代码具有可替换性
- 可扩充性:增加新的子类不影响已经存在的类结构
- 更加灵活
- 不能使用子类的特有内容
2.代码中如何实现多态
实现多态主要有以下三种方式:
-
接口实现
-
继承父类重写方法
-
同一类中进行方法重载
3.Java 中实现多态的机制是什么?
- 父类对象指向子类引用
内部类Lambda
1.内部类的作用?
- 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立.在单个外围类当中,可以让多个内部类以不同的方式实现同一接口,或者继承同一个类.创建内部类对象的时刻不依赖于外部类对象的创建。
- 内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.一个java文件内部可以有类?(非内部类)
- 只能有一个public公共类,但是可以有多个default修饰的类。
3.Lambda的使用前提是什么?
- 当需要一个接口的实现类对象,且接口中有且仅有一个抽象方法的时候,可以使用lambda完成这个实现类要做的事情;(替代匿名内部类)
4.Lambda与匿名内部类区别
- lambda表达式编译后并不会生成.class文件,而匿名内部类编译后会产生单独的class文件;
- 匿名内部类可以用在类,抽象类,接口中,而lambda表达式只能用在有且仅有一个抽象方法的接口中;
static关键字
1.是否可以在static环境中访问非static变量?
- static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
2.static都有哪些用法?
- 被static所修饰的变量/方法都属于类的静态资源,类实例所共享.
- static也用于静态块,多用于初始化操作.
- 此外static也多用于修饰内部类,此时称之为静态内部类.
3.静态变量和实例变量的区别?
- 静态变量存储在方法区,属于类所有。实例变量存储在堆当中,其引用存在当前线程栈。
4.static特点
- 如果修饰构造代码块,仅在类第一次加载的时候,执行一次;
- 如果修饰成员变量,这个变量的值属于类;可以被所有的对象共享;
- 如果修饰成员方法,在方法中不能使用this,super;
- 静态的内容优先于对象存在!
数据类型
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4请问s5==s2返回什么?
- 返回false。在编译过程中,编译器会将s2直接优化为”ab”,会将其放置在常量池当中,s5则是被创建在堆区,相当于s5=new String(“ab”);
2.3*0.1==0.3返回值是什么
- false,因为有些浮点数不能完全精确的表示出来
3.基本数据类型的默认值?基本数据类型所占的字节以及封装他们的类?
-
默认值
byte、short、int、long的默认值为0
-
float、double默认值为0.0
-
char默认值为空
-
boolean默认值为false
所占字节
byte 1个字节–Byte
short 2个字节–Short
char 2个字节–Character
int 4个字节–Integer
long 8个字节–Long
float 4个字节–Float
double 8个字节–Double
4.String属于那个类,以及常用的方法?
-
.java.lang.string
-
substring(),indexOf(),concat(),endswith(),length(),replace()
5.String, StringBuffer和StringBuilder区别
- String的值是不可改变的,这就导致每次对String的操作都会生成新的String对象,不禁效率底下, 而且浪费大量的内存空间;
- StringBuilder是可变类,任何对他指向的字符串的操作都不会产生新的对 象,但单线程不安全;
- StringBuffer底层方法使用了synchronized关键字,线程比较安全,但效率 较StringBuilder慢
异常相关
1.error和exception有什么区别
- error表示系统级的错误,是java运行环境内部错误或者硬件问题,不能指望程序来处理这样的问题,除了退出运行外别无选择,它是Java虚拟机抛出的。
- exception 表示程序需要捕捉、需要处理的异常,是由与程序设计的不完善而出现的问题,程序必须处理的问题
2.运行时异常和一般异常有何不同
- Java提供了两类主要的异常:runtimeException和checkedException
- 一般异常(checkedException)主要是指IO异常、SQL异常等。对于这种异常,JVM要求我们必须对其进行cathc处理,所以,面对这种异常,不管我们是否愿意,都是要写一大堆的catch块去处理可能出现的异常。
- 运行时异常(runtimeException)我们一般不处理,当出现这类异常的时候程序会由虚拟机接管。比如,我们从来没有去处理过NullPointerException,而且这个异常还是最常见的异常之一。
- 出现运行时异常的时候,程序会将异常一直向上抛,一直抛到遇到处理代码,如果没有catch块进行处理,到了最上层,如果是多线程就有Thread.run()抛出,如果不是多线程那么就由main.run()抛出。抛出之后,如果是线程,那么该线程也就终止了,如果是主程序,那么该程序也就终止了。
- 其实运行时异常的也是继承自Exception,也可以用catch块对其处理,只是我们一般不处理罢了,也就是说,如果不对运行时异常进行catch处理,那么结果不是线程退出就是主程序终止。
- 如果不想终止,那么我们就必须捕获所有可能出现的运行时异常。如果程序中出现了异常数据,但是它不影响下面的程序执行,那么我们就该在catch块里面将异常数据舍弃,然后记录日志。如果,它影响到了下面的程序运行,那么还是程序退出比较好些。
3.Java中异常处理机制的原理
Java通过面向对象的方式对异常进行处理,Java把异常按照不同的类型进行分类,并提供了良好的接口。当一个方法出现异常后就会抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并对异常进行处理。Java的异常处理是通过5个关键词来实现的:try catch throw throws finally。
一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws),我们可以通过它的类型来捕捉它,或最后由缺省处理器来处理它(finally)。
- try:用来指定一块预防所有异常的程序
- catch:紧跟在try后面,用来捕获异常
- throw:用来明确的抛出一个异常
- throws:用来标明一个成员函数可能抛出的各种异常
- finally:确保一段代码无论发生什么异常都会被执行的一段代码。
4.你平时在项目中是怎样对异常进行处理的。
- 尽量避免出现runtimeException 。例如对于可能出现空指针的代码,带使用对象之前一定要判断一下该对象是否为空,必要的时候对runtimeException
也进行try catch处理。
- 进行try catch处理的时候要在catch代码块中对异常信息进行记录,通过调用异常类的相关方法获取到异常的相关信息,返回到web端,不仅要给用户良好的用户体验,也要能帮助程序员良好的定位异常出现的位置及原因。例如,以前做的一个项目,程序遇到异常页面会显示一个图片告诉用户哪些操作导致程序出现了什么异常,同时图片上有一个按钮用来点击展示异常的详细信息给程序员看的。
5.throw和throws有什么区别?
- throw关键字用来在程序中明确的抛出异常,相反,throws语句用来表明方法不能处理的异常。每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异常是用逗号分隔的。
6.异常处理的时候,finally代码块的重要性是什么?
- 无论是否抛出异常,finally代码块总是会被执行。就算是没有catch语句同时又抛出异常的情况下,finally代码块仍然会被执行。最后要说的是,finally代码块主要用来释放资源,比如:I/O缓冲区,数据库连接。
7.请列出 5 个运行时异常?
- NullPointerException 空指针
- IndexOutOfBoundsException 索引越界
- ClassCastException 类型转换异常
- ArrayStoreException 当你试图将错误类型的对象存储到一个对象数组时抛出的异常
- BufferOverflowException 写入的长度超出了允许的长度
- IllegalArgumentException 方法的参数无效
- NoClassDefFoundException – JAVA运行时系统找不到所引用的类
8.try catch finally,try里有return,finally还执行么?**
- finally语句总会执行即使try里包含continue,break,return,try块结束后,finally块也会执行
- 如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、全局变量)
- 尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生。
- finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略
集合部分
1、List、Map、Set三个接口,存取元素时,各有什么特点?
- Set集合的add有一个boolean类型的返回值,当集合中没有某个元素时,则可以成功加入该 元素,返回结果为true;当集合中存在与某个元素equals方法相等 的元素时,则无法加入该元素, 取元素时只能用Iterator接口取得所有元素,在逐一遍历各个元素;
- List表示有先后顺序的集合,调用add()方法,指定当前对象在集合中的存放位置;一个对象可 以被反复存进集合中;每调用一次add()方法,该对象就会被插入集合中一次,其实,并不是把对 象本身存进了集合中,而是在集合中使用一个索引变量指向了该对象,当一个对象被add多次时, 即有多个索引指向了这个对象。List去元素时可以使用Iterator取出所有元素,在逐一遍历,还可 以使用get(int index)获取指定下表的元素;
- Map是双列元素的集合,调用put(key,value),要存储一对key/value,不能存储重复的key, 这个是根据eauals来判断;取元素时用get(key)来获取key所对 应的value,另外还可以获取 全部key,全部value
2、ArrayList和LinkedList的底层实现原理?他们为什么线程不安全?在多线程并发操作下,我们应该用什么替代?
- ArrayList底层通过数组实现,ArrayList允许按序号索引元素,而插入元素需要对数组进行移位等内存操作,所以索引快插入较慢;(扩容方式)一旦我们实例化了ArrayList 无参构造函数默认数组长度为10。add方法底层如 果增加的元素超过了10个,那么ArrayList底层会生成一个新的数组,长度为原来数组长度的1.5倍+1,然后将原数组内容复制到新数组中,并且后续加的内容都会放到新数组中。当新数组无法容纳增加元素时,重复该过程;
- LinkedList底层通过双向链表实现,取元素时需要进行前项或后项的遍历,插入元素时只需要记录本项的前后 项即可,所以插入快查询慢;
- ArrayList和LinkedList底层方法都没有加synchronized关键词,多线程访问时会出现多个线程先后更改数据造成得到的数据是脏数据;多线程并发操作下使用Vector来代替,Vector底层也是数组,但底层方法都加synchronized关键字使线程安全,效率较ArrayList差;
3、HashMap和HashTable有什么区别?其底层实现是什么?CurrentHashMap的锁机制又是如何?如果想将一个Map变为有序的,该如何实现?
- 区别:HashMap没有实现synchronized线程非安全,HashTable实现了synchronized线程安全;
- HashMap允许key和value为null,而HashTable不允许
4.什么是迭代器(Iterator)?
- Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object Obj)删除,可以通过迭代器的remove()方法删除
5.Arraylist 与 LinkedList 区别
- Arraylist:优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
- 缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
- 优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
6.Arraylist 与 LinkedList 应用场景?
- 当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
7.Collection 和 Collections的区别
- Collection是集合类的上级接口,继承与他的接口主要有Set 和List.Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作(带s的基本都是工具类,如Arrays)
8.为何Map接口不继承Collection接口?
- 尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。
- 如果Map继承Collection接口,那么元素去哪儿?Map包含key-value对,它提供抽取key或value列表集合的方法,但是它不适合“一组对象”规范。
10.HashMap和Hashtable有什么区别?
- HashMap是非线程安全的,HashTable是线程安全的。
- HashMap的键和值都允许有null值存在,而HashTable则不行。
- 因为线程安全的问题,HashMap效率比HashTable的要高。
- Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
一般现在不建议用HashTable
- 是HashTable是遗留类,内部实现很多没优化和冗余
- 即使在多线程环境下,现在也有同步的ConcurrentHashMap替代,没有必要因为是多线程而用HashTable。
11.List 和 Set 区别?
List,Set都是继承自Collection接口
- List特点:元素有放入顺序
- 元素可重复
- 元素无放入顺序
(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
12.Set和List对比?
- Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
- List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
13.当两个对象的hashcode相同会发生什么?
- 因为hashcde相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。
14.如果两个键的hashcode相同,你如何获取值对象?
- 当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,然后会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。
15.有没有可能两个不相等的对象有相同的hashcode?
- 有可能,(通话,重地)两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在 hashmap 中会有冲突。如果两个对象相等,必须有相同的hashcode 值,反之不成立。
16.HashMap、LinkedHashMap、TreeMap的区别?
- HashMap是根据键的hashcode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,取得的数据完全是随机的
- LinkedHashMap保存了记录的插入顺序,在使用Iterator进行遍历的时候,先得到的肯定是先插入的数据,可以在构造时带参数,按照应用次数来进行排序
- TreeMap实现SortMap接口,能够把它保存的记录根据键排序。默认的是升序排序,也可以指定排序的比较器,进行遍历的时候得到的是排序过的记录。
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。**
- HashMap是java数据结构中两大结构数组和链表的组合。HashMap底层数组,数组中的每一项又是一个链表。程序会先根据key的hashcode()方法返回值决定该Entry在数组中的
- 存储位置,如果该位置上没有元素,就会将元素放置在此位置上,如果两个Entry的key相同,会调用equals,返回值是true则覆盖原来的value值,返回false则会形成Entry链,位于头部。
- ArrrayList的底层实现是数组,在执行add操作时,会先检查数组 大小是否可以容纳新的元素,如果不够就会进行扩容。然后会将原来的数据拷贝到新的数组中。
- LinkedList底层是一个链表,其实现增删改查和数据结构中的操作完全相同,而且插入是有序的。
- LinkedHashMap的底层结构式是双链表,其他的逻辑处理与HashMap一致,同样没有锁保护,多线程使用时存在风险。
- ConcurrentHashMap是segment数组结构和HashEntry数组结构组成的,segment在ConcurrentHashMap中充当锁的角色,HashEntry用于存储键值对数据。segment的结构是数组和链表,一个segment中有一个HashEntry,每个HashEntry是一个链表结构的元素。对HashEntry中的数据进行修改时,需要先获得它所对应的segment锁。每个ConcurrentHashMap默认有16个segment。
18.==和 equals hashCode 的区别?
- 基本数据类型: ==比较的是内容 引用数据类型: ==比的是地址值,equals默认比地址值,重写按照规则比较,hashCode
19.自然排序Comparble和比较器排序Comparator的异同点?
相同点:
返回值的规则:
-
如果返回值为负数,表示当前存入的元素是较小值,存左边
-
如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
-
如果返回值为正数,表示当前存入的元素是较大值,存右边
不同点:
1.用到的接口不同
-
自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
-
比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
2.使用场景不同
-
自然排序能满足大部分情况
-
存储没有修改权限的类时可以使用
20.Iterator 和 ListIterator 有什么区别?
-
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
-
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
-
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
泛型
1.为什么使用泛型?
- 它提供了编译时类型安全检测机制,把运行时期的问题提前到了编译期间
- 避免了强制类型转换
2.泛型用在什么地方?
- 类,方法,接口
3.如何使用泛型类?
- 创建泛型类对象时,必须要给这个泛型确定具体的数据类型
树
1.什么是二叉树?
- 任意节点的子节点不超过2
2.什么是二叉查找树?
- 每个节点最多有两个子节点,左边比当前节点小,右边比当前节点大
3.什么是平衡二叉树?
- 二叉树左右子树的树高差不超过1,任意节点的左右子树都是平衡二叉树
- 通过左旋右旋保持树的平衡
序列化
1.什么是 Java 序列化?
- 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。
- 可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。
- 序列化是为了解决在对对象流进行读写操作时所引发的问题。
- 反序列化的过程,则是和序列化相反的过程。
- 另外,我们不能将序列化局限在 Java 对象转换成二进制数组,例如说,我们将一个 Java 对象,转换成 JSON 字符串,或者 XML 字符串,这也可以理解为是序列化。
2.如何实现 Java 序列化?
将需要被序列化的类,实现 Serializable 接口,该接口没有需要实现的方法,implements Serializable 只是为了标注该对象是可被序列化的。
序列化
- 然后,使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 #writeObject(Object obj) 方法,就可以将参数为 obj 的对象写出(即保存其状态)。
反序列化
- 要恢复的话则用输入流。
3.Java 序列话中,如果有些字段不想进行序列化怎么办?
- 对于不想进行序列化的变量,使用 transient 关键字修饰。
- 当对象被序列化时,阻止实例中那些用此关键字修饰的的变量序列化。
- 当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。
- transient 只能修饰变量,不能修饰类和方法。
4.对象操作流是字符流还是字节流?
- 字节流
5.如何在读写文件时指定字符集?
jdk11之前:
- 使用转换流InputStreamReader(输入转换流)字节转换字符桥梁/OutputStreamWriter(输出转换流)字符转字节桥梁
jdk11之后
- 直接使用FileReader指定
6.字符缓冲流特有方法?
- readLine():读取一整行,到达尾处为null
- newLine():跨平台换行
7.为什么使用对象流?
- 在开发中,经常需要将对象的信息保存到磁盘中,如果使用前面所学的知识来实现,会非常的繁琐。使用对象流就非常的方便
- 对象操作流可以将对象以字节的形式写到本地文件中,直接打开是看不懂的,需要时可以再次用对象操作流读到内存中
多线程
1.什么是线程?
- 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。线程是进程的一部分,是进程中的单个控制流,是一条执行路径
2.线程和进程有什么区别?
- 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。
3.如何在Java中实现线程?
- 继承Thread:可以直接调用Thread中的方法
- 实现Runnable接口,将实现类作为参数传递给Thread对象
- 实现Callabale接口,创建FutureTask对象,将Callable作为参数传递给FutureTask对象,再将FutureTask对象传递给Thread类
4.用Runnable还是Thread?
Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好了。
- Thread:实际中用的相对较少,扩展性太差
- 扩展性比较强,优先使用Runnable接口,需要执行完有返回值可以选择Callable接口
5.Thread 类中的start() 和 run() 方法有什么区别?
- start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。
当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
6.Java中Runnable和Callable有什么不同?
- Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。
7.Java内存模型是什么?
Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性地行为。它在多线程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系确保了:
-
线程内的代码能够按先后顺序执行,这被称为程序次序规则。
-
对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则。
-
前一个对volatile的写操作在后一个volatile的读操作之前,也叫volatile变量规则。
-
一个线程内的任何操作必需在这个线程的start()调用之后,也叫作线程启动规则。
-
一个线程的所有操作都会在线程终止之前,线程终止规则。
-
一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。
-
可传递性
8.Java中的volatile 变量是什么?
- volatile是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile变量可以保证下一个读取操作会在前一个写操作之后发生,就是上一题的volatile变量规则。
9.什么是线程安全?Vector是一个线程安全类吗?
- 多个线程可能会同时运行同一段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
10.Java中如何停止一个线程?
- 当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量或设置某个变量达到一定值的时候,来退出run()方法的循环或者是取消任务来中断线程。
11.Java中notify 和 notifyAll有什么区别?
- notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。
- notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行
12. 什么是线程池? 为什么要使用它?
- 创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)
13.如何写代码来解决生产者消费者问题?
- 在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型
14.Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
-
互斥条件:一个资源每次只能被一个进程使用。
-
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
-
不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
-
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
15.Java中synchronized 和 ReentrantLock 有什么不同?
- 这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。
16.详谈Synchronized
当Synchronized关键字修饰一个方法的时候,该方法叫做同步方法:java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法的时候,表示将对象上锁,此时其它任何线程都无法再去访问synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。
- 注意1:如果一个对象有多个synchronized方法,某一个时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其它线程是无法访问该对象的任何synchronzed方法的。
- 如果某个Synchronized方法是static的,那么当线程访问该方法时,它锁的并不是Synchronized方法所在的对象,而是Synchronized方法所在的对象所对象的Class对象,因为java中无论一个类有多少个对象,这些对象会对应唯一一个class对象,因此当线程分别访问同一个类的两个对象的两个static Synchronized方法的时候,他们执行的顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。
- jdk1.6之后对synchronized(偏向锁(根本就不加锁)、轻量级锁(CAS),重量级锁(悲观锁))进行了大量的优化
17.在Java中Lock接口与synchronized块的区别是什么?
- 用法不一样。synchronized既可以加在方法上,也可以加载特定的代码块上,括号中表示需要锁的对象。而Lock需要显示地指定起始位置和终止位置。synchronzied是托管给jvm执行的,Lock锁定是通过代码实现的。
- 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
- 锁的机制不一样。synchronized获得锁和释放的方式都是在块结构中,而且是自动释放锁。而Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁
18.synchronized 的原理是什么?有什么不足?
- 原理:[li]synchronized是 Java 内置的关键字,它提供了一种独占的加锁方式。
synchronized的获取和释放锁由JVM实现,用户不需要显示的释放锁,非常方便。[/li]
- 当线程尝试获取锁的时候,如果获取不到锁会一直阻塞。
19.关于成员变量和局部变量
- 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作的时候,他们对该成员变量是彼此影响的,也就是说一个线程对成员变量的改变会影响到另外一个线程;如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其它的线程。
20. 如果你提交任务时,线程池队列已满。会时发会生什么?
- 如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常。
21.volatile关键字的作用是?
- 保证变量的可见性。
- 在java内存结构中,每个线程都是有自己独立的内存空间(此处指的线程栈)。当需要对一个共享变量操作时,线程会将这个数据从主存空间复制到自己的独立空间内进行操作,然后在某个时刻将修改后的值刷新到主存空间。这个中间时间就会发生许多奇奇怪怪的线程安全问题了,volatile就出来了,它保证读取数据时只从主存空间读取,修改数据直接修改到主存空间中去,这样就保证了这个变量对多个操作线程的可见性了。换句话说,被volatile修饰的变量,能保证该变量的 单次读或者单次写 操作是原子的。
- 但是线程安全是两方面需要的 原子性(指的是多条操作)和可见性。volatile只能保证可见性,synchronized是两个均保证的。
- volatile轻量级,只能修饰变量;synchronized重量级,还可修饰方法。
- volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。
22.守护线程和非守护线程有什么区别?
- 程序运行完毕,JVM 会等待非守护线程完成后关闭,但是 JVM 不会等待守护线程
23.线程的生命周期?
线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。
-
新建:就是刚使用new方法,new出来的线程;
-
就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
-
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;
-
阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;
-
销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;
24.wait和sleep,notify()锁方面区别?
- wait:让线程等待,同时立即释放锁
- sleep():让线程休眠,但是不会释放锁
- notify()或notifyAll(): 唤醒等待的线程,但是不会立即释放锁
25.什么情况下会出现线程安全问题?
- 多线程环境
- 有共享数据
- 有对共享数据的操作
26.Java中规定了线程有哪几种状态?
- 新建、就绪、阻塞、等待、计时等待、死亡
27.什么是原子性?
- 所谓的原子性就是完成功能的所有操作要么都执行,要么都不执行
28.Java中哪些操作是原子操作?
- 除了long和double之外的所有原始类型的赋值
- 所有volatile变量的赋值
- java.concurrent.Atomic *类的所有操作
29.什么是CAS算法?
- 当预期值E==主内存中的值V,此时可以进行修改,将V改成新值
- 当预期值E!=主内存中的值V时,将主内存中的已经改变的值更新到自己的工作内存中,再次尝试比较,直到预期值E等于主内存中的值V,才可以修改。这个过程称为自旋
30.synchronized和CAS的区别?
- 相同点:在多线程情况下,都可以保证共享数据的安全性。
- synchronized总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每 次操作共享数据之前,都会上锁。(悲观锁)
31.并发容器Hashtable和ConcurrentHashMap特点?
- Hashtable:
Hashtable采取悲观锁synchronized的形式保证数据的安全性
-
只要有线程访问,会将整张表全部锁起来,所以Hashtable效率低下
采用sychronized+cas
线程安全,效率比Hashtable高,比HashMap低
反射类加载器
1.Java反射机制的作用?
- 在运行时判断任意一个对象所属的类。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时任意调用一个对象的方法
- 在运行时构造任意一个类的对象
2.什么是反射机制?
- 简单说,反射机制值得是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
3.哪里用到反射机制?
- Spring 框架的 IoC 基于反射创建对象和设置依赖属性。
- Spring MVC 的请求调用对应方法,也是通过反射。
- JDBC 的 Class#forName(String className) 方法,也是使用反射。
4.反射机制的优缺点?
- 静态编译:在编译时确定类型,绑定对象,即通过
- 运行时确定类型,绑定对象。动态编译最大限度的发挥了java的灵活性,体现了多态的应用,有利于降低类之间的耦合性。一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作
5.反射中,Class.forName 和 ClassLoader 区别
- java中class.forName()和classLoader都可用来对类进行加载。
- class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
- 而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
6.什么是双亲委派模型?
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
7.为什么要有双亲委派模型?
- 为了保证类的全局唯一性,如果自定义类与Java核心类库中的类重名了,会被编译但不会不执行
8.怎么利用反射使用私有成员?
- setAccessible(boolean flag)
网络通信
1.什么是三次握手?
-
客户端向服务器发出取消连接请求
-
服务器向客户端返回一个响应,告诉客户端收到了请求
-
客户端向服务器端再次发出确认信息建立连接
2.什么是四次挥手?
-
客户端向服务器发出取消连接请求
-
服务器向客户端返回一个响应,表示收到客户端取消请求
-
服务器向客户端发出确认信息
-
客户端再次发送确认信息,连接取消
3.TCP通信注意事项?
-
accept方法是阻塞的,作用就是等待客户端连接
-
客户端创建对象并连接服务器,此时是通过三次握手协议,保证跟服务器之间的连接
-
针对客户端来讲,是往外写的,所以是输出流 针对服务器来讲,是往里读的,所以是输入流
-
read方法也是阻塞的
-
客户端在关流的时候,还多了一个往服务器写结束标记的动作
-
最后一步断开连接,通过四次挥手协议保证连接终止
web阶段
jsp相关
1.jsp内置对象和EL内置对象的区别与联系
jsp内置对象:
-
jsp内可以在<%%>中直接使用的对象9个
EL表达式内置对象:
-
jsp呢可以在${}中直接使用的对象11个
pageContext对象是二者唯一相同的对象,其他都是各自独立的对象
2.说一下 jsp 的 4 种作用域?
JSP中的四种作用域包括page、request、session和application,具体来说:
-
page代表与一个页面相关的对象和属性。
-
request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域。
-
session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中。
-
application代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域。
3.ServletContext 与application的异同
- 相同:其实servletContext和application 是一样的,就相当于一个类创建了两个不同名称的变量。在 servlet中ServletContext就是application对象。大家只要打开jsp编译过后生成的Servlet中 jspService()方法就可以看到如下的声明: ServletContextapplication = null;application= pageContext.getServletContext();
- 两者的区别就是application用在jsp中,servletContext用在servlet中。application和page requestsession 都是JSP中的内置对象,在后台用ServletContext存储的属性数据可以用 application对象获得。 而且application的作用域是整个Tomcat启动的过程。 例如:ServletContext.setAttribute(\”username\”,username); 则在JSP网页中可以使用 application.getAttribute(\”username\”); 来得到这个用户名。
4.jsp 有哪些内置对象?作用分别是什么?
JSP有9个内置对象:
-
request:封装客户端的请求,其中包含来自GET或POST请求的参数;
-
response:封装服务器对客户端的响应;
-
pageContext:通过该对象可以获取其他对象;
-
session:封装用户会话的对象;
-
application:封装服务器运行环境的对象;
-
out:输出服务器响应的输出流对象;
-
config:Web应用的配置对象;
-
page:JSP页面本身(相当于Java程序中的this);
-
exception:封装页面抛出异常的对象。
概念相关
1.post和get区别?
- post:数据不会显示在地址栏
-
安全
-
大小无限制
-
可以提交二进制文件
get:
数据显示在地址栏
不安全
get方式提交有大小限制(约4kb)
2.相对路径和绝对路径?
-
相对路径
概念:
不以\”/\”开头,而是根据资源的相对位置关系的道德路径
写法:
-
从路径不一样的位置开始写 例如:bbb/bbb ..bbb/b.html (../表示退一级)
绝对路径
概念:
以\”/\”为开头的路径就是绝对路径.该路径不会随着位置变化而变化
写法:
-
当前资源在浏览器中的\”被访问路径\”,并省略\”http://localhost:8080\”
3.Cookie和session的区别?
session是基于cookie
多次请求之间共享数据
- cookie:
数据存储于客户端–不安全
-
只能存字符串
-
大小有限制
数据存储于服务器端–安全
类型无限制
大小无限制
4.servlet四大域对象的区别?
-
pageContext:当前jsp页面内共享数据
-
request:一次请求内共享数据,例如:请求转发和包含都是一次请求,可以使用request传递数据
-
session:一次会话范围内共享数据
-
servletContext:整个应用共享数据
5.什么是活化与钝化?
服务器自动完成(注意使用本地Tomcat才行)
- 钝化:
概念:序列化。把长时间不用,但还不到过期时间的 HttpSession 进行序列化,写到磁盘上
- 时机:当访问量很大时,服务器会根据 getLastAccessTime 来进行排序,对长时间不用,但是还没到过期时间的 HttpSession 进行序列化。
概念:相反的状态,从磁盘读取到内存
时机:tomcat重新启动时会将会话加载到内存
6.EL内置对象有哪些?
- 作用: 只能在EL 中使用,让EL 更加简单
注意:EL 表达式内置对象和,JSP 内置对象不是一回事,el表达式中想要使用jsp 中的对象需要使用pageContext 获取
7.如果有大量的网站访问量。那么会产生很多的session,该怎么解决?
session默认保存在内存中,内存资源宝贵,session数据量大导致内存利用率高,以下方案解决session内存存储问题:
- 可以设置session超时时间,达到超时时间session自动清空
<session-config>
<session-timeout>20</session-timeout>
</session-config>
- 将session中的数据序列化到硬盘中
- 不使用session,使用cookie(此方法存在安全性问题)
8.页面传递对象的方法?
- Request、session、application、cookie等
9.session 和 application的区别?
- 两者的作用范围不同:Session对象是用户级的,而Application是应用程序级别的
- 一个用户一个session对象,每个用户的session对象不同,在用户所访问的网站多个页面之间共享同一个session对象
- 一个Web应用程序一个application对象,每个Web应用程序的application对象不同,但一个Web应用程序的多个用户之间共享同一个application对象。
- session对象的生命周期:用户首次访问网站创建,用户离开该网站 (不一定要关闭浏览器) 消亡。
Servlet相关
1.解释一下什么是servlet
- Servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet 接口的init,service 和destroy方法表达。
- Web容器加载Servlet,Servlet被服务器实例化后,生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现,根据请求的不同调用不同的doXXX方法(doGet,doPost)方法。结束服务,web容器调用servlet的destroy()方法。
2.servlet的生命周期?
servlet容器负责管理servlet的生命周期,servlet生命周期如下:
- 加载和实例化 Servlet 容器装载和实例化一个 Servlet。创建出该 Servlet 类的一个实例。
- 初始化 在 Servlet 实例化完成之后,容器负责调用该 Servlet 实例的 init() 方法,在处理用户请求之前,来做一些额外的初始化工作。
- 处理请求 当 Servlet 容器接收到一个 Servlet 请求时,便运行与之对应的 Servlet 实例的 service() 方法,service() 方法再派遣运行与请求相对应的 doXX(doGet,doPost) 方法来处理用户请求。
- 销毁 当 Servlet 容器决定将一个 Servlet 从服务器中移除时 ( 如 Servlet 文件被更新 ),便调用该 Servlet 实例的 destroy() 方法,在销毁该 Servlet 实例之前, 来做一些其他的工作。
加载实例化,初始化,销毁,在整个生命周期中只会执行一次
补充:
-
Servlet实例化有两种:
第一次请求时,实例化servlet
-
在web.XML文件中的<Servlet></Servlet>之间添加<loadon-startup>1</loadon-startup>,tomcat启动时就会实例化servlet对象
3.servlet生命周期方法有哪些?
共有3个方法:
- public void init(ServletConfig config):这个方法是由servlet容器调用用来初始化servlet的,这个方法在servlet生命周期中仅被调用一次。
- servlet容器为每个客户端创建线程,然后都会执行service方法,但执行此方法前init方法必须已经被执行了。
- servlet从servlet容器中被移除时会调用此方法,仅被调用一次。
4.servlet过滤器的作用?
- 打印一些请求参数到日志中
- 授权请求访问资源
- 在将请求提交给servlet之前,对request请求头或请求体进行一些格式化的处理
- 将响应数据进行压缩再返回给浏览器。
- 解决乱码问题。
5.servlet监听器的作用?
- 监听客户端的请求,服务器端的操作等 。通过监听器,可以自动激发一些操作,比如监听在线的用户数量( 当增加一个HttpSession时,就自动触发sessionCreated(HttpSessionEvent se)方法,在这个方法中就可以统计在线人数了 ),另外还可以用来初始化一些资源,比如数据库连接池等(web.xml中配置的context-param只能是字符串不能使对象,这时就得使用ServletContextListener了,注意,有读者可能说ServletConext的setAttribute不是可以设置对象吗?但是这是在servlet创建之后才能调用的方法,如果希望web应用一启动就产生初始参数必须使用监听器)。
6.web.xml中组件的加载顺序?
- context-param -> listener -> filter -> servlet
- 而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的
7.如何确保servlet在应用启动之后被加载到内存?
- 通常情况下都是客户端请求一个servlet,这个servlet才会被加载到内存,但对于某些很大加载很耗时的servlet我们希望应用启动时就加载它们,这时我们可以在web.xml文件中配置或者使用webServlet注解(servlet3.0)告诉容器系统一启动就加载:
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>com.foo.servlets.Foo</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
- load-on-startup节点中必须配置一个整数,整数代表应用一启动就会被加载,负数表示当客户端请求之后才加载,正数的值越小,说明越先被加载。
8.HttpServlet为什么声明为抽象类?
- httpServlet类虽然是抽象类但却没有抽象方法,之所以这样设计,是因为doget,dopost等方法并没有业务逻辑,开发者至少应该重写一个service中的方法,这就是我们不能实例化HttpServlet的原因。
9.redirect(重定向)和forward(请求转发)区别?
重定向:
-
两次请求
-
地址栏发生变化
-
不可以使用request域的共享数据
-
不可以访问/WEB_INF下的资源
转发:
-
一次请求
-
地址栏不发生变化
-
可以使用request域的共享数据
-
可以访问/WEB_INF下的资源
补充:
servlet中怎么定义forward 和redirect?
- 转发:request.getRequestDispatcher (“demo.jsp\”). forward(request, response);
- 重定向:response.sendRedirect(“demo.jsp\”);
10.sevlet中的属性域有哪些?
servlet提供了一些域对象方便内部servlet之间的通信,我们可以通过set/get方法为web应用设置或取出属性值。servlet提供3个域(和jsp区分开来):
- request scope
- session scope
- application scope
分别由ServletRequest,HttpSession,ServletContext对象提供对应的set/get/remove方法去操作者三个域。
注:这跟web.xml中为servletConfig(针对单个servlet)和servletContext(针对web应用)定义的初始化参数不一样。
11.Servlet是否线程安全?
- HttpServlet的init和destroy方法在servlet声明周期中仅 调用一次,所以不用担心它们的线程安全。但是service方法以及doget,dopost等方法是存在线程安全问题的,因为servlet容器为每一个客户端请求都创建一个线程,这些线程在同一时刻可能访问同一个servlet的service方法,所以我们在使用这些方法时务必小心。
12.如何创建线程安全的servlet?(SingleThreadModel方法不算)
- 尽量使用局部变量,减少全局变量的使用。
- 对于共享变量,加上关键字synchronized。
注:servlet中常见线程安全与不安全的对象
- 线程安全:ServletRequest,ServletResponse
- 线程不安全:ServletContext,HttpSession。
对于 ServletContext,我们应尽量减少该对象中属性的修改。
而HttpSession对象在用户会话期间存在,只能在处理属于同一个Session的请求的线程中被访问,因此Session对象的属性访问理论上是线程安全的。但是当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性
13.是否有必要重写service方法?
- 一般情况下是没有必要的,因为service方法会根据请求的类型(get、post等)将请求分发给doxxx方法去执行。即使我们需要在处理请求之前需要做一些额外的事,我们也可以通过过滤器或监听器完成。
14.servlet包装类有什么用?
- servletAPI提供了两个包装类:HttpServletRequestWrapper类和HttpServletResponseWrapper类,这些包装类帮助开发者给出request和response的一般实现。我们可以继承它们并选择我们需要复写的方法进行复写(包装设计模式),而不用复写所有的方法。
15.在servlet中能否产生类似死锁情况?
- 可以的,你在doPost方法中调用doGet方法,在doGet方法中调用doPost方法,将产生死锁(最终会抛出stackoverflow异常)。
16.Servlet API中forward()与redirect()的区别?
- forward 是服务器转发,一次请求和响应,浏览器地址栏不会显示出转发后的地址;forward比较高效,而且有助于隐藏实际地址。eg: getServletContext().getRequest Dispatcher(“/servlet/secondservlet”).forward(request, response);
- eg: response.sendRedirect(\”http://www.baidu.com/\”);
17.ServletContext对象和ServletConfig对象的区别?
- 每个servlet都会有自己独有的servletConfig对象而servletContext对象是整个web应用共享的。
- servletConfig提供servlet的初始化参数(init-param),仅该servlet可以访问。而servletContext提供的初始化参数整个web应用的所有servlet都可以访问。
- servletContext对象提供了setAttribute方法设置共享参数,而servletConfig并没有对应的set方法。
18.PrintWriter和ServletOutPutStream类有什么区别?
- PrintWriter是字符流,ServletOutputStream是字节流。可以通过 PrintWriter向浏览器输出字符数组或者是字符串。也可以通过ServletOutPutStream向浏览器端输出字节数组。
- PrintWriter对象在servlet中可以通过response.getWriter()方法获取
- ServletOutputStream对象通过response.getOutputStream方法获取。
19.在一个servlet能否同时获取PrintWriter和ServletOutputStream对象?
- 不可以,如果同时获取,将会抛出java.lang.IllegalStateException异常。
20.Request对象的主要方法有哪些?
- setAttribute(String name,Object):设置名字为name的request 的参数值
- getAttribute(String name):返回由name指定的属性值
- getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例
- getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组
- getCharacterEncoding():返回请求中的字符编码方式
- getContentLength():返回请求的Body的长度
- getHeader(String name):获得HTTP协议定义的文件头信息
- getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例
- getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例
- getInputStream():返回请求的输入流,用于获得请求中的数据
- getMethod():获得客户端向服务器端传送数据的方法
- getParameter(String name):获得客户端传送给服务器端的有name指定的参数值
- getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
- getParametervalues(String name):获得有name指定的参数的所有值
- getProtocol():获取客户端向服务器端传送数据所依据的协议名称
- getQueryString():获得查询字符串
- getRequestURI():获取发出请求字符串的客户端地址
- getRemoteAddr():获取客户端的IP 地址
- getRemoteHost():获取客户端的名字
- getSession([Boolean create]):返回和请求相关Session
- getServerName():获取服务器的名字
- getServletPath():获取客户端所请求的脚本文件的路径
- getServerPort():获取服务器的端口号
- removeAttribute(String name):删除请求中的一个属性
21.jsp和servlet的异同点以及联系是什么?
-
jsp经编译后就变成了servlet(jsp本质就是servlet,jvm只能识别java的类,不能识别jsp代码,web容器将jsp的代码编译成jvm能够识别的java类)
-
jsp更擅长表现于页面显示,servlet更擅长于逻辑控制
-
setvlet中没有内置对象,jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象及HttpServlet对象得到
-
jsp是servlet的一种简化,使用jsp只需要完成程序员需用输出到客户端的内容,jsp中的java脚本如何镶嵌到一个类中,由jsp容器完成,而servlet则是个完整的java类,这个类的service方法用于生成对客户端的响应
数据库阶段
索引相关
1.什么是索引?
- 索引是一种数据结构,可以帮助我们快速的进行数据的查找
2.索引是个什么样的数据结构呢?
- 索引的数据结构和具体存储引擎的实现有关, 在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引.
3.在建立索引的时候,都有哪些需要考虑的因素呢?
- 建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合.如果需要建立联合索引的话,还需要考虑联合索引中的顺序.此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力.这些都和实际的表结构以及查询方式有关.
4.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?
在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们.
慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
所以优化也是针对这三个方向来的,
-
首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写.
-
分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引.
-
如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表.
5.区别B树,B-,B+,B*?
- B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
- B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点; 所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
- B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
- B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3;
6.MySQL优化策略?
- 开启查询缓存,优化查询
- explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的
- 当只要一行数据时使用limit 1,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据
- 为搜索字段建索引
- 使用 ENUM 而不是 VARCHAR,如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是VARCHAR。
- Prepared StatementsPrepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击
- 垂直分表
- 选择正确的存储引擎
7.key和index的区别?
- key 是数据库的物理结构,它包含两层意义和作用,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary key, unique key, foreign key 等
- index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间)以一个类似目录的结构存储。索引要分类的话,分为前缀索引、全文本索引等;
8.怎么验证 mysql 的索引是否满足需求?
- 使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
- explain 语法:explain select * from table where type=1。
事务相关
1.ACID是什么?可以详细说一下吗?
- A=Atomicity原子性,就是上面说的,要么全部成功,要么全部失败.不可能只执行一部分操作.
- 系统(数据库)总是从一个一致性的状态转移到另一个一致性的状态,不会存在中间状态.
- 隔离性: 通常来说:一个事务在完全提交之前,对其他事务是不可见的.注意前面的通常来说加了红色,意味着有例外情况.
- 持久性,一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果.
2.同时有多个事务在进行会怎么样呢?
多事务的并发进行一般会造成以下几个问题:
-
脏读: A事务读取到了B事务未提交的内容,而B事务后面进行了回滚.
-
不可重复读: 当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作.
-
幻读: A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据.造成\”幻觉\”.
3.怎么解决这些问题呢?MySQL的事务隔离级别了解吗?
MySQL的四种隔离级别如下:
- READ UNCOMMITTED(未提交读)
- 这就是上面所说的例外情况了,这个隔离级别下,其他事务可以看到本事务没有提交的部分修改.因此会造成脏读的问题(读取到了其他事务未提交的部分,而之后该事务进行了回滚).
- 这个级别的性能没有足够大的优势,但是又有很多的问题,因此很少使用.
READ COMMITTED(已提交读)
- 其他事务只能读取到本事务已经提交的部分.这个隔离级别有 不可重复读的问题,在同一个事务内的两次读取,拿到的结果竟然不一样,因为另外一个事务对数据进行了修改.
REPEATABLE READ(可重复读)
- 可重复读隔离级别解决了上面不可重复读的问题(看名字也知道),但是仍然有一个新问题,就是 幻读,当你读取id> 10 的数据行时,对涉及到的所有行加上了读锁,此时例外一个事务新插入了一条id=11的数据,因为是新插入的,所以不会触发上面的锁的排斥,那么进行本事务进行下一次的查询时会发现有一条id=11的数据,而上次的查询操作并没有获取到,再进行插入就会有主键冲突的问题.
SERIALIZABLE(可串行化)
- 这是最高的隔离级别,可以解决上面提到的所有问题,因为他强制将所以的操作串行执行,这会导致并发性能极速下降,因此也不是很常用.
4.Innodb使用的是哪种隔离级别呢?
- InnoDB默认使用的是可重复读隔离级别.
5.对MySQL的锁了解吗?
- 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制.
6.MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了?
从锁的类别上来讲,有共享锁和排他锁.
-
共享锁: 又叫做读锁. 当用户要进行数据的读取时,对数据加上共享锁.共享锁可以同时加上多个.
-
排他锁: 又叫做写锁. 当用户要进行数据的写入时,对数据加上排他锁.排他锁只可以加一个,他和其他的排他锁,共享锁都相斥.
用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的. 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以.
锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁.
他们的加锁开销从大到小,并发能力也是从大到小.
7.行级锁定的优点缺点?
- 优点:
当在许多线程中访问不同的行时只存在少量锁定冲突。
-
回滚时只有少量的更改
-
可以长时间锁定单一的行。
缺点:
- [ul]
比页级或表级锁定占用更多的内存。
-
当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。
-
如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。
-
用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。
[/ul]
8.说一下 mysql 的行锁和表锁?
- MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
-
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。
表设计相关
1. 为什么要尽量设定一个主键?
- 主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键.设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全.
2.主键使用自增ID还是UUID?
- 推荐使用自增ID,不要使用UUID.因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降.
补充:
- 关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键.
3. 字段为什么要求定义为not null?
- null值会占用更多的字节,且会在程序中造成很多与预期不符的情况.
4.varchar(10)和int(10)代表什么含义?
- varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示.
5.建表策略?
-
对于大数据字段,独立表进行存储,以便提高性能(例如:简介字段);
-
使用varchar类型代替char,因为varchar会动态分配长度,char指定长度是固定的;
-
给表创建主键,对于没有主键的表,在查询和索引定义上有一定的影响;
-
避免表字段运行为null,建议设置默认值(例如:int类型设置默认值为0)在索引查询上,效率立显;
-
建立索引,最好建立在唯一和非空的字段上,建立太多的索引对后期插入、更新都存在一定的影响(考虑实际情况来创建);
存储引擎相关
1. MySQL支持哪些存储引擎?
- MySQL支持多种存储引擎,比如InnoDB,MyISAM,Memory,Archive等等.在大多数的情况下,直接选择使用InnoDB引擎都是最合适的,InnoDB也是MySQL的默认存储引擎.
2.InnoDB和MyISAM有什么区别?
-
InnoDB支持事物,而MyISAM不支持事物
-
InnoDB支持行级锁,而MyISAM支持表级锁
-
InnoDB支持MVCC, 而MyISAM不支持
-
InnoDB支持外键,而MyISAM不支持
-
InnoDB不支持全文索引,而MyISAM支持。
3.什么是存储过程?有哪些优缺点?
存储过程是一些预编译的SQL语句。1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全
但是,在互联网项目中,其实是不太推荐存储过程的,比较出名的就是阿里的《Java开发手册》中禁止使用存储过程,我个人的理解是,在互联网项目中,迭代太快,项目的生命周期也比较短,人员流动相比于传统的项目也更加频繁,在这样的情况下,存储过程的管理确实是没有那么方便,同时,复用性也没有写在服务层那么好.
4.说一说三个范式?
- 第一范式: 每个列都不可以再拆分.
- 第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分.
- 第三范式: 非主键列只依赖于主键,不依赖于其他非主键.
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由.比如性能. 事实上我们经常会为了性能而妥协数据库的设计.