Java基础总结大全

概念

1、什么是面向对象?

万物皆对象,把现实中有共同特性行为的对象抽象成类,类是程序中最基本的单位。

2、类和对象

面向对象的思想是如何在java展现的呢? 就是通过类和对象

*类是 一组相关的属性和行为的集合。是一个抽象的概念。

*对象 是该类事物的具体表现形式。具体存在的个体。

类是对象的抽象,对象是类的实例。

*成员变量 事物的属性

*成员方法 事物的行为

3、java是如何实现跨平台的?

Java的跨平台是通过Java虚拟机JVM来实现的。不同的平台需要安装不同的虚拟机,java程序编译之后的代码不是能被硬件系统直接运行的代码,而是一种“中间码”——字节码。然后不同的硬件平台上安装有不同的Java虚拟机(JVM),由JVM来把字节码再“翻译”成所对应的硬件平台能够执行的代码。

4、JRE,JDK和JVM之间的关系

JDK包含JRE,JRE包含JVM

JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。所有的Java 程序都要在JRE下才能运行。普通用户只需要运行已开发好的java程序,安装JRE即可。

JDK(Java Development Kit)是程序开发者用来来编译、调试java程序用的开发工具包。JDK的工具也是Java程序,也需要JRE才能运行。jre是jdk的一部分。为了保持JDK的独立性和完整性,在JDK的安装过程中,JRE也是 安装的一部分。所以,在JDK的安装目录下有一个名为jre的目录,用于存放JRE文件。

JVM(JavaVirtualMachine,Java虚拟机)是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。

5、GC是什么? 为什么要有GC

   GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。

6、面向对象的特征有哪些方面

   主要有以下四方面:

1.抽象:抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处。抽象包括两个方面,一是过程抽象,二是数据抽象。

2.继承:子类继承父类,子类共享父类属性和方法的同时可以扩展自己的属性和方法。提高了软件的可重用性和可扩展性                      。

3.封装:把对象的属性和方法结合成一个整体,并隐藏内部的实现细节,提供对外的访问接口。

4. 多态性:不同对象对同一消息做出不同的响应处理,主要实现:子类继承父类,子类重写父类的方法,父类的引用指向子类的对象。

 7、对象和面向过程的区别

面向过程

       优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

       缺点:没有面向对象易维护、易复用、易扩展

面向对象

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

       缺点:性能比面向过程低

语法

7、作用域public,private,protected,以及不写时的区别

   区别如下:

作用域           当前类       同一package  子孙类       其他package

public            √              √          √             √

protected         √              √           √            ×

friendly          √              √           ×            ×

private           √              ×           ×            ×

不写时默认为friendly

8、&和&&的区别

   &:”与”是位运算符,表示按位与运算,左边是false右边还执行。&&:”并且”是逻辑运算符,表示逻辑与(and),左边是true右边才执行

9、什么时候用assert

   assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion检查通常是关闭的

       默认是关闭的,一般是测试的junit中用,判断结果和自己的预想值是否一致。

10、Java有没有goto

   java中的保留字,现在没有在java中使用

11、是否可以继承String类

   String类是final类故不可以继承,final是最终的。

12、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后

   会执行,在return前执行

13、用最有效率的方法算出2乘以8等於几

   2 << 3:表示2向左移3位,因为一个数左移 n位,就相当于 2的 n次方,那么一个数乘以 8只要将其左移 3位即可,而为运算符的效率最高,所以 2乘以 8等于几的最有效方法是 2<<3

14、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

   不对,有相同的hash code,因为equals比较hash code值相同才会返回true

15、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递

   是值传递。Java 编程语言只有值传递参数。

*值传递:是对所传递参数进行一次副本拷贝,对参数的修改只是对副本的修改,函数调用结束,副本丢弃,原来的变量不变(即实参不变),基本数据类型都是值传递。

*引用传递:参数被传递到函数时,不复制副本,而是直接将参数自身传入到函数,函数内对参数的任何改变都将反映到原来的变量上。

*对于基本类型,传递的是基本类型的值,而对于引用类型传递的是地址。

16、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上

   在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

17、String、StringBuffer和StringBuilder区别

String 是被final修饰的,长度是不可变的。StringBuffer和StringBuilder长度都是可变的

三者在执行速度方面的比较:StringBuilder > StringBuffer > String

如果要操作少量的数据用 String

单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

StringBuffer是线程安全的有锁,StringBuilder是线程不安全的,string是线程安全的因为final最终的。如果最后需要String,那么使用StringBuffer的toString()方法

18、谈谈final, finally, finalize的区别

   final—用于声明属性、类和方法,分别表示属性不可变,方法不可覆盖(重写),类不可被继承

finally—是异常处理语句结构的一部分,表示总是执行

finalize—是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法用于回收资源,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等

19、heap和stack有什么区别

   栈是一种线形集合,其添加和删除元素的操作应在同一段完成。栈按照先进后出的方式进行处理。栈是堆得组成元素,内存由堆,栈,池组成。堆是按照先进先出的原则。栈的空间由系统自动分配,堆的空间可以自己分配。

栈相当于你往泡菜坛子里装泡菜,从里面拿泡菜,先拿到的当然是上面的。也就是先进后出。堆(队列)相当于一个隧道,火车往里面开,不能回头,头先进去当然也先出来,这叫先进先出。

20、垃圾回收的优点和原理。并考虑2种回收机制

   Java语言中一个显著的特点就是引入了垃圾回收机制,垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。

对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。

回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

*分代复制垃圾回收:根据对象的生命周期不同,分为年轻代、年老代、持久代,分区回收。

*标记垃圾回收:一、标记阶段,标记所有可访问对象;二、收集阶段,标记垃圾回收算法回收首页未标记的对象,在此过程中会出现程序无响应。

*增量垃圾回收:主要是为了解决标记垃圾回收时长停顿的问题,设置GC最多中断的时间10ms,分时间段来回收垃圾。

21、描述一下JVM加载class文件的原理机制?

   JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。

1.装载:查找和导入class文件;new对象隐式装载,反射类显示装载,看log日志就知道什么是隐式/显式

2.连接:

      (1)检查:检查载入的class文件数据的正确性;

      (2)准备:为类的静态变量分配存储空间;

      (3)解析:将符号引用转换成直接引用(这一步是可选的)

3.初始化:初始化静态变量,静态代码块。

      这样的过程在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。

22、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

   可以。只有一个public类,并且类名与文件名相同。

23、java中会存在内存泄漏吗,请简单描述。

内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。

   会。长生命周期的对象持有短生命周期对象的引用就有可能发生内存泄露。比如像加载了一个对象放在缓存中而一直没有引用。

24、内存溢出和内存泄漏的区别

系统已经不能再分配出你所需要的空间,比如你需要100M的空间,系统只剩90M了,这就叫内存溢出。

内存泄露是对象没有引用的时候没有被回收,一直占据着内存。

25、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收

   对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

26、如何避免内存泄漏、溢出

1、尽早释放无用对象的引用
好的办法是使用临时变量的时候,让引用变量在推出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄漏。

2、程序进行字符串处理时,尽量避免使用String,而应该使用StringBuffer。
因为String类是不可变的,每一个String对象都会独立占用内存一块区域。

3、尽量少用静态变量
因为静态变量是全局的,存在方法区,GC不会回收。(用永久代实现的方法区,垃圾回收行为在这个区域是比较少出现的,垃圾回收器的主要目标是针对常量池和类型的卸载)

4、避免集中创建对象,尤其是大对象,如果可以的话尽量使用流操作
JVM会突然需要大量neicun,这时会出发GC优化系统内存环境

5、尽量运用对象池技术以提高系统性能
生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

6、不要在经常调用的方法中创建对象,尤其忌讳在循环中创建对象
可以适当的使用hashtable,vector创建一组对象容器,然后从容器中去取这些对象,而不用每次new之后又丢弃。

7、优化配置

Java 内存溢出java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因:JVM内存过小、程序不严密,产生了过多的垃圾。

导致OutOfMemoryError异常的常见原因有以下几种:

内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

代码中存在死循环或循环产生过多重复的对象实体;

使用的第三方软件中的BUG;

启动参数内存值设定的过小;

一、增加jvm的内存大小。方法有:

1)在执行某个class文件时候,可以使用java -Xmx256M aa.class来设置运行aa.class时jvm所允许占用的最大内存为256M。

2)对tomcat容器,可以在启动时对jvm设置内存限度。对tomcat,可以在catalina.bat中添加:

set CATALINA_OPTS=-Xms128M -Xmx256M

set JAVA_OPTS=-Xms128M -Xmx256M

或者把%CATALINA_OPTS%和%JAVA_OPTS%代替为-Xms128M -Xmx256M

3)对resin容器,同样可以在启动时对jvm设置内存限度。在bin文件夹下创建一个startup.bat文件,内容如下:

@echo off

call "httpd.exe"  "-Xms128M" "-Xmx256M"

:end

其中"-Xms128M"为最小内存,"-Xmx256M"为最大内存。

27、静态变量和实例变量的区别?

   static i = 10; //常量   class A a;  a.i =10;//可变

1)在语法定义上的区别:静态变量前要加 static 关键字,而实例变量(成员变量)前则不加。

2)在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。

28、是否可以从一个static方法内部发出对非static方法的调用?

   不可以,如果其中包含对象的method();不能保证对象初始化.

29、写clone()方法时,通常都有一行代码,是什么?

java赋值是复制对象引用,如果我们想要得到一个对象的副本,就需要使用克隆clone()

   Clone 有缺省行为,super.clone();他负责产生正确大小的空间,并逐位复制。

类使用克隆:

①    实现Cloneable接口,这是一个标记接口,自身没有方法。

②    对象.clone()方法得到克隆对象,Person p1=new Person();Person p2=(Person) p1.clone();

30、在JAVA中,如何跳出当前的多重嵌套循环?

   用break; return 方法。

31、说出一些常用的类,包,接口,请各举5个

   常用的类:BufferedReader  BufferedWriter  FileReader  FileWirter  String  Integer

常用的包:java.lang  java.awt  java.io  java.util  java.sql

常用的接口:Remote  List  Map  Document  NodeList

32、什么是值传递,什么是引用传递?

*值传递:是对所传递参数进行一次副本拷贝,对参数的修改只是对副本的修改,函数调用结束,副本丢弃,原来的变量不变(即实参不变),基本数据类型都是值传递。

*引用传递:参数被传递到函数时,不复制副本,而是直接将参数自身传入到函数,函数内对参数的任何改变都将反映到原来的变量上。

33、一个javabean的生命周期

加载、验证、准备、初始化、引用和卸载这六个过程

加载类,验证语法,准备(分配内存),初始化(父子类构造函数,赋值),引用,卸载(垃圾回收)

34、a++、++a、a+=1和a=a+1?

a += 1这个和 a = a +1 这两个是一样的 只不过一个是简写

++a  和   a++  这两个区别在于运算的先后 

比如:

   b = ++a;   这个是a先自增 然后才赋值   

b = a++; 这个是先赋值 后自增

35、简述Objiect类的几个方法

①clone():protected Object clone()创建并返回此对象的一个副本。

②equals():boolean equals(Object obj)指示其他某个对象是否与此对象“相等”。

③finalize():protected void finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

④getClass():Class<?> getClass()返回此 Object 的运行时类。

⑤hashCode():int hashCode()返回该对象的哈希码值。

⑥notify():void notify()唤醒在此对象监视器上等待的单个线程。

⑦notifyAll():void notifyAll()唤醒在此对象监视器上等待的所有线程。

⑧toString():String toString()返回该对象的字符串表示。

⑨wait():void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。

