java面试笔记,java面试题,java web笔试题,大厂


写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫码加微信好友进【程序员面试学习交流群】,免费领取。也欢迎各位一起在群里探讨技术。

JAVA面试大纲

1、Java程序执行过程

一个java程序的编译和执行过程如下:

(一).java文件 -------编译-----> .class文件

(二)类加载器负责加载各个字节码文件(.class)

(三)加载完.class文件,由执行引擎执行,在执行过程中,需要运行时数据区提供数据

2、JVM内存管理

JVM将内存划分为6个部分:PC寄存器(程序计数器)、虚拟机栈、堆、方法区、运行时常量池、本地方法栈




  •  
  • PC寄存器(程序计数器): 用于记录当前线程运行时的位置,每一个线程都有一个独立的程序计数器。线程的阻塞、恢复、挂起等一系列操作都需要程序计数器的参与、因此必须是线程私有的。




     
  • java虚拟机栈: 在创建线程时创建,用来存储栈帧,因此也是线程私有的。java程序中的方法在执行时,会创建一个栈帧,用来存储方法运行时的临时数据与中间结果,包括局部变量表、操作数栈、动态链接、方法出口等信息。这些栈帧就存储在栈中。如果栈深度大于虚拟机允许的最大深度,则抛出StackOverflowError异常。

     



    •  
    • 局部变量表:方法的局部变量列表,在编译时就被写入.class文件




       
    • 操作数栈:int x = 1;就需要将1压入操作数栈,再将1赋值给变量x

       




       



     
  • java堆: java堆被所有线程共享,堆的主要作用就是存储对象。如果堆空间不够,但扩展时又申请不到足够的内存时,则抛出OutOfMemoryError异常。




     
StackOverflowError OutOfMemoryError
java栈 java堆
栈深度超过范围了(比如:递归层数太多了) 内存空间不够了(需要及时释放内存)



  •  
  • 方法区: 方法区被各个线程共享,存放了要加载的信息(如类名、修饰符)、类中的静态变量、final定义的常量、类中的field、运行时常量池、方法信息,当开发人员调用类对象中的getName,isInterface等方法来获取信息时,这些数据来源于方法区。方法区是全局共享的,在一定条件下它也会被GC。当方法区使用的内存超过它允许的大小时,就会抛出OutOfMemory: PermGen Space异常(解决办法:加大内存,)。在Hotspot虚拟机中,这块区域对应的是Permanent Generation(持久代),一般的,方法区上执行的垃圾收集是很少的,因此方法区又被称为永久代的原因之一,但这也不代表着方法区上完全没有垃圾收集,其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。


     
  • 本地方法栈: 本地方法栈的主要作用就是支持native方法,比如在ava中调用C/C++。


     

3、GC回收机制




  •  
  • 哪些内存需要回收?


     
  • 什么时候开始回收?


     
  • 怎么回收?


     

(1)哪些内存需要回收




  •  
  • java堆、方法区的内存




































     
    线程私有 线程共享
    程序计数器、虚拟机栈、本地方法栈 java堆、方法区
    随线程生而生,随线程去而去。线程分配多少内存都是有数的,当线程销毁时,内存就被释放了 堆和方法区的内存都是动态分配的,所以也需要动态回收。这部分内存的回收依赖GC完成



     

(2)什么时候回收?




  •  
  • 引用计数法




     
  • 可达性分析

     

    一、引用计数法




     

给对象添加一个引用计数器,每当一个地方引用它时,计数器加一。反之每当一个引用失效时,计数器减一,当计数器为0时,则表示对象不被引用。

举个例子:


Object a = new Object(); //a的引用计数为1

a = null; //a的引用计数为0,等待GC回收

但是,引用计数法不能解决对象之间的循环引用,见下例


Object a = new Object(); //a的引用计数为1

Object b = new Object(); //b的引用计数为1

a.next = b; //a的引用计数为2

b.next = a; //b的引用计数为2

