面试题

基础语法

Q1:简单说说Java有哪些数据类型

答:①分为基本数据类型和引用数据类型。②基本数据类型包括:数值型(byte、short、int、long、float、double),字符型(char)以及布尔型(boolean)。除了基本类型外,其他数据类型都属于引用类型,包括类、接口、数组等。

Q2:float number=3.4;有没有问题?为什么?

答:有问题,因为3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于向下转型,可能会造成精度损失,所以必须进行强制类型转换,正确的写法是float number =(float)3.4;/ float number =3.4F;。

Q3:字符串拼接的方式以及效率?

答:①使用+直接拼接,String 是final对象,不会被修改,每次使用 +进行拼接都会创建新的对象,而不是改变原来的对象,效率低,是线程安全的。②使用StringBuffer可变字符串,效率较高,是线程安全的(StringBuffer的方法使用了synchronized关键字进行修饰)。③使用StringBuilder可变字符串,效率最高,但是线程不安全。

Q4:简述final,finally和finalize区别

答:①final可以修饰类,方法和变量,被final修饰的类不可继承,被final修饰的方法不可重写,被final修饰的变量引用不可更改,引用的内容可以更改。②finally用于try-catch代码块中,无论是否发生异常最后都将执行,作用是释放资源。③finalize是Object类的方法,在对象被垃圾回收之前将调用一次,一般用于资源的释放。

Q5:==和equals有什么区别?equals和hashCode有什么联系?

答:①如果是引用类型,==比较的是两个对象的引用是否完全相同,如果是基本类型,比较的是两个基本类型的数值是否相同。②如果没有重写的话,equals默认按照==进行比较,如果重写了equals()方法,则按照对应的比较规则比较。③两个对象如果相等,那么它们的hashCode值必须相等,但两个对象的hashCode值相等时,它们不一定相同。

Q6:Array和ArrayList的区别?

答:①Array长度在定义之后就不运行改变了,而ArrayList是长度可变的,可以自动扩容。②Array只能存储相同类型的数据,ArrayList可以存储不同类型的数据。③ArrayList提供了更多操作数据的方法。

Q7:&和&&的区别?

答:①&具有按位与和逻辑与两个功能。②&&作为逻辑与具有短路的特点,当前面的条件表达式为false时就不会进行后面条件表达式的判断,可以用来避免空指针异常。

Q9:Stream流了解吗?

答:①Stream流是JDK1.8的新特性,用于解决已有集合/数组类库的弊端,简化集合/数组的操作。②stream流的获取:集合:直接调用stream()方法获取;数组:使用静态方法Stream.of()/Arrays.stream()获取。③常用方法:forEach() 遍历;count() 统计个数;filter() 按条件过滤;limit() 取前面n个元素;skip() 跳过前面n个元素;map() 映射加工;concat() 合并stream流。④终结方法:foreach/count 调用终结方法后流不能继续使用;非终结方法:每次调用完返回一个新的stream对象,可以继续使用,支持链式编程。⑤收集stream流:把流转为Set集合 collect(Collections.toSet());把流转为List集合 collect(Collections.toList());把流转为Collection集合 collect(Collections.toCollection());把流转为数组 toArray()。

面向对象

Q1:简述面向对象的特性

答:①封装:建议成员变量私有,然后提供公有的getter/setter方法来获取值/赋值,封装的核心思想是合理隐藏,合理暴露,可以提高安全性,实现代码的组件化。②继承:一种子类到父类的关系,是“is a”关系,可以提高代码的复用性,相同代码可写到父类,子类的功能更加强大,不仅得到了父类的功能,还有自己的功能。③多态:同一个类型的对象执行相同的行为,在不同的状态下表现出不同的特征。多态可以降低类之间的耦合度,右边对象可以实现组件化切换,业务功能随之改变,便于扩展和维护。

Q2:类和对象有什么区别?

答:类是一个抽象的概念,是具有相同特征的事物的描述,是对象的模板。对象是一个个具体的存在,是类的实例。

Q3:列举Object类的方法

答:①equals(Object obj):判断其他对象是否与当前对象相等。②toString():打印当前对象的字符串表示。③wait():导致当前线程等待,等待其他线程唤醒,会释放锁。④notify()/notifyAll():随机唤醒一个/全部线程。⑤hashCode():返回当前对象的hashCode值。⑥finalize():当垃圾回收器要回收对象前调用。⑦clone():创建并返回对象的一个副本。

Q4:方法重载和方法重写的区别?

答:①方法重载是同一个类中具有不同参数列表的同名方法(无关返回值类型),方法重写是子类中具有和父类相同参数列表的同名方法,会覆盖父类原有的方法。②重载的返回值类型和权限修饰符,异常抛出类型没有要求,重写方法的返回值类型小于等于父类被重写方法的返回值类型,修饰符权限大于等于父类被重写方法权限修饰符,抛出的异常类型小于等于父类被重写方法抛出的异常类型。

Q5:接口和抽象类有什么区别?