void wait(long timeout, int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。

36、装箱和拆箱

装箱:将值类型转换为引用类型的过程称为装箱。int i=1; Object o=i

拆箱:将引用类型转换为值类型称为拆箱。int j=(int)o;

37、三种流程控制结构

*顺序结构:从上往下,依次执行

*选择结构:if—else结构、switch结构

*循环结构:while、do while、for循环

38、不同类型的参数传递值的变化

值类型:8大数据类型

引用类型:数组、类、字符串、接口等

以值传递方式传递值类型参数时,对它的修改不会保留;以值传递方式传递引用类型参数时,其值的修改会保留。

以引用传递方式传递值类型参数和引用类型参数时,其值的修改都会保留。

java中会自动区分参数类型,因此没有ref,因此没有引用传递方式。

39、实体类关系图

*矩形表示实体

*椭圆表示属性

*菱形表示联系

*直线用来连接

数据类型

40、String是最基本的数据类型吗?

   基本数据类型包括整数型4种:byte(1字节8位)、short(2字节16位)、int(4字节32位)、long(8字节64位);浮点型2种:float(4季节32位)、double(8字节64位);布尔型一种:boolean(1字节8位);字符型一种:char(2字节16位)。

       1字节=8位=8bit  1个汉子=2字节  这里的位是指二进制的位数

java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类

41、int 和 Integer 有什么区别

   Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。int是java的原始数据类型初始值是0,Integer是java为int提供的封装类,初始值是null。Java为每个原始类型提供了封装类,8大数据类型首字母大写就是封装类。

42、数组有没有length()这个方法? String有没有length()这个方法

   数组没有length()这个方法,有length的属性。String有length()这个方法

43、String s = new String("xyz");创建了几个String Object

   两个,一个字符对象,一个字符对象引用对象

44、Math.round(11.5)等於多少? Math.round(-11.5)等於多少

答:  Math.round(11.5)==12;Math.round(-11.5)==-11;round方法返回与参数最接近的长整数,参数加1/2后求其floor

45、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错

   short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型会报错)short s1 = 1; s1 += 1;(可以正确编译)自动转型小转大,大转小必须强制转型

i=i+2 比 i+=2多了一次对变量 i 的运算。i=i+2是先进行i+2的运算得出一个结果,再赋值给i。i+=2就是先赋值然后在进行加法,因此运算效率高,结果是一样的。

46、char型变量中能不能存贮一个中文汉字?为什么?

   是能够定义成为一个中文的,因为java中以unicode编码,一个char占16个字节,所以放一个中文是没问题的

47、float型float f=3.4是否正确?

答:不正确。精度不准确,有小数点的默认是double,应该用强制类型转换,如下所示:float f=(float)3.4或float f=3.4f

异常

48、error和exception有什么区别

   error 是不可控制的unchecked,用来表示系统错误或底层资源错误,如果有可能应该在系统级别被捕捉

exception 是可控的或不可控的(黑客攻击),表示程序级的错误,应该在程序级别被捕捉

49、给我一个你最常见到的runtime exception

1、空指针异常类:NullPointerException

2、数据类型转换异常:java.lang.ClassCastException

3、没有访问权限:java.lang.IllegalAccessException

4、方法的参数错误:java.lang.IllegalArgumentException

5、数组下标越界异常:java.lang.IndexOutOfBoundsException

6、文件已结束异常:EOFException

7、文件未找到异常:FileNotFoundException

8、字符串转换为数字异常:NumberFormatException

9、指定的类不存在: java.lang.ClassNotFoundException

10、实例化异常:java.lang.InstantiationException

50、运行时异常与一般异常有何异同

   异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。

出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run() 抛出 ,如果是单线程就被 main() 抛出 。

51、Java中的异常处理机制的简单原理和应用

原理:有错直接转到异常处理部分或向上抛出。

应用:JAVA 的异常就是错误,有两种一种是运行时,编码可以不用捕捉。一种是一般异常,如果throws 声明了,必须进行处理。

   当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。

52、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?

   Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理。

用try来指定一块预防所有"异常"的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的"异常"的类型。

throw语句用来明确地抛出一个"异常"。

throws用来标明一个成员函数可能抛出的各种"异常"。

Finally为确保一段代码不管发生什么"异常"都被执行一段代码。

可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,"异常"的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种"异常"进行处理,堆栈就会展开,直到遇到有处理这种"异常"的try语句。

53、日志

1. 常用的日志框架

①Java Logging API(Oracle)—— Java默认的日志框架

②Log4j(Apache)——开源日志框架

③Logback(Logback Project)——开源项目,被设计成Log4j版本1的后续版本

④tinylog(tinylog)——轻量级开源logger

log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。

ALL 最低等级的,用于打开所有日志记录。

TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。

DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。

INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。

WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。

ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。

FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。

OFF 最高等级的,用于关闭所有日志记录。

反射机制

53、什么是反射?

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

54、 哪里用到反射机制?

JDBC中,利用反射动态加载了数据库驱动程序。

Web服务器中利用反射调用了Sevlet的服务方法。

Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。

很多框架都用到反射机制,注入属性,调用方法,如Spring。

55、反射机制的优缺点?

优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。

缺点:对性能有影响,这类操作总是慢于直接执行java代码。

56、 动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。

动态代理的应用有 Spring AOP数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。

57、 怎么实现动态代理?

JDK 原生动态代理(发射机制)和 cglib 动态代理。

JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。

58、Java反射机制的作用

在运行时判断任意一个对象所属的类

在运行时构造任意一个类的对象

在运行时判断任意一个类所具有的成员变量和方法

在运行时调用任意一个对象的方法

59、获得一个类的类对象有哪些方式?

答:

- 方法1:类型.class,例如:String.class

- 方法2:对象.getClass(),例如:"hello".getClass()

- 方法3:Class.forName(),例如:Class.forName("java.lang.String")

60、如何通过反射创建对象?

答:

- 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()

- 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance("Hello");

61、如何通过反射获取和设置对象私有字段的值?

答:可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。

数组与集合

62、什么是数组?什么是集合?

数组是一种数据类型,即引用类型。数组是相同数据类型元素的集合。数组长度固定。

集合用来存放一组相同类型的对象,长度可变。

63、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?

Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。

Array大小是固定的,ArrayList的大小是动态变化的。

ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

64、集合和数组的转换?

list、set可以使用toArray()方法返回一个Obiect数组。数组转list可以使用Arrays.aslist()得到一个list,再用list构造set(强转)。

65、list和map的转换

得到key的集合,List<String> result = new ArrayList(map.keySet());

得到values的集合,List<String> result2 = new ArrayList(map.values());

list转map没有意义,不是键值对。

66、Collection 和 Collections的区别

   Collection是集合类的上级接口,继承与他的接口主要有Set 和List.

Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作

67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别

   Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等

equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值 

68、List, Set, Map是否继承自Collection接口

List,Set是,Map不是,

Map是一个独立的接口

AbstractMap<K,V> implements Map<K,V>

HashMap<K,V> extends AbstractMap<K,V>

69、ArrayList和Vector的区别,HashMap和Hashtable的区别

   就ArrayList与Vector主要从二方面来说.

一.同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的

二.数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半

就HashMap与HashTable主要从三方面来说。

一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现

二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的

三.值:只有HashMap的key或value可以为空值

70、介绍JAVA中的Collection FrameWork(包括如何写自己的数据结构)?

   Collection FrameWork如下:

Collection

├List 有序,可重复

│├LinkedList 底层数据结构是链表,查询慢,增删快,线程安全

│├ArrayList 底层数据结构是数组,查询快,增删慢,非线程安全

│└Vector 底层数据结构是数组,查询快,增删慢,线程安全

│ └Stack 栈类,先进后出

└Set 无序,唯一

│├HashSet 底层数据结构是哈希表,哈希表结合了数组的快速查询的优点又能融合链表方便快捷的增加删除元素的优势。线程不安全,在HashSet中,底层源码,其实就是一个HashMap,HashMap的key为HashSet中的值,而value为一个Object对象常量。

*哈希表依赖两个方法hashcode()和equals(),首先判断hasdcode()是否相同,是:继续执行equals(),是true说明元素重复不添加,false添加到集合

│├LinkedHashSet 底层数据结构由哈希表和链表组成,由链表保证元素有序性,由哈希表保证元素唯一性。非线程安全

│├CopyOnWriteArraySet 底层数据结构是数组,CopyOnWriteArraySet是利用CopyOnWriteArrayList来实现的,因为CopyOnWriteArrayList是线程安全的,所以 CopyOnWriteArraySet操作也是线程安全的

Map

├Hashtable 底层数据结构是哈希表,线程安全的,效率低,不允许空值,无序

├HashMap 底层数据结构是哈希表,线程不安全,效率高,允许空值,无序

└linkedHashMap 底层数据由哈希表+链表组成,由链表保证元素有序,哈希保证元素唯一,非线程安全

arrayList初始长度是10,hashMap初始长度是16

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)

Collections是集合的算法

71、说出ArrayList,Vector, LinkedList的存储性能和特性

   ArrayList,Vector底层数据结构都是数组,查询快,增删慢。ArrayList线程不安全,Vector线程安全但是效率慢。LinkedList线程安全,底层数据结构是链表,查询慢,增删快。

72、HashMap和Hashtable的区别

   HashMap和Hashtable底层数据结构都是哈希表。HashMap线程非安全,可以允许空值,效率高。HashTable线程安全,效率低。

73、你所知道的集合类都有哪些?主要方法?

   最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。

Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作"键"和"值"),其中每个键映射到一个值。通过map.entrySet().iterator()或map.keySet().iterator()来获取迭代器(iterator).hasNext()遍历元素。

74、List、Map、Set三个接口,存取元素时,各有什么特点?

   List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。

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

因为ArrayList的底层是数组实现,并且数组的默认值是10,如果插入10000条要不断的扩容,耗费时间,所以我们调用ArrayList的指定容量的构造器方法ArrayList(int size) 就可以实现不扩容,就提高了性能。

多态(接口与抽象类)

75、abstract class和interface有什么区别

       1:抽象类用abstract关键字,接口用interface

       2:接口只能定义方法,抽象类不仅可以定义抽象方法,还可以有实现方法

3:抽象类只能单一继承,接口可以被多重实现

   抽象定义的类叫抽象类,抽象类字段默认friendly(本包可见),用abstract关键字定义抽象类和抽象方法。

    4:抽象层次不同,抽象类是对类抽象,而接口是对行为的抽象。

抽象方法没有主体,有抽象方法的一定是抽象类。抽象类不一定必须有抽象方法,抽象类可以定义和实现。抽象类只能被单一继承extends。抽象类抽象方法不能使用private,因为不能被子类继承。抽象方法不能使用static,因为方法没有主体没有意义。

接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。接口可以被多重实现implements,接口的字段默认为public static final。instanceof 运算符可以用来决定某对象的类是否实现了接口

当存在继承关系时用抽象类,只需要使用单一功能用接口。

   *抽象类与接口都用于抽象,但是抽象类(JAVA中)可以有自己的部分实现,而接口则完全是一个标识(同时有多重继承的功能)。

Collection框架中实现比较要实现Comparable 接口和 Comparator 接口,这两个接口用于排序

76、抽象类abstract的方法method是否可同时是static,是否可同时是native,是否可同时是synchronized

   都不能,abstract是没有被实现的,而static一定要被实现的。Synchronized是需要同步的,abstract只有被子类继承的时候才能添加同步。Native本地方法,它把具体的实现交给了本地的函数库,没有通过虚拟机,是java与其他语言通信的一种机制。与抽象方法把实现交给子类实现冲突。

77、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)

   接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是抽象类必须能访问实体类的构造方法,子类默认调用父类的构造函数。如果实体了申明了一个private 的无参构造函数,则系统不会自动生成该类的无参构造函数,因此抽象类访问不到实体类的构造函数而编译失败。

78、构造器Constructor是否可被override

   构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading(有参、无参、多参的构造函数)