a = null; //a的引用计数为1,尽管已经显示的将a赋值为null,但是由于引用计数为1,GC无法回收a 

b = null; //b的引用计数为1,同理,GC也不回收b

二、可达性分析

设立若干根对象(GC Root),

没有一条从根到Object4和Object5的路径,说明这两个对象到根是不可达的,可以被回收。

补充:java中,可以作为GC Root的对象包括:




  •  
  • java虚拟机栈中引用的对象




     
  • 方法区中的静态变量引用的对象




     
  • 方法区中常量引用的对象




     
  • 本地方法栈中引用的对象

     

    三、怎么回收

     



    •  
    • 标记——清除算法


       
    • 复制算法


       
    • 分代算法


       
     

    (1)、标记——清除算法

     

    遍历所有的GC Root,分别标记可达的对象和不可达的对象,然后将不可达的对象回收。

     

    缺点是:效率低,回收得到的空间不连续

     

    (2)、复制算法

     

    将内存分为两块,每次只使用一块,当这一块内存满了,就将还存货的对象复制到另一块上,并且严格按照内存地址排列,然后把已使用的那块内存统一回收。

     

    优点是:能够得到连续的内存空间

     

    缺点是:浪费了一半内存

     

    (3)分代算法

     

    在java中,把内存中的对象按生命长短分为:

     



    •  
    • 新生代:活不了多久就go die了,比如局部变量


       
    • 老年代:老不死的,活的久但也会go die,比如一些生命周期长的对象


       
    • 永久带:千年乌龟老王八,不死,比如加载的class信息


       
     

    有一点需要注意:新生代和老年代存储在java虚拟机堆上:永久代存储在方法区上












































     
      回收方法
    新生代 使用复制算法
    老年代 使用标记——清除算法、标记——整理算法
    永久代 ——————————
     

    (4)、标记——整理算法

     

    标记过程与“标记——清楚算法一样,但后续步骤不是直接对可回收对象进行清理,而是让不可回收对象向边移动,将端边界以外的内存清理”




     

注意:

堆区是理解java GC机制最重要的区域,在JVM所管理的内存中,堆区是最大的一块,也是java GC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区用来存储对象实例及数组值,可以认为java中所有通过java创建的对象都在此分配。

为了让内存回收更加高效,从Sun JDK1.2开始对堆采用了分代管理方式,如下图所示:

年轻代

对象在被创建时,内存首先是在年轻代 上进行分配(注意,大对象可以直接在老年代上分配)。当年轻代需要回收时会触发Minor GC (也称作 Young GC)

年轻代由Eden Space和两块相同大小的Survivor Space(又称S0和S1)构成,可通过-Xmn参数来调整新生代大小。年轻代的Eden区内存是连续的,所以其分配非常快,同样Eden区的回收也非常快(因为大部分情况下Eden区对象存活时间非常短,而Eden区采用的复制回收算法,此算法在存活对象比例很少的情况下非常高效)

如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError: java Heap Space异常

老年代

老年代用于存放在年轻代中经过多次垃圾回收仍然存活的对象,可以理解为老一点的对象,例如缓存对象;新建的对象也可能在老年代上直接分配内存,这里有两种情况:一种为大对象,可以通过启动参数设置-XX:PretenureSizeThreshold=1024,表示超过多大时就不再年轻代分配,而是直接在老年代上分配。此参数在年轻代采用Parallel Scavenge GC时无效,因为其会根据运行情况自己决定什么对象直接在老年代分配内存。另一种为大的数组对象,且数组对象中有引用外部对象。

当老年代满了之后就需要对老年代进行垃圾回收,老年代的垃圾回收称作Major GC(也称作Full GC)。老年代所占用的内存大小为-Xmx 对应的值减去-Xmn对应的值。

4、JVM内存分配策略

对象的内存分配,在大方向上是在Java堆上进行内存分配。

大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够空间分配时,虚拟机将发起一次Minor GC。