答:①接口中只能定义public staic final修饰的常量,抽象类中可以定义普通变量。②接口和抽象类都不能实例化,但接口没有构造器,抽象类有构造器。③接口可以多实现,抽象类只能单继承。④接口在JDK1.8之前只能定义public abstract修饰的方法,JDK1.8开始可以定义默认方法和静态方法,JDK1.9开始可以定义私有方法,抽象类中的方法没有限制。

Q6:什么时候应该使用接口,什么时候应该使用抽象类?

答:①如果知道某个类应该成为基类,那么第一选择应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。②在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。通过抽象类建立行为模型会出现的问题:如果有一个抽象类Moblie,有两个继承它的类Mobile1和Moblie2,分别有自己的功能1和功能2,如果出现一个既有功能1又有功能2的新产品需求,由于Java不允许多继承就出现了问题,而如果是接口的话只需要同时实现两个接口即可。

Q7:内部类有什么作用?有哪些分类?

答:①内部类有更好的封装性,有更多的权限修饰符,封装性可以得到更多的控制。②静态内部类:由static修饰,属于类本身,只加载一次。类可以定义的成分静态内部类都可以定义,可以访问外部类的静态变量和方法,通过new 外部类.静态内部类构造器来创建对象。③成员内部类:属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可以访问外部类的所有内容,通过new 外部类构造器.new 成员内部类构造器来创建对象。④局部内部类:定义在方法、构造器、代码块、循环中。只能定义实例成员变量和实例方法,作用范围仅在局部代码块中。⑤匿名内部类:没有名字的局部内部类,可以简化代码,匿名内部类会立即创建一个匿名内部类的对象返回,对象类型相当于当前new的类的子类类型。

异常

Q1:异常有哪些分类?出现的原因是什么?

答:①Throwable是所有错误和异常的父类,Throwable分为Error和Exception。②Error指Java程序运行错误,出现Error通常是因为系统的内部错误或资源耗尽,Error不能在运行过程中被动态处理,如果程序运行中出现Error,系统只能记录错误的原因和安全终止。③Exception指Java程序运行异常,即运行中发生了不期望的情况,分为RuntimeException和CheckedException。RuntimeException指在Java虚拟机正常运行期间抛出的异常,可以被捕获并处理,例如空指针异常,数组越界等。CheckedException指编译阶段强制要求捕获并处理的异常,例如IO异常,SQL异常等。

Q2:有哪些异常处理方式?

答:①抛出异常:遇到异常不进行具体处理,而是将异常抛出给调用者,由调用者根据情况处理。抛出异常有2种形式,一种是throws,作用在方法上,一种是throw,作用在方法内。②使用try/catch进行异常的捕获处理,try中发生的异常会被catch代码块捕获,根据情况进行处理,如果有finally代码块无论是否发生异常都会执行,一般用于释放资源,JDK1.7开始可以将资源定义在try代码块中自动释放减少代码

集合

Q1:简述一下集合主要有哪些类和接口,各自有什么特点

答:①主要有两个接口Collection和Map,其中Collection又包括List、Set和Queue。②List是有序的,主要包括ArrayList,LinkedList和Vector,ArrayList底层通过数组实现,线程不安全,Vector是线程安全的ArrayList,但效率较低,LinkedList底层通过双向链表实现,与ArrayList相比增删快查询慢。③Set是唯一且无序的,主要包括HashSet,LinkedHashSet和TreeSet。HashSet底层其实就是HashMap,利用了key来保证元素的唯一性。LinkedHashSet可以按照key的操作顺序排序,TreeSet支持按照默认或指定的排序规则排序。④Queue是队列结构,主要有ArrayBlockingQueue基于数组的阻塞队列、LinkedBlockingQueue基于链表的阻塞队列等。⑤Map以key-value键值对的形式存储元素,主要包括HashMap、LinkedHashMap和TreeMap。HashMap底层通过数组+链表/红黑树实现,LinkedHashMap可以按照key的操作顺序对集合排序,TreeMap可以按照默认或指定的排序规则对集合排序。

Q3:List、Set、Map有什么区别?

答:①List是有序、可重复、有索引的集合,继承了Collection集合全部功能 除了Collection的三种遍历方式外,可用索引遍历。②Set是无序,不可重复的集合,Set的实现类LinkedHashSet和TreeSet是有序的,LinkedHashSet可以按照元素插入的顺序排序,也可以按照元素操作的时间排序,TreeSet可以按照默认的比较规则或者自定义的比较规则排序。③Map是无序、以key-value的键值对形式存储元素的集合,键不可重复,值无要求,重复的键对应的值会覆盖之前的值。

Q4:HashSet是如何去重的?

答:①对于基本类型的包装类,可以直接按值进行比较。②对于引用数据类型,会先比较hashCode()返回值是否相同,如果不同则代表不是同一个对象,如果相同则继续比较equals()方法返回值是否相同,都相同说明是同一个对象。③如果希望内容相同的对象就代表对象相同,那么除了重写equals()方法还要重写hashCode()方法,因为内容相同的对象hashCode()值不一定相同,因为只有hashCode()和equals()都相同才说明是同一个对象。

Q5:HashMap和HashSet的底层是怎么实现的?