79、Overload和Override的区别。

Overloaded的方法是否可以改变返回值的类型

方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。

子类重写父类的方法,方法名、参数类型个数、返回值类型必须相同。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。发生在继承类中,被重写的方法不能有更高的权限。

如果在一个类中定义了多个同名的方法,方法名相同,参数类型或个数不同,返回值的类型也可以不同。则称为方法的重载(Overloading)。发生在同一个类中,一般用于构造函数,对权限没有要求。

80、 匿名内部类(Anonymous Inner Class) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)

   匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现

81、Java的接口和C++的虚类的相同和不同处

   由于Java不支持多继承,而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性,现有的单继承机制就不能满足要求。与继承相比,接口有更高的灵活性,因为接口中没有任何实现代码。当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。

82、java中实现多态的机制是什么?

   方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。

多线程

83、为什么要使用多线程?

1发挥多核CPU的优势,类似与食堂多个窗口打饭

2防止阻塞,四车道与单车道的比较

3便于建模,可以把先后顺序关联性不强的任务拆分成几个同步进行,提高效率。比如在生成一个汽车骨架的时候,相应的其他零件也在同步生成,最后组装。

84、java实现多线程的几种方式

1、继承Thread类,重写run方法

2、实现Runnable接口

3、通过Callable和FutureTack创建线程

4、通过线程池创建线程

知道前面两种即可,相比实现Runnable接口更快捷,一Java支持单继承,继承Thread类就不能集成其他类,继承扩展性被占,二线程可能只要求可执行即可,Thread类相比开销过大。

85、说说进程,线程,协程之间的区别?

简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程.进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高.

线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位.同一进程中的多个线程之间可以并发执行.

86、你了解守护线程吗?它和非守护线程有什么区别

程序运行完毕,jvm会等待非守护线程完成后关闭,但是jvm不会等待守护线程.守护线程最典型的例子就是GC线程

87、什么是多线程上下文切换

多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。

88、wait()和sleep()的区别?

1)Sleeep来自Thread类,wait()来自Object类。

2)调用sleep()过程中,线程不会释放对象锁,wait()方法会释放。

3)sleep()睡眠后不让出系统资源,wait()让出资源

4)sleep(millssecond)需要指定一个睡眠时间,时间一到会自动唤醒

89、start()方法和run()方法的区别

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。

90、什么是线程安全和线程不安全?

通俗的说:加锁的就是是线程安全的,不加锁的就是是线程不安全的

线程安全: 就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

91、什么是乐观锁和悲观锁?

1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。

2)悲观锁:还是像它的名字一样,对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。

92、什么是CAS

CAS,全称为Compare and Swap,即比较-替换。假设有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为B并返回true,否则什么都不做并返回false。

93、线程的生命周期

新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。

*新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值

*就绪状态,当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行

*运行状态,如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态

*阻塞状态,当处于运行状态的线程失去所占用资源之后,便进入阻塞状态

*死亡状态,线程在run()方法执行结束后进入死亡状态。此外,如果线程执行了interrupt()或stop()方法,那么它也会以异常退出的方式进入死亡状态。

94、Java中实现线程阻塞的方法

(1)线程睡眠:Thread.sleep (long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

(2)线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait() 一样。wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用.

(3)线程礼让,Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.

(4)线程自闭,join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

95、什么是死锁

       死锁是指两个以上的进程在执行过程中,由于竞争资源或通信造成的一种阻塞现象,若无外力作用,它们将无法推行下去。

96、产生死锁的条件

1.互斥条件:一个资源每次只能被一个进程使用。

2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

97、如何避免死锁

1、不让产生死锁的四个条件同时成立

2、合理分配资源

3、使用银行家算法,如果该进程请求的资源当前操作系统余量可以满足,就分配

98、线程间的通信方式

(1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。

(2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。

(3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。

(4)消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺

(5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。

(6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。

(7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

(8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

99、java常见的几种锁?

1)自旋锁:自旋锁顾名思义,它会等待一定时间(自旋),在这期中会什么都不做就是等资源被释放,好处在于没有了内核态用户态切换的效率损失,但是如果它一直不能访问到资源的话就会一直占用cpu资源,所以它会循环一段时间后进入阻塞状态。

重量级锁:synchronized就是重量级锁的实现机制,抢不到资源的进程会进入阻塞状态

2)偏向锁:顾名思义,它会偏向第一个访问资源的进程,如果说只有一个进程执行同步代码块,那么就会上个偏向锁,如果有其他线程抢占资源,那么就会升级为轻量级锁

轻量级锁:偏向锁升级之后就是轻量级锁,锁只可以升级而不可以降级。轻量级锁中的其他进程会进入自选状态,如果说自选失败,就会升级会重量级锁

3)公平,非公平锁:主要是指线程是否先来后到拿到锁,synchronized是非公平的,而ReentrantLock默认非公平,可以设置为公平锁

4)悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

5)乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制(数据库中)和CAS算法实现

100、线程的sleep()和yield()方法有什么区别?

 1)sleep()给其它线程运行机会不会考虑线程优先级,yield()只会给相同优先级或更高优先级的线程机会

 2)线程执行sleep()方法后进入阻塞状态,而执行yeild()进入就绪状态

 3)sleep()方法需要抛出异常interupdateException,而yeild()不用抛异常

 4)sleep()比yield()有更好的移植性

101、如何设置线程的优先级

线程. setPriority()方法来设置线程的优先级,参数是1~10,默认是5。优先级和线程抢到资源的概率没有关系。结合yeild()就有用了。

102、多线程使用

1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。

2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。鉴于你是做WEB的,第1点可能你几乎不涉及。那这里我就讲第二点吧。--举个简单的例子:假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询),那么正常的顺序可能是(括号里面代表执行时间):

a、读取文件1 (10ms)

b、处理1的数据(1ms)

c、读取文件2 (10ms)

d、处理2的数据(1ms)

e、读取文件3 (10ms)

f、处理3的数据(1ms)

如果做 java web 方面开发的话几乎用不到多线程!因为有多线程的地方 servlet 容器或者其他开发框架都已经实现掉了!

一般在网络应用程序中使用多线程的地方非常多!

另外,你说的拷贝文件使用多线程,那是没有用的!以多线程来提高效率的场景一般在 CPU 计算型,而不是在 IO 读写型。CPU 可以会有多个核心并行处理计算,但是磁盘 IO 就没这功能了,磁头只有一个,根本不可能靠多线程提高效率!

一般来说,磁盘 IO 的并发能力为 0,也就是说无法支持并发!网络 IO 的话由于带宽的限制的,使用多线程处理最多也只能达到带宽的极值。

对于磁盘 IO 来说,多线程可以用于一个线程专门用于读写文件,其他的线程用于对读取数据进行处理,这样才有可能更好地利用 CPU 资源。

如果仅仅是单纯的文件复制,使用多线程操作的话,会使用磁头在磁盘上不停地进行寻道操作,使得效率更为低下!

 

1.创建+执行+销毁线程>单线程时间

2.一个线程默认占用1M,内存销毁

3.频繁切换线程上下文影响性能

103、一个线程运行时发生异常会怎样?

如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler 是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理。

25、Synchronized 有哪几种用法?

锁类、锁方法、锁代码块。

27、线程数过多会造成什么异常?

线程过多会造成栈溢出,也有可能会造成堆异常。

28、说说线程安全的和不安全的集合。

Java 中平时用的最多的 Map 集合就是 HashMap 了,它是线程不安全的

看下面两个场景:

1、当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其他线程访问

不了,所以这时也不存在线程安全不安全的问题了。

2、当用在单例对象成员变量的时候呢?这时候多个线程过来访问的就是同一个

HashMap 了,对同个 HashMap 操作这时候就存在线程安全的问题了。

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

java.lang.Thread#holdsLock 方法

32、线程同步需要注意什么?

1、尽量缩小同步的范围,增加系统吞吐量。

2、分布式同步锁无意义,要使用分布式锁。

3、防止死锁,注意加锁顺序。

35、线程之间如何传递数据?

通 过 在 线 程 之 间 共 享 对 象 就 可 以 了 , 然 后 通 过 wait/notify/notifyAll 、

await/signal/signalAll 进行唤起和等待,比方说阻塞队列 BlockingQueue 就是为线程之

间共享数据而设计的

设计模式

102、java的设计模式

1)工厂模式:有一个专门的类负责创建实例的过程。

2)单例模式:一个类始终只能创建一个实例。

3)代理模式:一个对象代表另一个对象采取行动。是一种非常广泛的设计模式,例如hibernate中A对象管理B对象,加载A对象的时候先加载一个B的代理对象,只有在实际使用到B对象的时候才会加载B的实体。

4)观察模式:观察者模式定义了一对多关联依赖关系,让一个或多个对象观察一个主题对象。当主题对象发生变化时,系统通知所有的观察者对象自动更新。

103、懒汉模式和饿汉模式

懒汉模式:在类加载的时候不被初始化。

饿汉模式:在类加载时就完成了初始化,但是加载比较慢,获取对象比较快。

饿汉模式是线程安全的,在类创建好一个静态对象提供给系统使用,懒汉模式在创建对象时不加上synchronized,会导致对象的访问不是线程安全的

104、什么是高内聚低耦合?

高内聚低耦合是软件设计的一个基本原则,说的是在程序的各个模块中,尽量让每个模块独立,相关的处理尽量在单个模块中完成。优点:能提降低各模块的之间的联系,减少“牵一发而动全身”的几率,提高开发效率,降低升级维护成本,也便于进行单元测试,提高软件质量。

105、软件设计的六大设计原则?

1)单一职责原则:一个类值负责一个功能的职责

2)开闭原则:扩展开放,修改关闭。

3)里氏代换原则:使用父类的地方都能使用子类对象

4)依赖倒转原则:针对接口编程,

5)接口隔离原则:针对不同部分用专门接口,不用总接口,需要哪些接口就用哪些接口

6)迪米特法则: 软件实体类,尽量不与其他实体类发生关系相互作用,对外都统一的暴露接口就行了

许多的设计模式,包括一些框架,都是参考高内聚低耦合这个点的。

IO/NIO

106、问:简单说说你平时使用的 Java IO 流中涉及到了哪些设计策略和设计模式?

答:首先 Java 的 IO 库提供了一种链接(Chaining)机制,可以将一个流处理器跟另一个流处理器首尾相接,以其中之一的输出作为另一个的输入而形成一个流管道链接,譬如常见的 new DataInputStream(new FileInputStream(file)) 就是把 FileInputStream 流当作 DataInputStream 流的管道链接。

其次,对于 Java IO 流还涉及一种对称性的设计策略,其表现为输入输出对称性(如 InputStream 和 OutputStream 的字节输入输出操作,Reader 和 Writer 的字符输入输出操作)和字节字符的对称性(InputStream 和 Reader 的字节字符输入操作,OutputStream 和 Writer 的字节字符输出操作)。

此外,对于 Java IO 流在整体设计上还涉及装饰者(Decorator)和适配器(Adapter)两种设计模式。

对于 IO 流涉及的装饰者设计模式例子如下:

//把InputStreamReader装饰成BufferedReader来成为具备缓冲能力的Reader。

BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

对于 IO 流涉及的适配器设计模式例子如下:

//把FileInputStream文件字节流适配成InputStreamReader字符流来操作文件字符串。

FileInputStream fileInput = new FileInputStream(file);

InputStreamReader inputStreamReader = new InputStreamReader(fileInput);

而对于上面涉及的两种设计模式通俗总结如下。

装饰者模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例(各种字符流间装饰,各种字节流间装饰)。

适配器模式就是将某个类的接口转换成我们期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题(字符流与字节流间互相适配)。

107、问:字节流与字符流有什么区别?

