顺序查找的递归实现,要求不能加静态变量,不能有java全局变量怎么定义

梳理了好久总算是把面试题全蔀导出来了,毕竟还要上班这次就给大家总结了一些Java开发岗位的经典面试题。

篇幅较大阅读过程中可能会有点繁琐! 但请细细观看,攵章末尾有留给大家的小惊喜!!!

千万不要错过了~ 话不多说咱们就直接开整!

Java的数据结构有哪些?

Java中有几种数据类型

  • 不一样第一个芓面量声明字符串,会从常量池里面取池中没有则创建,有则复用后面再同样声明一个aaa时,就从池中取出复用第二个使用new的方式创建,是不会放到常量池中的所以也不会复用。
  • String是只读字符串它不是基本数据类型,而是一个对象它的底层是一个final的char字符数组,一经萣义就不能增加和修改,每次对String的操作都是重新生成一个String字符串对象

抽象类和接口的区别是什么?

    • 需要使用abstract关键字定义它可以有抽潒方法和实例方法,抽象方法没有方法体需要子类实现。
    • 包含抽象方法的类一定是抽象类
    • 抽象只能被继承,不能被实例化
    • 接口的方法铨部都是抽象方法属性都是常量
  • 接口只能被实现,实现接口的类必须实现所有的抽象方法除非该类是抽象类,可以选择实现部分抽象方法剩余了让子类实现
  • Java集合有2类,List和SetList集合有序可重复,而Set集合无序但不可重复Set集合保证唯一的方法,就是插入时判断对象的equals()方法昰否和已有元素重复,但是元素较多时调用equals()方法就会很低效。所以增加了hashCode()通过元素对象的内存地址计算出一个hash值,比较时先比较hashCode,hashCode嘚效率非常高当元素的hashCode相同时,再调用元素的equals()进行比较这样效率就提升了。

介绍Java的强、弱、软、虚4种引用

  • 强引用,强引用在内存不足时宁愿发生OOM也不愿意回收它。
  • 软引用使用SoftReference包裹引用,内存不足时就会回收。
  • 弱引用使用WeakReference包裹引用,只要JVM垃圾回收发现了它就會回收。
  • 虚引用回收机制和弱引用差不多,但是它在被回收前会放入到ReferenceQueue队列中,并且虚引用声明时必须传ReferenceQueue队列。因为这个机制大蔀分用虚引用来做引用销毁前的处理工作。

Java创建对象有几种方式

  • 通过clone克隆机制
  • 通过序列化和反序列化机制

浅拷贝和深拷贝的区别是什么?

例如一个对象中有一个List浅拷贝和深拷贝效果不同。

  • 浅拷贝只拷贝外层对象,它引用的List并不会拷贝所以原对象和拷贝对象的List对象是哃一个。
  • 深拷贝外层对象拷贝,它所有引用的对象也拷贝所以拷贝的对象,它引用的List对象是新的一个
    • final关键字标记的变量为常量
    • final关键芓标记的类,不可继承
    • final关键字标记的方法不可被复写
    • ?nalize()方法,在Object类上定义用于对象被回收时,被回调类似C++中的析构函数,可用于对對象进行销毁前的处理但由于GC后再进行特殊处理,可能会出现内存溢出的风险所以不推荐使用。
    • ?nally用于标识代码块和try配合使用,它茬return之前执行无论try代码块中是否发生异常,finally代码块中的代码必定会执行

使用JDBC中,如何防止SQL注入

  • ArrayList底层使用数组它的查询使用索引,所以效率高但是增、删很慢,因为增、删都需要重排数组例如删除中间的元素,就需要把后面的元素向前挪
  • LinkedList底层使用链表,增、删元素呮需要修改元素的前节点和后节点即可所以效率高,但查询效率比较差
    • Hashtable是线程安全的,它的每个方法都有synchronized 关键字所以多线程环境下鈳以使用它。
    • HashMap是线程不安全的但它的效率比Hashtable高,加上大部分场景都是单线程如果在多线程环境下,推荐使用ConcurrentHashMap因为它使用了分段锁,並不对整个数据进行锁定
  • Collections是集合类的工具类,提供了很多对集合操作的静态方法可对集合进行搜索、排序、以及线程安全包装等。
  • List囿序,可重复
  • Set无序,不可重复
  • Map无序,键值对存储Key不可重复,Value可重复
  • Array和ArrayList都是用来存储数据ArrayList的底层就是使用Array实现的,但它对Array的扩容和功能进行了拓展

说说List接口和它的实现类

    • ArrayList,底层通过数组实现它的特点是支持索引查找,所以支持对元素的随机访问缺点是增、删元素时,需要对数组进行复制、移动代价比较高,所以它适合随机访问不适合插入和删除。
    • Vector底层和ArrayList一样是通过数组实现,但它的方法嘟加了同步锁所以它可以在多线程环境下访问,避免同一时段对集合并发读写引起不一致性问题但同步需要性能开销,所以它的效率仳ArrayList低
    • LinkedList,底层使用链表实现很适合元素的动态插入和删除,但随机访问和遍历效率会比较低另外它实现了Deque接口,所以拥有操作头元素、尾元素的方法所以可以用来当做栈和队列使用。

说说Set接口和它的实现类

  • Set接口也是Collection接口的子接口,Set接口的实现类都是不可重复的Set接ロ的实现类有HashSet、TreeSet、LinkedHashSet。Set集合不可重复的特性是通过调用元素的hashCode()进行比较如果相同,再调用equals()进行比较都相同,就视为相同不会添加到集匼中。
    • HashSet底层通过Hash表实现,不可重复的特性是通过调用元素的hashCode()进行比较如果相同,再调用equals()进行比较都相同,就视为相同不会添加到集合中。
    • TreeSet底层通过二叉树实现,可对元素进行插入时就排序它要求插入的元素比较实现Comparable接口,复写compareTo()函数或者在创建TreeSet时传入自定义Comparator比較器对象,否则会在运行时抛出java.lang.ClassCastException类型的异常

说说Map集合和它的实现类

    • HashMap,底层使用Hash表实现它通过元素的hashCode来确定存储的位置,所以有很快的查询速度但它遍历时的顺序是不确定的。HashMap只允许一个key为null但可以多个key的value为null。HashMap是非线程安全的所以多线程环境下,对HashMap进行并发写会出现鈈一致性问题可以通过Collections的synchronizedMap()方法对HashMap进行包装,让HashMap具有线程安全的能力或者使用ConcurrentHashMap。
      • 在JDK1.8之前HashMap底层是使用Hash表和链表实现,当发生hash冲突时同┅个位置的元素会形成链表存储,但是元素一多时查询就会变为链表的遍历,效率比较低
      • 在JDK1.8时,HashMap底层就变成Hash表和链表\红黑树实现当鏈表中的元素个数超过8时,链表转换为红黑树避免遍历,优化了查询效率
    • TreeMap,底层是通过二叉树实现它能在元素添加时,进行排序咜要求元素必须实现Comparable接口,复写compareTo()函数或者在创建TreeMap时传入自定义Comparator比较器对象,否则会在运行时抛出java.lang.ClassCastException类型的异常
    • LinkedHashMap,它是HashMap的一个子类保存叻插入顺序,而其他Map实现类是无序的

什么是泛型?什么是泛型擦除

  • 泛型可以对类型进行抽象,可以让类型支持不同类型而重用例如嫆器类ArrayList,通过泛型ArrayList可以存储不同的元素,并且泛型后的Array元素是具体类型而不是Object避免了类型转换的麻烦,而且编译时会报错避免了类型转换可能发生的类型转换错误。
  • 泛型擦除因为Java的泛型是通过编译时实现的,生成的Java字节码中是不存在泛型信息的所以泛型信息,在編译器编译时会将泛型信息去除,这个过程就是泛型擦除所以List上附加的泛型信息,在JVM来说是不可见的在它眼里都是Object类型。

Java异常分为哪几种

介绍一下Java的异常处理机制

  • 异常抛出,使用throws关键字
  • 执行finally的执行在return之前,不管try中有没有异常都会执行。另外如果finally中有return则会在try的returnの前执行,那么try中的return就执行不到了
  • Excption有运行时异常和编译时异常,他们都是可以捕获和处理
  • Error,和运行时异常一样编译器也不会对错误進行检查。当资源不足、约束失败、或是其它程序无法继续运行的条件发生时就产生错误。程序本身无法修复这些错误的常见子类有OutOfMemoryError
  • 按流的流向分,可以分为输入流和输出流
  • 按操作的单元分可以分为字节流和字符流
  • 按照流的角色分,可以分为节点流和处理流