答:①JDK1.8之前,HashMap的底层是数组加链表实现。数组中的每个元素都是一个单链表,链表中的每个元素都是Entry的实现类Node的一个实例,Node包括4个属性:key、value、hash值和用于指向单链表下一个元素的next。②HashMap在查找数据时,根据hash值可以快速定位到数组的具体下标,然后对链表进行遍历查找数据的时间复杂度为O(n)。JDK1.8起对HashMap进行了优化,底层改为数组+链表或红黑树,当链表中的元素超过8个之后,HashMap会将链表结构转换未红黑树以提高查询效率,时间复杂度为O(logn)。②HashSet的底层是基于HashMap实现的,HashSet中的元素只是存放在了底层HashMap的key上, 而value使用一个static final的Object对象标识。因此HashSet 的实现比较简单,相关操作基本上都是直接调用底层HashMap的相关方法来完成的。

Q6:Collection和Collections有什么区别?

答:①Collection是一个集合接口,它包括List有序集合、Set无序集合、Queue队列等。②Collections则是Collection的一个工具类,为Collection类型的对象提供了很多方便的方法,例如addAll可以直接对Collection集合批量添加元素,shuffle可以随机打乱List集合的元素顺序,sort可以对List集合进行默认或按比较器进行排序。

Q7:迭代器是什么?

答:①迭代器实现了Iterator接口,是用于遍历Collection集合元素的一个指针。②主要有三个方法:通过iterator()获得集合的迭代器;通过hasNext()判断集合当中是否还有元素,如果有返回true,没有则返回false,初始时迭代器位于第一个元素之前;通过next()获取集合的下一个元素,并向后移动一个元素的单位。

Q8:在使用foreach循环遍历集合元素时能否添加或删除元素?

答:使用foreach循环遍历元素集合时不能修改或删除元素,通过java -c查看字节码可以发现foreach循环实际上是用Iterator迭代器实现的,如果进行添加或删除元素会抛出ConcurrentModificationException异常,因为添加或删除元素会改变modCount的值,modCount是集合类的一个成员变量,代表集合的修改次数,当modCount的值和预期的exceptedModCount值不一致时就会抛出ConcurrentModificationException异常。

多线程

Q1:创建线程有哪几种实现方式?分别有什么优缺点?

答:①继承Thread类,重写run()方法即可。优点是编码简单,缺点是不能继承其他类,功能单一。②实现Runnable接口,重写run()方法,并将该实现类作为参数传入Thread构造器。优点是可以继承其他类,避免了单继承的局限性;适合多个相同程序代码的线程共享一个资源(同一个线程任务对象可被包装成多个线程对象),实现解耦操作,代码和线程独立。缺点是实现相对复杂。③实现Callable接口,重写call()方法,并包装成FutureTask对象,再作为参数传入Thread构造器。优点是相比方式二可以获取返回值,缺点是实现复杂。④可以通过线程池创建。

Q2:线程有哪些状态?

答:①New:用new操作创建一个新线程,此时程序还未开始运行线程中的代码。②Runnable:调用start()方法后进入可运行状态。③Blocked:阻塞状态,内部锁(不是juc中的锁)获取失败时进入阻塞状态。④Waiting:等待其他线程唤醒时进入等待状态。⑤Timed Waiting:计时等待,带超时参数的方法,例如sleep(long time)。⑥Terminated:终止状态,线程正常运行完毕或被未捕获异常终止。

Q3:什么是线程安全问题,如何解决?

答:当多个线程对同一个共享变量进行操作时可能会产生的问题。解决方法:①使用内部锁synchronized,可以使用同步代码块,如果是实例方法可用this作为锁对象,如果是静态方法,可以用类.class作为锁,或者使用同步方法底层和同步代码块一样,如果是实例方法默认用this作为锁,如果是静态方法默认使用类.class。②使用java.util.concurrent包中的锁,例如ReentrantLock。

Q6:说一说synchronized关键字的作用

答:①用于为Java对象、方法、代码块提供线程安全的操作,属于排它的悲观锁,也属于可重入锁。②被synchronized修饰的方法和代码块在同一时刻只能有一个线程访问,其他线程只有等待当前线程释放锁资源后才能访问。③Java中的每个对象都有一个monitor监视器对象,加锁就是在竞争monitor,对代码块加锁是通过在前后分别加上monitorenter和monitorexit指令实现的,对方是否加锁是通过一个标记位来判断的。

Q13:Lock接口有哪些方法?

答:①lock():给对象加锁。②tryLock()/tryLock(long time,TimeUnit unit):尝试给对象加锁,成功返回true,可以无参也可以指定等待时间。③unlock():释放锁,锁只能由持有者释放否则抛出异常。④newCondition():创建条件对象,使用条件对象管理那些已经获得锁但不满足有效条件的线程,调用await()方法把线程进入等待集,调用sign()/signAll()解除阻塞。⑤lockInterruptibly():如果当前线程未被中断则获取该锁。

Q22:线程池是什么?为什么需要线程池?

