Java面试题总结

来源:互联网 发布:淘宝免费店招图片 编辑:程序博客网 时间:2024/05/16 04:18

Java面试题总结

1、java八种基本数据类型的大小、以及它们的封装类.

答:byte(Byte) : 8位,short(Short) : 16位, int(Integer):32位, long(Long):64位 , float(Float) 32位, double(Double):64位, char(Char) 16位, boolean(Boolean) 1位;

2、Switch能否用String做参数?
答:可以,Switch支持byte、short、char、int、enum、String(1.7支持)作为参数。

3、equals与==的区别?
答:首先“==”是运算符,而equals是方法。“==”比较的是两个对象的地址是否相同,equals默认比较的也是地址。但String、Integer的equals的方法被重写,用来比较两个对象的值是否相同。

4、Object有哪些公有方法?
答:equals(比较两个对象地址是否相同)、hashcode(用来查找对象的地址)、getClass(获得对象的类)、wait、notify、notifyAll(线程间通信)、finallize(对象被销毁之前会调用该方法,使用该方法不代表一定会被JVM回收)、toString、clone

5、Java的四种引用、各自的应用场景
答:首先明确java提供这四种引用的目的:
(1)可以让程序员通过代码的方式决定某些对象的生命周期
(2)有利于JVM进行回收
强引用:指创建一个对象,并把该对象赋给一个应用变量
例如:Object o = new Object();
    String str = "hello world"

  强引用的对象不会被JVM回收
软引用:如果一个对象被软引用,只要有足够的内存空间,就不会被回收
  软引用可用来实现图片缓存,网页缓存,还能防止内存泄漏
弱引用:弱引用用来描述非必须对象,无论内存是否充足都有可能被回收
虚引用:不影响对象的生命周期、对象就跟没有引用一样
http://www.cnblogs.com/huajiezh/p/5835618.html

6、HashCode的作用?
答:HashCode使用来方便查找对象的,两个对象如果相同(即用equals比较返回true),则hashcode一定相同。如果equals方法被重写,hashcode也要重写。如果两个hashcode相同,则两个对象不一定相同。类比HashMap查找key的过程。

7、ArrayList、LinkedList、Vector的区别。
答:ArrayList是基于动态数组实现的(线程不安全),LinkedList是双向链表(线程不安全),vector是数组容器(线程安全)
  对于ArrayList,在多线程情况下可以使用Collections.synchronizedList返回一个线程安全的ArrayList类,或者使用concurrent包下的CopyOnWriteArrayList类。ArrayList的初始容量为10,超出的话会扩容(变为原始容量的1.5倍+1),扩容时会将老的元素拷贝到新的数组中,这样比较耗费资源,因此在使用ArrayList时最好指定初始容量大小,这样能避免多次扩容。

8、String、StringBuffer与StringBuilder的区别。
答:String是字符串常量、StringBuffer是字符串变量(线程安全)、StringBuilder是字符串变量(线程不安全)
  执行速度上,StringBuilder > StringBuffer > String
  为什么String执行速度慢呢?因为String是定义为final的,即不可变的,String添加子串的时候,会在常量池重新生成一个String。
  例如:
 
  String s= "ABC";
  s += "abc";

  如果要操作少量的数据用 String。
  单线程操作字符串缓冲区下操作大量数据 StringBuilder。
  多线程操作字符串缓冲区下操作大量数据 StringBuffer。
 
9、Collection包结构,与Collections的区别?
答:Collection包的结构如下图:
这里写图片描述
Collections是一个工具类,服务于Java集合框架,不能实例化
Collections的常用方法有:sort() binarySearch() shuffle() min() max() copy() fill()

10、HashMap与HashTable的区别?
答:HashMap根据键的HashCode存储数据,线程不安全、允许null键和值、初始容量为16,负载因子为0.75,扩容之后为之前的两倍。JAVA1.8的HashMap是基于数组+链表+红黑树实现的,当链表长度大于8时,转变为红黑树。
  HashTable功能与HashMap相同,但是任一时间只能有一个线程访问HashTable,并发性能不如ConcurrentHashMap,在单线程情况下使用HashTable、多线程情况下使用ConcurrentHashMap。
  详见:Java8系列之重新认识HashMap

