Java后台开发常见面试题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java后台开发常见面试题相关的知识,希望对你有一定的参考价值。

  • 八种基本数据类型的大小,以及他们的封装类

        整数型:        byte    1个字节    -128~127                    封装类:Byte
            short   2个字节        -32768~32767                        Short
            Int     4个字节        -2147483648~2147483647              Integer
            long    8个字节        -2的63方~2的63次方-1             Long
    
        浮点型:        float   4个字节        单精度                             Float
                        Double  8个字节        双精度                                 Double
    
        布尔类型:   boolean 4个字节        true或false                          Boolean
    
        字符类型:   char        2个字节                                        Character
  • 引用数据类型:
    分为3种,类、接口和数组

  • Switch能否用String做参数

            在jdk7以前,switch只支持byte、int、short、char或者对应的包装类和枚举。
  • equals和==的区别

            a)  对象类型不同 equals是超类Object的方法,而==是操作符
    
            b)  比较类型不同 equals用来检测两个对象是否相同,即两个对象的内容是否相等,==比较引用数据类型和基本数据类型时具有不同的功能。==比较的是变量(栈)内存中存放的对象的内存地址,用来判断两个对象的地址是否相同,即是否指向同一对象,比较的是真正意义上的指针操作,而equals用来比较的是两个对象的内容是否相同,适用于所有对象。
    
            c)  注意:如果没有对该对象进行覆盖的话,调用的仍然是超类Object的方法,而Object中的equals方法返回的是==的判断。
  • 自动拆装箱和常量池

            a)  Java自动将原始数据类型值转换成对应的对象,比如将int类型的变量转换成Integer类型,自动装箱时调用valueOf将原始数据类型转换成对应的对象。
    
            b)  反之,将Integer对象装换成int类型值,这个过程叫拆箱,自动拆箱通过调用类似intValue、doubleValue这类的方法将对象转换成对应的原始数据类型。
    
            c)  Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
                i.  静态常量池:即.*class文件中的常量池,class文件中的常量池不仅仅包含字符串,还包含类、方法的信息,占用class文件绝大部分空间。
                ii. 而运行时常量池:则是jvm虚拟机在完成类装载过程后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池就是指方法区中的运行时常量池。
  • Object中有哪些公用方法?

        a)  Clone:实现对象的浅复制,只有实现了cloneable接口才可以调用此方法,否则会抛出CloneNotSupportedException异常。
    
        b)  Equals:在Object中和==是一样的,子类一般需要重写此方法。
    
        c)  Hashcode:该方法用于哈希查找,重写了equals方法一般都要重写hashcode方法,这个方法在一些具有哈希功能的collection中用到。
    
        d)  getClass:获得运行时的类型。
    
        e)  wait:是当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是说具有该对象的锁!
    
        f)  Notify:唤醒在对象上等待的某个线程。
    
        g)  notifyAll:唤醒该对象上等待的所有线程。
    
        h)  toString:转换成字符串,一般子类都要重写此方法,否则打印句柄。
  • Java的四种引用,强弱软虚。

        a)  强引用:最常见,把一个对象赋给引用数据类型则为强引用。如果内存中不足,java虚拟机将会跑出OutOfMemoryError错误,从而将程序异常停止强引用的对象是不可以gc回收的,不可以随意回收具有强引用的对象来解决内存不足的问题。在java中,强引用是一种默认的状态,除非Java虚拟机停止工作。
    
        b)  软引用:如果一个对象具有软引用,内存空间足够,垃圾回收就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序继续使用。软引用用来实现内存敏感的高速缓存,比如网页缓存或图片缓存,使用软引用能防止内存泄露,增强程序的健壮性。
    
        c)  弱引用:用来描述非必需对象的,当jvm进行垃圾回收的时候,无论内存是否充足,都会回收被弱引用关联的对象。
    
        d)  虚引用:他不影响对象的生命周期,如果一个对象与虚引用关联,则跟没有与之关联一样,在任何时候都可能被垃圾回收器回收。
  • hashcode的作用

        比较两个对象是否相等,重写的equals方法一般比较全面,比较复杂,效率比较低,而采用hashcode方法进行对比,只需要生成一个hashcode进行比较就可以了!
  • Hashmap中的hashcode的作用

        a)  Hashcode的存’用于查找的快捷性,如hashtable、hashmap等,hashcode是在散列结构中确定对象的地址。
    
        b)  如果两个对象相同,就是适用equals方法,那么这两个对象的hashcode一定要相同。
    
        c)  如果对象的equals方法被重写,那么对象的hashcode也尽量重写,并且产生hashcode使用的对象,一定要和equals放法使用的一致,否则会违反上面的第二点。
    
        d)  两个对象的hashcode相同,并不代表这两个对象就相同,也就是不一定适用equals方法,只能说明这两个对象在散列存储结构中,如hashtable,他们“存放在同一个篮子里”。
  • 为什么重载hashcode方法?

            一般不需要重载hashcode方法,只有当类放在hshtable、hashmap、hashset等hash结构的集合时,才会重载hashcode。就hashmap来说,好比hashmap就是一个大内存块,里面有许多小内存块,小内存里面就是一系列的对象,可以利用hashcode查找小内存块,,所以当equals相等时,hashcode必需相等,而且如果是Object对象,必须重载hashcode和equals方法。
  • Arraylist、linkedlist和vector的区别?

        a)  Arraylist:底层数据结构是数组,查询快、增删慢,线程不安全。
    
        b)  Liskedlist;底层数据结构是链表,查询慢、增删块,线程不安全。
    
        c)  Vector:底层是数组,查询慢、增删慢,线程安全。
  • String、stringbuffer与stringbulder的区别?

        a)  String是不可变的对象,因此每次对string类型进行改变的时候,就等于生成了一个新的对象,然后蒋指针指向一个新的string的对象,因此经常改变内容的字符串最好不用string,因为每次生成对象都会对系统性能产生影响,特别是当内存中无引用对象过多时,jvm的gc就会开始工作,那么速度一定会非常慢。
    
        b)  而stringbuffer结果就完成不一样了,每次结果都会对stringbuffer本省进行操作,而不是生成新的对象,再改变对象的引用。是线程安全的。
    
        c)  Stringbuildere是jdk5以后新增的,其用法和stringbuffer完全一致,但它是线程不安全的,在单线程中是最佳的,因为不需要维护线程的安全。
  • Map、set、list、queue、stack的特点与用法。

        a)  Map是键值对,键key是唯一不能重复的,一个键对应一个值,值可以重复,treemap可以保证顺序,hashmap不保证顺序,即是无序的,map可以把key和value单独抽取出来,其中keyset()方法可以将所存的key抽取成一个set。而valuses方法可以将map中所有的value抽取成一个集合。
    
        b)  Set:不包含重复元素,且最多包含一个null元素,只能用iterater实现单向遍历, set没有同步方法。
    
        c)  List:有序的可重复集合,可以在任何位置增加和删除元素。用Iterator实现单向遍历,也可以用listIterator实现是双向遍历。
    
        d)  Queue:遵从先进先出原则,使用时尽量避免add()和remove()方法,而只是使用offer()来添加元素,使用poll来移除元素,它的优点是可以通过返回值来判断是否成功,LinkedList实现Queue接口,Queue通常不允许插入null元素。
    
        e)  Stack:遵从先进后出原则,stack继承自vector,它通过五个操作对类vector进行扩展,允许将向量视为堆栈,它提供push和pop操作,以及取堆栈顶点的peek()方法,测试堆栈是否为空的empty()方法等。
    
        f)  用法:如果涉及堆栈、队列等操作,建议使用list,对于快速插入和删除元素,建议使用linkedlist,如果,快速随机访问元素,建议使用ArrayList。
  • Hashmap和hashtable的区别?

    a) 都是map接口的实现类,都是基于hash表的实现类。

    b) Hashmap集合线程不安全的类,不同步,执行效率高,允许键和值是null。

    c) Hashtable集合是线程安全的类,同步,执行效率低,不允许键和值为null。

  • Jdk7和jdk8中的hashmap的实现。

        a)  Jdk7:hashmap底层维护一个数组,数组中的每一项都是一个entry,我们向hashmap中放置的对象实际上存储在该数组中,map中的key和value则以entry的形式存放在数组中,而这个key放在数组的哪一个位置上,是通过key的hashcode来计算的。
    
        b)  Jdk8:采用(位桶+链表)红黑树的方式,也是非线程安全的。
  • Hashmap和hashConcurrentHashmap的区别,hashmap的底层源码。

            Hashmap是线程非安全的,效率比较高,hashtable和ConcurrentHashmap是线程安全的,效率比hashmap差一点,但ConcurrentHashmap采用了更高级的分段锁机制,具体可以理解为把hashmap拆分为n个小的hashtable,根据key。Hashcode()来决定把key放到哪个hashtable中,在concurrenthashmap中,就是把map分为n个segment,put和get时,都是key.hashcode()算出放到哪个segment中。
  • 接口和继承的区别?接口内可以定义常量吗?继承可以继承父类的那些东西?

        a)  区别:
            i.  标识符不同,interface和extends
            ii. 接口支持多继承,而不支持继承的继承
            iii.    接口中只能定义全局变量和抽象变量,而继承中可以定义属性、方法、常量、变量等。
            iv. 某接口被实现,在类中一定要实现接口所有的方法,而继承只需要用哪一个就调用哪一个。
    
        b)  接口不可以定义常量。
    
        c)  继承可以继承父类所有的东西(成员方法、成员变量、包括私有)。
  • 如何修改父类中以private关键字修饰的变量?

        如果父类中有public的set方法,就可以通过set方法修改父类中以private修改的变量。
  • Java中public、private 、protect、default的区别?

        a)  Public:java中访问限制最宽的修饰符,即公共的,被修饰的类、属性、方法允许跨类访问,甚至可以跨包访问。
    
        b)  Private:是java中访问限制最窄的修饰符,被private修饰的类、属性、方法只能被本类的对象进行访问,其子类不能访问,更不允许跨包访问。
    
        c)  Protec:介于public和private之间的一种访问修饰符,一般称受保护的,被其修饰的类、方法、属性只能被本类和子类进行访问,即使子类不在同一个包下。
    
        d)  Default:意为默认的,即不加修饰符,该模式下只能同一个包下进行访问。
  • 数据库锁的问题?如何上锁?是不是行锁?

        a)  当多个用户同时对数据库进行操作时,会带来数据不一致的问题,所以锁主要是用于多用户环境下保证数据库完整性和一致性.
    
        b)  锁分类:从数据库系统来看:排它锁、悲观锁、更新锁
        从程序员角度来看:一种是乐观锁,一种是悲观锁。
        i.  悲观锁:很悲观,每次去拿数据的时候,都以为别人会修改,所以在每次拿数据的时候,都会上锁,这样别人拿这个数据就会block,直到它合锁。具有强烈的排他性和独占性,悲观锁的实现依靠数据库提供的机制,也只有数据库底层提供的机制才能保证数据访问的排他性。传统的关系型数据库用到了很多这同样的机制,比如行锁、表锁、读锁、写锁等,都是在操作前加上锁。
        ii. 乐观锁:很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。悲观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write—condition机制的其实都是提供的乐观锁。
  • c) 按作用性质分:

    i.  共享锁:也叫读锁,用于所有只读操作,不能同时增删改,可以查。
    例如:select * from 表 lock in share mode;
    
        ii. 排它锁:也叫读锁,表示对数据进行写操作,一个事务对象施加了排它锁,其他事务就不能加锁了。
    例如:查询时加排它锁,别人不能加共享锁和排它锁。
    Select * from 表 for update;
            仅允许一个事务封锁此表,其他事务必须等到此锁被释放才能访问。
            排它锁(x锁)一直到事务结束才能释放。
    iii.    更新锁:允许其他事务读,但不允许在施加x锁和u锁,当要被读取的对象要被更新的时候,则升级为x锁,防止死锁,如果一个数据在修改前直接申请更新锁,在修改时再升级为排它锁,就可以避免死锁。

    d) 按范围分:

    i.  行锁:锁的范围是行级别,数据能够确定哪些行需要锁的情况下使用行锁(inodb),如果在不知道会影响到哪些数据的时候就会使用表锁
    例如:一个用户表有主键id和birthday。
    Update …where id=?  行锁
    Update … where birthday=?   表锁
    
    ii. 表锁:锁的范围是整张表。 MyISAM

    22.事务的隔离性

    a)  隔离性级别越低,并发性越好,但数据库的一致性就越差。
    隔离级别越高,并发性越差,但数据库的一致性高。
    
    b)  由低到高
    读未提交<读提交<可重复读(默认)<序列化读
    
    c)  错误的级别由低到高:
    脏读、不可重复读、幻读
    脏读:两个事物,一个事务先修改,另一个事务读,结果是修改前的结果。
    不可重复读:两个事物,一个先读是一个结果,一个后修改,再读,又是一个结果。
    幻读:第一个事务表中有10、20、30、40几个部门,第二个事务插入表中50的部门,然后提交,第一个事务插入50部门,主键冲突。

    23.能否用一个sql语句解决库存判断问题(非查询语句)。

    用if语句:if(exper1,exper2,exper3)
            如果exper1的值是true,则返回是exper2的值,如果exper1的值是false,则返回exper3的值。
    例如:id   name        number
                1       苹果      300
                2       梨           100
    Update fruit set number=if(number>200,number,0)where if=’1’;
    即如果苹果的数量大于200,就不变,否则,number改为0,即就可以判断内存是否充足。

    24.红黑树

    a)  特性:
    
    i.  每个节点都是黑色或者红色。
    ii. 根节点是黑色。
    iii.    定义null为黑色。
    iv. 如果某个子节点是红色,那么它的两个儿子都是黑色,且父节点一定是黑色。
    v.  对于任意节点,它到叶子节点的每一条路径都包含相同数目的黑色节点
    性质5称之为黑高。

    b) 相对平衡:

    i.  若H(left)>=H(right),则H(left)=2*H(right)+1
    ii. 但BH(left)=BH(right),H(left)<H(right)同理。

    c) 在调整节点p之前,必需保证p的左子树left、右子树right都已经是rbt。

    i.  多个子问题成立->某个总问题成立
    ii. 插入调整:删除调整均是由底向上

    d) Rbt的插入调整(默认是红色)

    i. 无需调整

    1. X为根节点,将x由红染黑
    2. 父亲节点是黑色

    ii. 仅仅考虑父亲节点p是红色,由于性质4,爷爷节点必定是黑色,分为3中:

    1.  Case1:y为黑色,x可左可右;p、y染黑,g染红;x回溯至g
    2.  Case2:y为黑色,x为右孩子,左旋p,x指向p,转为case3
    3.  Case3:y为黑色,x为左孩子,p染黑,g染红,右旋g结束。
    Rbt的插入调整最多2次
    右旋转:逆时针旋转两个节点,使父亲节点被右孩子取代,而自己变成左孩子。
    左孩子:顺时针旋转两个子节点,使父亲节点被左孩子取代,自己变成右孩子。

    25.Session是什么?和cookie的区别?

    a)  Cookie通过客户端记录信息确认身份,session是通过服务端的信息确认身份。
    b)  客户端浏览器访问服务器的时候,服务端把客户端的信息以某种形式记录在服务器上,这就是session,用户与服务器建立连接的同时,服务器自动分配一个sessionid。
    c)  区别:cookie不×××全,别人可以分析本地存在的cookie并进行cookie欺骗,考虑到安全应当使用session。
    1. 有哪些排序算法?说一下堆排序?时间复杂度是多少?

      a)  直接插入排序:第一个元素已经排序,第二个与第一个元素进行比较,第一个大,第一个则与第二个交换位置,第三个分别于第一个和第二个比较,以此类推。
      时间复杂度:O(n*n)
      
      b)  希尔排序:按步长grep进行分组,然后将每组元素利用直接插入排序的方法进行排序;每一次结束后再将步长grep减半,循环上述操作,直到步长grep=1,利用直接插入排序,完成排序。
      时间复杂度:O(log n)
      
      c)  简单选择排序:首先在未排序序列中找到最小(或最大)的元素,放在排序序列的起始位置,然后再从未排序序列中找到最小(最大)的元素,放在已排序序列的后面。
      时间复杂度:O(n*n)
      
      d)  堆排序:堆排序过程就是将待排序序列构造成一个堆,选出堆中最大的移走,再把剩下的整成堆,找出最大的在移走,重复直至有序。
      i.  每次将根节点与左右节点最大的进行交换,直到根节点最大,然后把根节点放在最后一个位置,然后再次执行循环,找到最大值放在长度-1的位置。
      ii. 时间复杂度:O(n log n)
      
      e)  冒泡排序:每次比较两个元素,把小的放在前面。
      时间复杂度:O(n*n)
      
      f)  快速排序:把一个序列分为两个子序列,步骤可分为:
      i.  从数列中选出一个元素,作为基准。
      ii. 重新排序数列,所有比基准序列小的元素放在基准前面,所有比基准大的元素放在基准后面,相同的放在任意一边,在这个分区结束后,该基准处于中间位置。
      iii.    递归将小于基准的子序列和大于基准的子序列排序。
      iv. 即:先对大序列进行排序,大序列分为两个子序列,然后递归调用方法对这两个序列进行排序。
      
      g)  归并排序:将两个或两个以上的有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列都是有序的,然后再把整个序列合并成整体有序序列。
      时间复杂度:O(nlogn)
      
      h)  基数排序:将所有待比较的数(正整数统一为同样的数位长度),数位数不足的前面补0,然后从低位开始,依次进行一次排序,这个序列从最低位排序一直到最高位排序完成以后,数列将变成一个有序序列。
      时间复杂度:O(d*(n+r))
      D为位数,r为基数,n为数据个数

    27.Statement和preparestatement的区别?

    a)  代码的可读性和可维护性preparestatement更好。
    b)  Preparestatement尽最大可能提高性能。
    c)  提高安全性,preparestatement防止sql注入。

    28.NIO和IO到底有什么区别?有什么关系?

    a)  NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式去写入和读出的,肯定NIO的效率比IO的效率高出好多。
    b)  NIO不是和IO一样用Ouputstream和Inputstream输入流形式来处理数据,但是基于这种流的形式,而是采用通道和缓冲流的形式来处理数据的。
    c)  NIO通道可以是双向的,IO中的流只能是单向的。
    d)  还有就是NIO的缓冲区(其实也是一个字符数组)还可以进行分片,可以建立只读缓冲区、直接缓冲区和间接缓冲区,只读缓冲区很明显就字面意思,直接缓冲区是为了加快I/O速度,而以一种特殊的方式分配其内存的缓冲区。

    29.数据库索引的分类,索引底层的实现,说一下b+树,b-树?
    a) 索引的作用:

    i.  提高查询速度
    ii. 确保数据的唯一性
    iii.    可以加快表与表之间的连接,实现表和表之间的完整性。
    iv. 使用分组和排序字句进行数据检查时,可以减少分组和排序的时间。
    v.  全文检索字段进行搜索优化。

    b) 分类;

    i.  主键索引(PRIMAY_KEY):确保数据记录的唯一性,一个表只有一个。
    ii. 唯一索引(UNIQUE):避免一个表中某些数据列中的值重复。可以有多个。
    iii.    常规索引(INDEX):快速定位特定数据。
    iv. 全文索引(FULLTEXT):快速定位特定数据,只能用于MyISAM类型的数据表。

    c) 索引底层实现:把平衡树当做数据表默认的索引数据结构,平衡树也就你、b+tree或者b-tree。

    d) B-tree:适用于外查找的树,是平衡树的多叉树。

    i.  一个m阶b树是一颗平衡的m路搜索树,它或者是空树,或者满足下列性质:
    
    1.  定义任意非叶子节点最多有m个儿子,且m>=2;
    2.  根节点的儿子数[2,m];
    3.  除根节点以外的叶子节点的儿子数{m/2,m};
    4.  每个节点存放m/2-1(向上取整)和至多m-1个关键字(至少2个)。
    5.  非叶子节点的关键字个数=指向儿子的指针个数-1;
    6.  非叶子节点的关键字:k[1]、k{2}…k[m-1],且k{i}<k{i+1}。
    7.  非叶子节点的指针:p{1} 、p{2} 、p{3}、 p{4} …p{m},其中p[1】指向小于k[1]的子树,p[m]指向关键字属于k{i}和k{i+1}之间的子树。
    8.  所有子树节点位于同一层。

    ii. B-树的特性:

    1.  关键字集合分布在整棵树中。
    2.  任何一个关键字出现且只出现一个节点中。
    3.  搜索可能在非叶子节点结束。
    4.  其搜索性能等价于在在关键字全集中做一次二分查找。
    5.  自动层次控制。

    e) B+树:

        i.  B+树的定义:
            1.  其定义与b-树基本相同,除了:
            2.  非叶子节点的子树指针与关键字个数相同。
            3.  非叶子节点的子树指针p[i],指向关键字属于k[i],k[i+1]的子树。
            4.  为所有关键字增加一个键指针。
            5.  所有关键字在叶子节点出现。
    
        ii. B+树的特性:
    
    1.  所有关键字都出现叶子节点的链表中(稠密索引)且链表中的关键字恰好是有序的。
    2.  不可能在非叶子节点命中。
    3.  非叶子节点相当于叶子节点的索引(稀疏索引),叶子节点相当于存储数据(关键字)的数据层。
    4.  更适合文件索引系统。

    以上是关于Java后台开发常见面试题的主要内容,如果未能解决你的问题,请参考以下文章

    Android开发,java开发程序员常见面试题,求100-200之间的质数,java逻辑代码

    Java软件开发常见面试题

    java主线程等待所有子线程执行完毕在执行(常见面试题)

    Spring常见面试题

    java面试java中Spring开发框架的常见面试题

    Java基础常见面试题总结(下)