zoukankan      html  css  js  c++  java
  • java面试题整理(1)

    1、Equals与==的区别?

      ==是判断两个变量或者实例是不是指向同一个内存地址

      equals是判断两个变量或者实例所指向的内存地址中的值是不是相同

    2、Object有哪些公用方法?

      方法equals()测试两个对象是否相等

      方法clone()进行对象拷贝

      方法getClass()返回和当前对象相关的Class对象

      方法notify(),notifyall(),wait()都是用来对给定对象进行线程同步的

    3、实际开发中软引用或者弱引用的使用场景:

      利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题

      通过软引用对象重载方法实现java对象的的高速缓存:比如我们创建一个Employee的类,如果每次需要查询一个雇员的信息。哪怕是几秒钟之前刚刚查询过的,都要重新构建一个实例,这时就会消耗很多的时间。我们可以通过软引用和HaspMap的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap上,key为雇员的id,value为这个对象的软引用,另一方面是取出引用,缓冲中是否有该Employee实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新一个实例,并保存对这个新建实例的引用。

    4、Hashcode的作用,与equal有什么区别:

      同样是用来判断两个对象是否相等,java集合中有List和Set两个类,其中set不允许对象重复实现,这个不允许重复实现的方法,如果用equal()方法去比较的话,若存在1000个元素,new一个新的元素出来,就需要去调用1000次equal()方法去逐个和他们去比较是否是同一个对象,这样就会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal()方法与新元素进行比较,相同的话就不存了,散列在其他地址上。

    5、String、StringBuffer与StringBuilder的区别:

      String类型和StringBuffer类型的主要性能区别在了String是不可变的对象, StringBuffer是可变对象

      StringBuffer和StringBuild底层是char[]数组实现的

      StringBuffer是线程安全的,而StringBuild是线程不安全的。

    6、Override和Overload含义的区别:

      Overload重新加载的意思,它可以表现类的多态性,可以是函数里面可以有相同的函数名,但是参数名、返回值、类型不能相同;或者说可以改变参数、类型、返回值但是函数名称依然不变。

      Override重写的意思,在子类继承父类的时候子类中可以定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类相当于被覆盖(重写)了

    7、抽象类和接口的区别:

      一个类只能一个类即一个子类只能有一个父类,但是可以继承多个接口

      接口强调特定功能的实现,而抽象类强调所属关系

      抽象类中的所有方法并不一定要是抽象方法,你可以选择在抽象类中实现一些基本的方法。而接口要求所有的方法都必须是抽象的。

    8、解析XML的几种方式的原理与特点:DOM、SAX、PULL

      DOM(Document Object Model):消耗内存:先把XML文档都读到内存当中,然后再用DOM API来访问树形结构,并获取数据。这个写起来简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能就会直接死机。

      SAX(Simple API for XML):解析效率高,占用内存少,基于时间驱动的:更简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时,通知事件处理函数,由事件处理函数做出相应的动作,然后继续同样的扫描,直到文档结束。

      PULL():与SAX类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档、结束文档、开始标签、结束标签),当处于某个元素时可以调用XmlPullParser的getAttribute()方法来获取属性值,也可调用它的nextTest()获取本节点的值。

    9、wait()和sleep()的区别:

      sleep()来自Thread类,和wait()来自Object类

      调用sleep()方法的过程中,线程不会释放对象锁。而调用wait()方法线程会释放对象锁

      sleep()睡眠后不让出系统资源,wait()让出系统资源其他线程可以占用CPU

      sleep(milliseconds)需要指定一个睡眠时间,时间一定到会自动唤醒

    10、java多态的实现原理:

      抽象的来讲,多态的意思就是同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。

      实现的原理是动态绑定,程序调用的方法在运行期减才动态绑定,追溯源码可以发现,JVM通过参数的自动转型来找到合适的办法。

    11、java垃圾回收与内存分配策略:

      (1)垃圾回收是什么?

       就是释放那些不在持有引用的对象的内存。

      (2)怎么判断一个对象是否需要收集?

       引用计数(最简单古老的方法):指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。

       对象引用遍历(现在大多数JVM使用的方法):对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它做为垃圾收集。

       引用计数缺陷:引用计数无法解决循环引用问题:假设对象A、B都已经被实例化,让A=B,B=A,除此之外这两个对象再无任何引用,此时计数器的值就永远不可能为0,但是引用计数器无法通知gc回收他们。

      (3)java的四种引用的区别:

       强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出OutOfMemoryError错误,使程序一场终止。如果想中断强引用和某个对象之间的联系,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

       软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。

       弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当JVM进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。

       虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

      (4)介绍垃圾回收机制:

       标记回收法:遍历对象图并且记录可达到的对象,一遍删除不可到达的对象,一般使用单线程工作并且可能产生内存碎片。

       标记-压缩回收法:前期与第一种方法相同,只是多了一步,将所有的存活对象压缩到内存的一端,这样内存碎片就可以合成一大块可再利用的内存区域,提高了内存利用率。

       复制回收法:把现有的内存空间分成两部分,gc运行时,它把可到达对象复制到另一半空间,再清空正在使用的空间的全部对象。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

       分代回收法:把内存空间分为两个或者多个域,如年轻代和老年代,年轻代的特点是对象很快被回收,因此在年轻代使用效率比较高的算法。当一个对象经过几次回收后依然存货,对象就会被放入称为老年的内存空间,老年代则采取标记-压缩算法。

      (5)java中堆和栈的区别:

      基本数据类型变量和对象的引用都是在栈分配

      堆内存用来存放由new创建的对象和数组

      类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中。

      实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的“物理位置”,实例变量的生命周期---当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存。

      局部变量:由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一旦脱离作用域,内存立即释放。

    12、java集合系列问题

      (1)ArrayList、LinkedList、Vector的区别:

       ArrayList 和Vector底层是采用数组方式存储数据,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差
    LinkedList使用双向链表实现存储,随机存取比较慢
    HashMap的底层源码实现:当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
    Fail-Fast机制:在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast机制。这一机制在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map

      (2)HashMap和HashTable的区别

       HashTable比较老,是基于Dictionary 类实现的,HashTable 则是基于 Map接口实现的
    HashTable 是线程安全的, HashMap 则是线程不安全的
    HashMap可以让你将空值作为一个表的条目的key或value

    13、什么是线程池,线程池的作用是什么?

      答:线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。就好比原来去食堂打饭是每个人看谁抢的赢,谁先抢到谁先吃,有了线程吃之后,就是排好队形,今天我跟你关系好,你先来吃饭。比如:一个应用要和网络打交道,有很多步骤需要访问网络,为了不阻塞主线程,每个步骤都创建个线程,在线程中和网络交互,用线程池就变的简单,线程池是对线程的一种封装,让线程用起来更加简便,只需要创一个线程池,把这些步骤像任务一样放进线程池,在程序销毁时只要调用线程池的销毁函数即可。
    单个线程的弊端:a. 每次new Thread新建对象性能差b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或者OOM,c. 缺乏更多功能,如定时执行、定期执行、线程中断。
    java提供的四种线程池的好处在于:a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。c. 提供定时执行、定期执行、单线程、并发数控制等功能。 

    转自链接:http://www.imooc.com/article/19234

  • 相关阅读:
    C# 根据主窗体的位置弹窗信息窗体一直保持在主窗体中间
    c# winForm父子窗口 通过委托进行信息传递
    使用devexpress插件 消除运行时弹窗
    C# 获取当前时间戳
    WinForm实现Loading等待界面
    转载 C#设置控件 Enabled 为 false 时背景色不改变
    DEV gridView中加入加载条显示进度,必须为圆角型
    winfrom 圆角化
    列表元素的反转、排序——python
    使用for循环和while循环打印九九乘法表——python
  • 原文地址:https://www.cnblogs.com/lihuibin/p/7533300.html
Copyright © 2011-2022 走看看