答:计算机中的一切最终都是以二进制字节形式存在的,对于我们经常操作的字符串,在写入时其实都是先得到了其对应的字节,然后将字节写入到输出流,在读取时其实都是先读到的是字节,然后将字节直接使用或者转换为字符给我们使用。由于对于字节和字符两种操作的需求比较广泛,所以 Java 专门提供了字符流与字节流相关IO类。

对于程序运行的底层设备来说永远都只接受字节数据,所以当我们往设备写数据时无论是字节还是字符最终都是写的字节流。字符流是字节流的包装类,所以当我们将字符流向字节流转换时要注意编码问题(因为字符串转成字节数组的实质是转成该字符串的某种字节编码)。

字符流和字节流的使用非常相似,但是实际上字节流的操作不会经过缓冲区(内存)而是直接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件。

108、问:什么是缓冲区?有什么作用?

答:缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能。

对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

109、问:字节流和字符流哪个好?怎么选择?

答:大多数情况下使用字节流会更好,而大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的)。

而如果对于操作需要通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能。

110、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?

   字节流,字符流。字节流继承于InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。

计算机中的底层一切最终都是二进制的字节形式存在。首先读取的是字节,然后用字符流读取字符,字符流只能处理字符或者字符串。字节流一般用于传输,字符用于读取字符。字节流可以用于任何类型的对象,包括二进制,但它不能直接处理unicode字符,字符流可以。

111、什么是java序列化,如何实现java序列化?

*序列化:把Java对象转换为字节序列的过程。

*反序列化:把字节序列恢复为Java对象的过程。

   序列化就是一种用来处理对象流的机制,把对象转换成字节流方便网络传输。

序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法。implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

泛型

112、Java中的泛型是什么 ? 使用泛型的好处是什么?

泛型,即“参数化类型”。创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。

Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

类型擦除的主要过程如下:

1).将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。

2).移除所有的类型参数。

113、 Java的泛型是如何工作的 ? 什么是类型擦除 ?

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List<String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。根据你对这个泛型问题的回答情况,你会得到一些后续提问,比如为什么泛型是由类型擦除来实现的或者给你展示一些会导致编译器出错的错误泛型代码。请阅读我的Java中泛型是如何工作的来了解更多信息。

114、什么是泛型中的限定通配符和非限定通配符 ?

限定通配符对类型进行了限制。有两种限定通配符,一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面<?>表示了非限定通配符,因为<?>可以用任意类型来替代。更多信息请参阅我的文章泛型中限定通配符和非限定通配符之间的区别。

115、 List<? extends T>和List <? super T>之间有什么区别 ?

这两个List的声明都是限定通配符的例子,List<? extends T>可以接受任何继承自T的类型的List,而List<? super T>可以接受任何T的父类构成的List。例如List<? extends Number>可以接受List<Integer>或List<Float>。在本段出现的连接中可以找到更多信息。

116、 如何编写一个泛型方法,让它能接受泛型参数并返回泛型类型?

编写泛型方法并不困难,你需要用泛型类型来替代原始类型,比如使用T, E or K,V等被广泛认可的类型占位符。泛型方法的例子请参阅Java集合类框架。最简单的情况下,一个泛型方法可能会像这样:

       public V put(K key, V value) {

               return cache.put(key, value);  

}

117、 你可以把List<String>传递给一个接受List<Object>参数的方法吗?

这样做的话会导致编译错误。因为List<Object>可以存储任何类型的对象包括String, Integer等等,而List<String>却只能用来存储Strings。

List<Object> objectList;

List<String> stringList;

objectList = stringList;

118、Array中可以用泛型吗?

Array不支持泛型,这也是List代替Array的一个原因,因为List可以提供编译期的类型安全保证,而Array却不能。

119、 如何阻止Java中的类型未检查的警告?

如果你把泛型和原始类型混合起来使用,例如下列代码,Java 5的javac编译器会产生类型未检查的警告,例如

List<String> rawList = new ArrayList()

算法

120、排序都有哪几种方法?请列举

     排序的方法有:插入排序(直接插入排序、希尔排序),交换排序(冒泡排序、快速排序),选择排序(直接选择排序、堆排序),归并排序,分配排序(箱排序、基数排序)

快速排序是一种常用的排序算法,比冒泡排序快很多。

**在快速排序中使用了大量的递归,快速排序的三个步骤:

1、选择基准值

2、将数组分成两个子数组;小于基准值的元素和大于基准值的元素

3、对这两个子数组进行快速排序(递归)

快速排序的速度取决于选择的基准值,运行速度记做 O(n longn ),大O表示法底数默认为2

**选择排序的数组位移在外层循环,而冒泡排序的位移在内循环。

121、旅行商算法

最慢的算法,有一个旅行商要到N个城市去旅游,希望计算出最短的路线。计算公式为n!=1×2×3×...×n。也就是n的阶乘。

XML与JSON

 

1、Xml与JSON区别

区别:

xml是重量级、json是轻量级

xml比较占带宽、json占带宽小,易于压缩

json在webservice 用的比较少、xml用的较多

相同:

两者都用在项目交互下  例如  移动app接口用的就是json、在web项目中与其他项目对接用xml较多。

json常用解析方法 gson、jsonobject、jackson等 xml dom sax pull 解析

框架

1、什么是dao模式

DAO模式的组成部分:

         1.DAO接口

         2.DAO实现类

         3.实体类

         4.数据库连接和关闭工具类

DAO模式的作用

         1.隔离业务逻辑代码和数据访问代码

         2.隔离不同数据库的实现

Spring MVC

122、什么是Spring MVC ?简单介绍下你对springMVC的理解?

Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

123、什么是轻量级

轻量级是指代码的侵入性,可以理解为框架与业务代码的耦合程度。SpringMVC是通过注解或外部文件进行配置的,不需要继承框架里的类或显示调用框架里的类或方法,因此是轻量级的。

123、SpringMVC的流程?

(1)用户发送请求至前端控制器DispatcherServlet;

(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,查找匹配该url 的handle,并返回一个执行链,没有则返回404

(3)DispatcherServlet 调用 HandlerAdapter处理器适配器返回ModelAndView;

(4)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析并返回视图View;

(5)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中),并把数据装入到request域,返回给用户

124、Springmvc的优点:

(1)可以支持各种视图技术,而不仅仅局限于JSP;

(2)与Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。

(4) 支持各种请求资源的映射策略。

125、Spring MVC的主要组件?

(1)前端控制器 DispatcherServlet(不需要程序员开发)

作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。

(2)处理器映射器HandlerMapping(不需要程序员开发)

作用:根据请求的URL来查找Handler

(3)处理器适配器HandlerAdapter

注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。

(4)处理器Handler(需要程序员开发)

(5)视图解析器 ViewResolver(不需要程序员开发)

作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)

(6)视图View(需要程序员开发jsp)

View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

126、springMVC和struts2的区别有哪些?

(1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。

(2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。

(3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。

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

(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

 

7、SpringMvc怎么和AJAX相互调用的?

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :

(1)加入Jackson.jar

(2)在配置文件中配置json的映射

(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。

128、如何解决POST请求中文乱码问题,GET的又如何处理呢?

(1)解决post请求乱码问题:

在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8;

(2)get请求中文参数出现乱码解决方法有两个:

①修改tomcat配置文件添加编码与工程编码一致,如下:

<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

②另外一种方法对参数进行重新编码:

String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。

129、Spring MVC的异常处理 ?

答:可以将异常抛给Spring框架,由Spring框架来处理;我们只需要配置简单的异常处理器,在异常处理器中添视图页面即可。

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

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

131、 SpringMVC常用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

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

答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。

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

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

134、怎样在方法里面得到Request,或者Session?

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

135、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?

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

 

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

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

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

答:返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

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

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

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

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

140、SpringMvc里面拦截器是怎么写的:

有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可:

  <!-- 配置SpringMvc的拦截器 -->

<mvc:interceptors>

    <!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 -->

    <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean>

    <!-- 只针对部分请求拦截 -->

    <mvc:interceptor>

       <mvc:mapping path="/modelMap.do" />

       <bean class="com.zwp.action.MyHandlerInterceptorAdapter" />

    </mvc:interceptor>

</mvc:interceptors>

 

141、注解原理:

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

Struts2

142、描述Struts2的执行流程

Struts 2框架本身大致可以分为3个部分:核心控制器FilterDispatcher、业务控制器Action和用户实现的企业业务逻辑组件。   1)核心控制器FilterDispatcher是Struts 2框架的基础,包含了框架内部的控制流程和处理机制。 

 2)业务控制器Action和业务逻辑组件是需要用户来自己实现的。用户在开发Action和业务逻辑组件的同时,还需要编写相关的配置文件,供核心控制器FilterDispatcher来使用。 

 Struts 2的工作流程相对于Struts 1要简单,与WebWork框架基本相同,所以说Struts 2是WebWork的升级版本。 

 

 基本简要流程如下:

 1)客户端浏览器发出HTTP请求。 

 2)根据web.xml配置,该请求被FilterDispatcher接收。 

 3)根据struts.xml配置,找到需要调用的Action类和方法, 并通过IoC方式,将值注入给Aciton。 

 4)Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证。 

 5)Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面。

 6)返回HTTP响应到客户端浏览器。

143、Struts2中的拦截器有什么用?列举框架提供的拦截器名称?(至少3种,可用中文名)

 1)拦截器是struts2核心组成部分,它提供了一种机制,使得开发者可以定义一个特定的功能模块,这个模块会在Action执行之前或者之后执行,也可以在Action执行之前阻止Action执行。 

 2)常用的拦截器有: 

 chain:在不同请求之间将请求参数在不同名字件转换,请求内容不变 

 fileUpload:提供文件上传。 

 ​i18n:记录用户选择的区域环境 

 logger:输出Action的名字

 params:将请求中的参数设置到Action中去。

144、Struts2有哪些优点?

 1)在软件设计上Struts2的应用可以不依赖于Servlet API和struts API。 Struts2的这种设计属于无侵入式设计; 

 2)拦截器,实现如参数拦截注入等功能;

 3)类型转换器,可以把特殊的请求参数转换成需要的类型; 

 4)多种表现层技术,如:JSP、freeMarker、Velocity等;

 5)Struts2的输入校验可以对指定某个方法进行校验;

 6)提供了全局范围、包范围和Action范围的国际化资源文件管理实现 

 7) 实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现。有丰富的tag可以用,大大提高了开发效率。(简要)

145、什么是OGNL,有什么用途?如何访问存放在session中叫user的对象的username属性

​ OGNL是Object-Graph Navigation Language的缩写,也叫对象导航语言。它是Struts的一种功能强大的表达式语言列如:访问session中的user对象的username属性:注意的是:使用前需要在页面头部导入taglib prefix="s" uri="/struts-tags"

​146、什么是国际化,struts2实现国际化的原理?

国际化是根据不同的国家和地区的语言文化的不同,所设计的适用于不同地区的编码格式。 

 实现方法: 

 1)首先在src目录下新建message_en.properties(英文); 

 2)页面获取国际化信息或者使用 

原理:程序得到当前运行环境的国际/区域,语言环境并存放于Locale,ResourceBundle根据Locale中信息自动搜索对应的国际化资源文件并加载。

 

147、AJAX是什么? 描述ajax的原理

Ajax又叫异步刷新,(JavaScript和xml)原理:使用HttpRequest向服务器发送异步请求,服务器返回处理结果

148、什么是反射?请用反射动态创建一个类的对象(写关键代码,其它可省略)

反射,程序运行时动态获取类型信息,完成对象创建,方法调用等。

例如:

Class myclass=Class.forNama("包名.类名");

Student stu=Factory.createInstance("stu1");

149、在struts2中如何实现转发和重定向?

在struts.xml中配置type="redirect"(重定向);type="redirectAction"(转发)