答:①在生产中为每一个任务创建一个线程存在一些缺陷,如果无限制地大量创建线程会消耗很多资源,影响系统稳定性和性能,产生内存溢出等问题。②线程池是管理一组同构工作线程的资源池,线程池与工作队列密切相关,工作队列中保存了所有需要等待执行的任务。工作线程的任务很简单,从工作队列获取任务,执行任务,返回线程池并等待下一次任务。③线程池通过重用现有的线程,可以在处理多个请求时分摊线程在创建和撤销过程中的开销,另一个好处是当请求到达时工作线程通常已经存在,不会出现等待线程而延迟的任务的执行,提高了响应性。通过调整线程池的大小,可以创建足够多的线程保持处理器处于忙碌状态,同时还可以防止线程过多导致内存资源耗尽。

Q23:创建线程池时,ThreadPoolExecutor构造器中都有哪些参数,有什么含义?

答:①corePoolSize: 线程池核心大小,即在没有任务执行时线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。②maximumPoolSize: 线程池最大大小,表示可同时活动的线程数量的上限。③keepAliveTime:存活时间,如果某个线程的空闲时间超过了存活时间,那么将被标记为可回收的,并且当线程池的当前大小超过基本大小时,这个线程将被终止。④unit: 存活时间的单位,可选的参数为TimeUnit枚举中的几个静态变量: NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。⑤workQueue: 线程池所使用的阻塞队列。⑥thread factory:线程池使用的创建线程工厂方法,可省略,将使用默认工厂。⑦handler:所用的拒绝执行处理策略,可省略,将使用默认拒绝执行策略。

Q25:线程池的拒绝执行策略有哪些选择?

答:①AbortPolicy(): 线程池默认的拒绝策略,抛出RejectedExecutionException异常。②CallerRunsPolicy(): 重试添加当前的任务,他会自动重复调用execute()方法。③DiscardOldestPolicy(): 抛弃旧的任务,加入新的任务。④DiscardPolicy(): 直接抛弃当前的任务。

Q26:创建线程池的方法有哪些?

答:可以通过Executors的静态工厂方法创建线程池,内部通过重载ThreadExecutorPool不同的构造器创建线程池。①newFixedThreadPool,创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化(如果某个线程由于发生了未预期的异常而结束,那么线程池会补充一个新的线程)。将线程池的核心大小和最大大小都设置为参数中指定的值,创建的线程不会超时,使用LinkedBlockingQueue。②newCachedThreadPool,创建一个可缓存的线程池,如果线程池的当前规模超过了处理器需求,那么将回收空闲的线程,而当需求增加时,可以添加新的线程,线程池的规模不存在任何限制。将线程池的最大大小设置为Integer.MAX_VALUE,而将核心大小设置为0,并将超时设为1分钟,使用SynchronousQueue,这种方法创建出的线程池可被无限扩展,并当需求降低时自动收缩。③newSingleThreadExecutor,一个单线程的Executor,创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来代替。确保依照任务在队列中的顺序来串行执行。将核心线程和最大线程数都设置为1,使用LinkedBlockingQueue。④newScheduledThreadPool,创建一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer,使用DelayedWorkQueue。

Q27:线程池的工作原理?

答:①线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。即使队列里面有任务,线程池也不会马上执行它们。②通过 execute(Runnable command)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是Runnable类型对象的run()方法。③如果workerCount<corePoolSize,那么创建并启动一个线程执行新提交的任务。如果workerCount>=corePoolSize,且线程池内的阻塞队列未满,那么将这个任务放入队列。如果workerCount>=corePoolSize,且阻塞队列已满,若满足workerCount<maximumPoolSize,那么还是要创建并启动一个线程执行新提交的任务。若阻塞队列已满,并且workerCount>=maximumPoolSize,则根据 handler所指定的策略来处理此任务,默认的处理方式直接抛出异常。也就是处理任务的优先级为: 核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。④当一个线程完成任务时,它会从队列中取下一个任务来执行。⑤当一个线程没有任务可执行,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize时,那么这个线程会被停用掉,所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

Q31:讲一讲wait、sleep、yield、join方法的区别

答:①wait是Object类的方法,调用wait方法的线程会进入WAITING状态,只有等待其他线程的通知或被中断后才会解除阻塞,调用wait方法会释放锁资源。②sleep是Thread类的方法,调用sleep方法会导致当前线程进入休眠状态,与wait不同的是该方法不会释放锁资源,进入的是TIMED-WAITING状态。③yiled方法会使当前线程让出CPU时间片给优先级相同或更高的线程,回到RUNNABLE状态,与其他线程一起重新竞争CPU时间片。④join方法用于等待其他线程运行终止,如果当前线程调用了另一个线程的join方法,则当前线程进入阻塞状态,当另一个线程结束时当前线程才能从阻塞状态转为就绪态,等待获取CPU时间片。底层使用的是wait,也会释放锁。

Q34:start和run方法的区别?

答:①start方法用于启动线程,真正实现了多线程,调用了start方法后,会在后台创建一个新的线程来执行,不需要等待run方法执行完毕就可以继续执行其他代码。调用start方法时,该线程处于就绪状态,并没有开始运行。②run方法也叫做线程体,包含了要执行的线程的逻辑代码,在调用run方法并没有创建新的线程,而是直接运行run方法中的代码。

反射

Q1:简述反射的基本概念,优缺点和使用场景。

