Java面试题

java基础

1.jdk与jre的区别?

jdk:java development kit的简称,是Java开发工具,提供了Java的开发环境和运行环境。
jre:java runtime environment的简称,提供了Java的运行环境
实际上,jdk包含了jre

2.一个".java"源文件中是否可以包含多个类(不是内部类)?

可以有多个类,但必须只有一个public类,而且public类必须与文件名一致

3.什么是内部类?

内部类指定义在另一个类或方法里的类,常见内部类有成员内部类局部内部类匿名内部类静态内部类
成员内部类:成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有;而外部类想要访问内部类,就必须创建内部类对象,通过对象去访问。如果成员内部类的属性或方法和外部类重了,可通过外部类.属性名或方法名来调用。创建内部类对象方法:外部类.内部类 对象=new 外部类().new 内部类();
注意 :成员内部类不能包含静态属性或方法
局部内部类:存在于方法中的内部类,定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。
匿名内部类:匿名内部类就是一个没有名字的内部类,实现匿名内部类有一个前提条件,就是必须继承一个父类或实现一个接口。
实例代码:

abstract class Person {

    public abstract void eat();

}

 

public class Demo {

    public static void main(String[] args) {

        Person p = new Person() {

            public void eat() {

                System.out.println("eat something");

            }

        };

        p.eat();

    }

}

注意事项:匿名内部类没有构造方法。
静态内部类:静态内部类和成员内部类相比就多了一个static,静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量。

4.内部类的好处?

①内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
②内部类不为同一包的其他类所见,具有很好的封装性。

5.==与equals的区别?

==解读:
注:基本数据类型比较的是值,引用数据类型比较的是内存地址
它的作用是判断两个对象的地址是不是相等,即,判断两个对象是不是同一个对象。
equals 解读:
它的作用也是判断两个对象是否相等,一般存在两种情况:
1.类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“ == ”比较这两个对象。
2.类覆盖了 equals() 方法。若它们的内容相等,则返回 true (即,认为这两个对象相等)。
代码示例:

String x = “string”;
String y = “string”;
String z = new String(“string”);
System.out.println(x= =y); // true
System.out.println(x= =z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
String a = new String(“AA”);
String b = new String(“AA”);
System.out.println(a.equals(b));//true
Cat c1 = new Cat(“精彩猿笔记”);
Cat c2 = new Cat(“精彩猿笔记”);
System.out.println(c1.equals(c2)); // false

总结:== 对于基本数据类型来说是值比较,对于引用数据类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等,这种情况下 equals 比较的是内容是否相等。

6.final在Java中有什么作用?

final修饰的类是最终类,不能被继承
final修饰的方法不能被重写
final修饰的变量叫做常量,必须初始化,并且初始化后不能被修改

7.String属于基础数据类型吗?

不属于,基础数据类型有八种:byte,short,int,long,char,float,double,boolean,而String属于对象

8.Java中操作字符串的有哪些类?有什么区别?

操作字符串的有三种:String,StringBuffer,StringBuilder
区别:StringBuffer和StringBuilder都继承自抽象类AbstractStringBuilder
而StringBuffer,StringBuilder存储数据的数组没有被final修饰,说明值可以被改变,AbstractStringBuilder内部有一个自动扩容机制,当发现长度不够时(默认长度是16),会自动扩容,扩展为原来长度的二倍加二,创建一个新的数组,并将原数组中的数据复制到新数组中,综上所述,对于字符串拼接时,StringBuffer,StringBuilder的效率会更高。
线程安全性:StringBuffer由于很多方法都被synchronized修饰了,所以线程安全,但是当多线程访问时,加锁和释放锁的过程很频繁,所以相比StringBuilder的效率会低一点。相反,StringBuilder执行效率会高一点,但是线程不安全。
所以,单线程时推荐使用StringBuilder(单线程下安全,考虑到速度,所以选择StringBuilder),多线程是选择StringBuffer(考虑到安全性)

9.String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存分配不同,String str="i"方式,Java虚拟机会将其分配到常量池中,如果常量池中有,就返回"i"的地址,如果没有就创建,然后返回其地址;而new String(“i”)方式,则会被分配到堆内存空间新开辟一块空间。

10.普通类和抽象类的区别?

①普通类不能有抽象方法,抽象类可以有抽象方法
②抽象类不能被实例化
③抽象方法不能被声明为静态
④抽象方法不能用private,final修饰

11.接口和抽象类有什么区别?

①抽象类是被子类继承,接口是被类实现
②抽象类可以有构造函数,接口没有构造函数
③一个类可以实现多个接口但是只能继承一个抽象类
④接口强调特定功能的实现,而抽象类强调所属关系

12.Java中IO流分为几种?

按功能分:输入流、输出流
按类型分:字节流、字符流
字节流和字符流之间的区别:字节流是以8位传输以字节为单位输入输出数据,字符流是以16位传输以字符为单位输入输出数据

13.BIO,NIO,AIO 有什么区别?

BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

14.什么是反射机制?

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

15.反射机制优缺点

优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

16.Java获取反射的三种方法

1.通过new对象实现反射机制
2.通过路径实现反射机制
3.通过类名实现反射机制

17.String 类的常用方法都有那些?

length():返回字符串长度。
equals():字符串比较。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。

18.JDK 中常用的包有哪些?

java.lang:这个是系统的基础类;
java.io:这里面是所有输入输出有关的类,比如文件操作等;
java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
java.net:这里面是与网络有关的类;
java.util:这个是系统辅助类,特别是集合类;
java.sql:这个是数据库操作的类。

19.什么是序列化,什么是反序列化?

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

20.什么时候需要实现序列化?

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
当你想用套接字在网络上传送对象的时候;
当你想通过RMI传输对象的时候;

21.序列化及反序列化的过程?

对象序列化的过程:
   1、创建一个对象输出流,它可以包装一个其他类型的输出流(文件输出流)
   2、通过对象输出流的writeObject()将对象->字节序列。
对象反序列化的过程:
   1、 创建一个对象输入流,它可以包装一个其他类型的源输入流(文件输入流)
   2、通过对象输入流的readObject()将字节序列->对象。

22.Java中this关键字含义是什么?有什么作用?

this关键字主要有三个作用:
①this调用本类的属性,也就是类中的成员变量。
②this调用本类中的其他方法。
③this调用本类中的其他构造方法,调用时要放在构造方法首行。

23.常见设计模式?

单例模式:就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例。
①单例模式下的懒汉模式:

public class Singleton {
    //懒汉模式
    private static Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }
}

②单例模式下的饿汉模式:

public class Singleton {
    //饿汉模式
    private static Singleton singleton=new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return singleton;
    }
}

观察者模式:对象间一对多的依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
装饰者模式:对已有的逻辑进一步的封装,使其增加额外的功能。
适配器模式:将两种不同的事务联系到一起
工厂模式:有四个角色,抽象工厂模式,具体工厂模式,抽象产品模式,具体产品模式。不再是由一个工厂类去实例化具体的产品,而是由抽象工厂的子类去实例化产品

java集合框架

1.集合和数组之间的区别?

①数组可以存放基本数据类型和对象,而集合仅能存放对象,不能存放基本数据类型
②数组容量容易固定,无法动态改变;集合类容量可以动态改变
③数组无法判断其存了多少个元素,length只是告诉了数组的容量,集合的size可以确切指出元素的个数
④数组仅采用顺序表方式,而集合有多种实现方式。
⑤集合以类的形式存在,具有封装、继承、多态的特性,大大提高了软件的开发效率。

2.Java容器有哪些?