150、Struts2中的type类型有哪些?至少写4种

dispatcher:result type默认的类型,相当于servlet的foward方式跳转页面。客户端看到的是struts2中配置的地址,而不是真正页面的地址,一般用于跳转到jsp页面,页面能拿到值

redirect:页面重定向,客户端跳转,数据全部丢失,地址栏发生变化,页面不能拿到值

chain:将请求转发给一个Action,Action能通过getAttribute(“uname”)拿到值

redirect-action:一般用于跳转到Action,Action不能通过getAttribute(“uname”)拿到值10、struts2默认能解决get和post提交方式的乱码问题吗?

答:不能。struts.i18n.encoding=UTF-8属性值只能解析POST提交下的乱码问题。

151、说下Struts的设计模式

MVC模式: 

 1)web应用程序启动时就会加载并初始化ActionServler。

 2)用户提交表单时,一个配置好的ActionForm对象被创建,并被填入表单相应的数据,ActionServler根据Struts-config.xml文件配置好的设置决定是否需要表单验证,如果需要就调用ActionForm的Validate()验证后选择将请求发送到哪个Action,如果Action不存在,ActionServlet会先创建这个对象,然后调用Action的execute()方法. 

 3)Execute()从ActionForm对象中获取数据,完成业务逻辑,返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指定的jsp组件,ActionForward对象指定的jsp生成动态的网页,返回给客户。

152、拦截器和过滤器的区别

 1)拦截器是基于java反射机制的,而过滤器是基于函数回调的。 

 2)过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。

 3)拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。 

 4)拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。 

 5)在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

153、请你写出struts2中至少5个的默认拦截器?

 fileUpload 提供文件上传功能 

 i18n 记录用户选择的locale 

 cookies 使用配置的name,value来是指cookies 

 checkbox 添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的 checkbox。 

 chain 让前一个Action的属性可以被后一个Action访问,现在和chain类型的result()结合使用。

 alias 在不同请求之间将请求参数在不同名字件转换,请求内容不变

154、ActionContext、ServletContext、pageContext的区别? 

 1)ActionContext是当前的Action的上下文环境,通过ActionContext可以获取到request、session、ServletContext等与Action有关的对象的引用; 

 2)ServletContext是域对象,一个web应用中只有一个ServletContext,生命周期伴随整个web应用; 

 3)pageContext是JSP中的最重要的一个内置对象,可以通过pageContext获取其他域对象的应用,同时它是一个域对象,作用范围只针对当前页面,当前页面结束时,pageContext销毁, 生命周期是JSP四个域对象中最小的。

155、拦截器的生命周期与工作过程? 

 1)每个拦截器都是实现了Interceptor接口的 Java 类; 

 2)init(): 该方法将在拦截器被创建后立即被调用, 它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化; 

 3)intercept(ActionInvocation invocation): 每拦截一个动作请求, 该方法就会被调用一次; 

 4)destroy: 该方法将在拦截器被销毁之前被调用, 它在拦截器的生命周期内也只被调用一次; 

 5)struts2中有内置了18个拦截器。

Mybatis

156、什么是Mybatis?

(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。

(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

(3)通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。

157、Mybaits的优点:

(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。

(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;

(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。

(4)能够与Spring很好的集成;

(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

158、MyBatis框架的缺点:

(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。

(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

159、MyBatis框架适用场合:

(1)MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。

(2)对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。 

160、MyBatis与Hibernate有哪些不同?

(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。

(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。 

(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。 

160、#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

Mybatis在处理${}时,就是把${}替换成变量的值。

使用#{}可以有效的防止SQL注入,提高系统安全性。

161、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。

第2种: 通过<resultMap>来映射字段名和实体类属性名的一一对应的关系。

162、 模糊查询like语句该怎么写?

第1种:在Java代码中添加sql通配符。

第2种:在sql语句中拼接通配符,会引起sql注入

163、通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。

Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MapperStatement对象。

举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面 id 为 findStudentById 的 MapperStatement。

Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。

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

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

165、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

第一种是使用<resultMap>标签,逐一定义数据库列名和对象属性名之间的映射关系。

第二种是使用sql列的别名功能,将列的别名书写为对象属性名。

有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

166、如何执行批量插入?

首先,创建一个简单的insert语句:mapper.xml中

然后在java代码中批量赋值:业务层调用dao层执行插入

167、如何获取自动生成的(主)键值?

在insert语句中开启usegeneratedkeys=”true” keyproperty=”id”

insert 方法总是返回一个int值 ,这个值代表的是插入的行数。

如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。

168、在mapper中如何传递多个参数?

(1)第一种:

//DAO层的函数

Public UserselectUser(String name,String area); 

//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。

<select id="selectUser"resultMap="BaseResultMap"> 

    select *  fromuser_user_t   whereuser_name = #{0} anduser_area=#{1} 

</select> 

(2)第二种: 使用 @param 注解:

public interface usermapper {

   user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword);

}

然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):

<select id=”selectuser” resulttype=”user”>

         select id, username, hashedpassword

         from some_table

         where username = #{username}

         and hashedpassword = #{hashedpassword}

</select>

(3)第三种:多个参数封装成map

try{

//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL

//由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数

Map<String, Object> map = new HashMap();

     map.put("start", start);

     map.put("end", end);

     return sqlSession.selectList("StudentID.pagination", map);

 }catch(Exception e){

     e.printStackTrace();

     sqlSession.rollback();

    throw e; }

finally{

 MybatisUtil.closeSqlSession();

 }

169、Mybatis动态sql有什么用?执行原理?有哪些动态sql?

Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。

Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。

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

<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上动态sql的9个标签,其中<sql>为sql片段标签,通过<include>标签引入sql片段,<selectKey>为不支持自增的主键生成策略标签。

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

不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;

原因就是namespace+id是作为Map<String, MapperStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。

但是,在以前的Mybatis版本的namespace是可选的,不过新版本的namespace已经是必须的了。

172、为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

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

173、 一对一、一对多的关联查询 ? 

association 一对一, 一对多  collection,多对多 discrimination

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

有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成;

嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。

175、MyBatis实现一对多有几种方式,怎么操作的?

有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的collection节点配置一对多的类就可以完成;嵌套查询是先查一个表,根据这个表里面的 结果的外键id,去再另外一个表里面查询数据,也是通过配置collection,但另外一个表的查询通过select节点配置。

176、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。

 177、Mybatis的一级、二级缓存:

1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。

2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/> ;

3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。

178、什么是MyBatis的接口绑定?有哪些实现方式?

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

接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

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

①  Mapper接口方法名和mapper.xml中定义的每个sql的id相同;

②  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;

③  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;

③      Mapper.xml文件中的namespace即是mapper接口的类路径。

180、Mapper编写有哪几种方式?

第一种:接口实现类继承SqlSessionDaoSupport:使用此种方法需要编写mapper接口,mapper接口实现类、mapper.xml文件。

(1)在sqlMapConfig.xml中配置mapper.xml的位置

<mappers>

    <mapper resource="mapper.xml文件的地址" />

    <mapper resource="mapper.xml文件的地址" />

</mappers>

(2)定义mapper接口

(3)实现类集成SqlSessionDaoSupport

mapper方法中可以this.getSqlSession()进行数据增删改查。

(4)spring 配置

<bean id=" " class="mapper接口的实现">

    <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>

</bean>

第二种:使用org.mybatis.spring.mapper.MapperFactoryBean:

(1)在sqlMapConfig.xml中配置mapper.xml的位置,如果mapper.xml和mappre接口的名称相同且在同一个目录,这里可以不用配置

<mappers>

    <mapper resource="mapper.xml文件的地址" />

    <mapper resource="mapper.xml文件的地址" />

</mappers>

(2)定义mapper接口:

①mapper.xml中的namespace为mapper接口的地址

②mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致

③Spring中定义

<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">

    <property name="mapperInterface"   value="mapper接口地址" /> 

    <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 

</bean>

第三种:使用mapper扫描器:

(1)mapper.xml文件编写:

mapper.xml中的namespace为mapper接口的地址;

mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致;

如果将mapper.xml和mapper接口的名称保持一致则不用在sqlMapConfig.xml中进行配置。 

(2)定义mapper接口:

注意mapper.xml的文件名和mapper的接口名称保持一致,且放在同一个目录

(3)配置mapper扫描器:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <property name="basePackage" value="mapper接口包地址"></property>

    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 

</bean>

(4)使用扫描器后从spring容器中获取mapper的实现对象。

181、简述Mybatis的插件运行原理,以及如何编写一个插件。

Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

编写插件:实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

Hibernate

182、Hibernate的核心思想

Hibernate的核心思想是ROM对象关系映射机制。它是将表与表之间的操作映射成对象与对象之间的操作。从数据库中提取的信息会自动按照你设置的映射要求封装成特点的对象,使得对对象的修改对应数据行的修改。

183、Hibernate工作原理及为什么要用?

读取并解析配置文件

读取并解析映射信息,创建SessionFactory

打开Sesssion

创建事务Transation

持久化操作

提交事务

关闭Session

关闭SesstionFactory

使用Hibernate框架就不用我们写很多繁琐的SQL语句。Hibernate实现了ORM,能够将对象映射成数据库表,从而简化我们的开发!

184、Hibernate是如何延迟加载(懒加载)?

通过设置属性lazy进行设置是否需要懒加载

当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。

185、Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)

它们通过配置文件中的many-to-one、one-to-many、many-to-many来实现类之间的关联关系的。

186、hibernate的三种状态之间如何转换

Hibernate中对象的状态:

临时/瞬时状态

持久化状态

游离状态

new出来的对象是瞬时状态->保存到数据库中(受Session管理)就是持久化状态->将session close掉就是游离状态

187、比较hibernate的三种检索策略优缺点

1)立即检索:

优点: 对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象;

缺点: 1.select语句太多;2.可能会加载应用程序不需要访问的对象白白浪费许多内存空间;

立即检索:lazy=false;

2)延迟检索:

优点: 由应用程序决定需要加载哪些对象,可以避免可执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并且能节省内存空间;

缺点: 应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化;

延迟加载:lazy=true;

3)迫切左外连接检索:

优点: 1对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便地冲一个对象导航到与它关联的对象。2使用了外连接,select语句数目少;

缺点: 1 可能会加载应用程序不需要访问的对象,白白浪费许多内存空间;2复杂的数据库表连接也会影响检索性能;

预先抓取: fetch=“join”;

188、hibernate都支持哪些缓存策略

4种:

放入二级缓存的对象,只读(Read-only);

非严格的读写(Nonstrict read/write)

读写; 放入二级缓存的对象可以读、写(Read/write);

基于事务的策略(Transactional)

189、hibernate里面的sorted collection 和ordered collection有什么区别

sorted collection是在内存中通过Java比较器进行排序的

ordered collection是在数据库中通过order by进行排序的

对于比较大的数据集,为了避免在内存中对它们进行排序而出现 Java中的OutOfMemoryError,最好使用ordered collection。

190、说下Hibernate的缓存机制

一级缓存:

Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!

只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!

Session的缓存由hibernate维护,用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。

二级缓存:

二级缓存是基于应用程序的缓存,所有的Session都可以使用

Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。

如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。

Hibernate二级缓存:存储的是常用的类

191、Hibernate的查询方式有几种

一、对象导航查询(objectcomposition)

二、HQL查询

1、 属性查询

2、 参数查询、命名参数查询

3、 关联查询

4、 分页查询

5、 统计函数

三、Criteria 查询

四、SQLQuery本地SQL查询

192、如何优化Hibernate?

Ø 数据库设计调整

Ø HQL优化

Ø API的正确使用(如根据不同的业务类型选用不同的集合及查询API)

Ø 主配置参数(日志,查询缓存,fetch_size, batch_size等)

Ø 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)

Ø 一级缓存的管理

Ø 针对二级缓存,还有许多特有的策略

详情可参考资料:

193、谈谈Hibernate中inverse(反转)的作用

inverse属性默认是false,就是说关系的两端都来维护关系。

比如Student和Teacher是多对多关系,用一个中间表TeacherStudent维护。Gp)

如果Student这边inverse=”true”, 那么关系由另一端Teacher维护,就是说当插入Student时,不会操作TeacherStudent表(中间表)。只有Teacher插入或删除时才会触发对中间表的操作。所以两边都inverse=”true”是不对的,会导致任何操作都不触发对中间表的影响;当两边都inverse=”false”或默认时,会导致在中间表中插入两次关系。

如果表之间的关联关系是“一对多”的话,那么inverse只能在“一”的一方来配置!

194、JDBC hibernate 和 ibatis 的区别

jdbc:手动

手动写sql

delete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。

select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。

ibatis的特点:半自动化

sql要手动写

delete、insert、update:直接传入一个对象

select:直接返回一个对象

hibernate:全自动

不写sql,自动封装

delete、insert、update:直接传入一个对象

select:直接返回一个对象

195、在数据库中条件查询速度很慢的时候,如何优化?

建索引

减少表之间的关联

优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据量大的表排在前面

简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据

196、什么是SessionFactory,她是线程安全么

SessionFactory 是Hibrenate单例数据存储和线程安全的,以至于可以多线程同时访问。一个SessionFactory 在启动的时候只能建立一次。SessionFactory应该包装各种单例以至于它能很简单的在一个应用代码中储存.

197、get和load区别

get()立即查询

load()懒加载

1)get如果没有找到会返回null, load如果没有找到会抛出异常。

2)get会先查一级缓存, 再查二级缓存,然后查数据库;load会先查一级缓存,如果没有找到,就创建代理对象, 等需要的时候去查询二级缓存和数据库。

198、merge的含义:

如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例

如果session没有相应的持久实例,则尝试从数据库中加载,或创建新的持久化实例,最后返回该持久实例

用户给出的这个对象没有被关联到session上,它依旧是托管的

199、persist和save的区别

persist不保证立即执行,可能要等到flush;

persist不更新缓存;

save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert

使用 save() 方法保存持久化对象时,该方法返回该持久化对象的标识属性值(即对应记录的主键值);

使用 persist() 方法来保存持久化对象时,该方法没有任何返回值。

200、主键生成 策略有哪些

主键的自动生成策略

identity 自增长(mysql,db2)

sequence 自增长(序列), oracle中自增长是以序列方法实现**

native 自增长【会根据底层数据库自增长的方式选择identity或sequence】

如果是mysql数据库, 采用的自增长方式是identity

如果是oracle数据库, 使用sequence序列的方式实现自增长

increment 自增长(会有并发访问的问题,一般在服务器集群环境使用会存在问题。)

指定主键生成策略为手动指定主键的值

assigned

指定主键生成策略为UUID生成的值

uuid

foreign(外键的方式)

201、简述hibernate中getCurrentSession和openSession区别

1、getCurrentSession会绑定当前线程,而openSession不会,因为我们把hibernate交给我们的spring来管理之后,我们是有事务配置,这个有事务的线程就会绑定当前的工厂里面的每一个session,而openSession是创建一个新session。

2、getCurrentSession事务是有spring来控制的,而openSession需要我们手动开启和手动提交事务,

3、getCurrentSession是不需要我们手动关闭的,因为工厂会自己管理,而openSession需要我们手动关闭。

4、而getCurrentSession需要我们手动设置绑定事务的机制,有三种设置方式,jdbc本地的Thread、JTA、第三种是spring提供的事务管理机制org.springframework.orm.hibernate4.SpringSessionContext,而且srping默认使用该种事务管理机制

202、Hibernate中的命名SQL查询指的是什么?

命名查询指的是用<sql-query>标签在影射文档中定义的SQL查询,可以通过使用Session.getNamedQuery()方法对它进行调用。命名查询使你可以使用你所指定的一个名字拿到某个特定的查询。

Hibernate中的命名查询可以使用注解来定义,也可以使用我前面提到的xml影射问句来定义。在Hibernate中,@NameQuery用来定义单个的命名查询,@NameQueries用来定义多个命名查询。

203、为什么在Hibernate的实体类中要提供一个无参数的构造器这一点非常重要?

每个Hibernate实体类必须包含一个 无参数的构造器, 这是因为Hibernate框架要使用Reflection API,通过调用Class.newInstance()来创建这些实体类的实例。如果在实体类中找不到无参数的构造器,这个方法就会抛出一个InstantiationException异常。

204、可不可以将Hibernate的实体类定义为final类?

你可以将Hibernate的实体类定义为final类,但这种做法并不好。因为Hibernate会使用代理模式在延迟关联的情况下提高性能,如果你把实体类定义成final类之后,因为 Java不允许对final类进行扩展,所以Hibernate就无法再使用代理了, 如此一来就限制了使用可以提升性能的手段。

Spring

205、Spring是什么?

Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。

主要由以下几个模块组成:

Spring Core:核心类库,提供IOC服务;

Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);