答:①在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java的反射机制。② 优点是运行时动态获取类的全部信息,缺点是破坏了类的封装性,泛型的约束性。③是框架的核心灵魂,动态代理设计模式采用了反射机制,还有 Spring、Hibernate 等框架也大量使用到了反射机制。

Q2:获取Class对象有哪几种方式?能通过Class对象获取类的哪些信息?

答:①通过类名.class②通过对象.getClass()③通过Class.forName(类的全限名);④可以通过Class对象获取类的成员变量,方法或构造器。带declared的获取方法可以获取到类的一个或全部成员变量,方法,构造器,不带declared的方法只能获取到类的public修饰的成员变量、方法或构造器,包括父类public修饰的成员变量、方法或构造器。

IO流

Q1:简单说说File对象表示的是什么?File类有哪些常用方法?

答:①File对象表示的是操作系统上的文件或目录。②获取:getAbsolutePath() 获取绝对路径;getPath() 获取文件定义时使用的路径;getName() 获取文件名,带后缀;length() 返回文件长度,单位是字节。③判断:exists() 判断File对象表示的文件或目录是否存在;isDirectory() 判断是否是目录; isFile() 判断是否是文件。④创建和删除:createNewFile() 不存在时创建新文件;delete() 删除文件,目录(非空目录不能删除);mkdir() 创建一级目录;mkdirs() 创建多级目录,推荐使用;⑤遍历:list 获取当前目录下所有一级文件名称到一个字符串数组并返回;listFiles 获取当前目录下所有一级File对象到File数组返回。

Q2:英文、数字和中文字符在文件中分别占多大的空间?

答:①英文和数字在任何编码中都占1个字节。②中文字符在GBK编码下占2个字节,在UTF-8编码下占3个字节。

Q3:简述传统IO有哪些分类?

答:①按流的方向:输出流:把内存中的数据写出到磁盘文件或网络介质中;输入流:把磁盘文件或网络介质中的数据读取到内存中。②按流的内容:字节流:流中数据的最小单位是字节;字符流:流中数据的最小单位是字符(针对文本内容)。顶层的抽象类包括InputStream、OutputStream、Reader、Writer,它们都实现了Closeable接口。③缓冲流(BufferedInputStream/BufferedOutputStream/BufferedReader/BufferedWriter):自带一个8KB大小的缓冲池,可以将字节/字符流为缓冲字节/缓冲字符流。④字符转换流(InputStreamReader/OutputStreamWriter):可以将对应的字节流转换为字符流。⑤打印流:PrintStream,方便快速打印数据,参数是什么就打印什么。

Q5:序列化和反序列化是什么,有什么要求?

答:①Java在JVM运行时被创建、更新和消耗,当JVM退出时,对象也会随之销毁。可以通过Java序列化实现持久化存储,保存对象及其状态信息到字节数组中。②反序列化就是再将字节数组中存储的信息转换回Java对象。③要求类必须实现序列化接口,并且序列化和反序列化必须保持序列化的ID一致。④静态变量和被transient修饰的变量不会被序列化。

javaweb

Q1:HTTP有哪些特点

答:①HTTP是基于TCP/IP协议的。②HTTP使用的默认端口号是80。③HTTP是基于请求/响应模型的,一次请求对应一次响应。④HTTP是无状态的,每次请求之间相互独立,不能交互数据。⑤HTTP1.0每一次请求响应都会建立新的连接,HTTP1.1会复用连接。

Q2:HTTP请求数据的数据格式是什么?

答:①请求行,包括了请求方式、请求url、请求协议/版本。HTTP协议有7种请求方式,常用的有2种。GET方式,请求参数在请求行中,在url后、 请求的url长度有限制的、不太安全;POST方式,请求参数在请求体中、请求的url长度没有限制的、相对安全。②请求头,是客户端浏览器告诉服务器的一些信息,常见的请求头例如User-Agent,告诉服务器使用的浏览器版本信息,可以在服务器端获取该头的信息,解决浏览器的兼容性问题。Referer,可以告诉服务器,当前请求从哪里来,可以防盗链或者进行统计数据。③请求空行,用于分割POST请求的请求头和请求体的。④请求体(正文),封装POST请求消息的请求参数的。

Q3:转发和重定向的区别?

答:①转发的特点: 转发地址栏路径不变、 转发只能访问当前服务器下的资源、转发是一次请求,可以使用request对象来共享数据。②重定向的特点:地址栏发生变化、重定向可以访问其他站点(服务器)的资源、重定向是两次请求,不能使用request对象来共享数据。

Q4:讲一讲Cookie

答:①Cookie是客户端会话技术,将数据保存到客户端。②创建Cookie对象,绑定数据:new Cookie(String name, String value);发送Cookie对象:response.addCookie(Cookie cookie),一次可以发送多个Cookie;获取Cookie,拿到数据:request.getCookies()。③浏览器对于单个cookie 的大小有限制(4kb) 以及对同一个域名下的总cookie数量也有限制(20个),cookie一般用于存出少量的不太敏感的数据,在不登录的情况下,完成服务器对客户端的身份识别。

Q5:Cookie的生命周期?