Java容器大致可分为两大类:collection,map
Collection的子接口包括:Set、List
List集合有序列表,允许存放重复元素,允许存放null
其实现类有:ArrayList、LinkedList、Vector
ArrayList:基于动态数组实现,支持随机访问,查询快、增删慢,轻量级,线程不安全
LinkedList:基于双向链表实现,只能顺序访问,增删快、查询慢,轻量级,线程不安全
Vector:基于动态数组实现,重量级,线程安全(使用少)
Set集合无序列表,不允许存放重复元素,允许存放null
其实现类有:TreeSet、HashSet、LinkedHashSet
TreeSet:基于红黑树实现,支持有序操作,但查询效率不如HashSet
HashSet:基于哈希表实现,查询效率高,不支持有序操作,线程不安全,允许存放null
(不允许元素重复是因为,HashSet是同时通过equals和Hashcode来判断元素是否相同的)
LinkHashSet:是一个双向链表,具有HashSet的查找效率,且内部使用双向链表维护元素的插入顺序。


Map的子接口包括:HashMap、TreeMap、LinkedHashMap、HashTable

HashMap:键值对形式,键不可重复,值可重复;允许null键或值;具有很高的访问速度;不允许线程同步。
TreeMap:基于红黑树实现,是一个有序的key-value集合

3.HashMap和HashTable的区别?

①null值:HashMap允许放入null值,HashTable不允许放入null值。
②线程安全:HashTable 内部的方法基本都经过 synchronized 修饰;HashMap 是非线程安全的,HashTable 是线程安全的(如果要保证线程安全的话就使用 ConcurrentHashMap )。
③继承父类不同:hashmap继承自abstractmap,hashtable继承自dictionary类。
④效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。
⑤初始容量和扩充容量不同:Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。

4.ArrayList和LinkedList区别?

①ArrayList是基于动态数组实现的,LinkedList是基于双向链表实现的
②对于随机访问,ArrayList优于LinkedList,因为LinkedList要移动指针
③ArrayList查询快、增删慢,LinkedList增删快、查询慢
④LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。

5.Hashmap与Treemap之间的区别?

①HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,查询速度慢。
②在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果要按自然顺序或自定义顺序遍历键,那么TreeMap速度会更快

6.HashMap讲解

结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。

6.1 HashMap底层结构

(1) 从源码可知,HashMap类中有一个非常重要的字段,就是 Node[] table,即哈希桶数组,它是一个Node的数组。Node是HashMap的一个内部类,实现了Map.Entry接口,本质是就是一个键值对
(2) HashMap就是使用哈希表来存储的。哈希表为解决冲突,可以采用开放寻址法和拉链法等来解决问题,Java中HashMap采用了拉链法。拉链法,将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。

6.2 HashMap的put方法

在这里插入图片描述
①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容;
②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,put操作完成,如果table[i]不为空,转向③;
③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals;
④.判断table[i] 是否为treeNode(红黑树),如果是红黑树,则直接在树中插入键值对,否则转向⑤;
⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;
⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。

6.3 HashMap的扩容操作

①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容;
②.每次扩展的时候,都是扩展2倍;
③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

JVM基础知识

1.JVM 的主要组成部分及其作用

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
过程: 首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

2.JVM 运行时数据区

在这里插入图片描述
栈:主要存放的是局部变量,用来引出堆和方法区中的对象和常量
堆:主要存放对象的实例
方法区:存放的是常量和静态变量以及被编译后的代码
(方法区的回收主要是对常量池的回收以及对类型的卸载)
程序计数器:主要作用是指示当前程序执行到了哪一行

3.内存泄漏

内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。
java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

4.垃圾回收机制

在java中,垃圾回收是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。
Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。

5.JVM 有哪些垃圾回收算法?

标记-清除算法: 标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
复制算法: 按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
标记-整理算法: 标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
分代算法: 根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。

Spring

Spring是一个轻量级的IOC和AOP容器框架,是一个分层框架,更多作为管理,目的是为了解决企业开发的复杂性,简化Java开发。
Spring有两个核心特性,也就是依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP)。

1.Spring 框架中都用到了哪些设计模式?

工厂模式: BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
单例模式: Bean默认为单例模式。
代理模式: Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
模板方法: 用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
观察者模式: 定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

2.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进行加载实例化;ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。
3.创建方式: BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建。

3.Spring控制反转(IOC)

控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。

3.1 IOC的优点

(1): IOC 或 依赖注入把应用的代码量降到最低。
(2): 它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
(3): 最小的代价和最小的侵入性使松散耦合得以实现。

