Java面试题

一、Java 基础
1.JDK 和 JRE 有什么区别?

    答:JDK是java的开发工具包,它包含了运行环境和开发环境
        JRE是java的运行环境  
   
   
2.== 和 equals 的区别是什么?

    答:==可以用来比较基本数据类型和引用数据类型
        而equals比较的是其内容
        如果用==来比较基本数据类型的话 比较的是其值
        比较的是引用数据类型则是内存地址
        equals只能对比较引用数据类型 比较的是其值,也就是内容
        
3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
   
    答:不一定,在Object的hashCode方法写了hashCode的几个约定,
        其中就有一条表示,equals方法返回false,不代表hashCode就不相等。
        言下之意,就是hashCode相等时,equals方法返回的可能是false。
        当然,要尽量为equals方法返回false的对象,返回不同的hashCode


4.final 在 java 中有什么作用?

    答:final可以用来修饰类则该类不可以被继承,
		final还可以修饰方法,则该方法不能被重写,但是可以被重载、
		final可以修饰属性,则该属性就是一个不可改变的量,也就是常量

5.java 中的 Math.round(-1.5) 等于多少?

    答:-1

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

    答:不是,String是引用数据类型 因为String是java中定义的一个类

7.java 中操作字符串都有哪些类?它们之间有什么区别?

    答:有String,StringBuffer,StringBuilder
        其中String是被final修饰的类  它是不可修改和继承的  所以每操作一次都会产生一个新的对象
        而StringBuffer和StringBuilder都是在原对象上进行操作的
        但是其中StringBuffer是线程安全的因为它的方法被synchronized修饰
   
8.String str="i"与 String str=new String(“i”)一样吗?
   
    答:不一样,因为String str="i"会被分配到常量池中,而String str=new String(“i”)创建了一个对象,会被分配到堆中。

9.如何将字符串反转?

    答:可以使用StringBuffer或者StringBuilder中的内置方法reverse()方法。

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

    答:有:indexOf(),charAt(),toString(),replace(),trim(),toUpperCase(),split()
            toLowerCase(),length(),equals(),concat(),substring()


11.抽象类必须要有抽象方法吗?

    答:不是必须的,抽象类不一定有抽象方法;但是包含一个抽象方法的类一定是抽象类

12.普通类和抽象类有哪些区别?

    答: 区别在于普通类可以被实例化,而抽象类不能实例化,
        但是可以通过子类继承,实例化子类的时候抽象类也会被实例化。
        这其实用到了多态,向上转型。父类引用指向子类对象
   
13.抽象类能使用 final 修饰吗?

    答:抽象类不能被final修饰,因为抽象类的作用就是用来被继承的。
        如果被final修饰的话怎么不能被继承了,两者相互冲突。
   
14.接口和抽象类有什么区别?

    答:区别:在java中接口时多实现,而类是单继承,
        接口中不能存在除了抽象方法以外的方法,同时它的成员变量都被public static修饰的,
        而抽象类可以有0-多个抽象方法,而且不能被实例化,
        接口只关注一个操作,而不关注是怎样操作的,也就是说它只定义方法的声明,不关注方法的具体实现
   
   
15.java 中 IO 流分为几种?

    答: java中的流分为两种,一种是字节流,另一种是字符流


17.Files的常用方法都有哪些?

    答: Files.exists():检测文件路径是否存在。
            Files.createFile():创建文件。
            Files.createDirectory():创建文件夹。
            Files.delete():删除一个文件或目录。
            Files.copy():复制文件。
            Files.move():移动文件。
            Files.size():查看文件个数。
            Files.read():读取文件。
            Files.write():写入文件。

二、容器

18.java 容器都有哪些?

    答:数组和集合  比如:List,Set,Map

19.Collection 和 Collections 有什么区别?

    答:Collection是集合的父接口,而Collectios是一个工具类,它包含有各种有关集合操作的静态多态方法,不能实例化