答:①默认情况下,当浏览器关闭后,Cookie数据被销毁。②如果想要持久化存储,可以使用setMaxAge(int seconds)。正数:将Cookie数据写到硬盘的文件中,持久化存储,并指定cookie存活时间,时间到后,cookie文件自动失效。负数:默认值。零:删除cookie信息。

Q8:讲一讲Session

答:①Session是服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。②获取HttpSession对象:request.getSession();使用HttpSession对象:Object getAttribute(String name)、void setAttribute(String name, Object value)、void removeAttribute(String name)。③Session的实现是依赖于Cookie的,服务器是通过cookie中的JESSIONID判断session是否是同一个的。

Q9:Session的生命周期?当客户端关闭后,服务器不关闭,两次获取session是否为同一个?客户端不关闭,服务器关闭后,两次获取的session是同一个吗?

答:①服务器关闭、session对象调用invalidate() 时销毁,session默认失效时间 30分钟。②在默认情况下,当客户端关闭服务端不关闭时,两次获取session值不是同一个。③如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。④客户端不关闭,服务端关闭,两次获取的session值也不是同一个。但是要确保数据不丢失。tomcat自动完成以下工作。session的钝化: 在服务器正常关闭之前,将session对象序列化到硬盘上。session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。但是IDEA不支持这种操作,因为每次用IDEA重启tomcat时会自动删除catalina_base中work目录(程序动态生成的文件),这样在关闭tomcat时生成的session序列化文件也会被删除。

Q10:Session的特点,和Cookie有什么区别?

答:①Session用于存储一次会话的多次请求的数据,存在服务器端。session可以存储任意类型,任意大小的数据。②Session存储数据在服务器端,Cookie存储数据在客户端。
Session没有存储数据的大小限制,Cookie有数据大小限制。Session存储数据是安全的,使用Cookie存储数据相对于使用Session来说不安全。

Q15:过滤器是什么?如何使用?

答:①当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。②需要实现Filter接口,使用注解方式可以在类名上加上注解@WebFilter(“拦截路径”),使用XML的方式可以配置web.xml中的filter和filter-mapping标签,设置过滤器类和拦截路径。

Q16:过滤器的执行流程和生命周期是什么?

答:①执行流程:执行过滤器,执行放行后的资源,回来执行过滤器放行代码下边的代码。②生命周期:init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次,一般用于加载资源。doFilter:在每一次请求被拦截资源时执行,会执行多次。destroy:在服务器关闭后,Filter对象被销毁,如果服务器是正常关闭,则会执行destroy方法。只执行一次。一般用于释放资源。

Q18:AJAX是什么?

答:①Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。②通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。③传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面,使用Ajax技术可以提升用户的体验。

Q19:JSON是什么?如何把Java对象转为JSON?如何把JSON转回Java对象?

答:①JSON指JavaScript Object Notation JavaScript对象表示法。②JSON现在多用于存储和交换文本信息的语法,进行数据的传输。③JSON的优势是想比XML来说占用空间更小、操作数据更快,更易解析。④将Java对象转为JSON时,需要先导入jackson的相关jar包,创建Jackson核心对象 ObjectMapper,之后调用ObjectMapper的writeValue(参数,obj)进行转换,如果参数是File类型,可以将obj对象转换为JSON字符串,并保存到指定的文件中;如果参数是Writer类型,可以将obj对象转换为JSON字符串,并将json数据填充到字符输出流中;如果参数是OutputStream类型,可以将obj对象转换为JSON字符串,并将JSON数据填充到字节输出流中。⑤将JSON转会Java对象时使用readValue的方法,参数为要转回的Java对象的Class字节码对象。

Spring

Q1:Spring的IOC和DI是什么?

答:①IOC即控制反转,简单来说就是把对象的控制权委托给spring框架,作用是降低代码的耦合度。②DI即依赖注入,是IOC的一种具体实现方式。假设一个Car类需要Engine的对象,那么一般需要new一个Engine,利用IOC就是只需要定义一个私有的Engine引用变量,容器会在运行时创建一个Engine的实例对象并将引用自动注入给变量。

Q2:简述Spring中bean对象的生命周期

答:①Spring对bean进行实例化。②Spring将值和bean的引用注入到其对应的属性中。③调用BeanNameAware的setBeanName方法。④调用BeanFactoryAware的setBeanFactory方法。⑤调用AppicationContxtAware的setApplicationContext方法。⑥调用BeanPostProcessor的post-ProcessBeforeInitialization方法。⑦调用InitializingBean的after-PropertiesSet方法。如果bean使用init-method声明了自定义初始化方法,该方法也会被调用。⑧调用BeanPostProcessor的post-ProcessAfterInitialization方法。⑨使用bean。⑩调用DisposableBean的destroy方法,如果bean使用destroy-method声明了自定义销毁方法,该方法也会被调用。

Q3:简述bean的作用范围

答:通过scope指定bean的作用范围,有①singleton:单例的,每次容器返回的对象是同一个。②prototype :多例的,每次返回的对象是新创建的实例。③request:仅作用于HttpRequest,每次Http请求都会创建一个新的bean。④session:仅作用于HttpSession,不同的Session使用不同的实例,相同的Session使用同一个实例。⑤global session :仅作用于HttpSession,所有的Session使用同一个实例。