3.2 依赖注入实现方式

注:接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。
构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。

Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。

构造函数注入setter 注入
没有部分注入有部分注入
不会覆盖 setter 属性会覆盖 setter 属性
任意修改都会创建一个新实例任意修改不会创建一个新实例
适用于设置很多属性适用于设置少量属性

4.Spring面向切面编程(AOP)

面向切面编程,通过预编译和运行期动态代理实现程序功能的一种技术,是对oop的补充,在不影响原来功能的基础上,使用动态代理加入一些自己需要的功能。

4.1 JDK动态代理和CGLIB动态代理的区别

JDK动态代理只提供接口的代理,不支持类的代理。
CGLIB是通过继承的方式做的动态代理,如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。

5.什么是Spring beans?

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

6.Spring基于xml注入bean的几种方式

①Set方法注入;
②构造器注入:1.通过index设置参数的位置;2.通过type设置参数类型;
③静态工厂注入;
④实例工厂;

7.Spring支持的几种bean的作用域

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

8.Spring框架中的单例bean是线程安全的吗?

Spring框架中的单例bean不是线程安全的
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。

9.Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

10.Spring框架中bean的生命周期

在这里插入图片描述
1.Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化

2.Bean实例化后对将Bean的引入和值注入到Bean的属性中

3.如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法

4.如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入

5.如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。

6.如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

7.如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用

8.如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

9.此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。

10.如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

11.Spring注解

@Configuration: 用来标记类可以当做一个bean的定义,被Spring IOC容器使用。
@Component: 将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller: 将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service: 此注解是组件注解的特化。
@Repository: 它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器。
@Autowired: 自动装配注解,默认是按照类型装配注入的。
@Resource: 默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

12.Spring支持的事务管理类型

编程式事务管理: 这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
声明式事务管理: 这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。

Spring MVC

1.Spring MVC的主要组件?

(1)前端控制器 DispatcherServlet(不需要程序员开发)
(2)处理器映射器HandlerMapping(不需要程序员开发)
(3)处理器适配器HandlerAdapter
(4)处理器Handler(需要程序员开发)
(5)视图解析器 ViewResolver(不需要程序员开发)
(6)视图View(需要程序员开发jsp)

2.Spring MVC的工作流程?

①用户发出请求,请求被前端控制器dispatcherservlet捕获。
②dispatcherservlet收到请求后,把请求信息交给handlermapping
③handlermapping根据用户的URL请求,找到匹配的handler
④dispatcherservlet将请求转发给handler
⑤通过handleradapter执行handler的业务逻辑,并返回一个modelandview
⑥dispatcherservlet查询到视图解析器,将modelandview渲染成视图
⑦dispatcherservlet再将页面响应给用户。

3.Spring MVC注解

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

MyBatis

mybatis是一个半自动的orm持久层框架,专注于sql操作,底层就是一个封装了jdbc的组件。

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

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

2.MyBatis的工作原理

①首先加载mybatis全局配置文件,MyBatis基于XML配置文件生成Configuration。
②SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory。
③SqlSessionFactory再根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。
④SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。

3.Mybatis中的#{}和${}的区别?

1、#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理
2、${}将传入的数据直接显示生成在sql中。
3、#{}方式可以很大程度上防止sql注入,而${}无法防止sql注入。
4、涉及到动态表名、列名和排序时使用order by动态参数时需要使用${}

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

第1种: 通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
第2种: 通过<resultMap> 来映射字段名和实体类属性名的一一对应的关系。

5.Mybatis动态sql

Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
Mybatis提供了9种动态sql标签trim、where、set、foreach、if、choose、when、otherwise、bind。

SpringCloud

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

1.Spring Cloud核心组件

Eureka: 服务治理组件,包括服务端的注册中心和客户端的服务发现机制;
Ribbon: 负载均衡的服务调用组件,具有多种负载均衡调用策略;
Hystrix: 服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;
Feign: 基于Ribbon和Hystrix的声明式服务调用组件;
Zuul: API网关组件,对请求提供路由及过滤功能。