11、TreeMap、HashMap、LinkedHashMap的区别。
答:TreeMap的key值是默认升序排列的,可以指定排序规则。HashMap默认无序排列,LinkedHashMap按照插入的顺序排列

12、try catch finally,try里有return,finally还执行么?
答:1、不管有木有出现异常,finally块中代码都会执行;
  2、当try和catch中有return时,finally仍然会执行;
  3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
  4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

13、Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
答:
情况一:
  Java.lang.OutOfMemoryError: Java heap space 堆内存不够、或者程序中有死循环。
如果是java堆内存不够的话,可以通过调整JVM下面的配置来解决:
  < jvm-arg>-Xms3062m < / jvm-arg>
  < jvm-arg>-Xmx3062m < / jvm-arg>
  (-Xms调整初始堆大小 ,-Xmx调整最大堆大小)
  详见JVM调优总结
  
情况二:
  java.lang.OutOfMemoryError: GC overhead limit exceeded
【解释】:JDK6新增错误类型,当GC为释放很小空间占用大量时间时抛出;一般是因为堆太小,导致异常的原因,没有足够的内存。
  【解决方案】:
  1、查看系统是否有使用大内存的代码或死循环;
  2、通过添加JVM配置,来限制使用内存:
  < jvm-arg>-XX:-UseGCOverheadLimit< /jvm-arg>
  
情况三:
  java.lang.OutOfMemoryError: PermGen space:这种是P区内存不够,可通过调整JVM的配置:
  < jvm-arg>-XX:MaxPermSize=128m< /jvm-arg>
  < jvm-arg>-XXermSize=128m< /jvm-arg>
  【注】:
  JVM的Perm区主要用于存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space,这个区域成为年老代,GC在主程序运行期间不会对年老区进行清理,默认是64M大小,当程序需要加载的对象比较多时,超过64M就会报这部分内存溢出了,需要加大内存分配,一般128m足够。
  
情况四:
  java.lang.OutOfMemoryError: Direct buffer memory
  调整-XX:MaxDirectMemorySize= 参数,如添加JVM配置:
  < jvm-arg>-XX:MaxDirectMemorySize=128m< /jvm-arg>

情况五:
  java.lang.OutOfMemoryError: unable to create new native thread
  【原因】:Stack空间不足以创建额外的线程,要么是创建的线程过多,要么是Stack空间确实小了。
  【解决】:由于JVM没有提供参数设置总的stack空间大小,但可以设置单个线程栈的大小;而系统的用户空间一共是3G,除了Text/Data/BSS /MemoryMapping几个段之外,Heap和Stack空间的总量有限,是此消彼长的。因此遇到这个错误,可以通过两个途径解决:
  1.通过 -Xss启动参数减少单个线程栈大小,这样便能开更多线程(当然不能太小,太小会出现StackOverflowError);
  2.通过-Xms -Xmx 两参数减少Heap大小,将内存让给Stack(前提是保证Heap空间够用)。

【情况六】:
  java.lang.StackOverflowError
  【原因】:这也内存溢出错误的一种,即线程栈的溢出,要么是方法调用层次过多(比如存在无限递归调用),要么是线程栈太小。
  【解决】:优化程序设计,减少方法调用层次;调整-Xss参数增加线程栈大小。

14、interface与abstract类的区别。
答:一个类可以实现多个interface,但却只能继承一个abstract类。interface定义了一种行为规范,强调特定功能的实现,abstract类定义了事物的本质,强调的是事物的关系,两者都不可实例化。
详见:abstract class和interface的区别

15、锁的等级
方法锁、对象锁、类锁
对象锁使用synchronized修饰方法,或者修饰this,例如:

public class DemoClass{    public synchronized void demoMethod(){}}

或者