Q6:依赖注入可以注入哪些数据类型?有哪些注入方式?

答:①可以注入的数据类型有基本数据类型、String、Bean、以及集合等复杂数据类型。②有三种注入方式,第一种是通过构造器注入,通过constructor-arg标签实现,缺点是即使不需要该属性也必须注入;第二种是通过Set方法注入,通过property标签实现,优点是创建对象时没有明确限制,缺点是某个成员变量必须有值,在获取对象时set方法可能还没有执行;第三种是通过注解注入,利用@Autowired自动按类型注入,如果有多个匹配则按照指定bean的id查找,查找不到会报错;@Qualifier在自动按照类型注入的基础之上,再按照 Bean 的 id 注入,给成员变量注入时必须搭配@Autowired,给方法注入时可单独使用;@Resource直接按照 Bean 的 id 注入;@Value用于注入基本数据类型和String。

Q7:有哪些配置Bean的注解,各有什么区别?

答:①@Component,把当前类对象存入spring容器中,相当于在 xml 中配置一个 bean。value属性指定 bean 的 id,如果不指定 value 属性,默认 id 是当前类的类名,首字母小写。②@Service,一般用于业务层。③@Controller:一般用于表现层。④@Repository:一般用于持久层。⑤@Controller @Service @Repository都是针对@Component的衍生注解,作用及属性都是一模一样的,只是提供了更加明确的语义化。

SpringAOP

Q1:Spring Aop的基本原理是什么?

答:Aop即面向切面编程,简单地说就是将代码中重复的部分抽取出来,在需要执行的时候使用动态代理的技术,在不修改源码的基础上对方法进行增强。优点是可以减少代码的冗余,提高开发效率,维护方便。Spring会根据类是否实现了接口来判断动态代理的方式,如果实现了接口会使用JDK的动态代理,核心是InvocationHandler接口和Proxy类,如果没有实现接口会使用cglib的动态代理,cglib是在运行时动态生成某个类的子类,如果某一个类被标记为final,是不能使用cglib动态代理的。

Q2:简单解释一下AOP的相关术语

答:①Joinpoint(连接点):指那些被拦截到的点,在 spring 中这些点指的是方法,因为 spring 只支持方法类型的连接点。例如业务层实现类中的方法都是连接点。②Pointcut(切入点):指我们要对哪些 Joinpoint 进行拦截的定义。例如业务层实现类中被增强的方法都是切入点,切入点一定是连接点,但连接点不一定是切入点。③Advice(通知/增强):指拦截到 Joinpoint 之后所要做的事情。④Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下可以在运行期为类动态地添加一些方法或 Field。⑤Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。⑥Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。⑦Target(目标):代理的目标对象。⑧Aspect(切面):是切入点和通知(引介)的结合。

Q3:Spring Aop有哪些相关注解?

答:@Before前置通知,@AfterThrowing异常通知,@AfterReturning后置通知,@After最终通知,@Around环绕通知。最终通知会在后置通知之前执行,为解决此问题一般使用环绕通知。

SpingMVC

Q1:SpringMVC的作用是什么?MVC的含义分别是什么?

答:①springMVC是一种基于Java实现的mvc设计模型的请求驱动类型的轻量级Web层框架,作用包括:参数绑定(获取请求参数)、调用业务层 、进行请求响应。②mvc全名是model view controller模型视图控制器,model指数据模型,JavaBean的类,用来封装数据;view指jsp,html等用来展示数据给用户的界面;controller是整个流程的控制器,用来接收用户请求以及进行数据校验等功能。

Q3:SpringMVC的基础响应流程是怎样的?

答:①浏览器发送请求,被 DispatherServlet 捕获,该 Servlet 并不处理请求,而是把请求转发出去(控制器类),转发的路径是根据请求 URL,匹配@RequestMapping 中的内容②根据执行方法的返回值和视图解析器(InternalResourceViewResolver),去指定的目录下查找指定名称的视图文件,Tomcat服务器渲染页面,做出响应。



Q4:SpringMVC响应流程中会涉及到哪些组件?

答:①DispatcherServlet:前端控制器,用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。②HandlerMapping:处理器映射器,负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。③Handler:处理器,它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。④HandlAdapter:处理器适配器,
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行⑤View Resolver:视图解析器,负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。⑥View:视图,SpringMVC 提供了很多 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

Q5:讲一讲@RequestMapping注解

答:①作用:建立请求url和处理方法之间的对应关系。②作用位置:类,请求url的第一级访问目录,如果不写相当于根目录,需要以/开头;方法,请求url的第二级访问目录,可以不以/开头。③属性:value/path,绑定路径,支持多个路径,一般只配置一个路径;method 指定访问方式,可配置多个允许的访问方式,默认任何方法都支持,例如POST、GET等

Q6:SpringMVC的参数绑定支持哪些类型,分别有哪些要求?

答:①基本数据类型和String,要求请求参数的参数名必须和控制器中方法的形参名一致,例如请求参数为name,控制器方法的形参也必须为name。②可以是Java对象,要求请求属性必须和对应的Java类中的成员变量名一致,例如input标签的name属性值为id,类中也必须有id这一个成员变量。也可以是Java对象中的List或Map集合。