2.Spring Cloud 和dubbo区别?

(1)服务调用方式 dubbo是RPC springcloud是REST Api
(2)注册中心,dubbo是zookeeper;springcloud是eureka,也可以是zookeeper。

Redis

Redis是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。
Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。
与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。

1.Redis有哪些数据类型

Redis主要有5种数据类型,包括String,List,Set,Zset,Hash,满足大部分的使用要求。

数据类型可以存储的值应用场景
String字符串、整数或者浮点数做简单的键值对缓存
List列表存储一些列表型的数据结构
Set无序集合交集、并集、差集的操作
Hash包含键值对的无序散列表结构化的数据,比如一个对象
Zset有序集合去重但可以排序

2.Redis 的持久化机制

Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制
RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。
AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。

3.RDB和AOF区别

1.AOF文件比RDB更新频率高,优先使用AOF还原数据。
2.AOF比RDB更安全也更大
3.RDB性能比AOF好
4.如果两个都配了优先加载AOF

4.Redis的过期键的删除策略

定时过期: 每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期: 只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期: 每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

5.缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2.一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
3.给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

6.缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
1.接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2.从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
3.采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力

数据库

1.数据库三大范式

第一范式:每个列都不可以再拆分。

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。

第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

2.MySQL存储引擎

Innodb引擎(默认): Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
MyIASM引擎: 不提供事务的支持,也不支持行级锁和外键。

3.索引

索引(Index)是帮助MySQL高效获取数据的数据结构,一种快速查找排序的数据结构。

3.1 索引优缺点?

优点:
1.可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
2.通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
缺点:
1.时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
2.空间方面:索引需要占物理空间

3.2 索引的数据结构(b树,hash)

索引的数据结构和具体存储引擎的实现有关,在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引。

4.数据库设计索引的原则?

①选择的唯一性(主键索引和唯一索引,在查询效率中是最高的)
②为经常需要排序、分组、和联合查询的字段建立索引。
③为经常作为where查询条件的字段建立索引。
④尽量使用前缀作为索引
⑤限制索引的数目。
⑥删除不再使用或很少使用的索引。
⑦大表加索引,要在业务不繁忙时操作。

5.事务四大特性(ACID)

什么是事务:是数据库操作的最小工作单元,这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合;
原子性(Atomicity):是指事务是一个不可分割的单位,事务中的操作要么都执行,要么都不执行(全部回滚)
一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏,比如:A向B转账,不可能A扣了钱,B却没收到。
隔离性(Isolation):指当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间相互隔离。
持久性(Durability):指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

6.五大隔离级别

为了防止出现脏读、不可重复读、幻读等情况,通常数据库都设有隔离级别。
Default:数据库默认的隔离级别
未提交读(read uncommited):脏读、不可重复读、幻读都有可能发生
已提交读(read commited):避免脏读,不可重复读、幻读有可能发生
可重复读(repeatable read):避免脏读和不可重复读,幻读有可能发生
串行化(serializable):避免以上所有读的问题
在这里插入图片描述

7.事务的七大传播特性

※保证在同一个事务中
propagation_required:如果存在一个事务,则支持该事务;如果没有事务则开启一个新事物
propagation_supports:如果存在一个事务,则支持该事务;如果没有,就不使用事务
propagation_mandatory:如果存在一个事务,则支持该事务;如果没有,则抛出异常
※保证没有在同一个事务中
propagation_requires_new: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
propagation_not_supported: 总是非事务地执行,并挂起任何存在的事务。
propagation_never: 总是非事务地执行,如果存在一个活动事务,则抛出异常
propagation_nested:如果一个活动的事务存在,则运行在一个嵌套的事务中

8.常用sql语句

#1.查询出student表中birthday,并去除其重复的数据
select distinct biryear from student
#2.查询出年龄在1997到1998之间的学生信息(两种)
select * from student where biryear in(1997,1998)
select * from student where biryear between 1997 and 1998
#3.查询姓名中带有华的学生信息
select * from student where sname like '%华%'
#4.查询所有学生信息,并按升序排序
select * from student order by biryear ASC;
#5.查询出年龄大于1998的人数
select count(*) as 年龄大于1998的人数 from student where biryear>1998
#6.查询出最大年龄学生的所有信息
select * from student where biryear=(select max(biryear) from student)
#7.查询出前四条数据
select * from student limit 4