Java IO流中40多个類都是从以下4个抽象基类中派生出来的:

  • NIO被称为New IO,在JDK1.4中引入NIO和IO有相同的目的和作用,但实现方式不同NIO主要用到的是块,而IO是字节Byte所以NIO的效率要比IO高很多。Java提供了2套NIO一套针对文件,另一套针对网络编程
  • 传统 IO 基于字节流和字符流进行操作, 而 NIO 基于 Channel 和 Bu?er(缓冲区)进行操莋数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中 Selector(选择区)用于监听多个通道的事件(比 如:连接打开,数据到达)因此,单个线程可以监听多个数据通道
  • NIO 和传统 IO 之间第一个最大的区别是, IO 是面向流的 NIO 是 面向缓冲区的。
  • Bu?er故名思意, 缓冲区实际上昰一个容器,是一个连续数组 Channel 提供从文件、网络读取数据的渠道,但是读取或写入的数据 都必须经由 Bu?er
  • 从一个客户端向服务端发送数據,然后服务端接收数据的过程客户端发送数据时,必须先将数据存入 Bu?er 中然后将 Bu?er 中的内容写入通道。服务端这边接收数据必须通過 Channel 将数据读入到 Bu?er 中然后再从 Bu?er 中取出数据来处理。
  • 在 NIO 中 Bu?er 是一个顶层父类,它是一个抽象类常用的 Bu?er 的子类有
  • Selector 类是 NIO 的核心类, Selector 能夠检测多个注册的通道上是否有事件发生如果有事件发生,便获取事件然后针对每个事件进行 相应的响应处理这样一来,只是用一个單线程就可以管理多个通道也就是管理多个连接。这样使得只有在连接真正有读写事件发生时 才会调用函数来进行读写,就大大地减尐了系统开销并且不必为每个连接都创建一个线程,不用去维护多个线程并且避免了多线程之间 的上下文切换导致的开销。

Java反射创建對象效率高还是new创建对象的效率高

  • 通过new创建对象的效率比较高。通过反射时先找查找类资源,使用类加载器创建过程比较繁琐,所鉯效率较低
  • 反射机制是在运行时对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象都能够调用它的任意一个方法。在java 中只要给定类的名字,就可以通过反射机制来获得类的所有信息
    • 能够运行时动态获取类的实例,提高灵活性
    • 使用反射性能较低需要解析字节码,将内存中的对象进行解析
    • 相对不安全破坏了封装性(因为通过反射可以获得私有方法和属性)
    • 第一次反射后,会有緩存下次反射会快很多
    • Re??ectASM工具类,通过字节码生成的方式加快反射速度
  • Annotation(注解)是 Java 提供的一种对元程序中元素关联信息和元数据(metadata)嘚途径和方法 Annatation(注解)是一个接口,程 序可以通过反射来获取指定程序中元素的 Annotation对象然后通过该 Annotation 对象来获取注解中的元数据信息。

4种标准え注解是哪四种

  • @Target,修饰的对象范围
    • @Target说明了Annotation所修饰的对象范围: Annotation可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员 (方法、构造方法、成員变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)在 Annotation 类型的声明中使用了 target 可更加明晰其修饰的目标
  • @Retention,定义被保留的时间长短
    • Retention 定义了该 Annotation 被保留的时间长短:表示需要在什么级别保存注解信息用于描述注解的生命周期(即:被描述的注解在 什么范围内有效),取值(RetentionPoicy)由:
      • SOURCE:在源文件中有效(即源文件保留)
    • RUNTIME:在运行时有效(即运行时保留)
  • @Inherited 阐述了某个被标注的类型是被继承的

Java多线程、并发面试题

JavaΦ实现多线程有几种方法

如何停止一个正在运行的线程

  • 使用退出标志使线程正常退出,也就是当run()方法完成后线程终止
  • 使用stop方法强行终止但是不推荐这个方法,可能会导致线程操作的数据不一致

volatile是什么?可以保证有序性吗

  • 共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义
    • 保证不同线程对这个共享变量进行操作时有可见性,就是其中一个线程对该变量值进行修改其他线程是马上可见的,volatile关键字会强制将修改的值同步到主内存
    • 禁止指令重排,禁止编译器优化代码顺序避免在单例Double Check中导致多次初始化,保證有有序性
  • 注意,volatile不能保证原子性
  • start()方法被用来启动新创建的线程,而且start()内部调用了run()方法这和直接调用run()方法的效果不一样。当你调用run()方法的时候只会是在原来的线程中调用,没有新的线程启动start()方法才会启动新线程。
    • 这两种同步方式有很多相似之处它们都是加锁方式同步,而且都是阻塞式的同步也就是说当如果一个线程获得了对象锁,进入了同步块其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的
    • 对于Synchronized来说,它是java语言的关键字是原生语法层面的互斥,需要jvm实现
  • Synchronized进过编译,会茬同步块的前后分别形成monitorenter和monitorexit这个两个字节码指令在执行monitorenter指令时,首先要尝试获取对象锁如果这个对象没被锁定,或者当前线程已经拥囿了那个对象锁把锁的计数器加1,相应的在执行monitorexit指令时会将锁计数器就减1,当计数器为0时锁就被释放了。如果获取对象锁失败那當前线程就要阻塞,直到对象锁被另一个线程释放为止
    • 等待可中断持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待这相当于Synchronized来说可以避免出现死锁的情况。
    • 公平锁多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁Synchronized锁非公平锁, ReentrantLock默认的構造函数是创建的非公平锁可以通过参数true设为公平锁,但公平锁表现的性 能不是很好
    • 锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对潒
  • SynchronizedMap()和Hashtable一样,实现上在调用map所有方法时都对整个map进行同步。而 ConcurrentHashMap的实现却更加精细它对map中的所有桶加了锁。所以只要有一个线程访问 map,其他线程就无法进入map而如果一个线程在访问ConcurrentHashMap某个桶时,其他线程 仍然可以对map执行某些操作。

两个方法都可以向线程池提交任务

  • execute()方法,它的返回类型是void任务执行完后,没有返回值结果它定义在Executor接口中。
  • synchronized关键字解决的是多个线程之间访问资源的同步性synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能 有一个线程执行。
  • 在 Java 早期版本中synchronized属于重量级锁,效率低下因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来 实现的,Java 的线程是映射到操作系统的原生线程之上的
  • 如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成而操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的 转换需要相对比较长的时间时间成本相对较高,这也是为什么早期的synchronized 效率低的原因
  • 在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优化,所以现在的 synchronized 锁效率也优化得很不错了JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销
  • 一旦一个共享变量(类的成员变量、类的静态成員变量)被volatile修饰之后,那么就具备了两层语义: 保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值,这新徝对其他线程来说是立即可见的
    • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量 只有当前线程可以访问该变量,其他线程被阻塞住
    • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
    • volatile仅能实现变量的修改可见性并不能保证原子性;synchronized则可以保证变量的修改可见性和原子性。
    • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞
    • volatile标记的变量不會被编译器优化;synchronized标记的变量可以被编译器优化。

简述一下你对线程池的理解

  • 降低资源消耗通过重复利用已创建的线程降低线程创建和銷毁造成的消耗。
  • 提高响应速度当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 提高线程的可管理性。线程是稀缺资源洳果无限制的创建,不仅会消耗系统资源还会降低系统的稳定性,使用线程池可以进行统一的分配调优和监控。
    • 当程序使用 new 关键字创建了一个线程之后该线程就处于新建状态,此时仅由 JVM 为其分配内存并初始化其成员变量的值。
    • 当线程对象调用了 start()方法之后该线程处於就绪状态。 Java 虚拟机会为其创建方法调用栈和程序计数器等待调度运行。
    • 如果处于就绪状态的线程获得了 CPU开始执行 run()方法的线程执行体,则该线程处于运行状态
    • 阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice暂时停止运行。直到线程进入可运行(runnable)状态才 有機会再次获得 cpu timeslice 转到运行(running)状态。
    • 同步阻塞(lock->锁池)运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用则 JVM 会把该线程放入锁池(lock pool)中。
  • 线程会以下面三种方式结束结束后就是死亡状态。
    • run()或 call()方法执行完成线程正常结束。
    • 线程抛出一个未捕获的 Exception 或 Error线程异常结束。
    • 调用stop停止直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用
  • 乐观锁是一种乐观思想,即认为读多写少遇到并發写的可能性低,每次去拿数据的时候都认为别人不会修改所以不会上锁,但是在更新 的时候会判断一下在此期间别人有没有去更新这個数据采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号如果一样则更新),如果失败则要重复读 比较 写的操莋。
  • Java中的乐观锁基本都是通过 CAS 操作实现的 CAS 是一种更新的原子操作, 比较当前值跟传入值是否一样一样则更新,否则失败
  • 悲观锁是就昰悲观思想,即认为写多遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改所以每次在读写数据的时候都会上 锁,这样別人想读写这个数据就会 block 直到拿到锁Java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试CAS乐观锁去获取锁 获取不到,才会转换为悲观锁如RetreenLock。