大多数情况下,大对象直接进入老年代,虚拟机提供了参数来定义大对象的阀值,超过阀值的直接进入老年代。

进过多次Minor GC仍然存活的对象将进入老年代,虚拟机提供了参数,可以设置阀值。

5、JVM常见启动参数




  •  
  • -Xmx 3550m:设置jvm最大堆内存为3550M。


     
  • -Xms 3550:设置jvm初始堆内存为3550M。辞职可以设置成与Xmn一样,以避免每次垃圾回收后jvm重新分配内存。


     
  • -Xss 128k:设置每个线程的栈大小。JDK5.0以后每个线程大小为1M,之前每个线程栈大小为256K。应当根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,大概在3000-5000左右。需要注意的是:当这个值被设置的较大(例如>2M)时将会在很大程度上降低系统的性能。


     
  • -Xmn 2G:设置年轻代大小为2G,在整个堆内存大小确定的情况下,增大年轻代将会减小年老代,反之亦然。此值关系得到JVM垃圾回收,对系统性能影响较大,官方推荐配置未整个堆大小的3/8。


     
  • -XX:NewSize=1024m:设置年轻代初始值为1024M。


     
  • -XX:MaxNewSize=1024:设置年轻代最大值为1024M。


     
  • -XX:PermSize=256M:设置持久代初始值为256M。


     
  • -XX:MaxPermSize=256M:设置持久代最大值为256M。


     
  • -XX:NewRatio=4:设置年轻代(包括一个Eden和2个Survivor区)与老年代的比值,表示年轻代比年老代为1:4。


     
  • -XX:SuvivorRatio=4:设置年轻代中的Eden区与Survivor区的比值,表示2个Survivor区与一个Eden区的比值为2:4,即一个Survivor区占整个年轻代内存大小的1/6。


     

疑问解答

-Xmn,-XX:NewSize/-XX:MaxNewSize,-XX:NewRatio 3组参数都可以影响年轻代的大小,混合使用情况下,优先级是什么?

如下:

1.高优先级:-XX:NewSize/-XX:MaxNewSize

2.中优先级:-Xmn(默认等效-Xmn = -XX:NewSize = -XX:MaxNewSize =?)

3.低优先级:-XX:NewRatio

这三个参数推荐使用-Xmn,原因是这个参数简洁,相当于一次设定-XX:NewSize与-XX:MaxNewSize,而且两者相等,适用于生产环境,-Xmn配合-Xmx与-Xms,即可完成堆内存布局完成。

-Xmn参数是在JDK1.4开始支持。

JVM服务参数调优实战

大型网站服务器按理

承受海量访问的动态web应用

服务器配置:8 CPU,8G MEN,JDK1.6.x

参数方案:

-server -Xmx3550m -Xms3550m -Xmn1256m -Xss128k -XX:SurvivorRatio=6 -XX:MaxPermSize=256m -XX:ParallelGCThreads=8 -XX:MaxTenuringThreshold=0 -XX:+UseConcMarkSweepGC

调优说明:




  •  
  • Xmx3550m -Xms3550m 相同避免每次垃圾回收后,jvm重新申请内存,-Xmx的大小约为系统内存的一半大小,充分利用了系统资源,又给予系统安全运行必要的内存空间。


     
  • -Xmn设置为1256m,此值对系统性能影响比较大,Sun官方建议设置年轻代大小为整个堆的3/8,-Xmn/-Xmx约等于3/8。


     
  • -Xss设置为128K,设置较小的线程栈,以支持创建更多的线程,支持海量访问,并提高系统性能。


     
  • -XX:SurvivorRatio设置为6,表示堆内存的年轻代中的2个Survivor区与Eden区的比值为2/6,一个Survivor区占整个年轻代内存大小的1/8。官方默认设置比值为8。


     
  • -XX:ParallelGCThreads=8,表示配置并行收集器的个数为8个,即同时8个线程一起执行垃圾回收。此值一般设置成跟CPU数目相等。


     