9.varchar和char的使用场景?

类型使用场景
varchar字符长度经常改变的
char字符长度固定的

10.数据库的五大约束?

1.主键约束(Primay Key Coustraint) 唯一性,非空性;
2.唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个;
3.默认约束 (Default Counstraint) 该数据的默认值;
4.外键约束 (Foreign Key Counstraint) 需要建立两表间的关系;
5.非空约束(Not Null Counstraint):设置非空约束,该字段不能为空。

11.如何优化sql语句?

1.避免全查询,对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.避免查询不必要的字段
3.避免使用不等式判断。

12.如何防止sql注入?

1.多使用预编译功能
2.减少使用动态sql语句
3.对于sql拼接参数时,尽量用#{}号代替${}

并发异常

1.Nginx负载均衡有哪几种?

1.轮询的方式,它是upstream模块默认的负载均衡策略。每个请求会按时间顺序逐一分配到不同的后端服务器。
2.权重方式,在轮询策略的基础上指定轮询的几率。
3.ip_hash,指定负载均衡器按照基于客户端IP的分配方式,这个方法确保了相同的客户端的请求一直发送到相同的服务器,以保证session会话。
4.fair,按照服务器端的响应时间来分配请求,响应时间短的优先分配。
5.url_hash,按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。

2.常见runtime exception

NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
SQLException
FileNotFoundException
IOException …

3.sleep() 和 wait() 有什么区别?

sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,将执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

4.释放锁的方式?

第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,
第二种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。

5.什么是线程安全?什么是线程不安全?

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

6.如何创建线程?

1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程

7.什么是死锁?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象

8.死锁产生必要条件?如何避免死锁?

互斥条件:进程要求对所分配的资源进行排他性控制,即一段时间内某资源仅为某一进程所占有。
不可剥夺条件:进程所获得的的资源在未使用完毕前,不可被剥夺。
请求和保持条件:进程保持了至少一个资源,但又提出了新的资源请求,该资源已被占用,此时进程被阻塞,但对自己的资源保持不放。
循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。
避免死锁:
①给线程按照一定的顺序加锁。
②加锁时限
③死锁检测

9.如何保证线程安全?

保证线程安全是以需要同步手段进行分类,分为同步方案和非同步方案:
同步方案:
1、互斥同步
2、非阻塞同步
无需同步方案(保证线程安全不一定需要线程同步):
1、可重入代码:可重入代码又称纯代码,可以在代码执行的任何阶段打断它,转而去执行另一段代码,在控制权返回后,原来程序不会发生错误。所有的可重入代码都是安全的。
2、线程本地存储:把共享数据的可见范围限制在同一个线程之内。这样无需同步也能保证线程之间不出现数据的争用问题。

10.Nginx如何实现负载均衡?

Nginx是一个反向代理服务器,主要作用就是处理高并发、高访问,解决服务器的压力
Nginx实现负载均衡:
修改Nginx.conf文件,在upstream模块里,添加负载均衡的服务器列表
在设置负载均衡时,Nginx默认的是采用轮询方式,一比一分配,也可修改权重,
自己制定分配方式。
负载均衡策略:①轮询
②权重
③ip_hash(是基于客户端IP的分配方式,保证了
相同的客户端发送的请求可以一直发送到相同的服务器,保证了session回话)

网络

1.session和cookie区别?

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗
考虑到安全应当使用session
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用cookie
4、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的cookie不能3K。

Git