Spring AOP:AOP服务;

Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;

Spring ORM:对现有的ORM框架的支持;

Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;

Spring MVC:提供面向Web应用的Model-View-Controller实现。

206、Spring 的优点?

(1)spring属于低侵入式设计,代码的污染极低;

(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;

(3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。

(4)spring对于主流的应用框架提供了集成支持。

207、Spring的AOP理解:

OOP面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

        ①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。

        ②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

 InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):proxy是最终生成的代理实例;  method 是被代理目标实例的某个具体方法;  args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

208、Spring的IoC理解:

(1)IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。

(2)最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

(3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。

IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

209、BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

①继承MessageSource,因此支持国际化。

②统一的资源文件访问方式。

③提供在监听器中注册bean的事件。

④同时加载多个配置文件。

⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

 ③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

210、请解释Spring Bean的生命周期?

       首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

 Spring上下文中的Bean生命周期也类似,如下:

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

211、 解释Spring支持的几种bean的作用域。

Spring容器中的bean可以分为5个范围:

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个bean请求提供一个实例。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

212、Spring框架中的单例Beans是线程安全的么?

Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

213、Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

 

214、Spring基于xml注入bean的几种方式:

(1)Set方法注入;

(2)构造器注入:①通过index设置参数的位置;②通过type设置参数类型;

(3)静态工厂注入;

(4)实例工厂;

215、Spring的自动装配:

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。

在Spring框架xml配置中共有5种自动装配:

(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。

(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。 

(3)byType:通过参数的数据类型进行自动装配。

(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

基于注解的方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法

注:@Autowired和@Resource之间的区别

(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

216、Spring 框架中都用到了哪些设计模式?

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。

217、Spring事务的实现方式和实现原理:

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

(1)Spring事务的种类:

spring支持编程式事务管理和声明式事务管理两种方式:

①编程式事务管理使用TransactionTemplate。

②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。

声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

(2)spring的事务传播行为:

spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

(3)Spring中的隔离级别:

① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

13、Spring框架中有哪些不同类型的事件?

Spring 提供了以下5种标准的事件:

(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

 

14、解释一下Spring AOP里面的几个名词:

(1)切面(Aspect):被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

(2)连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。 

(3)通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

(4)切入点(Pointcut):切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add*、search*。

(5)引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

(6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

(7)织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。

218、Spring通知有哪些类型?

(1)前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。 

(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。 

(4)后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 

(5)环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。 

同一个aspect,不同advice的执行顺序:

①没有异常情况下的执行顺序:

around before advice

before advice

target method 执行

around after advice

after advice

afterReturning

 

②有异常情况下的执行顺序:

around before advice

before advice

target method 执行

around after advice

after advice

afterThrowing:异常发生

java.lang.RuntimeException: 异常发生

Spring Boot

218、什么是 Spring Boot?

Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。集成了44种服务。

219、为什么要用 Spring Boot?

Spring Boot 优点非常多,如:

独立运行

简化配置

应用监控(本地调试生产环境)

上手容易

220、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。

bootstrap 配置文件有以下几个应用场景。

使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;

一些固定的不能被覆盖的属性;

一些加密/解密的场景;

具体请看这篇文章《Spring Boot 核心配置文件详解》。

221、Spring Boot 的配置文件有哪几种格式?它们有什么区别?

.properties 和 .yml,它们的区别主要是书写格式不同。

1).properties

app.user.name = javastack

2).yml

app:

  user:

    name: javastack

另外,.yml 格式不支持 @PropertySource 注解导入配置。

他们都要求层级关系。

222、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

@ComponentScan:Spring组件扫描。

223、开启 Spring Boot 特性有哪几种方式?

1)继承spring-boot-starter-parent项目

2)导入spring-boot-dependencies项目依赖

224、Spring Boot 需要独立的容器运行吗?

可以不需要,内置了 Tomcat/ Jetty 等容器。

225、运行 Spring Boot 有哪几种方式?

1)打包用命令或者放到容器中运行

2)用 Maven/ Gradle 插件运行

3)直接执行 main 方法运行

226、Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

227、Spring Boot 的目录结构是怎样的?

cn

 +- javastack

     +- MyApplication.java

     |

     +- customer

     |   +- Customer.java

     |   +- CustomerController.java

     |   +- CustomerService.java

     |   +- CustomerRepository.java

     |

     +- order

         +- Order.java

         +- OrderController.java

         +- OrderService.java

         +- OrderRepository.java

Application类要处于bean的最上一层,否则扫描不到层级高于它的bean。这个目录结构是主流及推荐的做法,而在主入口类上加上 @SpringBootApplication 注解来开启 Spring Boot 的各项能力,如自动配置、组件扫描等。具体看这篇文章《Spring Boot 主类及目录结构介绍》。

228、你如何理解 Spring Boot 中的 Starters?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。

Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。具体请看这篇文章《Spring Boot Starters启动器》。

229、如何在 Spring Boot 启动的时候运行一些特定的代码?

可以实现接口 ApplicationRunner 或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个 run 方法,具体请看这篇文章《Spring Boot Runner启动器》。

230、Spring Boot 有哪几种读取配置的方式?

Spring Boot 可以通过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量,具体请看这篇文章《Spring Boot读取配置的几种方式》。

231、Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架,如果你使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架,具体请看这篇文章《Spring Boot日志集成》。

232、SpringBoot 实现热部署有哪几种方式?

主要有两种方式:

Spring Loaded

Spring-boot-devtools

233、你如何理解 Spring Boot 配置加载顺序?

在 Spring Boot 里面,可以使用以下几种方式来加载配置。

1)properties文件;

2)YAML文件;

3)系统环境变量;

4)命令行参数;

234、Spring Boot 如何定义多套不同环境配置?

提供多套配置文件,如:

applcation.properties

application-dev.properties

application-test.properties

application-prod.properties

运行时指定具体的配置文件,具体请看这篇文章《Spring Boot Profile 不同环境配置》。

235、Spring Boot 可以兼容老 Spring 项目吗,如何做?

可以兼容,使用 @ImportResource 注解导入老 Spring 项目配置文件。

236、保护 Spring Boot 应用有哪些方法?

在生产中使用HTTPS

使用Snyk检查你的依赖关系

升级到最新版本

启用CSRF保护

使用内容安全策略防止XSS攻击

237、Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?

配置变更

JDK 版本升级

第三方类库升级

响应式 Spring 编程支持

HTTP/2 支持

配置属性绑定

更多改进与加强…

数据库

238、什么是事务?

事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并当做一个整体提交。要么都执行,要么都不执行。

239、事务四大特性ACID

*原子性Atomicity:不可分割的操作单元,事务中所有操作,要么全部成功;要么撤回到执行事务之前的状态

*一致性Consistency:如果在执行事务之前数据库是一致的,那么在执行事务之后数据库也还是一致的;