20.List、Set、Map 之间的区别是什么?

    答:List是有序,元素可以重复,可以通过迭代器取出所有元素,也可以使用get通过下标来获取元素
        Set是无序,元素不可重复,只能通过迭代器取出所有元素。
        Map是无序,可重复,这里要注意Map是以键值对存在的所有键是唯一的 ,这里可重复是指值可以重复。
   
21.HashMap 和 Hashtable 有什么区别?

    答:HashMap是线程不安全的,而HashTable是线程安全的
        HashMap可以存在Null,但是HashTable是不可以存在Null的
        HashTable是继承自Dictionary类,而HashMap是继承自AbstractMap类
   
22.如何决定使用 HashMap 还是 TreeMap?           
                           
    答:TreeMap<K,V>的Key值是要求实现java.lang.Comparable(排序接口),所以迭代的时候TreeMap默认是按照Key值升序排序的;
        TreeMap的实现是基于红黑树结构。适用于按自然顺序或自定义顺序遍历键(key)。
   
   HashMap<K,V>的Key值实现散列hashCode(),分布是散列的、均匀的,不支持排序;数据结构主要是桶(数组),链表或红黑树。
   适用于在Map中插入、删除和定位元素。

   结论
   如果你需要得到一个有序的结果时就应该使用TreeMap(因为HashMap中元素的排列顺序是不固定的)。
   除此之外,由于HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap。

23.说一下 HashMap 的实现原理?

    答:简答 底层是数组+链表  jdk1.8之后还引入了红黑树

24.说一下 HashSet 的实现原理?

    答:它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,
        因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成
    
25.ArrayList 和 LinkedList 的区别是什么?

    答:ArrayList是基于动态数组实现的,LinkedList是基于链表实现的。
        LinkedList比ArrayList更加占用内存,因为LinkedList的节点除了存储数据,
        还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
        对于随机访问ArrayList要优于LinkedList。
        对于插入和删除操作,LinkedList优于ArrayList。 

26.如何实现数组和 List 之间的转换?

    答:将数组转换成List,使用Arrays的asList方法,
        将List转换为数组,使用ArrayList的toArray方法
    实例:
    /**
       * 实现数组和List之间的相互转换
       * @author Administrator
       *
       */
      public class ArrayAndList
      {
        public static void main(String[] args)
        {
            //将数组转换成List,Arrays的asList方法
            List<String> list = Arrays.asList("aa","bb","cc");
            
            for(int i = 0,len = list.size(); i < len; i++)
            {
                System.out.println(list.get(i));   
            }
            
            System.out.println("----------------------------------");
            
            //List转换为数组:ArrayList的toArray方法
            List<String> sList = new ArrayList<String>();
            
            sList.add("dd");
            sList.add("ee");
            sList.add("ff");
            
            Object[] str =  sList.toArray();
            
            for(int i = 0,len = str.length;i< len; i++)
            {
                System.out.println((String)str[i]);
            }
            
        }
      
      }



27.ArrayList 和 Vector 的区别是什么?

    答:首先两个类都实现了List接口。他们都是有序不唯一的集合
        Vector是线程安全的,ArrayList是线程不安全的
    
28.Array 和 ArrayList 有何区别?

    答:前者是数组,后者是集合

29.在 Queue 中 poll()和 remove()有什么区别?

    答:poll()和remove()都将移除并且返回对头
        ,但是在poll()在队列为空时返回null,
        而remove()会抛出NoSuchElementException异常。
  

30.哪些集合类是线程安全的?

    答:Vector,Hashtable
    
31.迭代器 Iterator 是什么?

    答:迭代器(Iterator)是一个对象,它的工作是遍历并选择序列中的对象,
        它提供了一种访问一个容器(container)对象中的各个元素,
        而又不必暴露该对象内部细节的方法
    
32.Iterator 怎么使用?有什么特点?

    答:使用iterator()方法会返回一个Iterator的对象,
        iterator()方法是java.lang.iterator接口里被Collection继承.
        使用hasNext()检查序列中是否还有元素。
        使用next()获取下一个元素
        使用remove()将迭代器新返回的元素删除。
        Iterator的特点?
        (1) Iterator遍历集合元素的过程中不允许线程对集合元素进行修改,否则会抛出ConcurrentModificationException的异常。
        (2)Iterator遍历集合元素的过程中可以通过remove方法来移除集合中的元素,删除的是上一次Iterator.next()方法返回的对象。
        (3)Iterator必须依附于一个集合类对象而存在,Iterator本身不具有装载数据对象的功能。