高性能数据处理的工具应用

服务器配置:1 CPU, 4G MEM, JDK 1.6.X

参数方案:

-server -XX:PermSize=196m -XX:MaxPermSize=196m -Xmn320m -Xms768m -Xmx1024m

调优说明:




  •  
  • -XX:PermSize=196m -XX:MaxPermSize=196m 大规模的系统编译可能需要加载大量的java类到内存中,所以需要预先分配好大量的持久代内存是高效和必要的。


     
  • -Xmn320m 等于-Xmn320m = -XX:NewSize = -XX:MaxNewSize = 320m;遵循年轻代大小为3/8


     
  • -Xms768m -Xmx1024m根据系统大致配置能够承受的堆内存大小设置即可。


     

6、JVM调优

查看堆内存空间大小(年轻代、老年代、持久代分配)

垃圾回收监控(长时间监控回收情况)

线程信息监控:系统线程数量

线程状态监控:各个线程都处在什么样的状态下

线程详细信息监控:查看线程内部运行情况,死锁检查

CPU热点:检查系统哪些方法占用大量的CPU时间

内存热点:检查哪些对象在系统中数量最大

7、JAVA类的生命周期

java类从被加载到虚拟机中开始,知道卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载,七个阶段。

8、性能优化的几个方式

1、SQL优化(常用到)

2、java代码优化

3、前端代码优化

4、JVM优化

5、tomcat/jboss等中间件优化

sql优化

1、索引的优化




  •  
  • 只要列中含有null值,就最好不要在此列设置索引


     
  • 尽量使用短索引,如果可以,应该制定一个前缀长度


     
  • 对应经常在where字句使用的列,最好设置索引,这样会加快查找速度


     
  • 尽量不要在列上进行运算(函数操作与表达式操作)


     
  • 尽量不要使用not in和<>操作


     

2、SQL语句的优化




  •  
  • 查询时,能不要就不要写,尽量写全字段名


     
  • 大部分情况连接效率远大于子查询


     
  • 多表连接时,尽量小表驱动大表,即小表join大表(小表数据量小,循环查询次数比大表的循环查询次数少,查询次数为表数据行数)


     
  • 在千万级分页时使用limit


     
  • 对于经常使用的查询,可以开启缓存


     

3、表的优化




  •  
  • 表的字段尽可能用NOT NULL


     
  • 字段长度固定的表查询速度会更快


     
  • 海量数据情况,大表按时间或按一定标志分为小表


     
  • 将表分区


     

java代码优化

1、及时清除不再使用的对象,设为null

2、尽量使用原始类型和栈


Integer i = 888; //存储在堆上

int i = 999; //存储在栈上

//使用数组时情况可能会变得更糟糕

Integer[] i = {122,32342}; //在堆上生成3个对象

int[] i = {122,32342}; //仅在堆上生成一个对象

//应该极力避免使用包装类,这样做的坏处是创建了很多对象,给GC带来非常大的压力,GC将会为清楚包装类生成的对象忙得不可开交。所以一个有效的优化方法是使用基本数据类型,定长数组,并用一系列分隔变量来标识对象在数组所处的位置

3、使用带缓冲的输入输出流来进行IO操作,带缓冲的输出流:即 BufferedReader、BufferedWriter、BufferedInputStream,这可以极大的提升IO效率。

4、不要让public方法中有太多的形参,形参多了可以考虑封装一个实体类

5、使用数据库连接池和线程池。这两个池都是可重用对象的,前者可以避免频繁的打开和关闭连接,后者可以避免频繁的创建和销毁线程。

6、乘法和除法使用移位操作


for(val = 0; val <10000;v ++){

  a = val * 8;

  b = val / 2;

}

//使用 移位操作可以极大提高新能,因为在计算机底层,对位的操作是最方便的最快的,因此建议修改为:

  for(val = 0; val <10000;v ++){

  a = val << 3;

  b = val >> 1;

}