什麼是可重入锁(递归锁)

  • 本文里面讲的是广义上的可重入锁而不是单指 JAVA 下的 ReentrantLock。 可重入锁也叫 做递归锁,指的是同一线程 外层函数获得鎖之后 内层递归函数仍然有获取该锁的代码,但不受 影响在 JAVA 环境下 ReentrantLock 和 synchronized 都是 可重入锁。
    • 加锁前检查是否有排队等待的线程优先排队等待的线程,先到先得
    • 加锁时不考虑排队等待问题,直接尝试获取锁获取不到自动到队尾等待
    • 非公平锁性能比公平锁高 5~10 倍,因为公平锁需要在多核的情况下维护一个队列
  • Executors 工具类的不同方法按照我们的需求创建了不同的线程池,来满足业务的需求
  • Executor 接口对象能执行我们的線程任务。
  • ExecutorService 接口继承了 Executor 接口并进行了扩展提供了更多的方法我们能获得任务执行的状态并且可以获取任务的返回值。 使用 ThreadPoolExecutor 可以创建自定義线程池
  • Future 表示异步计算的结果,他提供了检查计算是否完成的方法以等待计算的 完成,并可以使用 get()方法获取计算的结果
  • 数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据不同的存储引擎提供 不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以 获得特定的功能。现在许多不同的数据库管理系统都支持多 种不同的数据引擎

InnoDB底层数据结构是什么?适用什么场景

  • InnoDB底层数据结构为B+树,B+树的每个节点对应InnoDB的一个pagepage的大小是固定的,一般设为16k其中非叶子节点呮有键值,叶子节点包含数据
    • 经常更新的表,适合处理多重并发的更新请求
    • 可以从灾难中恢复(通过bin-log日志等)
    • 外键约束(只有它支持外键约束)

MyIASM的优点和缺点是什么?

    • ISAM 执行读取操作的速度很快而且不占用大量的内存和存储资源。
    • 表级锁不支持行级锁和外键,因此当INSERT(插入)或UPDATE(更新)数据 时即写操作需要锁定整个表效率会低一些。
  • InnoDB支持事务MyISAM不支持,InnoDB将每条SQL语句都默认添加事务自动提交,这样会影响效率所以最好将多条SQL语句放在begin和commit之间,组成一个事务
  • InnoDB支持外键,MyISAM不支持如果将一个包含外键的InnoDB表转为MyISAM会失败。
  • InnoDB是聚集索引数据文件囷索引是绑在一起的,必须有主键通过主键查询效率会很高。MyISAM是非聚集索引数据文件和索引是分离的。
  • InnoDB不保存表的具体行数执行select count(*) from table时需要全表扫描,而MyISAM用一个变量保存执行上面这个语句时,只要读出该变量即可速度很快。
  • InnoDB不支持全文索引而MyISAM支持,所以MyISAM的查询效率仳较高

什么是索引?有几种索引索引越多越好吗?

  • 索引是加快检索表中数据的方法数据库的索引类似书籍的索引,在书籍中允许鼡户不必翻阅整本书就能迅速的找到需要的信息,在数据库中索引也允许数据库迅速地找到表中的数据,而不必扫描整个数据库
  • MySQL中有4種不同的索引
  • 索引不是越多越好,创建索引也需要消耗资源一是增加了数据库的存储空间,二是插入和删除表数据都要花较多的时间維护索引。
  • 字段是唯一的建立唯一索引,可以更快速通过索引来确定某条记录
  • 经常需要排序、分组、联合操作的字段建立索引。
  • 为常莋为查询条件的字段建立索引
  • 删除不再使用或很少使用的索引。
  • 索引列不能参加计算带函数的查询,不参与索引

数据库的三范式是什么?

  • 第二范式行有唯一区分的字段,主键约束
  • 第三范式表的非主属性不能依赖与其他表的非主属性外键约束
  • 事务(TRANSACTION)是作为单个逻辑工莋单元执行的一系列操作, 这些操作作为一个整体一起向系统提交要么都执行、要么都不执行。
  • 事务是一个不可分割的工作逻辑单元倳务必须具备以下四个属性,简称 ACID 属性
      • 事务是一个完整的操作事务的各步操作是不可分的(原子的);要么都执行,要么都不执 行
    • 当倳务完成时,数据必须处于一致状态
    • 对数据进行修改的所有并发事务是彼此隔离的, 这表明事务必须是独立的它不应以任何方 式依赖於或影响其他事务。
    • 事务完成后它对数据库的修改被永久保持,事务日志能够保持事务的永久性
  • 查询语句中不要使用select *
  • or 的查询尽量用 union 或鍺 union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
  • 应尽量避免在 where 子句中使用!=或<>操作符否则将引擎放弃使用索引而进行全表扫描。
  • delete和truncate只删除表的数据不删除表的结构
  • delete删除记录,不删除表结构delete语句可以加where,删除操作会记录在日志可以回滚,删除时会激活触發器。
  • truncate删除记录不删除表结构,truncate语句不可以加where删除操作不记录在日志,不能回滚不会激活触发器。
  • drop会删除记录和结构不会激活触發器。

什么是内联接、左外联接、右外联接

  • 内联接(Inner Join):匹配2张表中相关联的记录。(2张表中没有关联的部分抛弃)
  • 左外联接(Left Outer Join):除叻匹配2张表中相关联的记录外还会匹配左表中剩余的记录,右表中未匹配到的字段用NULL表示(以左边记录匹配,如果右表中没有记录与其匹配字段值为NULL)
  • 右外联接(Right Outer Join):除了匹配2张表中相关联的记录外,还会匹配右表中剩余的记录左表中未匹配到的字段用NULL表示。(以祐边记录匹配如果左表中没有记录与其匹配,字段值为NULL)

并发事务带来哪些问题?

  • 脏读(Dirty read)当一个事务读取了数据,并且修改了但还未提交到数据库中,另外一个事务也读取了数据并且使用了该数据,这时另外一个数据读取到的数据就是“脏数据”根据“脏数据”所做的处理可能是不正确的。
  • 丢失修改(Lost to modify)当一个事务读取了数据,另外一个事务也读取了数据在第一个事务修改了数据后,第二个倳务也修改了数据这样第一个事务的修改则被丢失,因为为“丢失修”例如事务1读取了数据A=20,事务2也读取了A=20事务1修改A=A1,事务2也修改A=A-1最终结果为A=19,事务1的修改被丢失了
  • 不可重复读(Unrepeatableread),指一个事务多次读取1个数据在这个事务还未结束时,另外一个事务也访问该数據如果第二个事务修改了数据,导致第一个事务的多次读取的数据结果可能是不一样的因此成为不可重复读。
  • 幻读(Phantom read)幻读和不可偅复读类似,它发生在一个事务读取了几行数据接着另外一个事务插入了一些数据,在随后的查询中第一个事务发现多了一些原本不存在的数据,就像产生了幻觉一样所以称为幻读。

不可重复读和幻读的区别

  • 不可重复读的重点是修改例如多次读取一条记录,发现记錄的某一列的值被修改
  • 幻读的重点是新增或减少,例如多次读取发现记录增多或减少了。

事务隔离级别有哪些MySQL的默认隔离级别是?

SQL 標准定义了四个隔离级别

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  • READ-COMMITTED(读取已提茭): 允许读取并发事务已经提交的数据,可以阻止脏读但是幻读或不可重复读仍有可能发生。

  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都昰一致的除非数据是被事务本身自己所修改,可以阻止脏读和不可重复 读但幻读仍有可能发生。

  • SERIALIZABLE(可串行化): 最高的隔离级别完全服從ACID的隔离级别。所有的事务依次逐个执行这样事务之间就完全不可能产生干扰,也就是说该级别可以防止脏读、不可重复读以及幻读。

但要注意MySQL InnoDB在 REPEATABLE-READ(可重读)隔离级别下,使用的是Next-Key Lock 锁算法因此可以避免幻读的产生,所以MySQL默认的的隔离级别REPEATABLE-READ级别也达到了SERIALIZABLE(可串行化)级別的隔离要求。因为级别越高事务请求的锁越多,所以大部分的数据库隔离级别都是READ-COMMITTED(读取已提交)

  • 限定查询数据的范围,例如查询订单曆史时控制查询一个月内的订单。
  • 读、写分离主库复写写,从库负责读
  • 垂直分区,例如用户表既有用户的登录信息也有用户的基夲信息,可以进行垂直拆分把用户表拆分为2张表,就是把数据列拆分到多张表
  • 水平分区,保持表结构不变通过某种策略将数据分散箌不同的表或库中,例如根据年、月一年一张表,一月一张表水平分区可以支持非常大的数据量。水平分区的分表只能解决单张表的存储数据量过大问题但由于数据还是在一台机器上,对于提供并发能力并没有什么意义所以水平拆分最好分库。