三、多线程

35.并行和并发有什么区别?

    答:并行是指在同一时间上,两个任务互不干扰的同时执行
        并发是指在同一时间上,只用一个任务执行,并且是两个任务交替执行
    
36.线程和进程的区别?

    答:进程包含多个线程,线程是进程中执行运算的最小单位,是进程中的一个实体。

37.守护线程是什么?

    答:守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,
        连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,
        连jvm都停止运行了,守护线程当然也就停止执行了
        可以使用setDaemon(true)将该线程为守护线程;
    
38.创建线程有哪几种方式?

    答:继承Thread类型重写run 方法
        实现Runnable接口
        实现Callable接口
        Callable的实现方式:
        public class CallableDemoTest implements Callable {
            public Object call() {
                return "HelloCallable!";
            }
            @Test
            public void test() throws ExecutionException, InterruptedException {
                CallableDemoTest callableDemoTest = new CallableDemoTest();
                FutureTask futureTask = new FutureTask(callableDemoTest);
                Thread thread = new Thread(futureTask);
                thread.start();
                //获取返回值
                futureTask.get();
            }
        }
    
39.说一下 runnable 和 callable 有什么区别?

    答:1,Callable call方法 可以有返回值,Runnable 的run 方法不可以,
        2,Callable异常可以抛出,Runnable 不能上抛
        3,Callable可以返回装载有计算结果的Future对象

40.线程有哪些状态?

    答:新建,就绪,运行,阻塞,死亡

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

    答:sleep()和wait()都是线程暂停执行的方法。
        而sleep()方法是在Thread类中的静态方法,而wait是Object类中的成员方法
        调用sleep()方法是不会释放锁的,而wait方法会释放锁
        sleep()方法是不依赖与synchronized关键字,而wait()方法依赖于synchronized关键字
        sleep()方法一般用于当前线程的休眠或者是轮询等操作,而wait()则多于与通信
        sleep不需要被唤醒,wait需要被唤醒
    
42.notify()和 notifyAll()有什么区别?

    答:notify()是唤醒一个处于等待状态的线程,不能明确的唤醒某一个线程,而是由JVM确定的
        notifyAll()唤醒所有处入等待状态的线程
        43.线程的 run()和 start()有什么区别?

四、反射

57.什么是反射?

    答:Java 反射,就是在运行状态中。
          获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
          获取任意对象的属性,并且能改变对象的属性
          调用任意对象的方法
          判断任意一个对象所属的类
          实例化任意一个类的对象
      
58.什么是 java 序列化?什么情况下需要序列化?

    答:序列化:将 Java 对象转换成字节流的过程。
        当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,
        就需要对 Java 对象进行序列化处理。
        补充:
        反序列化:将字节流转换成 Java 对象的过程。
        序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。
        实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
        注意事项:
        某个类可以被序列化,则其子类也可以被序列化
        声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
        反序列化读取序列化对象的顺序要保持一致
    
59.动态代理是什么?有哪些应用?
    
    答:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。
        可以给这个类创建一个代理,故名思议就是创建一个新的类,
        这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。
        这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强
        动态代理的应用:Spring的AOP,加事务,加权限,加日志。
    
60.怎么实现动态代理?

    答:实现InvocationHandler接口(这只是一种)

五、对象拷贝

61.为什么要使用克隆?

    答:想对一个对象进行处理,又想保留原有的数据进行接下来的操作,
        就需要克隆了,Java语言中克隆针对的是类的实例。
    