//左移一位乘2,右移一位除于2。移位操作虽然快,但是可能会使代码不太好理解,最好加上相应的注释

7、当复制大量数据时,使用System.arraycopy()方法。

8、尽量重用对象,特别是String对象的使用,由于java虚拟机不仅要花费时间来生成对象,以后还需要花费时间将这些对象进行垃圾回收和处理,因此生成过多的对象会对系统的性能造成很大的影响。

代码优化的目标是:

1、减小代码的体积

2、提高代码的运行效率

前端优化

1、减少http请求次数,如将多个js文件合并成一个,这样就只需要引用一个

2、文件压缩,包括js、css、图片资源等

3、缓存ajax,使用懒加载等技术

3、减少iframe数量

4、对图片等资源可以考虑使用CDN技术、Gzip压缩传输文件,避免空的图片src

5、减少cookie大小

6、将脚本置底、使用外部js和css文件

7、减少DOM访问

9、JAVA中常用的设计模式

1、单例模式

单例模式有以下几个特点




  •  
  • 单例类只能有一个实例


     
  • 单例类必须自己创建自己的唯一实例


     
  • 单例类必须给其他所有实例创建这一实例


     

// 1、懒汉示单例类,在第一次调用的时候实例化自己,这个方法需要将构造函数私有化,防止外部实例化这个类。不过懒汉式单例类线程不安全,并发环境下也许存在多个singleton的情况

public class Singleton{

  private Singleton(){};

  private static Singleton single = null;

  //静态工厂方法

  public static Singleton getInstance(){

    if(single == null){

      single = new Singleton();

    }

    return single;

  }

}

// 2、在getInstance()方法上加同步

  public static synchronized Singleton getInstance(){

    if(single == null){

      single = new Singleton();

    }

    return single;

  }

// 3、双重检查

public static Singleton getInstance(){

    if(single == null){

      synchronized(Singleton.class){

        if(single == null){

          single = new Singleton();

        }

      }

    }

    return single;

  }

// 4、静态内部类方式创建单例,这种方式既实现了线程安全,又避免了同步带来的性能损失。java机制规定,内部类LazyHolder只有再第一次调用getInstance()方法时才会被加载,而且加载过程是线程安全的。

public class Singleton{

    private static class LazyHolder{

      private static final Singleton INSTANCE = new Singleton();

    }

    private Singleton(){}

  

    public static final Singleton getInstance(){

      return LazyHolder.INSTANCE;

    }

}

// 5、饿汉示,在类创建的同时就已经创建好了一个静态的对象供给系统使用,以后不再改变,因此天生是线程安全的

public class Singleton{

  private Singleton(){}

  

  private static final Singleton single = new Singleton();

  

  public static Singleton getInstance(){

    return single;

  }

  

}

2、工厂模式

工厂模式的两种情况:




  •  
  • 在编码时不能预见需要创建哪些类的实例


     
  • 系统不应该依赖于产品类实例如何被创建、组合和表达的细节


     

3、建造者模式

该模式其实就是说,一个对象的组成可能有很多其他的对象一起组成,比如说,一个对象的实现非常复杂,有很多属性,而这些属性又是其他对象的引用,可能这些对象的引用又包括很多其他对象的引用,封装这些复杂性,就可以使用建造模式。

10、Collection集合

集合类继承图

Collection主要方法:

boolean add(Object o) 添加对象到集合

boolean remove(Object o) 删除指定的对象

int size() 返回当前集合元素的数量

boolean contains(Object o) 查找集合内是否有指定的对象

boolean isEnpty() 判断集合是否为空

Iterator iterator() 返回一个迭代器

boolean containsAll(Collection c) 查找集合内是否有集合c中的元素

boolean addAll(Collection c) 将集合c所有的元素添加给该集合

void clear() 删除集合内所有的元素

void removeAll(Collection c) 从集合内删除c集合也有的元素

void retainAll(Collection c) 从集合中删除集合c中不包含的元素