*隔离性Isolation:事务操作之间彼此独立和透明互不影响。事务独立运行。这通常使用锁来实现。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。

*持久性Durability:事务一旦提交,其结果就是永久的。即便发生系统故障,也能恢复。

240、MySQL的事务隔离级别

①未提交读(Read Uncommitted):允许脏读,其他事务只要修改了数据,即使未提交,本事务也能看到修改后的数据值。也就是可能读取到其他会话中未提交事务修改的数据

②提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。

③可重复读(Repeated Read):可重复读。无论其他事务是否修改并提交了数据,在这个事务中看到的数据值始终不受其他事务影响。

④串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

MySQL数据库(InnoDB引擎)默认使用可重复读( Repeatable read)

241、索引

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。采取的是空间换时间的概念。

MyISAM引擎和InnoDB引擎使用B+Tree作为索引结构

242、MySQL数据库的四类索引:

  index  ----  普通索引,数据可以重复,没有任何限制。

  unique   ---- 唯一索引,要求索引列的值必须唯一,但允许有空值;如果是组合索引,那么列值的组合必须唯一。

  primary key ---- 主键索引,是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值,一般是在创建表的同时创建主键索引。

  组合索引 ----  在多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。

  fulltext ---- 全文索引,是对于大表的文本域:char,varchar,text列才能创建全文索引,主要用于查找文本中的关键字,并不是直接与索引中的值进行比较。fulltext更像是一个搜索引擎,配合match against操作使用,而不是一般的where语句加like。

  注:全文索引目前只有MyISAM存储引擎支持全文索引,InnoDB引擎5.6以下版本还不支持全文索引

  所有存储引擎对每个表至少支持16个索引,总索引长度至少为256字节,索引有两种存储类型,包括B型树索引和哈希索引。

  索引可以提高查询的速度,但是创建和维护索引需要耗费时间,同时也会影响插入的速度,如果需要插入大量的数据时,最好是先删除索引,插入数据后再建立索引。

243、索引生效条件

假设index(a,b,c)

1)最左前缀匹配:模糊查询时,使用%匹配时:’a%‘会使用索引,’%a‘不会使用索引

2)条件中有or,索引不会生效

3) a and c,a生效,c不生效

b and c,都不生效

检测索引的效果:

show status like '%handler_read%'越大越好

244、sql语句分类:

DDL:数据定义语言(create drop)

DML:数据操作语句(insert update delete)

DQL:数据查询语句(select )

DCL:数据控制语句,进行授权和权限回收(grant revoke)

TPL:数据事务语句(commit collback savapoint)

245、数据库三范式:

第一范式:确保每列的原子性,确保每列都是最小的不可再分割的数据单元。

第二范式:确保表中的每列都和主键相关。

第三范式:确保每列都和主键直接相关,而不是间接相关。除了主键列,其他的列和列之间不存在依赖关系。

246、脏读&不可重复读&幻读

*脏读: 是指事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。

*不可重复读 :是指在数据库访问时,一个事务范围内的两次相同查询却返回了不同数据。在一个事务内多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么在第一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

*幻读: 是指当事务不是独立执行时发生的一种现象,比如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么就会发生,操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

不可重复读&幻读区别:

如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

不可重复读重点在于update和delete,而幻读的重点在于insert。如何通过锁机制来解决他们产生的问题

247、mysql的存储引擎

1)MyISAM 不支持事务,不支持外键,优势是访问速度快,对事务完整性没有要求,或者以select、insert为主的可以使用

2)InnoDB 支持事务,外键约束,自增,写的效率差一些,更占据空间

3)Memory 使用内存中的内容来创建表,访问速度非常快,使用哈希索引。但是一旦服务关闭,表中的数据就会丢失。

4)Merge 是一组MyISAM表的组合,这些表必须结构完全相同,merge本身没有数据。对merge的查询、更新、删除实际是对MyISAM的修改。

248、存储引擎 MyISAM和InnoDB区别:

1)InnoDB支持事务,MyISAM不支持。

2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用。

3)InnoDB支持外键,MyISAM不支持。

4)从MySQL5.5.5以后,InnoDB是默认引擎。

5)MyISAM支持全文类型索引,而InnoDB不支持全文索引。

6)InnoDB中不保存表的总行数,select count(*) from table时,InnoDB需要扫描整个表计算有多少行,但MyISAM只需简单读出保存好的总行数即可。注:当count(*)语句包含where条件时MyISAM也需扫描整个表。

7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。

8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。MyisAM使用delete语句删除后并不会立刻清理磁盘空间,需要定时清理,命令:OPTIMIZE table dept;

9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’)

10)Myisam创建表生成三个文件:.frm 数据表结构 、 .myd 数据文件 、 .myi 索引文件,Innodb只生成一个 .frm文件,数据存放在ibdata1.log

现在一般都选用InnoDB,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的。

应用场景:

MyISAM不支持事务处理等高级功能,但它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。

InnoDB用于需要事务处理的应用程序,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。

249、CHAR和VARCHAR的区别:

CHAR和VARCHAR类型在存储和检索方面有所不同

CHAR列长度固定为创建表时声明的长度,长度值范围是1到255

当CHAR值被存储时,它们被用空格填充到特定长度,检索CHAR值时需删除尾随空格。

250、数据库使用

1.    一些全表扫描的慎用,or、like、<>、distinct(排除)、not in、not exists,not null的慎用。如有必然请用正向逻辑。

2.    一些重要操作请开启事物

3.    数据库不擅长运算,请把你的运算放在逻辑代码中,或者放在=号右边。

4.    Limit分页的提醒,limit 10000,10所查询到的结果是1到10010条,而不是你所想的10条。大量数据请记得优化。

5.    Sql执行顺序:

(1)FROM [left_table]

(2)ON <join_condition>

(3)<join_type> JOIN <right_table>

(4)WHERE <where_condition>

(5)GROUP BY <group_by_list>

(6)WITH <CUBE | RollUP>

(7)HAVING <having_condition>

(8)SELECT

(9)DISTINCT 

(10)ORDER BY <order_by_list>

(11)<Top Num> <select list>

251、数据库查询优化

1)避免全部扫描,比如对null值进行筛选判读;使用!=或<>、like、or等等都将放弃索引全表扫描

2)考虑在where及order by涉及的列上建立索引

3)使用正向逻辑(not in,not exists)

4)数据库不擅长运算,把运算交给逻辑代码,非要有把运算放在右边

5)合理建表,使用合理的字段,善用非空、外键约束保证数据的完整性

6)索引并不是越多越好,一个表最好不要超过6个,多了影响增、删、改的性能。这个影响很大

7)多从业务逻辑方面考虑问题,合理使用中间件

8)对于数据量太大的数据分库分表,使用中间件比如mycat

252、分表分库

①:垂直分割(并不常用)

就是将一个表按照字段来分,每张表保证有相同的主键就好。一般来说,将常用字段和大字段分表来放。

优势:比没有分表来说,提高了查询速度,降低了查询结果所用内存;

劣势:没有解决大量记录的问题,对于单表来说随着记录增多,性能还是下降很快;

②: 水平分割(重要,实际应用中使用最多)

水平分割是企业最常用到的,水平拆分就是大表按照记录分为很多子表:

水平分的规则完全是自定义的,有以下几种参考设计:

1 hash、自增id取模:

对某个字段进行hash来确定创建几张表,并根据hash结果存入不同的表;

2 按时间

根据业务可以按照天、月、年来进行拆分;

3 按每个表的固定记录数

一般按照自增ID进行拆表,一张表的数据行到了指定的数量,就自动保存到下一张表中。比如规定一张表只能存1-1000个记录;

4 将老数据迁移到一张历史表

比如日志表,一般只查询3个月之内的数据,对于超过3个月的记录将之迁移到历史子表中;

253、数据库的备份

什么是物理冷备?科普一下:

(1)热备:在数据库运行时,直接进行备份,对运行的数据库没有影响。

(2)冷备:在数据库停止运行的时候进行备份,这种备份方式最为简单,只需要拷贝数据库物理文件即可。

(3)温备:同样是在数据库运行的时候进行备份的,但对当前数据库的操作会产生影响。

热备份的缺点:

  1.尽量不要出错,否则后果会很严重。

  2.如果热备份不成功,所得结果不可用于时间点的数据恢复。

  3.维护的工作比较困难。

冷备份的缺点:

  1.单独使用时,只能提供到"某一时间点的上"的恢复。

  2.再实施备份的全过程中,数据库必须是关闭状态。

  3.不能按表或按用户恢复。

综上,如果你不是大牛大能,物理备份还是选择冷备份吧,自动保存7天数据。

254、Mysql中有哪几种锁?

MyISAM支持表锁,InnoDB支持表锁和行锁,默认为行锁

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低

行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高

255、存储过程

我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

一个存储过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式。

优点:

(1).存储过程增强了SQL语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

(2).存储过程允许标准组件是编程。存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。

(3).存储过程能实现较快的执行速度。如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

(4).存储过程能过减少网络流量。针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织程存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增加了网络流量并降低了网络负载。

(5).存储过程可被作为一种安全机制来充分利用。系统管理员通过执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

256、delete、drop、truncate区别

truncate 和 delete只删除数据,不删除表结构 ,drop删除表结构,并且释放所占的空间。

删除数据的速度,drop> truncate > delete

delete属于DML语言,需要事务管理,commit之后才能生效。drop和truncate属于DDL语言,操作立刻生效,不可回滚。

使用场合:

当你不再需要该表时, 用 drop;

当你仍要保留该表,但要删除所有记录时, 用 truncate;

当你要删除部分记录时(always with a where clause), 用 delete

257、CAP定理(布鲁尔定律)

CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

一致性(Consistency)   所有节点访问同一份最新的数据副本;

可用性(Availability)   每次请求都能获取到非错的响应,但是不保证获取的数据为最新数据;

分区容错性(Partition tolerance)      分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障;

CAP之间是不能共存的,我们最多只能满足两个条件:

CA (Consistency + Availability):关注一致性和可用性,代表作:关系型数据库MySQL。

CP (consistency + partition tolerance):关注一致性和分区容错性,代表作:分布式数据库hadoop。

AP (availability + partition tolerance):关心可用性和分区容错性,代表作:非关系型数据库Redis。

258、Bse理论

BASE 理论是对 CAP 理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。

基本可用(Basically Available): 基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。

软状态(Soft State): 软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。MySQL Replication 的异步复制也是一种体现。

最终一致性(Eventual Consistency): 最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。

Redis

1、什么是redis?

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。

2、Redis支持的数据类型?

1)St ing字符串:格式: set key value

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型,一个键最大能存储512MB。

2)Hash(哈希)格式: hmset name  key1 value1 key2 value2

Redis hash 是一个键值(key=>value)对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

3)   lsit(列表)Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

 

4)set(集合)

5)zset(有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

3、什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

Redis 提供了两种持久化方式:RDB(默认) 和AOF

RDB:rdb是Redis DataBase缩写

功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数

AOF:Aof是Append-only file缩写

每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作

aof写入保存:

WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件

SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

比较:

1、aof文件比rdb更新频率高,优先使用aof还原数据。

2、aof比rdb更安全也更大

3、rdb性能比aof好

4、如果两个都配了优先加载AOF

4、什么是RESP?有什么特点?

RESP 是redis客户端和服务端之前使用的一种通讯协议;

RESP 的特点:实现简单、快速解析、可读性好

5、Redis 有哪些架构模式?讲讲各自的特点

1)单机版

特点:简单

问题:1、内存容量有限 2、处理能力有限 3、无法高可用。

2)哨兵

Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:

监控(Monitoring):    Sentinel  会不断地检查你的主服务器和从服务器是否运作正常。

提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。

特点:1、保证高可用2、监控各个节点3、自动故障迁移