62.如何实现对象克隆?

    答:有两种方式:
        实现Cloneable接口并重写Object类中的clone()方法;
        实现Serializable接口,通过对象的序列化和反序列化实现克隆,
        可以实现真正的深度克隆
        实现克隆的代码:
  
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    
    public class MyUtil {
    
        private MyUtil() {
            throw new AssertionError();
        }
    
        @SuppressWarnings("unchecked")
        public static <T extends Serializable> T clone(T obj) throws Exception {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bout);
            oos.writeObject(obj);
    
            ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bin);
            return (T) ois.readObject();
    
            // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
            // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
        }
    }
    
    测试代码:
    import java.io.Serializable;
    
    /**
     * 人类
     * @author nnngu
     *
     */
    class Person implements Serializable {
        private static final long serialVersionUID = -9102017020286042305L;
    
        private String name;    // 姓名
        private int age;        // 年龄
        private Car car;        // 座驾
    
        public Person(String name, int age, Car car) {
            this.name = name;
            this.age = age;
            this.car = car;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Car getCar() {
            return car;
        }
    
        public void setCar(Car car) {
            this.car = car;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
        }
    
    }
    
    /**
     * 小汽车类
     * @author nnngu
     *
     */
    class Car implements Serializable {
        private static final long serialVersionUID = -5713945027627603702L;
    
        private String brand;       // 品牌
        private int maxSpeed;       // 最高时速
    
        public Car(String brand, int maxSpeed) {
            this.brand = brand;
            this.maxSpeed = maxSpeed;
        }
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public int getMaxSpeed() {
            return maxSpeed;
        }
    
        public void setMaxSpeed(int maxSpeed) {
            this.maxSpeed = maxSpeed;
        }
    
        @Override
        public String toString() {
            return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
        }
    
    }
    
    class CloneTest {
    
        public static void main(String[] args) {
            try {
                Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
                Person p2 = MyUtil.clone(p1);   // 深度克隆
                p2.getCar().setBrand("BYD");
                // 修改克隆的Person对象p2关联的汽车对象的品牌属性
                // 原来的Person对象p1关联的汽车不会受到任何影响
                // 因为在克隆Person对象时其关联的汽车对象也被克隆了
                System.out.println(p1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    

63.深拷贝和浅拷贝区别是什么?

    答:浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,
        所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(例:assign())
        深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,
        这就是深拷贝(例:JSON.parse()和JSON.stringify(),但是此方法无法复制函数类型)
   
六、Java Web
64.jsp 和 servlet 有什么区别?

    答:jsp实际上就是Servlet的扩展,本质上还是Servlet
        每一个jsp页面就是一个Servlet实例
        Jsp页面会被Web容器编译成Servlet,Servlet再负责响应用户请求
        而servlet是一种服务端的java应用程序
        由 Web 容器加载和管理,用于生成动态 Web 内容,负责处理客户端请求
        区别:
        Servlet 适合动态输出 Web 数据和业务逻辑处理,对于 html 页面内容的修改非常不方便;Jsp 是在 Html 代码中嵌入 Java 代码,适合页面的显示
        内置对象不同,获取内置对象的方式不同
    
65.jsp 有哪些内置对象?作用分别是什么?

    答:1.HttpServletRequet类的Request对象:代表请求对象,主要用于接受客户端通过HTTP协议连接传输服务器端的数据。
        2.HttpSevletResponse类的Response对象:代表响应对象,主要用于向客户端发送数据。
        3.JspWriter类的out对象:主要用于向客户端输出数据,out的基类是jspWriter
        4.HttpSession类的session对象:主要用来分别保存每个月的信息与请求关联的会话;会话状态的维持是web应用开发者必须面对的问题。
        5.ServletContext类的application对象:主要用于保存用户信息,代码片段的运行环境;它是一个共享的内置对象,即一个容器中的多个用户共享一个application  
        ,故其保存的信息被所有用户所共享。 
        6.PageContext类的PageContext对象:管理网页属性,为jsp页面包装页面的上下文,管理对属于jsp的特殊可见部分中已经命名对象的访问,它的创建和初始化都是由容器来完成的。 
        7.ServletConfig类的Config对象:代码片段配置对象,标识Servlet的配置。
        8.Object类的Page对象,处理jsp页面,是object类的一个实例,指的是jsp实现类的实例
        9.Exception对象:处理jsp文件执行时发生的错误和异常,只有在错误页面里才使用,前提是在页面指令里要有isErrorPage=true。




71.如何避免 sql 注入?
    
    答:预编译 SQL,也就是使用PreparedStatement对象(最简单的办法)
    

七、异常

74.throw 和 throws 的区别?

    答:throw是抛出异常
    代码实例:
       private void checkIndex(int index) {
          if (index <= size - 1 && index >= 0) {
          } else {
             throw new IndexOutOfBoundsException("index:" + index + "  size:"
                   + size);
          }
    
       }
       
      throws是声明异常
      代码实例:
      /**
        * 文件拷贝
        * 
        * @param fromPath
        * @param toPath
        * @throws IOException
        */
       public static void fileCopy(String from, String to) throws IOException {
          // 1、建立联系 file对象。源:存在且为文件+目的地:文件可以不存在
          File fromPath = new File(from);
          File toPath = new File(to);
          fileCopy(fromPath, toPath);
       }
        

    
75.final、finally、finalize 有什么区别?
    
    答:final可以用来修饰类则该类不可以被继承,
        修饰方法则方法不能被重写,但是可以重载,
        修饰属性则属性的值不可被修改.
        
        finally则是java保证某一段重点代码一定要被执行的修饰符,例
        如:我们需要用try块让JDBC保证连接,保证unlock锁等动作
    
        finalize是基础类java.lang.Object的一个方法,
        它的设计目的是为了保证对象在垃圾回收之前完成特定资源的回收
    

76.try-catch-finally 中哪个部分可以省略?

    答:catch 和 finally 语句块可以省略其中一个

77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
    
    答:会执行,在return 前执行

78.常见的异常类有哪些?
     
     答:Throwable 是异常的根类,
         Throwable 包含子类 错误-Error 和 异常-Exception 。
         Exception 又分为 一般异常和运行时异常 RuntimeException。


九、设计模式


    
89.简单工厂和抽象工厂有什么区别?

    答:简单工厂模式
      是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例
      可以生产结构中的任意产品,不能增加新的产品
      
   
      抽象工厂模式
      提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品
      生产不同产品族的全部产品,不能新增产品,可以新增产品族
 
 
十、Spring/Spring MVC

90.为什么要使用 spring?
 
     答:因为Spring是一个轻量级的控制反转和面向切面的一个开源框架同时也是非入侵式的框架
           
         spring的好处:方便解耦,便于开发,
                        spring支持aop编程
                        支持声明式事务
                        方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序
                        方便集成各种优秀的框架
                        ....
91.解释一下什么是 aop?
    
    答:在业务系统中,总有一些不得不处理的事情,我们
          将这些重复性的代码抽取出来,放在专门的类中,
          在通过spring的AOP的核心对代码段进行增强处理。
          在不改变原代码的基础上进行功能增强。有五种
          增强方式,前置增强,后置增强,环绕增强,引介增强。异常增强

92.解释一下什么是 ioc?

    答:ioc实际上就是控制反转,比如说把原本自己制造,使用的对象,
        现在交由别人制造,而通过构造函数,
        setter方法或方法(这里指使用这个对象的方法)参数的方式传给你,由你使用,
        这里就实现了控制反转,也就是说将对象的创建权力由我们自己转交给了spring来创建管理。
    
93.spring 有哪些主要模块?
    
    答:总共由七个模块:
        Spring Core:Spring框架的核心容器,他提供了Spring框架的基本功能
        Spring AOP:采用了面向切面编程的思想
        Spring ORM:提供了对现有的ORM框架的支持,例如Hibernate等
        Spring DAO:提供了对DAO(Data Access Object,数据访问对象)模式和JDBC的支持
        Spring Web:提供了Servlet监听器的Context和Web应用的上下文
        Spring Context:扩展核心容器,提供了Spring上下文环境
        Spring Web MVC:提供了一个构建Web应用程序的MVC的实现
        
94.spring 常用的注入方式有哪些?

    答:三种:构造方法注入,setter注入,基于注解的注入

95.spring 中的 bean 是线程安全的吗?
  
    答:一般无状态情况下是安全的,因为spring并没有对bean进行多线程的封装
        所以在无状态的情况下bean是线程安全的,但是如果有状态的话则不一定
        (有状态:有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,
        可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态)
        
        (无状态:无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象  .不能保存数据,是不变类,是线程安全的。)

96.spring 支持几种 bean 的作用域?
    
     答:七种:
         singleton单例模式,在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例
         prototype:原型模式,每次通过容器的getbean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
         
         application:bean被定义在ServletContext的生命周期中复用一个单例对象。
         websocket: bean被定义在websocket的生命周期中复用一个单例对象
         只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效
         request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
         session:同一个 Session 共享一个 bean 实例。
         global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。
      
97.spring 自动装配 bean 有哪些方式?

     答:五种:
        no:默认方式,手动装配方式,需要通过ref设定bean的依赖关系
        byName:根据bean的名字进行装配,当一个bean的名称和其他bean的属性一致,则自动装配
        byType:根据bean的类型进行装配,当一个bean的属性类型与其他bean的属性的数据类型一致,则自动装配
        constructor:根据构造器进行装配,与 byType 类似,如果bean的构造器有与其他bean类型相同的属性,则进行自动装配
        autodetect:如果有默认构造器,则以constructor方式进行装配,否则以byType方式进行装配
     
98.spring 事务实现方式有哪些?

        答:第一种:使用 TransactionTemplate 事务模板对象
            第二种:使用 事务管理器 PlatformTransactionManager 对象
            第三种:基于Aspectj AOP开启事务
            
99.说一下 spring 的事务隔离?

                                                                Dirty Read   Non-Repeatable Reads
        答:名称                            结果                 脏读 不可重复读  幻读(Phatom Reads)
          读未提交 Read UnCommitted    什么都不解决                  √      √        √
          读提交Read Committed    解   决了脏读的问题                     ——       √         √
          重复读 Repeatable Read  mysql的默认级别 解决了不可重复读  ——       ——        √
          序列化 Serializable         解决所有问题               ——       ——    ——
         spring事务的隔离级别就是数据库的隔离级别,如果两者的隔离级别不同的话
         则以spring的事务隔离级别为准,但是数据库如果不支持的话则以数据库的为准

100.说一下 spring mvc 运行流程?
        
        答;第一步是当用户发送请求至前端控制器DispatcherServlet 
            DispatcherServlet接收到了请求后 会对url进行解析得到请求资源标识符(URI)
            第二步:DispatcherServlet调用HandlerMapping处理器映射器
            第三步:处理器映射器找到具体的处理器,生成一个处理器和一个处理器拦截器,然后返回给DispatcherServlet
            第四步:DispatcherServlet调用处理器适配器HandlerAdapter
            第五步: HandlerAdapter经过适配调用具体的处理器(Controller)
            第六步:Controller执行完成后返回ModelAndView
            第七步:HandlerAdapter将Controller的结果ModelAndVier返回给DispatcherServlet
            第八步:DispacherServlet将ModelAndView传给ViewReslover视图解析器
            第九步:ViewReslover解析返回具体的View
            第十步:DispatcherServlet根据view进行渲染视图
            第十一步:DispatcherServlet响应用户
            

101.spring mvc 有哪些组件?

    答:  前端控制器(DispatcherServlet):核心 主要负责捕获来自客户端的请求和调度各个组件
          处理器映射器(HandlerMapping) :根据url查找后端控制器Handler
          处理器适配器(HandlerAdapter) :执行后端控制器(Handler),拿到后端控制器返回的结果ModelAndView后将结果返回给前端控制器DispatcherServlet
          拦截器(HandlerInterceptor)
          语言环境处理器(LocaleResolver)
          主题解析器(ThemeResolver)
          视图解析器(ViewResolver) 
          文件上传处理器(MultipartResolver)
          异常处理器(HandlerExceptionResolver) 
          数据转换(DataBinder)
          消息转换器(HttpMessageConverter)
          请求转视图翻译器(RequestToViewNameTranslator)
          页面跳转参数管理器(FlashMapManager)
          处理程序执行链(HandlerExecutionChain) 
     

102.@RequestMapping 的作用是什么?
        
        答:RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。
            用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径
            
103.@Autowired 的作用是什么?

    答:自动装配的作用
        @Autowired 是一个注解,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
        @Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean

十一、Spring Boot/Spring Cloud

104.什么是 spring boot?
    
    答:SpringBoot基本上是 Spring框架的扩展,
        它消除了设置 Spring应用程序所需的 XML配置,为更快,
        更高效的开发生态系统铺平了道路。

105.为什么要用 spring boot?
   
    答:Spring Boot 有很多的优点,可以简化开发,提高整体生产力
        如:独立运行、简化配置、自动配置和无需部署war文件等等

106.spring boot 核心配置文件是什么?

    答:Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件

107.spring boot 配置文件有哪几种类型?它们有什么区别?
        
     答:两种一种是.properties,另一种是.yml格式的
         yml采取的是缩进的格式 不支持@PeopertySource注解导入配置

108.spring boot 有哪些方式可以实现热部署?
    
     答:两种  一种是引入依赖devtools
                另一种是idea本身的

十三、Mybatis

125.mybatis 中 #{}和 ${}的区别是什么?


    答:#{}在mybatis中是预编译处理,而${}是拼接符,也就是字符串替换
        其中前者是可以防止sql注入的,后者不行,因为前者调用的是PreparedStatement()方法
        mybatis在处理#{}时,会将sql中的#{}替换为?号
        mybatis在处理${}时,就是把${}替换成变量的值
        
126.mybatis 有几种分页方式?

      答:利用sql关键字limit来实现
            也利用PageHelper来实现  
            .....


128.mybatis 逻辑分页和物理分页的区别是什么?

        答:物理分页依赖于数据库比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果
            逻辑分页依赖的是程序员编写的代码数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据

129.mybatis 是否支持延迟加载?延迟加载的原理是什么?

        答:mybatis只支持一对一或者是一对多
            要想支持延迟加载则需要配置  lazyLoadingEnabled=true|false。
            原理就是使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,
            比如调用a.getB().getName(),
            拦截器invoke()方法发现a.getB()是null值,
            那么就会单独发送事先保存好的查询
            关联B对象的sql,把B查询上来,然后调用a.setB(b),
            于是a的对象b属性就有值了,
            接着完成a.getB().getName()方法的调用。
            这就是延迟加载的基本原理
      
130.说一下 mybatis 的一级缓存和二级缓存?
        
        答:Mybatis的一级缓存是指Session缓存。
            一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存
            当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空
            
            Mybatis的二级缓存是指mapper映射文件。
            二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。
            Mybatis需要手动设置启动二级缓存
            
            二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如想取消,
            则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false
           
            <settings>
            
              <setting name="cacheEnabled" value="false" />
            
            </settings>
            
131.mybatis 和 hibernate 的区别有哪些?
        
        答:mybatis是一个半自动的orm框架,而后者是一个全自动的orm框架
            因为mybatis是依赖于sql编写的所以他的移植性很差,但是sql灵活度很高,
            而hibernate的移植性则高于mybatis
            
             hibernate拥有完整的日志系统,mybatis则欠缺一些
             hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;
             而mybatis则除了基本记录功能外,功能薄弱很多
             
             sql优化上,mybatis要比hibernate方便很多
             因为mybatis的sql都是写在xml文件里的,跟应用程序是分离的因此优化sql比hibernate方便很多,
             而hibernate的基本都是自动生成的
             
132.mybatis 有哪些执行器(Executor)?

        答:Mybatis 共有三种执行器:
          
          SIMPLE: 默认的执行器, 对每条sql进行预编译->设置参数->执行等操作
          BATCH: 批量执行器, 对相同sql进行一次预编译, 然后设置参数, 最后统一执行操作
          REUSE: REUSE 执行器会重用预处理语句(prepared statements
          
          局部设置
          在获取sqlSession时设置, 需要注意的时, 如果选择的是批量执行器时, 需要手工提交事务.
            // 获取指定执行器的sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)
            
            // 获取批量执行器时, 需要手动提交事务
            sqlSession.commit();
           全局配置
           可在全局配置文件中配置, 但是笔者不推荐这种方式, 了解即可.
            <settings>
                <setting name="defaultExecutorType" value="BATCH" />
            </settings>

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

十七、MySql

164.数据库的三范式是什么?
        
        答:第一范式(1NF):列的原子性,即列不能够再分出其他列
            第二范式(2NF):首先满足第一范式,然后是表中必须有一个主键。
                                其次是没有包含在主键中的列必须完全依赖于主键,而不能只依赖主键的一部分
            第三范式(3NF):首先满足第二范式,另外非主键列必须直接依赖于主键,不能存在传递依赖(即张三认识李四 李四认识王五  而张三和王五不认识,不能因为李四跟王五认识就说张三认识王五)
165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
        
        答:在mysql8.0之前的话如果引擎类型是MyISAM则是8,
            MyISAM表会把自增主键的最大ID记录到数据文件里面重启MySQL后,
            自增主键的最大ID也不会丢失
            如果引擎类型是InnoDB则是6因为 InnoDB表把自增主键的最大ID记录到内存中,
            所以重启数据库后会使最大ID(其实是AUTO_INCREMENT 计数器的值)丢失
            一旦数据库重新运行,数据库会自动计算自增主键的
            最大ID(其实就是把最后一条记录 ID 加 1 并赋值给 AUTO_INCREMENT)再次放入到内存中
            
166.如何获取当前数据库版本?

        答:如果使用sql语句的话 : select version();
            cmd  : mysql -V 或者 mysql --version

167.说一下 ACID 是什么?

        答:1.Atomicity 原子性
          
          2.Consistency 一致性
          
          3.Isolation 隔离性
          
          4.Durability 持久性
          
          原子性,指的是整个事务是一个独立的单元,要么操作成功,要么操作不成功
          
          一致性,事务必须要保持和系统处于一致的状态(如果不一致会导致系统其它的方出现bug)
          
          隔离性,事务是并发控制机制,他们的交错也需要一致性,隔离隐藏,一般通过悲观或者乐观锁实现
          
          持久性,一个成功的事务将永久性地改变系统的状态,所以在它结束之前,所有导致状态的变化都
                记录在一个持久的事务日志中
        
168.char 和 varchar 的区别是什么?

        答:前者是字符,长度是不可变的,后者是字符串,长度可变

169.float 和 double 的区别是什么?

        答:float类型表示单精度浮点数值,double类型表示双精度浮点数值

170.mysql 的内连接、左连接、右连接有什么区别?
        
        答:1.内连接,显示两个表中有联系的所有数据;
          
          2.左链接,以左表为参照,显示所有数据,右表中没有则以null显示
          
          3.右链接,以右表为参照显示数据,,左表中没有则以null显示

173.说一下数据库的事务隔离?

        答:Read Uncommitted(读未提交)   事务可以看到和读取到其他未提交事务的执行结果,这样一个事务读取到另一个事务还有没提交的记录,就很可能造成脏读。
            Read Committed(读已提交)   事务只能看见已经提交的事务所做的改变,但是这种隔离级别可能会导致不可重复读,因为同一事务的其他实例在该实例处理其间可能会有新的 commit,所以同一个查询操作执行两次或者多次的结果可能不一致。
            Repeatable Read(可重复读)  事务的多个实例在并发读取数据时读到同样的数据行,这种隔离级别可能会导致出现幻读,比如当用户读取某一个范围的数据行时,这时候另一个事务在这个数据行范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 “幻影” 数据
            Serializable(串行化)  通过在每个读的数据行上加共享锁,这时候事务就会有顺序的执行,这样事务之间就不会出现冲突了,幻读问题也就解决了,不过由于加了锁,就会出现锁竞争和等待获取锁的情况
          

174.说一下 mysql 常用的引擎?

        答: InnoDB  , Myisam




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值