List、主要子接口对象

list都是可重复有序的

||-LinkedList没有同步方法

||-ArrayList非同步的

|-Vector(同步)非常类似ArrayList,但是它是同步的,这个是最大的区别,Vector类的大多数公开方法都用synchronized声明过,所以是同步的

Set、不包含重复的元素

Map

map没有继承Collection接口,map提供key到value的映射

几个主要的方法:

boolean equals(Object o) 比较对象

boolean remove(Object o) 删除一个对象

put(Object key , Object value) 添加一个key和value

|-HashTable 任何非空( non-null ) 的对象。同步的

|-HashMap 可空的对象,不同步,但是效率高。

SortedMap —— TreeMap

总结:

a、如果涉及到堆栈,队列(先进后出)等操作,应该考虑List,对于需要快速插入,删除元素,应该使用LinkedList。如果需要快速随机访问元素,则使用ArrayList.

b、尽量返回接口而非实际的类型,如返回List而不是返回ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端就不用改代码,这就是针对接口编程。

几个常见的面试问题

1、ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?

答:Vector和HashTable是线程同步的,大部分的public方法都是synchronized修饰了的。性能上ArrayList和HashMap比较优秀。单线程或操作不影响数据的使用非同步的比较好。

2、大致讲解java集合的体系结构

答:List、Set、Map是集合体系中最主要的三个接口。其中List和Set继承自Collection接口。

Set不允许数据重复,HashSet和TreeSet是两个主要的实现类

List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类

Map也属于集合系统,但和Collection接口不通,map是key对value的映射集合,其中key列就是一个集合,key不能重复,但是value可以重复,hashMap、TreeMap、HashTable是三个主要的实现类。SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序。

3、为什么集合类没有实现Cloneable和Serializable接口?

答:因为接口类指定了一组叫元素的对象,集合类接口的每一种具体的实现类都可以选择它自己的方式对元素进行保存和排序,有的集合允许重复的键,有些不允许。克隆或者是序列化的语义和含义是跟具体的实现相关的,因此应该由集合类的具体实现来决定如何被克隆或者是序列化。

4、什么是迭代器(Iterator)

答:Iterator接口提供了很多对集合元素进行迭代的方法,每一个集合类都包含了可以返回迭代器实例的迭代方法,迭代器可以在迭代的过程中删除底层集合的元素,安全。Iterator迭代器是工厂模式设计的,不同的集合返回对应的实例。

5、快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?

Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响,java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器则不会抛出这样的异常。

6、hashMap的工作原理是什么

java中的hashMap是以键值对的形式存储元素的。hashmap需要一个hash函数,它使用hashCode()和equals()方法来向集合或从集合添加和检索元素。

当调用put()方法的时候,hashMap会计算key的hash值,然后把键值对存储在集合中合适的索引位置上。如果key已经存在,value值会被更新成新值,get()方法同理。

7、hashCode()和equals()方法的重要性体现在什么地方?

java中的hashMap通过hashCode()和equals()方法来确定键值对的索引,当用put()或get()方法时,如果没有正确的实现这两个方法,两个不同的键值对可能会有相同的hash值,因此可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素,所以这两个方法的实现对hashMap的精确性和正确性相当重要。

8、ArrayList和LinkedList有什么区别?

两者都实现List接口,他们有以下不同点:

数据结构上:

ArrayList是基于索引的数组形式,可随机访问

LinkedList是元素列表的形式存储它的数据,每一个元素都和他的前一个和后一个元素链接在一起

操作上:

ArrayList添加、删除操作比较慢,需要重新计算大小或者更新索引

LinkedList的插入、删除操作比较快,不需要更新索引

内存上:

LinkedList更占用内存,因为每个LinkedList为每个节点存储了两个引用,一个指向前一个元素,一个指向后一个元素

9、集合类跟数组array的区别

数组特点:大小固定,只能存储相同类型的数据

集合特点:大小可动态扩展,可以存储不同类型的数据