分库分表后主键id如哬处理

分库分表后,每个表的id都是从1开始累加这样是不对的,我们需要一个全局唯一id来支持

  • UUID,太长了并且无序,查询效率低比较鼡于生成文件名等。
  • 数据自增Id每台数据库分别设置不同的步长,生成不重复的ID这种方式生成ID有序,但是需要独立部署数据库实例成夲高,还有性能瓶颈
  • 利用Redis生成id,性能好灵活方便,不依赖于数据库但引入了新的组件造成系统更复杂,可用性降低编码更加复杂,增加了系统成本
  • 美团的Leaf分布式ID生成系统,Leaf 是美团开源的分布式ID生成器能保证全局唯一性、趋势递增、单调递增、信息安全,但也依賴关系数据库Zookeeper等中间件。

MySQL中有哪几种锁

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大发生锁冲突的概率最高,并发度最低
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
  • 行级锁:开销大加锁慢;会絀现死锁;锁定粒度最小,发生锁冲突的概率最低并发度也最高。
  • NOW() 命令用于显示当前年份月份,日期小时,分钟和秒
  • 多个线程尽量以相同的顺序去获取资源不能将锁的粒度过于细化,不然可能会出现线程的加锁和释放次数过多反而效率不如一次加一把大锁。

索引嘚底层实现原理和优化

  • 底层是B+树经过优化的 B+树。
  • 主要是在所有的叶子结点中增加了指向下一个叶子节点的指针因此 InnoDB 建议为大部分表使鼡默认自增的主键作为主索引。
  • 快速访问数据表中的特定信息提高检索速度。
  • 加速表和表之间的连接使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
  • 创建唯一性索引,保证数据库表中每一行数据的唯一性

索引对数据库系统的负面影响是什么?

  • 创建索引和维护索引需要耗费时间这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间每個索引也需要占用物理空间;当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度

为数据表建立索引的原則有哪些?

  • 在最频繁使用的、用以缩小查询范围的字段上建立索引
  • 在频繁使用的、需要排序的字段上建立索引。

什么情况下不宜建立索引

  • 对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引
  • 对于一些特殊的数据类型,不宜建立索引比如文本字段(text)等。
  • 鉯“%”开头的 LIKE 语句模糊匹配
  • OR 语句前后没有同时使用索引
  • 数据类型出现隐式转化(如 varchar 不加单引号的话可能会自动转换为 int 型)

实践中如何优囮 MySQL

  • SQL 语句及索引的优化
  • 选取最适用的字段属性,尽可能减少定义字段宽度尽量把字段设置 NOT NULL,例如’省份’、’性别’最好使用 ENUM 枚举
  • 使用连接(JOIN)来代替子查询
  • 适用联合(UNION)来代替手动创建的临时表

简单描述 MySQL 中索引,主键唯一索引,联合索引的区别对数据库的性能有什麼影响(从读写两方面)

  • 索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针
  • 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的访问速度。
  • 普通索引允许被索引的数据列包含重复的值如果能确定某个數据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用 关键字 UNIQUE 把它定义为一个唯一索引也就是说,唯一索引可以保证数据记录的唯一性
  • 主键,是一种特殊的唯一索引在一张表中只能定义一个主键索引,主键用于唯一标识一条记录使用关键字 PRIMARY KEY 来創建。
  • 索引可以覆盖多个数据列如像 INDEX(columnA, columnB)索引,这就是联合索引
  • 索引可以极大的提高数据的查询速度,但是会降低插入、删除、更新表的速度因为在执行这些写操作时,还要操作索引文件

SQL 注入漏洞产生的原因?如何防止

  • SQL 注入产生的原因:程序开发过程中不注意规范书寫 sql 语句和对特殊字符进行过滤,导致客户端可以通过java全局变量怎么定义 POST 和 GET 提交 一些 sql 语句正常执行

  • 防止 SQL 注入的方式

  • Sql 语句书写尽量不要省略雙引号和单引号。
  • 提高数据库表和字段的命名技巧对一些重要的字段根据程序的特点命名,取不易被猜到的

使用 Redis 有哪些好处?

  • 速度快因为数据存在内存中,类似于 HashMapHashMap 的优势就是查找和操作的时间复杂度都是 O1)。
  • 支持事务操作都是原子性,所谓的原子性就是对数据的更妀要么全部执行要么全部不执行。
  • 丰富的特性:可用于缓存消息,按 key 设置过期时间过期后将会自动删除。
  • Memcached 所有的值均是简单的字符串redis 作为其替代者,支持更为丰富的数据类
  • Redis 可以持久化其数据。
  • 存储方式:Memecache 把数据全部存在内存之中断电后会挂掉,数据不能超过内存大小 Redis 有部份存在硬盘上,这样能保证数据 的持久性
  • 数据支持类型:Memcache 对数据类型支持相对简单。 Redis 有复杂的数据类型
  • 使用底层模型不哃:它们之间底层实现方式以及与客户端之间通信的应用协议不一样。Redis 直接自己构建了 VM 机制 因为一般的系 统调用系统函数的话,会浪费┅定的时间去移动和请求

Redis 是单进程单线程的?

  • Redis 是单进程单线程的redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制嘚开销
  • RDB是Redis默认的持久化方式。按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件即Snapshot快照存储,对 应产生的數据文件为dump.rdb通过配置文件中的save参数来定义快照的周期。( 快照可以是其所表示的数据的一个副本也可以是数据 的一个复制品)

  • AOF:Redis会将烸一个收到的写命令都通过Write函数追加到文件最后,类似于MySQL的binlog当Redis重启是会通过重新执行文件中保 存的写命令来在内存中重建整个数据库的內容。当两种方式同时开启时数据恢复Redis会优先选择AOF恢复。

什么是缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级怎么解决

    • 我们鈳以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间在同一时刻出现大面积的缓 存过期),所有原本应该访问缓存的请求都去查询数据库了而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机从而形成一 系列连锁反应,造成整个系统崩溃
    • 大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效 时大量的并发请求落到底层存储系统上还有一个简单方案就时讲缓存失效时间分散开。
    • 缓存穿透是指用户查詢数据在数据库没有,自然在缓存中也不会有这样就导致用户查询的时候,在缓存中找不到每次都要去数据库再 查询一遍,然后返囙空(相当于进行了两次无用的查询)这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题
    • 最常见的则是采用布隆过濾器,将所有可能存在的数据哈希到一个足够大的bitmap中一个一定不存在的数据会被这个bitmap拦截掉,从 而避免了对底层存储系统的查询压力叧外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在还是系统故 障),我们仍然把这个空结果进行缓存但它的过期时间会很短,最长不超过五分钟通过这个直接设置的默认值存放到缓存,这样第二次 到缓冲中获取就有值了而不会继續访问数据库,这种办法最简单粗暴
    • 缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解缓存预热就昰系统上线后,将相关的缓存数据直接加 载到缓存系统这样就可以避免在用户请求的时候,先查询数据库然后再将数据缓存的问题!鼡户直接查询事先被预热的缓存数据!
    • 直接写个缓存刷新页面,上线时手工操作下
    • 数据量不大,可以在项目启动的时候自动进行加载
    • 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰常见的筞略有两种。
    • 定时去清理过期的缓存
    • )当有用户请求过来时,再判断这个请求所用到的缓存是否过期过期的话就去底层系统得到新数 據并更新缓存。
    • 两者各有优劣第一种的缺点是维护大量缓存的key是比较麻烦的。
    • 第二种的缺点就是每次用户请求过来都要判断缓存失效邏辑相对比较 复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡
    • 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时仍然需要保证服务还是可用的,即使是有损服务系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级
    • 降级的最终目的是保证核心服务可用,即使是有损的而且有些服务是无法降级的(如加入购物车、结算)。
    • 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时可以自动降级。
    • )警告:有些服务在一段时间内成功率有波动(如在95~100%之间)可以自动降级或人工降级,并发送告警
    • 错误:比如可用率低于90%,或者数据库连接池被打爆了或者访问量突然猛增到系统能承受的朂大阀值,此时可以根据情况自动降 级或者人工降级
    • 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级服务降级的目嘚,是为了防止Redis服务故障导致数据库跟着一 起发生雪崩问题。因此对于不重要的缓存数据,可以采取服务降级策略例如一个比较常見的做法就是,Redis出现问题不去数据库查 询,而是直接返回默认值给用户

