美文网首页java面试题
Java面试题收藏

Java面试题收藏

作者: Luliang | 来源:发表于2017-07-08 22:47 被阅读156次

    Java面试题收藏

    一篇比较好的面试题整理:

    Java面试题集

    自己的一些收藏:


    静态变量和实例变量的区别

    静态变量存储在方法区, 属于类所有,实例变量存储在当中, 其引用存在当前线程的栈


    switch中能否使用string做参数

    在jdk1.7之前, switch只能支持byte, short, char, int或者其对应的封装类以及Enum类型. 从jdk1.7之后, switch开始支持String


    String对象的intern()是干什么的

    intern()方法会首先从常量池中查找是否存在该常量值, 如果常量池中不存在则先在常量池中创建, 如果已经存在则直接返回, 如:

    String s1="aa"; 
    String s2=s1.intern(); 
    System.out.print(s1==s2);//返回true
    

    equals()和hashcode()的联系

    hashCode()是Object类的一个方法, 返回一个哈希值, 如果两个对象根据equal()方法比较相等, 那么调用这两个对象中任意一个对象的hashCode()方法必须产生相同的哈希值. 如果两个对象根据eqaul()方法比较不相等, 那么产生的哈希值不一定相等(碰撞的情况下还是会相等的)


    final, finalize和finally的不同之处

    • final是一个修饰符,可以修饰变量、方法和类。如果final修饰变量,意味着该变量的值在初始化后不能被改变

    • finalize方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。

    • finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。


    Thread类中的start()run()方法有什么区别

    start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。


    wait()与sleep()的区别

    sleep()来自Thread类,而wait()来自Object类. 调用sleep()方法的过程中,线程不会释放对象锁。而调用 wait()方法线程会释放对象锁. sleep()睡眠后不出让系统资源,而wait()会让出系统资源. sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒.而wait()需要配合notify()或者notifyAll()使用


    ThreadLoal的作用是什么

    简单说ThreadLocal就是一种以空间换时间的做法, 在每个Thread里面维护了一个ThreadLocal。ThreadLocalMap把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了。


    如果你提交任务时,线程池队列已满,这时会发生什么

    如果你使用的LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为LinkedBlockingQueue可以近乎认为是一个无穷大的队列,可以无限存放任务;如果你使用的是有界队列比方说ArrayBlockingQueue的话,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy


    volatile类型变量提供什么保证

    volatile主要有两方面的作用:

    1. 避免指令重排
    2. 可见性保证
      例如,JVM 或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的(低32位和高32位),但 volatile 类型的 double 和 long 就是原子的.

    Comparator和Comparable的区别

    Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。


    Fail-fast和Fail-safe有什么区别

    Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail->fast的,而java.util.concurrent中的集合类都为fail-safe的。当检测到正在遍历的集合的结构被改变时,Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。


    简述JVM内存分配

    1. 基本数据类型变量和对象的引用都是在栈分配的
    2. 堆内存用来存放由new创建的对象和数组
    3. 类变量(static修饰的变量),程序在加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中
    4. 实例变量,当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的物理位置。实例变量的生命周期: 当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收名单中,但并不是马上就释放堆中内存。
    5. 局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在中开辟内存,当局部变量一但脱离作用域,内存立即释放

    父类的静态方法能否被子类重写

    不能, 重写只适用于实例方法, 不能用于静态方法, 而子类当中含有和父类相同签名的静态方法, 我们一般称之为隐藏


    怎么唤醒一个阻塞的线程

    如果线程是因为调用了wait()、sleep()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。


    HashMap的实现原理

    http://www.cnblogs.com/chenssy/p/3521565.html

    HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
    HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个链表散列的数据结构,即数组和链表的结合体。
    当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根据hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上.
    需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)


    2张图记住Java的集合框架

    图1 图2

    JVM相关

    深入JVM垃圾回收算法
    http://gityuan.com/2016/01/09/java-memory/
    小节:
    JVM内存整理算法

    • 标记清除算法(Mark-Sweep)
      过程: 暂停进程, 标记每个需要清除的对象, 开始清除, 重新开启进程

    • 标记复制算法(Mark——Copy)
      内存被一分为二, 使用区和空闲区, 每次只使用一块区域, 当需要进行内存整理时, 暂停进程, 将使用区的对象复制到空闲区, 此时空闲区变成使用区, 而原来的使用区变成空闲区, 如此循环往复即可

    • 标记整理算法(Mark——Compat)
      让所有存活的对象都向内存的一端移动, 然后直接清理掉端边界以外的内存


    • 分代收集算法


      分代收集算法结合了标记-复制和标记-整理的优势。一般做法是将Java堆分为新生代和老年代。由于新生代会不断产生新生对象,因此采用了标记-复制算法;而年老代的对象存活率较高,因此采用了标记-整理算法。在新生代中,我们可以看到新生代=Eden+S0+S1;他们设计的默认比例是8:1:1;这个参数是可以通过虚拟机参数进行调整的。
      参考文章(http://www.jianshu.com/p/7c708a66ff42)

    分代收集只是根据对象生存周期的不同来选择不同的算法,其本身并没有任何新思想。


    static关键字

    public class Test {
        static int i = 0;
        public int test() {
            i++;// 1
            return i;
        }
        public static void main(String[] args) {
            Test test = new Test();
            test.test();
            System.out.println(new Test().test());
        }
    }
    // 输出结果为2
    

    内部类的初始化

    public class Outer {
        public void someOuterMethod() {
            // line3
            new Inner();// 正确的初始化内部类
        }
    
        public class Inner {
        }
    
        public static void main(String[] args) {
            Outer outer = new Outer();
            // line8
            // new Inner(); // error, 不能直接new内部类
            // new Outer.Inner(); // error, 没有这种写法
            // new outer.Inner(); // error,
        }
    }
    

    Thread

    public class X extends Thread implements Runnable{
        public void run() {
            System.out.println("this is run()");
        }
        
        public static void main(String[] args) {
            Thread thread = new Thread(new X());// Thread implements Runnable
            thread.start();
        }
    
    }
    // 输出this is run()
    

    原码反码与补码

    http://www.cnblogs.com/wxf0701/archive/2008/08/14/1267639.html
    在计算机系统中,数值一律用补码来表示(存储)。
    主要原因:使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补
    码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
    补码与原码的转换过程几乎是相同的。
    已知原码求补码
    数值的补码表示也分两种情况:
    正数的补码:与原码相同。
    例如,+9的补码是0000 1001。
    负数的补码符号位为1,其余位为该数绝对值的原码按位取反;然后整个数加1
    例如,-7的补码:因为是负数,则符号位为“1”,整个为10000111;其余7位为-7的绝对值+7的原码
    0000111按位取反为1111000;再加1,所以-7的补码是11111001。

    已知补码求源码
    已知一个数的补码,求原码的操作分两种情况:
    (1)如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
    (2)如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1,其余各位取反,然后再整个数加1
    例如,已知一个补码为11111001,则原码是1000 0111(-7):因为符号位为“1”,表示是一个负数,所以该位不变,仍为 “1”;其余7位111 1001取反后为000 0110;再加1,所以是1000 0111。


    StringBuffer是如何实现线程安全的?

    synchronized关键字


    了解过HTTP吗?说说它的特点,它里面有哪些方法,有了解过吗?知道 HTTPS 吗?这两者有什么区别?

    关于HTTP协议,一篇就够了

    Http和https的区别

    1. Https是ssl加密传输,Http是明文传输
    2. Https是使用端口443,而Http使用80
    3. HttpsSSL+HTTP协议构建的可进行加密传输、身份认证的网络协议要比Http协议安全
    4. Https协议需要到CA申请证书

    ssl是什么?: SSL(Secure Sockets Layer 安全套接层), 及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。 TLS与SSL在传输层对网络连接进行加密。
    CA是什么?: 证书机构


    你平常是怎么进行加密的? MD5加密是可逆的吗?

    对称加密: AES,DES
    非对称加密: RSA、DSA(数字签名用), ECC(移动设备用)
    HASH算法: MD5,SHA1

    对称:使用相同密钥,需要在网络传输,安全性不高。
    非对称:使用一对密钥,公钥和私钥,私钥不在网络传输,因此安全性高。
    Hash算法: Hash算法特别的地方在于它是一种单向算法,用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值,却不能通过这个Hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。

    MD5加密是不可逆

    Base64算法: Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节可表示4个可打印字符。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。
    Base64算法


    ArrayList源码分析

    http://www.jianshu.com/p/f10edaec36fa


    了解过Java的集合吗?说说HashMap的底层实现原理?ArrayList 和 LinkedList 的区别?Java 集合中哪些是线程安全的?

    在你写代码的过程中有使用过设计模式吗?你知道哪些?为什么要这样用,能解决什么问题?
    了解注解吗?了解反射吗?为什么要使用反射?
    数据结构中常用排序算法?

    相关文章

      网友评论

        本文标题:Java面试题收藏

        本文链接:https://www.haomeiwen.com/subject/vsgjhxtx.html