Q9:SpringMVC的常用注解有哪些?

答:①@RequestParam:作用是将请求参数和控制器中方法形参绑定(请求参数名和形参名不再要求相同)。属性包括:name/value,当和请求参数名一致可省略;required指定请求参数是否必填项;defaultValue是未提供请求参数时的默认值。②@RequestBody:作用是用于获取请求体的内容,直接使用得到的是key=value形式的字符串,把获取的json数据转换成pojo对象(get方式不可用)。③@RequestBody:作用是将控制器中方法返回的对象通过适当的转换器转换为指定的格式之后进行响应,通常用来返回JSON数据或者是XML。④@PathVariable:作用是绑定url中的占位符,例如请求url中/delete/{id},{id}就是url占位符。url支持占位符是spring3.0后加入的,是springmvc支持rest风格url的一个重要标志。属性包括name/value 指定url中占位符名称;required指定是否必须提供占位符。⑤@RequestHeader:作用是获取指定请求头的值。属性:value代表请求头的名称。⑥@CookieValue:作用是用于把指定 cookie 名称的值传入控制器方法参数。属性包括value:指定 cookie 的名称。required:是否必须有此 cookie。⑦@ModelAttribute:是 SpringMVC4.3 版本以后加入的,它可以修饰方法和参数,出现在方法上表示当前方法会在控制器的方法执行之前先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。出现在参数上,获取指定的数据给参数赋值。属性value用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。

Q10:响应数据的格式有哪些?

答:①字符串,控制器中的方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址,例如返回”success”时可解析为success.jsp页面。②返回值为空,默认访问视图解析器前缀+requestmapping路径+视图解析器后缀的视图。③ModelandView,可以通过setViewName()方法设置视图名实现指定视图的跳转。

Q11:SpringMVC中如何实现转发和重定向,有什么区别?

答:①前提是控制器方法返回值类型必须是String类型。②转发到页面return”forward:+绝对地址”。转发到控制器其他方法:return的是”forward:+类上requestmapping的地址+方法上requestmapping的地址”。③重定向到页面:return的是”redirect:+绝对地址”,注意不能重定向访问WEB-INF下的资源。重定向到控制器其他方法:return的是”redirect:+类上requestmapping的地址+方法上requestmapping的地址”。重定向到外部链接:return的是”redirect:+链接地址(http://www.qq.com)"。④转发和重定向的区别是转发只是一次请求,重定向是两次请求;转发地址栏不变,重定向地址栏将改变;转发只能到内部资源,重定向可以到内部或外部资源;转发可以到WEB-INF下资源,重定向不可以。

Q12:SpringMVC实现简单文件上传有哪些要求?

答:①浏览器端要求:表单提交方式为post(get有文件大小限制)。提供文件上传框对应的标签:。表单的entype属性必须为multipart/form-data。②服务器端要求:使用**request.getInputStream()**获取数据。springmvc底层封装了commons-fileupload文件上传工具包。

Mybatis

mybatis执行原理

1.通过SqlSessionFactoryBuilder创建SqlSessionFactory对象

2.通过SqlSessionFactory创建SqlSession对象

3.通过SqlSession拿到Mapper代理对象

4.通过MapperProxy调用Mapper中增删改查的方法

Mysql

事务的特性 ACDI

并发事务带来哪些问题?怎么解决?默认隔离级别



Q2:索引是什么?

答:MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

Q3:索引的优缺点有哪些?

答:①优势:提高数据检索的效率,降低数据库的IO成本。通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。②劣势:实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

Q11:MySQL数据库的隔离级别有哪些?分别有什么特点?

答:①未提交读,一个事务会读取到另一个事务没有提交的数据,存在脏读、不可重复读、幻读的问题。②已提交读,一个事务可以读取到另一个事务已经提交的数据,解决了幻读的问题,存在不可重复读、幻读的问题。③可重复读,MySQL默认的隔离级别,在一次事务中读取同一个数据结果是一样的,解决了不可重复读的问题,存在幻读问题。④可串行化,每次读都需要获得表级共享锁,读写互相阻塞,效率低,解决了幻读问题

Q12:读取数据库时可能出现哪些问题?

答:①脏读,一个事务中会读取到另一个事务中还没有提交的数据,如果另一事务最终回滚了数据,那么所读取到的数据就是无效的。②不可重复读,一个事务中可以读取到另一个事务中已经提交的数据,在同一次事务中对同一数据读取的结果可能不同。③幻读,一个事务在读取数据时,当另一个事务在表中插入了一些新数据时再次读取表时会多出几行,如同出现了幻觉。

Q14:简述主从复制的基本原理

答:①主从复制是指一台服务器充当主数据库服务器,另外一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器中。对于多级复制,数据库服务器既可充当主机也可充当从机。②MySQL主从复制的基础是主服务器对数据库修改二进制记录,从服务器通过主服务器的二进制日志自动执行更新。

Springboot

自动配置

5. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含
了以下 3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项, 例
如: java 如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。

32. Spring Boot 中如何解决跨域问题 ?

跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请
求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Crossorigin resource sharing) 来解决跨域问题。这种解决方案并非 Spring Boot 特有的,在传统的
SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,
现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。