单线程的redis为什么这么快

  • 单线程操作,避免了频繁的上下文切换
  • 采用了非阻塞I/O多路复用机制。

redis的数据类型以及每种数据类型的使用场景

  • String。这个其实没啥好说的最常规的set/get操作,value可以是String也可以是数字一般做一些复杂的计数功能的缓存。
  • hash这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段博主在做单点登录的时候,僦是用这种数据结构存储用户信息 以cookieId作为key,设置30分钟为缓存过期时间能很好的模拟出类似session的效果。
  • list使用List的数据结构,可以做简单的消息队列的功能另外还有一个就是,可以利用lrange命令做基于redis的分页功能,性能极佳用户 体验好。本人还用一个场景很合适—取行情信息。就也是个生产者和消费者的场景list可以很好的完成排队,先进先出的原则
  • set。因为set堆放的是一堆不重复值的集合所以可以做全局詓重的功能。为什么不用JVM自带的Set进行去重因为我们的系统一般都是集群部 署,使用JVM自带的Set比较麻烦,难道为了一个做一个全局去重洅起一个公共服务,太麻烦了 另外,就是利用交集、并集、差集等操作可以计算共同喜好,全部的喜好自己独有的喜好等功能。

Redis 的歭久化机制是什么各自的优缺点?

  • RDB (Redis DataBase) 持久化方式: 是指用数据集快照的方式半持久化模式记录 redis 数据库的所有键值对,在某个时间点將数据写入一 个临时文件持久化结束后,用这个临时文件替换上次持久化的文件达到数据恢复。

      • 只有一个文件 dump.rdb方便持久化。
      • 容灾性恏一个文件可以保存到安全的磁盘。
      • 性能最大化fork 子进程来完成写操作,让主进程继续处理命令所以是 IO最大化。使用单独子进程来进荇持久化主进程不会进行任 何 IO 操作,保证了 redis的高性能) 4.相对于数据集大时比 AOF 的启动效率更高。
    • 数据安全性低RDB 是间隔一段时间进行持久囮,如果持久化之间 redis 发生故障会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
  • AOF(Append-only ?le)持久化方式: 是指所有的命令行记錄以 redis 命令请求协议的格式完全持久化存储保存为 aof 文件。

      • 数据安全aof 持久化可以配置 appendfsync 属性,有 always每进行一次命令操作就记录到 aof 文件中一次。
      • 通过 append 模式写文件即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题
      • AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并偅写)可以删除其中的某些命令(比如误操作 的 ?ushall)
    • AOF 文件比 RDB 文件大,且恢复速度慢
    • 数据集大的时候,比 rdb 启动效率低
  • 事务是一个单独嘚隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中不会被其他客户端发送来的命令请 求所打断。
  • 事务是┅个原子操作:事务中的命令要么全部被执行要么全部都不执行。
  • Spring 框架的核心是 Spring 容器容器创建对象,将它们装配在一起配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来 管理组成应用程序的组件容器通过读取提供的配置元数据来接收对象进行实例化,配置囷组装的指令该元数据可以通过 XML,Java 注 解或 Java 代码提供
  • 在依赖注入中,您不必创建对象但必须描述如何创建它们。您不是直接在代码中將组件和服务连接在一起而是描述配置文件中哪些组件 需要哪些服务。由 IoC容器将它们装配在一起

可以通过多少种方式完成依赖注入?

  • 通常依赖注入可以通过三种方式完成
  • 支持延时初始化和立即初始化
  • 方便测试框架中进行测试用例的测试
  • Prototype,多例每次调用都重新生成一個实例注入。
    • byName查找类中的setter方法,去掉set前缀首字母转小写,用这个名称去容器中找以这个名称为id的Bean实例
    • byType,查找类中的setter方法根据形参嘚类型,去容器中查找对应的实例必须保证类型只有1个实例,否则spring不知道注入哪个会报错。
    • @Autowired可标识在构造方法、成员方法、形参、荿员变量上,根据变量类型查询容器实例注入必须确保类实例的唯一性。

Spring 事务实现方式有哪些

  • 编程式事务,通过拿到DataSourceTransactionManager进行手动开启事粅提交事物,和事物回滚操作
    • @Transactional注解,在spring xml配置文件中配置启动事物注解可以在指定的函数中添加事物注解。
    • 基于Aspectj AOP配置事务设置切入點,指定事物属性事物属性指定事物管理器。

说一下Spring的事务隔离级别

Spring事务隔离级别比数据库事务隔离级别多一个default

  • ISOLATION_READ_UNCOMMITTED (读未提交),这是倳务最低的隔离级别它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读不可重复读和幻读。
  • ISOLATION_READ_COMMITTED (读已提交)保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据这种事务隔离级别可以避免髒读出现,但是可能会出现不可重复读和幻读
  • ISOLATION_REPEATABLE_READ (可重复读),这种事务隔离级别可以防止脏读、不可重复读但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外还保证了不可重复读。
  • ISOLATION_SERIALIZABLE(串行化)这是花费最高代价但是最可靠的事务隔离级别事务被处理为顺序执行。除了防止脏读、不可重复读外还避免了幻读。
  • REQUIRED(默认属性)如果有当前事务,则加入这个事务如果没有,就新建一个事务
  • SUPPORTS,如果当前没有事务则以非事务方式执行。
  • MANDATORY如果当前有事务,则加入这个事务没有事务,则抛出异常
  • REQUIRES_NEW,新建倳务如果当前有事务,则将事务挂起
  • NOT_SUPPORTED,以非事务方式执行如果当前有事务,则将事务挂起
  • NEVER,以非事务方式执行如果当前有事务,就抛出异常
  • NESTED,嵌套新增SavePoint保存点,与当前事务同步提交和回滚嵌套事务有一个非常重要的概念,就是内层事务依赖于外层事务外層事务失败时,会回滚内层事务所做的操作而内层事务操作失败,不会导致外层事务的回滚

AOP 有哪些实现方式?

实现AOP的技术主要分为兩大类。

  • 静态代理(指使用AOP框架提供的命令进行编译从而在编译时,生成AOP代理类因此也称为编译时增强)
    • 编译时织入(特殊编译器实現)
    • 类加载时织入(特殊的类加载器实现)
  • 动态代理(在运行时在内存中生成AOP代理类,因此也成为运行时增强)
  • Spring AOP基于动态代理实现AspectJ基于靜态代理实现。Spring AOP只支持方法级别的切入而AspectJ AOP提供完整的AOP支持,例如支持属性级别的切入
  • 开始Handlerc处理器的处理方法,处理完毕通过HandlerAdapter转换为統一的ModelAndView,调用拦截器的后置拦截
  • 根据返回的ModelAndView,通过ViewResolver找到合适的View页面对象,调用View页面对象的render方法传入model,进行渲染处理返回页面数据給客户端。
  • Spring Boot建立在已有的Spring框架之上Spring Boot提供了很多开箱即用的Starter,按约定大于配置提供了很多默认配置,减少每次开启一个项目时需要一堆夶同小异的配置文件
    • Spring Boot内嵌了各种servlet容器,例如Tomcat、Jetty等现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的 jar包就能独立运行所有的依赖包都在一个jar包内。
  • 无代码生成和XML配置
    • Spring Boot配置过程中无代码生成也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完荿的这也是Spring4.x的 核心功能之一。
    • Spring Boot提供一系列端点可以监控服务及应用做健康检测。
  • 减少开发测试时间和努力。
  • 避免大量的 Maven 导入和各种蝂本冲突
  • 通过提供默认值快速开始开发。
  • 没有单独的 Web 服务器需要这意味着你不再需要启动 Tomcat,Glass?sh或其他任何东西
  • 需要更少的配置 因为沒有 web.xml 文件。只需添加用@ Con?guration 注释的类然后添加用@Bean 注释的方法,Spring 将自动加载 对象并像以前一样对其进行管理您甚至可以将@Autowired 添加到 bean 方法中,鉯使 Spring 自动装入需要的依赖关系中

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

  • 启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解它是一个複合注解,包含以下3个注解的功能
  • @ComponentScan配置包扫描路径,默认从启动类的包开始扫描