1、git是一个分布式版本控制系统,使用c语言开发的
2、集中式版本控制系统与分布式控制系统的区别:集中式版本控制系统,版本库是集中存放在中央服务器的,一旦中央服务器坏掉时,所有人工作都不能正常进行。而分布式控制系统,没有中央服务器,每个电脑都有完整的一个版本库,要比集中式版本控制系统安全得多。
初始化一个git仓库:git init
添加文件到仓库 ①git add 文件名 ②git commit -m “提示信息”
查看工作区状态:git status
查看修改的内容:git diff
显示从最近到最远的提交日志:git log 嫌输出信息多输入:git log --pretty=online
恢复到以前的版本:git reset --hard HEAD 注意:HEAD是当前版本 HEAD^是上一版本 …
恢复到以前版本后又想恢复恢复前的版本:git reset --hard 版本号 版本号可通过git log命令查看,不用全输,如果你关机了,用git reflog查看日志
git存储原理:git版本库中存储了很多东西,首先文件通过git add命令先存储到stage暂存区中,git会自动创建一个分支;然后通过git commit,把暂存区中的东西,存储到了分支里。
修改:①当你修改还没添加到暂存区时,git checkout – 文件名(–后面有一个空格)
②当你把修改内容添加到了暂存区,用git reset HEAD 文件名,回到场景①,在执行①
③当你把修改提交到版本库时,采用版本回退方法
删除:①rm 文件名或git rm 文件名
恢复已删除文件:①以rm删除方式删除的,直接用git checkout – 文件名恢复
②以git rm方式删除的,用git reset HEAD 文件名回到上一场景,再以场景一方式恢复
可以看出,修改和删除有一个共同点,git rm 文件名与git rm 文件名的效果是一样的
关联远程库:git remote add origin 自己的url
关联后推送:首次推送:git push -u origin master
之后推送:git push origin master
克隆仓库:git clone url
创建分支:git branch 分支名
查看分支:git branch
切换分支:git checkout 分支名 或 git switch 分支名
创建+切换分支:git checkout -b 分支名 或 git switch -c 分支名
合并某分支到当前分支:git merge 分支名
删除分支:git branch -d 分支名
通常情况下,合并分支时,都会禁用Fast forword模式,如果不禁用,删除分支后会丢失分支信息,禁用后,删除分支,会在merage时生成一个commit,这样从分支历史上就可以看出分支信息。git merge --no-ff -m “提示信息” 分支名
开发一个新的功能时,最好新建一个分支,如果要丢弃一个还没有被合并过的分支,可强行删除:git branch -D 分支名
当从远程仓库克隆时,实际上git自动把本地的master分支和远程的master对应起来了,远程仓库的默认名是origin,
查看远程库信息:git remote
详查远程仓库信息:git remote -v
推送分支到远程仓库:git push origin 分支名
并不是什么分支都推送到远程仓库,到底什么分支需要推送?
①master分支是主分支,时刻要与远程保持一致
②dev是开发分支,也要时刻保持一致
③bug分支只用于在本地修复bug,就没有必要推送到远程了
④feature分支是否推送,取决于团队
多人协作时,工作模式是这样的:
1.首先可以用git push origin 分支名来推送自己的修改
2.如果推送失败,是因为远程分支比你的本地更新,需要用git pull试图合并
3.如果合并失败,则解决冲突,并在本地提交
4.没有冲突或解决掉冲突后,再执行1
(如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to 分支名 origin/分支名)
小结:
①查看远程库信息,使用git remote -v;
②本地新建的分支如果不推送到远程,对其他人就是不可见的;
③从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
④在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
⑤建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
⑥从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

1.代码托管

①git init
②git add .
③git commit -m “first commit”
④git remote add origin https://gitee.com/********/basic-structure.git
⑤git push origin master
⑥git checkout -b ****** 创建并切换该分支
⑦git push origin ****** 推送该分支

Maven

1.常用打包命令:

mvn clean compile -U 重新下载依赖包
mvn clean package -Dmaven.test.skip=true
mvn clean deploy -Dmaven.test.skip=true
-Dmaven.test.skip=true 这句是打包时跳过单元测试
mvn clean package:依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)等7个阶段。
mvn clean install:依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install等8个阶段。
mvn clean deploy:依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install、deploy等9个阶段
综上:package命令完成了项目编译、单元测试、打包功能,但没有把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库
install命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程maven私服仓库
deploy命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值