转换:

将数组转换为集合:Arrays.asList(数组); 这里注意当数组元素是数字时需要将数字封装成包装类才能转换

将集合转换为数组:集合.toArray();

示例:


        //数组转换成集合

        int[] arr = {1,2,3,4,5};

        int size = arr.length;

        Integer[] integers = new Integer[size];

        for (int i = 0;i<size;i++){

            Integer ii = arr[i];

            integers[i] = ii;

        }

        List list =  Arrays.asList(integers);

        //集合转换成数组

        List list = new ArrayList();

        list.add("a");

        list.add("b");

        String[] strs = list.toArray();

遍历map的方式

a、最常规的一种遍历方法,最常规也就是最常用的,虽不复杂但是很重要


public static void work(Map<String, Student> map) {

    Collection c = map.values();

  

    Iterator it = c.iterator();

    

    for(;it.hasNext();){

      System.out.println(it.next()); 

    }

}

b、根据keySet进行遍历,它的有点在于可以根据你所想要的key值得到你想要的values,更具灵活性


public static void workByKeySet(Map<String, Student> map) {    

    Set keys  = map.keySet();

    for(Iterator i = keys.iterator();i.hasNext();){

      String key = (String)i.next();

      System.out.println(map.get(key)); 

    }

}

c、比较复杂的一种遍历在这里,暴力,它的灵活性太强了。想得到什么就能得到什么,这种效率比较高


public static void workByEntry(Map<String, Student> map) { 

    Set<Map.Enter<String, Student>> set = map.entrySet();

  for (Map.Entry<String, Student> me : set) {    

    

        System.out.println(me.getKey() + "—>" + me.getValue());    

    }     

}

11、java异常分类和常见的几个异常




  •  
  • Error


     
  • Runtime Exception运行时异常


     
  • Exception


     
  • throw 用户自定义异常


     

异常类分为两大类型:

1、Error类代表编译和系统的错误,不允许捕获;

2、Exception代表标准的java库激发出的异常,Exception包含运行时异常和非运行时异常两个直接的子类

运行时异常对应于编译错误,它是指java程序在运行时产生的由解释器引发的各种异常。异常可能出现在任何地方,且出现频率很高,因此为了避免巨大的系统资源开销,编译器不对运行时异常进行检查,所以java语言中的运行异常不一定被捕获,出现运行错误往往表示代码有错误,如:算数异常(如被0除)、下标异常(如数组下标越界)等。

非运行异常时Non_RuntimeException类及其子类的实例,又称为可检测异常。Java编译器利用分析方法或构造方法中可能产生的结果来检测Java程序中是否含有检测异常的处理程序,对于每个可能的可检测异常,方法或构造方法的throws子句必须列出该异常对应的类。在Java的标准包java.lang java.util 和 java.net 中定义的异常都是非运行异常。

常见异常:

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

文件已结束异常:EOFException

字符串转换为数字异常:NumberFormatException

操作数据库异常:SQLException

输入输出异常:IOException

方法未找到异常:NoSuchMethodException

java.lang.IllegalAccessError:违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常。

java.lang.NoClassDefFoundError

未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。

java.lang.OutOfMemoryError

内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。

java.lang.StackOverflowError

堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。

12、jvm运行机制

1、java源码使用javac编译成*.class文件(字节码文件)

2、类加载

3、类执行


转载:https://www.cnblogs.com/linjianqing/p/8494687.html

推荐内容:
100道Java基础面试题
图解Java常用数据结构(一)
2019 Java面试题
ERP不规范,同事两行泪
上周面试回来后写的Java面试总结,想进BAT必看
面试 10:玩转 Java 选择和插入排序,附冒泡最终源码
208道最常见的Java面试题整理(面试必备)
JAVA基础总结【面试】
两道面试题,带你解析Java类加载机制
Java面试题——中级(下)

猜你喜欢

转载自blog.csdn.net/bee_wa/article/details/89419431
今日推荐