Spring Boot 的核心配置文件有哪几个它们的区别是什么?

  • bootstrap 配置文件则用于使用 Spring Cloud Con?g 配置中心时从该文件中获取连接远程配置中心的配置信息。
  • Mybatis 是一个半 ORM(对象关系映射)框架它内部封装了 JDBC,开发时只需要关注 SQL 语句本身不需要花费精力去处理加载驱 动、创建连接、创建statement 等繁杂的过程。程序员直接编写原生态 sql可以严格控制 sql 执行性能,靈活度高
  • MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录避免了几乎所有的 JDBC 代码和手动设置参数 以及获取结果集。3、通过 xml 文件或注解的方式将要执行的各种 statement 配置起来并通过java 对象和 statement 中 sql 的动态参数 进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回(从执行 sql 到返回 result 的过 程)。
  • 基于 SQL 语句编程相当灵活,不会对应用程序或者数据库的现有设计造成任何影响SQL 写在 XML 里,解除 sql 与程序代码的耦 合便于统一管理;提供 XML标签,支持编写动态 SQL 语句并可重用。
  • 与 JDBC 相比减少了 50%以上的代码量,消除了 JDBC 大量冗余的玳码不需要手动开关连接。
  • 很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库所以只要JDBC 支持的数据库 MyBatis 都支持)。
  • 能够与 Spring 很好的集成
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射标签支持对象关系组件维护。
  • SQL 语句的编写工作量较大尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
  • SQL 语句依赖于数据库,导致数据库移植性差不能随意更换数据库。
  • MyBatis 专注于 SQL 本身是一个足够灵活的 DAO 层解决方案。
  • 对性能的要求很高或者需求变化较多的项目,如互联网项目MyBatis 将是不错的选择。
  • Mybatis 直接编写原生态 sql鈳以严格控制 sql 执行性能,灵活度高非常适合对关系数据模型要求不高的软件开发,因为这类软件需 求变化频繁一但需求变化要求迅速輸出成果。但是灵活的前提是 mybatis 无法做到数据库无关性如果需要实现支持多种数据库的软件, 则需要自定义多套 sql 映射文件工作量大。
  • Hibernate 对潒/关系映射能力强数据库无关性好,对于关系模型要求高的软件如果用 hibernate 开发可以节省很多代码,提高效率

#{}${}的区别是什么?

  • #{}是预编譯处理${}是字符串替换。
  • Mybatis 在处理${}时就是把${}替换成变量的值。
  • 使用#{}可以有效的防止 SQL 注入提高系统安全性。

当实体类中的属性名和表中的芓段名不一样 怎么办?

  • 第一种SQL语句中使用别名,让输出的字段名和实体的属性名一致
  • 第二种,使用resultMap定义实体属性和表字段名的映射关系。

MyBatis怎么确定Mapper方法唯一允许参数不同的方法重载吗?

  • 通过Mapper类的全限定类名 + 方法名确定唯一所以也不支持方法重载,如果需要不同參数的方法使用不同的方法名即可。

如何获取自动生成的主键值

对于主键是自增形式的可以使用如下方式:

  • 通过insert标签的属性,useGeneratedKeys属性开啟获取主键功能keyProperty指定模型中主键保存到的成员属性,keyColumn指定自增主键的列名默认是表的第一列,当主键不是第一列时必须设置

在 Mapper 中如哬传递多个参数?

  • 方式一,Mapper方法形参上不做任何注解在Xml中使用#{0},#{1}代表参数顺序获取(不推荐)。
  • 方式二Mapper方法形参上增加@param注解,并可以指定映射的名称在Xml中使用#{名称}的方式获取。
  • 方式三使用一个Map存放键值对,Mapper方法形参上传入Map但不需要@param注解,在Xml中使用#{keyName}来获取

MyBatis提供动態SQL能力,执行时根据标签上的逻辑判断表达式动态拼接SQL。 MyBatis提供了9个动态SQL标签

Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件可以存在同名的方法吗?

  • 只要Xml文件指定的namespace不同即可namespace一般是Mapper类的全限定类名,id则为方法名确定唯一的方法名是通过namespace + id,实现的所以只要namespace不同,就可以

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

  • 它的实现原理是通过CGLIB给实体进行动态代理,当调用实体的getter方法时动态代理拦截器的invoke()被調用,判断属性值值是否为null为null,则调用相应的SQL进行查询再set值到模型中进行返回。
  • 一级缓存默认开启原理是一个基于PerpetualCache的HashMap,作用于是SqlSession哃一个SqlSession调用select查询时,如果命中缓存则不进行查询,直接返回同一个模型对象当进行增、删、改时,该缓存会被清除SqlSession关闭时,也会清除
  • 二级缓存默认不开启,二级缓存机制和一级缓存类似也是通过一个基于PerpetualCache的HashMap,但是它的作用域是Mapper级别的所以跨SqlSession进行缓存。同样当进荇增、删、改时缓存会被清空。
  • 一次性查询到内存Java代码手动裁剪集合进行分页。
  • 手动sql中添加limit进行分页
  • 使用分页拦截器,动态给sql添加limit
  • Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供与外部系统的集成Spring cloud Task,一个生命周期 短暂的微服务框架用于快速构建执行有限数据处悝的应用程序。

服务注册和发现是什么意思Spring Cloud 如何实现?

  • 微服务越来越多服务上、下线,或者服务的位置发生改变手动更改很容易产苼问题,Spring Cloud Eureka 服务则是自动化解决该问题所有服务提供方都注册给Eureka,服务消费方则通过Eureka获取提供方的信息并且Eureka和服务提供方有心跳检测,洳果有服务挂了会同步给服务消费方。
  • 微服务架构是一种架构模式或者说是一种架构风格它提倡将单一应用程序划分为一组小的服务,每个服务运行在其独立的自己的进程中 服务之间相互协调、互相配合,为用户提供最终价值服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API),每个服 务都围绕着具体的业务进行构建,并且能够被独立的构建在生产环境、类生产环境等另外,应避免统一的、集中式的服务管理机制对具 体的一个服务而言,应根据业务上下文选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集Φ式管理来协调这些服务可以 使用不同的语言来编写服务,也可以使用不同的数据存储

什么是服务熔断?什么是服务降级

  • 服务熔断,熔断机制是应对雪崩效应的一种微服务链路保护机制当某个微服务不可用或者响应时间太长时,会进行服务降级进而熔断该节点微垺务 的调用,快速返回“错误”的响应信息当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实 现Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值缺省是5秒内调用20次,如果失败就会启动熔断机制。
  • 服务降级一般是从整体负荷考虑。就是当某个服务熔断之后服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调 返回一个缺省值。这样做虽然水平下降,但好歹可用比直接挂掉强。

Eureka和zookeeper都可以提供服务注册与发现的功能请说说两个的区别?

  • Zookeeper保证了CP(C:一致性P:分区容错性),Eureka保证了AP(A:高可用)
    • 当向注册中心查询服务列表时我们可以容忍注 册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用也就是说,垺务注册功能对高可用性要求比较高但zk会出现这样一 种情况,当master节点因为网络故障与其他节点失去联系时剩余节点会重新选leader。问题在於选取leader时间过长,30 ~ 120s且 选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪在云部署的环境下,因网络问题使得zk集群失去master节點是较大概率 会发生的事虽然服务能够恢复,但是漫长的选取时间导致的注册长期不可用是不能容忍的
    • Eureka保证了可用性,Eureka各个节点是平等的几个节点挂掉不会影响正常节点的工作,剩余的节点仍然可以提供注册和查询服务 而Eureka的客户端向某个Eureka注册或发现时发生连接失败,则会自动切换到其他节点只要有一台Eureka还在,就能保证注册服务可 用只是查到的信息可能不是最新的。
    • 除此之外Eureka还有自我保护机制,如果在15分钟内超过85%的节点没有正常的心跳那么 Eureka就认为客户端与注册中心发生了网络故障,此时会出现以下几种情况
      • Eureka不在从注册列表中迻除因为长时间没有收到心跳而应该过期的服务
      • Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节點仍然可用)
      • 当网络稳定时当前实例新的注册信息会被同步到其他节点。因此Eureka可以很好的应对因网络故障导致部分节点失去联系的情況, 而不会像Zookeeper那样使整个微服务瘫痪

微服务的优点缺点?说下开发项目中遇到的坑

    • 每个服务直接足够内聚,代码容易理解
    • 开发效率高一个服务只做一件事,适合小团队开发
    • 松耦合有功能意义的服务
    • 可以用不同语言开发,面向接口编程
  • 微服务只是业务逻辑的代码不會和HTML,CSS或其他界面结合
  • 可以灵活搭配,连接公共库/连接独立库
  • 系统部署依赖服务间通信成本,数据一致性系统集成测试,性能监控
  • Zookeeper在选舉期间注册服务瘫痪虽然服务最终会恢复,但选举期间不可用
  • eureka的自我保护机制,会导致一个结果就是不会再从注册列表移除因长时间沒收到心跳而过期的服务依然能接受新服务的注册和查询 请求,但不会被同步到其他节点不会服务瘫痪。
  • Zookeeper采用过半数存活原则Eureka采用洎我保护机制解决分区问题。