缺点:主从模式,切换需要时间丢数据,没有解决 master 写的压力

 

3)集群(proxy 型):

Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。

特点:1、多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins

2、支持失败节点自动删除

3、后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致

缺点:增加了新的 proxy,需要维护其高可用。failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预

4)集群(直连型):从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

特点:1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。

2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。

3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。

4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本

5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。

缺点:

1、资源隔离性较差,容易出现相互影响的情况。

2、数据通过异步复制,不保证数据的强一致性

6、使用过Redis分布式锁么,它是怎么实现的?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

7、如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!

8、使用过Redis做异步队列么,你是怎么用的?有什么缺点?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

9、能不能生产一次消费多次呢?

使用pub/sub主题订阅者模式,可以实现1:N的消息队列。

10、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免:

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免:

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

Web编程Jsp&Servlet技术

257、简单说说 tomcat的配置?

JAVA_HOME=JDK 的根目录

CATALINA_HOME=tomcat 的根目录

CATALINA-HOME\conf\server.xml:可以配置tomcat 的端口,可以配置tomcat 中下连接

池。

CATALINA-HOME\common\lib:存放公用的类包

258、JSP中动态 include与静态include的区别?

jsp:include:在运行时调用另一个页面,变量是可以重复的。

<%@include file=””%>:在转译时合在一起,会成为同一个类,变量不可以重复。

259、forward和 redirect的区别?

重定向是客户端行为,转发是服务器端行为

重定向时服务器产生两次请求,转发产生一次请求,重定向时可以转发到项目以外的任何网址,转发只能在当前项目里转发

重定向会导致request对象信息丢失。转发则不会

转发的url不会变,request.getRequestDispatch()。forward()

重定向的url会改变,response.getRedirect();

260、Servlet的体系结构是什么?

Servlet

GenericServlet

HttpServlet

自定义

261、如何实现一个自定义的 servlet?

extends HttpServlet 并覆盖doPost 或doGet 方法

在web.xml 中进行部署

262、Servlet的生命周期是什么?

Init

多次执行doGet 或doPost

destroy

263、jsp就是一个 servlet是否正确?

264、请罗列jsp中的脚本、指令及动作?

脚本

<%%> <%=%> <%!%> <%----%>

指令

<%@page contentType=”text/html;charset=utf-8” language=”java”

import=””%>

<%@include file=””%>

<%@taglib uri=”” prefix=””%>

动作:

<jsp:useBean class=”” id=”” scope=””> 在scope 中如果没有

实例化一个对象,如果有直接用以前的。

<jsp:getProperty name=”” property=””> 向一个bean 中设置属性

<jsp:forward > jsp 页的转发

<jsp:include page=””> 导入一个jsp 页面

265、JSP的内置对象及方法

JSP一共有9个内置对象:request、response、session、application、out、pagecontext、config、page、exception。

1、Request request 表示HttpServletRequest 对象。取客户端表单域信息及cookie,header, 和session

2、response 表示HttpServletResponse 对象,对客户端的响应返回文本、写cookies。

3、out 向客户端打印html 文本.

4、pageContext :当前jsp 页面的上下文环境,可以得到session、request、application等内置对象,在自定义标签中使用的很多。

5、session 表示一个请求的javax.servlet.http.HttpSession 对象。Session 一个用户多个页面共享同一变量。

6、applicaton 表示一个javax.servle.ServletContext 对象。存放容器级

的变量。

7、config 表示一个javax.servlet.ServletConfig 对象。该对象用于存取servlet实例的初始化参数。

8、page 表示从该页面产生的一个servlet 实例

9、exception:异常,当iserrorpage=true

266、四种会话跟踪技术

1).隐藏表单域:<input type="hidden">,非常适合步需要大量数据存储的会话应用。

2).URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。

3).Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至在客户端计算机重启后它仍可以保留其值

4).Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话

267、说出在 JSP页面里是怎么分页的?

页面需要保存以下参数:(数据库的分页及比较)

总行数:根据sql 语句得到总行数

每页显示行数:设定值

当前页数:请求参数

页面根据当前页数和每页行数计算出当前页第一行行数,定位结果集到此行,对结果集

取出每页显示行数的行即可。

268、include的两种实现方式的区别?

<@include file>:在将jsp 生成servlet 类前将两个文件和在一起,生成一个java 类,

一起运行的。所以是一家子,当中的变量名不能重名。

<jsp:include page>:是两个类,是一个调用关系,在运行时动态的调用,不是一家子,

可以重复变量。

269、jsp页面中两种跳转方式分别是什么?有什么区别?

转发: 保留上次的request

<jsp:forward>

actionMapping.findForWard(“”);

pageContext.forward();

request.getRequestDispacher(“a.jsp”).forward(request,response)

跳转:不保留上次的request

Response.setRedirect(“”)

270、描述 JSP和Servlet的区别、共同点、各自应用的范围

Jsp 主要在于页面的显示动态生成页面,可以与html 标记一起使用,其还是要生成为一个servlet。

Servlet:主要是控制的处理,如调用业务层,跳转不同的jsp 页面。

Mvc

Jsp:v

Servlet:c

271、在 JSP中如何读取客户端的请求,如何确定某个 Jsp文件的真实路径?

Request.getparameter(“”)

<%=application.getRealPath("aa.jsp") %>

272、描述 Cookie和Session的作用,区别和各自的应用范围,Session工作原理。

Cookie:主要用在保存客户端,其值在客户端与服务端之间传送,不安全,存储的数据量有限。

Session:保存在服务端,每一个session 在服务端有一个sessionID 作一个标识。存储的数据量大,安全性高。占用服务端的内存资源。

273、说明 Jsp中errorPage的作用,应用范围。

正常页面中

%@page erropage=”error.jsp”%

错误页面

<%@page iserrorpage=”true”%>

有一内置对象:exception

274、介绍在 Jsp中如何使用 JavaBeans

<jsp:useBean class=”” id=”” scope=””/>

<%

New 类();

%>

275、简单介绍 JSP的标记库

做一个标记处理类extends TagSupport

通过tld 说明标记处理的类的前缀及后缀

在web.xml 中说明tld 文件

<taglib>

<taglib-uri>

<taglib-location>

<taglib>

在jsp 页面是引用tld<%@taglib uri=”” prefix=””%>

276、Servlet中的核心类有那些,各有什么特点?

ServletContext:容器,放置全局变量

setAtribute()

getAttribute()

ServletConfig:一个servlet 的配置

getInitParameter(”名称”)

HttpServletRequest:封装的所有的请求

getParameterValue(”名称”)

getParameterValues(”称”)

getSession();

getAttribute(” 名称”);

getRequestDispatch(”a.jsp”).forward(request,response)

HttpServletResponse:响应

getOut();

sendRedirect(””)

HttpSession:一个用户多个页面共享同一变量

setAttribute(””,””)

277、Servlet中重要的包有那些,有什么区别?

javax.servlet.*;javax.servlet.http.*;

278、说出 Servlet的生命周期,并说出 Servlet和 CGI的区别?

Servlet 被服务器实例化后,容器运行其init 方法,请求到达时运行其service 方法,service 方法自动派遣运行与请求对应的doXXX 方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy 方法。

与cgi 的区别在于servlet 处理服务器进程中,它通过多线程方式运行其service 方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI 对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。

279、什么情况下调用 doGet()和doPost()?

Jsp 页面中的form 标签里的method 属性为get 时调用doGet(),为post 时调用

doPost()。

280、如何现实 servlet的单线程模式

在doGet 及doPost 方法前加入synchoronized

JSP:

<%@ page isThreadSafe="true"%>

281、Request对象的主要方法:

setAttribute(String name,Object):设置名字为name 的request 的参数值

getAttribute(String name):返回由name 指定的属性值

getAttributeNames():返回request 对象所有属性的名字集合,结果是一个枚举的实例

getCookies():返回客户端的所有Cookie 对象,结果是一个Cookie 数组

getCharacterEncoding():返回请求中的字符编码方式

getContentLength():返回请求的Body 的长度

实例

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):删除请求中的一个属性

282、我们在 web应用开发过程中经常遇到输出某种编码的字符,如 iso8859-1等,如何输出一个某种编码的字符串?

Public String translate (String str) {

String tempStr = "";

try {

tempStr = new String(str.getBytes("ISO-8859-1"), "GBK");

tempStr = tempStr.trim();

}catch (Exception e) {

System.err.println(e.getMessage());

}

return tempStr;

}

283、Servlet执行时一般实现哪几个方法?

public void init(ServletConfig config)

public ServletConfig getServletConfig()

public String getServletInfo()

public void service(ServletRequest request,ServletResponse response)

public void destroy()

284、rvlet的执行流程。doGet和doPost的区别

Servlet的执行流程也就是servlet的生命周期,当服务器启动的时候生命周期开始,然后通过init()《启动顺序根据web.xml里的startup-on-load来确定加载顺序》方法初始化servlet,再根据不同请求调用doGet或doPost方法,最后再通过destroy()方法进行销毁。

doGet和doPost都是接受用户请求的方法,doGet处理get请求,doPost处理post请求,doGet用于地址栏提交,doPost用于表单提交,在页面提交数据时,get的数据大小有限制4k,post没有限制,get请求提交的数据会在地址栏显示,post不显示,所以post比get安全.

285、vice有一个实例变量,doGet和doPost去调用这个变量,会出现什么问题,你是如何解决的。

会出现线程不安全问题。无论是doGet还是doPost去调用,服务器端处理的过程都是一样的,那么我们可以把处理过程单独写在另外一个方法handle里,让两个方法都去调用handle,根据不同请求去调用不同的方法。

286、servlet的线程不安全问题

线程安全就是多线程操作同一个对象不会有问题,线程同步一般来保护线程安全,所以可以在Servlet的线程里面加上同步方法或同步块。(Synchronized)可以保证在同一时间只有一个线程访问,(使用同步块会导致性能变差,最好不去使用实例变量)

287、Jsp和servlet的区别

jsp的可读性强,容易维护,并且jsp在最后会编译成servlet

servlet容易调试

288、Jsp的九大内置对象,三大指令,七大动作的具体功能

九大内置对象:

pageContext :只对当前jsp页面有效,里面封装了基本的request和session的对象

Request :对当前请求进行封装

Session :浏览器会话对象,浏览器范围内有效

Application :应用程序对象,对整个web工程都有效

Out :页面打印对象,在jsp页面打印字符串

Response :返回服务器端信息给用户

Config :单个servlet的配置对象,相当于servletConfig对象

Page :当前页面对象,也就是this

Exception :错误页面的exception对象,如果指定的是错误页面,这个就是异常对象

三大指令:

Page :指令是针对当前页面的指令

Include :用于指定如何包含另一个页面

Taglib :用于定义和指定自定义标签

七大动作:

Forward,执行页面跳转,将请求的处理转发到另一个页面

Param :用于传递参数

Include :用于动态引入一个jsp页面

Plugin :用于下载javaBean或applet到客户端执行

useBean :使用javaBean

setProperty :修改javaBean实例的属性值

getProperty :获取javaBean实例的属性值

获取页面的元素和值有几种方式,分别说一下

request.getParameter() 返回客户端的请求参数与值

request.getParameterNames() 返回所有可用属性名的枚举

request.getParameterValues() 返回包含参数的所有值的数组

289、et和javaScript的区别,他们分别是什么作用

一个是服务端,一个是客户端

Servlet是独立于平台和协议的服务器端的java应用程序,可以动态生成web页面,并采用响应--请求的模式提供web服务

javaScript是一种解释性语言,用于向html页面提供交互行为,通常被直接嵌入在html页面中

servlet是java语言编写的web应用

js是基于html上的一种解释语言

posted @ 2020-03-20 13:48  威兰达  阅读(748)  评论(0编辑  收藏  举报