public class DemoClass{    public void demoMethod(){        synchronized (this)        {            //other thread safe code        }    }}

或者

public class DemoClass{    private final Object lock = new Object();    public void demoMethod(){        synchronized (lock)        {            //other thread safe code        }    }}

类锁修饰静态方法,或者直接修饰类名.class
例如:

public class DemoClass{    public synchronized static void demoMethod(){}}

或者

public class DemoClass{    public void demoMethod(){        synchronized (DemoClass.class)        {            //other thread safe code        }    }}

或者

public class DemoClass{    private final static Object lock = new Object();    public void demoMethod(){        synchronized (lock)        {            //other thread safe code        }    }}

详见:对象级别锁 vs 类级别锁 – Java

16、写出生产者消费者模式
答:使用notify、wait实现
要注意,wait要在while里面使用

public class Main {    public static void main(String args[]) throws InterruptedException {        int maxSize = 10;        Queue<Integer> queue = new LinkedList<>();        Producer1 producer1 = new Producer1(queue,maxSize,"Producer1");        Consumer1 consumer1 = new Consumer1(queue,maxSize,"Consumer1");        producer1.start();        consumer1.start();    }}class Producer1 extends Thread {    private Queue<Integer> queue;    private int maxSize;    public Producer1(Queue<Integer> queue, int maxSize, String name) {        super(name);        this.maxSize = maxSize;        this.queue = queue;    }    public void run() {        while (true) {            synchronized (queue) {                while (queue.size() == maxSize) {                    try {                        queue.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                int i = new Random().nextInt();                queue.add(i);                queue.notifyAll();            }        }    }}class Consumer1 extends Thread {    private Queue<Integer> queue;    private int maxSize;    public Consumer1(Queue<Integer> queue, int maxSize, String name) {        super(name);        this.maxSize = maxSize;        this.queue = queue;    }    public void run() {        while (true) {            synchronized (queue) {                while (queue.isEmpty()) {                    try {                        queue.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                queue.remove();                queue.notifyAll();            }        }    }}

17、ThreadLocal的设计理念与作用
答:
它是一种线程局部变量,即给在每个线程上分配一个局部变量的副本,这样每个线程都可独立更改各自的变量而互不影响。ThreadLocal类是使用Map来存放值的。
ThreadLocal的应用场景:用来解决数据库连接和Session管理等。
详见:Java并发编程:深入剖析ThreadLocal

18、ThreadPool用法与优势。
答:线程池减少了创建和销毁线程的次数,每个工作线程都可以重复利用,可执行多个任务,有四种线程池:
  1. newSingleThreadExecutor
 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
  2.newFixedThreadPool
 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
  3. newCachedThreadPool
 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。这个线程池看起来比较完美,能够只能调整线程池大小,并且回收空闲线程
  4.newScheduledThreadPool
 创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

19、Concurrent包的内容
答:
主要包括
参见: Java 并发工具包 java.util.concurrent 用户指南

20、wait和sleep的区别
答:执行wait之后,会放弃同步锁,进入等待队列,可由notify唤醒,唤醒之后状态变为可运行状态,等待cpu时间片(注意:wait和notify要在synchronized中使用)。sleep执行之后不会放弃同步锁。

21、foreach与for效率比较
答:需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问比较好。
  需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃。】
详情见链接:for遍历和foreach遍历的性能比较
  为什么使用迭代器iterator遍历Linkedlist要比普通for快

22、反射的作用与原理
答:反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象都能调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能成为java语言的反射机制。
  获取Class的三种方法

    Car car = new Car();    Class cls1 = car.getClass();    Class cls2 = Car.class;    Class cls3 = Class.forName("类的全名称")

通过反射可以获取类中所有的信息,包括方法名、返回值和方法参数
例如:

Class c = obj.getClass();System.out.println("类的名称是:" + c.getName());Method[] methods = c.getMethods();for(int i = 0; i < methods.length; i++) {    Class returnType = methods[i].getReturnType();    System.out.print(returnType.getName() + " ");    System.out.print(methods[i].getName() + "(");    Class[] parameterizedTypes = methods[i].getParameterTypes();    for(Class c1 : parameterizedTypes) {        System.out.print(c1.getName() + ",");    }    System.out.println(")");}

方法的反射:method.invoke(对象,参数列表)

23、java1.8新特性
答:PermGen空间被移除,用Metaspace取代。
函数式接口、Lambda表达式等

原创粉丝点击