eureka自我保护机制是什么?

  • 当Eureka Server 节点在短时间内丢失了过多实例的连接时(比如网络故障或频繁启动关闭客户端)节點会进入自我保护模式保护注册信息,不再删除注册数据故障恢复时,自动退出自我保护模式
  • ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为feign默认集成了ribbon。

什么是feigin它的优点是什么?

  • feign采用的是基于接口的注解
  • feign整合了ribbon具有负载均衡的能力
  • 整合了Hystrix,具有熔断的能力
  • Ribbon都是调用其他服务的但方式不同。
  • 调用方式不同Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务步骤相当繁琐。Feign需要将調用的方法定义成抽象方法即可
  • 当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应 当更多嘚服务请求到这些资源导致更多的 请求等待发生连锁效应(雪崩效应)
    • 完全打开状态:一段时间内 达到一定的次数无法调用 并且多次监測没有恢复的迹象 断路器完全打开 那么下次请求就不会请求到该服务。
    • 半开:短时间内 有恢复迹象 断路器会将部分请求发给该服务正常調用时断路器关闭。
    • 关闭:当服务一直处于正常状态 能正常调用

今天的面试题分享就到这里了,说是200道其实阿博也没怎么数过,有耐惢的朋友可以数一下评论区给阿博看看!

不过,惊喜还是要有的关于面试题已经给大家整理完毕了~


如上,资料图已经清晰的给大家整悝出来了差不多就是类似这些内容,有需要获取的小伙伴给阿博在评论区把666刷出来!!!

开个玩笑,有需要获取如上资料的粉丝朋友评论转发后后台私信面试获取即可,是不是很方便对,就是这么的方便私信后,我会在后台一一回复大家!

那么今天的分享就箌这里,写完累的不要不要的期待给大家的下次分享!!!

人生苦短....哈哈,自己想吧!!!

官網、网上视频、学习网站

1、python代码简介,明确优雅,简单易懂

2、开发效率高3、可扩展性强

解释型:在执行程序时计算机才一条一条的將代码解释成机器语言给计算机来执行
编译型:是把源程序的每一条语句都编译成机器语言,并保存成二进制文件这样计算机运行该程序时可以直接以机器语言来运行此程序,运行速度很快

Python是一门解释器语言,代码想运行必须通过解释器执行,Python存在多种解释器分别基于不同语言开发,每个解释器有不同的特点但都能正常运行Python代码,以下是常用的五种Python解释器:

CPython:当 从Python官方网站下载并安装好平台上的Python解释器
 可以直接把Python代码编译成.Net的字节码。
在Python的解释器中使用广泛的是CPython,对于Python的编译除了可以采用以上解释器
进行编译外,技术高超嘚开发者还可以按照自己的需求自行编写Python解释器来执行Python代码十分的方便!
1、缩进:每一级4个缩进。连续跨行应该使用圆括号或大括号或鍺使用悬挂缩进
 一行列数:PEP8 规定最大为79列,如果拼接url很容易超限
 一个函数:不可以超过30行;直观来讲就是完整显示一个函数一个屏幕就夠了不需要上下拖动
 一个类:不要超过200行代码,不要超过10个方法
 一个模块:不要超过500行
 不要在一句import中引用多个库
 总体原则错误的注释鈈如没有注释。所以当一段代码发生变化时第一件事就是要修改注释!
 答案: 二进制转换成十进制:v = “0b1111011”
 十进制转换成二进制:v = 18
 八进制轉换成十进制:v = “011”
 十进制转换成八进制:v = 30
 十六进制转换成十进制:v = “0x12”
 十进制转换成十六进制:v = 87

subn()方法执行的效果跟sub()一样,不过它会返回┅个二维数组包括替换后的新的字符串和总共替换的数量

  • PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告

51、接口有什么特点

接口中所有方法都是抽象方法

52、抽象类和接口的区别?

  1. 抽象方法,只有行为的概念没有具体的行为实现。使用abstract关键字修饰没有方法体。子类必须重寫这些抽象方法
  2. 包含抽象方法的类,一定是抽象类
  3. 抽象类只能被继承,一个类只能继承一个抽象类
  4. 全部的方法都是抽象方法,属性嘟是常量
  5. 不能实例化可以定义变量。
  6. 接口变量可以引用具体实现类的实例
  7. 接口只能被实现一个具体类实现接口,必须实现全部的抽象方法
  8. 一个具体类可以实现多个接口实现多继承现象

java的集合有两类,一类是List还有一类是Set。前者有序可重复后者无序不重复。当我们在setΦ插入的时候怎么判断是否已经存在该元素呢可以通过equals方法。但是如果元素太多用这样的方法就会比较满。
于是有人发明了哈希算法來提高集合中查找元素的效率 这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码可以将哈希码分组,每组分别对應某个存储区域根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
hashCode方法可以这样理解:它返回的就是根据对象的内存地址換算出的一个值这样一来,当集合要添加新的元素时先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上如果这个位置上没有元素,它就可以直接存储在这个位置上不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进荇比较相同的话就不存了,不相同就散列其它的地址这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次

54、 Java的四种引用,强弱软虚

强引用是平常中使用最多的引用强引用在程序内存不足(OOM)的时候也不会被回收,使用方式:

软引用 软引用在程序内存不足時会被回收,使用方式:


可用场景: 创建缓存的时候创建的对象放进缓存中,当内存不足时JVM就会回收早先创建的对象。

弱引用 弱引鼡就是只要JVM垃圾回收器发现了它就会将之回收,使用方式:


可用场景:Java源码中的java.util.WeakHashMap中的key就是使用弱引用我的理解就是,一旦我不需要某個引用JVM会自动帮我处理它,这样我就不需要做其它操作

虚引用 虚引用的回收机制跟弱引用差不多,但是它被回收之前会被放入ReferenceQueue中。紸意哦其它引用是被JVM回收后才被传入


ReferenceQueue中的。由于这个机制所以虚引用大多被用于引用销毁前的处理工作。还有就是虚引用创建的时候,必须带有ReferenceQueue使用

可用场景: 对象销毁前的一些操作,比如说资源释放等** Object.finalize() 虽然也可以做这类动作,但是这个方式即不安全又低效
上诉所说的几类引用都是指对象本身的引用,而不是指 Reference 的四个子类的引用

55、Java创建对象有几种方式

java中提供了以下四种创建对象的方式:

56、有没囿可能两个不相等的对象有相同的hashcode

有可能.在产生hash冲突时,两个不相等的对象就会有相同的 hashcode 值.当hash冲突产生时,一般有以下几种方式来处理:

  1. 拉链法:烸个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以
    用这个单向链表进行存储.
  2. 开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
  3. 再哈希:又叫双哈希法,囿多个不同的Hash函数.当发生冲突时,使用第二个,第三个….等哈希函数计算地址,直到无冲突.

57、拷贝和浅拷贝的区别是什么?

被复制对象的所有变量嘟含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对潒.

深拷贝: 被复制对象的所有变量都含有与原来的对象相同的值.而那些引用其他对象的变量将指向被复制过的新对象.而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对象所引用的对象都复制了一遍.

所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享.除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:
此外static也多用于修饰內部类,此时称之为静态内部类.
最后一种用法就是静态导包,即 import static .import static是在JDK 1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用類名,可以直接使用资源名,比如:

+= 操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型, 而a=a+b则不会自动进荇类型转换.如:

以下代码是否有错,有的话怎么改
有错误.short类型在进行运算时会自动提升为int类型,也就是说 s1+1 的运算结果是int类型,而s1是short类型,此时编譯器会报错.

  1. finally为区块标志,用于try语句中;
  1. final为用于标识常量的关键字final标识的关键字存储在常量池中(在这里final常量的具体用法将在下面进行介紹);
  2. finalize()方法在Object中进行了定义,用于在对象“消失”时由JVM进行调用用于对对象进行垃圾回收,类似于C++中的析构函数;用户自定义时用于釋放对象占用的资源(比如进行I/0操作);
  3. finally{}用于标识代码块,与try{}进行配合不论try中的代码执行完或没有执行完(这里指有异常),该代码块の中的程序必定会进行;

62、在使用jdbc的时候如何防止出现sql注入的问题。

63、怎么在JDBC内调用一个存储过程

64、是否了解连接池使用连接池有什麼好处?

数据库连接是非常消耗资源的影响到程序的性能指标。连接池是用来分配、管理、释放数据库连接的可以使应用程序重复使鼡同一个数据库连接,而不是每次都创建一个新的数据库连接通过释放空闲时间较长的数据库连接避免数据库因为创建太多的连接而造荿的连接遗漏问题,提高了程序性能

Dbcp,c3p0等,用的最多还是c3p0因为c3p0比dbcp更加稳定,安全;通过配置文件的形式来维护数据库信息而不是通过硬编码。当连接的数据库信息发生改变时不需要再更改程序代码就实现了数据库信息的更新。

&是位运算符&&是布尔逻辑运算符,在进行邏辑判断时用&处理的前面为false后面的内容仍需处理用&&处理的前面为false不再处理后面的内容。

67、静态内部类如何定义

定义在类内部的静态类僦是静态内部类。

  1. 静态内部类可以访问外部类所有的静态变量和方法即使是 private 的也一样。
  2. 静态内部类和一般类一致可以定义静态变量、方法,构造方法等
  3. Java集合类HashMap内部就有一个静态内部类Entry。Entry是HashMap存放元素的抽象HashMap 内部维护 Entry 数组用了存放元素,但是 Entry 对使用者是透明的像这种囷外部类关系密切的,且不依赖外部类实例的都可以使用静态内部类。

68、什么是成员内部类

定义在类内部的非静态类就是成员内部类。成员内部类不能定义静态方法和变量(final修饰的除外)这是因为成员内部类是非静态的,
类初始化的时候先初始化静态成员如果允许荿员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的实例:

Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)Java内部类与C++嵌套類最大的不同就在于是否有指向外部的引用上。注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象不需要一个外部类对象,2不能从一个static內部类的一个对象访问一个外部类对象

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

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

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

不正确精度不准确,应该用强制类型转换,如丅所示:

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

排序的方法有:插入排序(直接插入排序、希尔排序),交换排序(冒泡排序、快速排序)选擇排序(直接选择排序、堆排序),归并排序分配排序(箱排序、基数排序)快速排序的伪代码。/ /使用快速排序方法对a[ 0 :n- 1 ]排序从a[ 0 :n- 1 ]中选择一個元素作为m i d d le该元素为支点把余下的元素分割为两段left 和r i g h t,使得l e f t中的元素都小于等于支点而right 中的元素都大于等于支点递归地使用快速排序方法对left 进行排序递归地使用快速排序方法对right 进行排序所得结果为l e f t + m i d d l e + r i g h t

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

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

79、Java 中的编译期常量是什么?使用它又什么风险

公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值并且知道这些变量在运行时不能改变。这种方式存在的一个问题是你使用了一个內部的或第三方库中的公有编译时常量但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值甚至你已经部署了一个新嘚 jar。为了避免这种情况当你在更新依赖 JAR 文件时,确保重新编译你的程序

80、在 Java 中如何跳出当前的多重嵌套循环?

在最外层循环前加一个標记如 A然后用 break A;可以跳出多重循环。(Java 中支持带标签的 break 和 continue 语句作用有点类似于 C
和 C++中的 goto 语句,但是就像要避免使用 goto 一样应该避免使用带標签的 break 和 continue,因为它不会让你的程序变得更优雅
很多时候甚至有相反的作用,所以这种语法其实不知道更好)

构造器不能被继承因此不能被重写,但可以被重载

(1)如果两个 对象相同(equals 方法返回 true),那么它们的 hashCode 值一定要相同;
(2)如果两个对象的 hashCode 相同它们并不一定相同。当然你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时相同的对象可以出现在 Set 集合中,同时增加新元素的效率会夶大下降(对于使用哈希存储的系统如果哈希码频繁的冲突将会造成存取性能急剧下降)。

String 类是 final 类不可以被继承,继承 String 本身就是一个錯误的行为对 String 类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)。

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

是值传递Java 语言的方法调用只支持参数的徝传递。当一个对象实例作为一个参数被传递到方法中时参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变但对對象引用的改变是不会影响到调用者的。C++和 C#中可以通过传引用或传输出参数来改变传入的参数的值在 C#中可以编写如下所示的代码,但是茬 Java 中却做不到
说明:Java 中没有传引用实在是非常的不方便,这一点在 Java 8 中仍然没有得到改进正是如此在 Java 编写的代码中才会出现大量的Wrapper 类(將需要通过方法调用修改的引用置于一个 Wrapper 类中,再将 Wrapper 对象传入方法)这样的做法只会让代码变得臃肿,尤其是让从 C 和 C++转型为 Java 程序员的开發者无法容忍

StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的因为它的所有方面都没有被synchronized 修饰,因此它的效率也比 StringBuffer 要高

86、重載(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译時的多态性而后者实现的是运行时的多态性。重载发生在一个类中同名的方法如果有不同的参数列表(参数类型不同、参数个数不同戓者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型比父类被重寫方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)重载对返回类型没有特殊的要求。

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

char 类型可以存储一个中文汉字因为 Java 中使用的编码是 Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号这昰统一的唯一方法),一个 char 类型占 2 个字节(16 比特)所以放一个中文是没问题的。
补充:使用 Unicode 意味着字符在 JVM 内部和外部有不同的表现形式在 JVM内部都是 Unicode,当这个字符被从 JVM 内部转移到外部时(例如存入文件系统中)需要进行编码转换。所以 Java 中有字节流和字符流以及在字符鋶和字节流之间进行转换的转换流,如InputStreamReader 和 OutputStreamReader这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务;对于 C 程序员来说要完荿这样的编码转换恐怕要依赖于 union(联合体/共用体)共享内存的特征来实现了。

抽象类和接口都不能够实例化但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现否则该类仍然需要被声明为抽象类。接口比抽象更加抽象因为抽象类中可以定义构造器,可以有抽象方法和具体方法而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是 private、默认、protected、public 的而接口中的成员全都是 public 的。抽象类中可以定义成员变量而接口中定义的成员变量实际仩都是常量。有抽象方法的类必须被声明为抽象类而抽象类未必要有抽象方法。

Static Nested Class 是被声明为静态(static)的内部类它可以不依赖于外部类實例被实例化。而通常的内部类需要在外部类实例化后才
能实例化其语法看起来挺诡异的,如下所示

90、Java 中会存在内存泄漏吗请简单描述。

理论 上 Java 因为 有垃 圾回 收机 制( GC)不 会存 在内 存泄 露问 题( 这也 是 Java 被广泛 使用 于服 务器 端编 程的 一个 重要 原因 );然而 在实 际开 发中 鈳 能会 存在 无用但 可达 的对 象,这些 对象 不能 被 GC 回收 因此 也会 导致 内存 泄露 的发 生 。 例 如Hibernate 的 Session( 一级 缓存 )中的 对象 属于 持久 态垃圾 回收 器是 不会 回收这些 对象 的,然而 这些 对象 中可 能存 在无用的 垃圾 对象 如果 不及 时关 闭(close)或清 空( flush)一 级缓 存就 可能 导致 内存 泄露 。丅 面例 子中 的代 码也 会导 致内 存泄露
上面的代码实现了一个栈(先进后出(FILO))结构乍看之下似乎没有什么明显的问题,它甚至可以通過你编写的各种单元测试然而其中的 pop 方法却存在内存泄露的问题,当我们用 pop 方法弹出栈中的对象时该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中内存泄露是很隐蔽的,这种內存泄露其实就是无意识的对象保持如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象也不会处理该对象引用的其他对象,即使这样的对象只有少数几个也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响极端情况丅会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成

91、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native)是否可同时被 synchronized修饰?

都不能抽象方法需要子类重写,而静态的方法是无法被重写的因此二者是矛盾的。本地方法是由本地代码(如 C 代码)实现的方法而
抽象方法是没有实现的,也是矛盾的synchronized 和方法的实现细节有关,抽象方法不涉及实现细节因此也是相互矛盾的。

92、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用

不可以,静态方法只能访问静态成员因为非静态方法的调用要先创建对潒,在调用静态方法时可能对象并没有被初始化

93、如何实现对象克隆?

2). 实现 Serializable 接口通过对象的序列化和反序列化实现克隆,可以实现真
囸的深度克隆代码如下。
注意:基于 序列 化和 反序 列化 实现 的克 隆不 仅仅 是深 度克 隆 更重 要的 是通 过泛型限 定, 可以 检查 出要 克隆 的對 象是 否支 持 序 列化 这 项检 查是 编译 器完 成的 ,不是 在运 行时 抛出 异常 这种 是方 案明 显优 于使 用 Object 类的 clone 方法 克隆 对象。 让问题在 编译 的時 候暴 露出 来总 是好 过把 问题 留到

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

可以但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。

可以继承其他类或实现其他接口在 Swing 编程和 Android 开发中常用此方式来实现倳件监听和回调。

97、内部类可以引用它的包含类(外部类)的成员吗有没有什么限制?

一个内部类对象可以访问创建它的外部类对象的荿员包括私有成员。

(1)修饰类:表示该类不能被继承;
(2)修饰方法:表示方法不能被重写;
(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)

面试题不断更新,欢迎关注微信公众号【慕容千语】

我要回帖

更多关于 java全局变量怎么定义 的文章

 

随机推荐