Java面试题收集

一、Java基础

1.java中==和equals的区别
基本数据类型:byte,short,char,int,long,float,double,boolean 他们用==比较的是他们的值。

复合数据类型: 当他们用==进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。

对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的。

2.什么时候需要重写equals()?
答:默认equals在比较两个对象时,是看他们是否指向同一个地址的。但有时,希望两个对象只要是某些属性相同就认为他们的quals为true。比如:Student s1 = new Student(1,“name”); Student s2 = new Student(1,“name”);如果不重写equals的话,他们是不相同的,因为引用s1和s2指向的堆内存地址显然不一样,所以我们要重些equals,判断只要他们的id和名字相同equals就为true,在一些集合里有时也这样用,集合里的contain也是用equals来比较的。

3.为什么重写了euqals需要重写hashCode()?
答:hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。如果我们对一个对象重写了euqals,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,导致混淆。同时还有一个重要的原因,我们都知道hash冲突是怎么解决的,用散列表!如果两个对象对应的hashCode相同,那么冲突的对象自然是放在后面的链表上面。

4.final关键字的基本用法

  • 修饰类:当用final修饰一个类时,表明这个类不能被继承
  • 修饰方法:表示该方法不能被覆盖
  • 修饰变量:如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象

5.接口和抽象类有什么区别

  • 接口和抽象类都不能实例化对象
  • 抽象类可以有构造器,接口不能有构造器
  • 抽象类有默认的方法实现,接口完全是抽象,不存在方法的实现
  • 抽象类可以有静态代码块和静态方法,接口中不能含有静态代码块以及静态方法
  • 抽象方法可以有public、protected和default这些修饰符(不能private,因为抽象方法要被子类覆写);但是,成员方法(非抽象方法)和成员属性可以是private
  • 接口中的变量会被隐式地指定为public static final变量(并且只能是public static final常量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中的方法必须都是抽象方法,即所有方法都必须只有方法名,没有方法体。

6.重载和重写的区别? 子类可以重载父类的方法吗?
override(重写)

  • 方法名、参数、返回值相同。
  • 子类方法不能缩小父类方法的访问权限。
  • 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
  • 存在于父类和子类之间。
  • 方法被定义为final不能被重写。

overload(重载)

  • 参数类型、个数、顺序至少有一个不相同。
  • 不能重载只有返回值不同的方法名。
  • 存在同类中,是一个类中多态性的一种表现。

子类不可以重载父类的方法,只能重写。

1.ArrayList和LinkedList的区别?

  • ArrayList是一个动态的数组结构,而LinkedList是双向链表结构;
  • 随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针;
  • 插入/删除数据时,ArrayList的开销就比LinkedList更大,因为对于ArrayList,插入/删除一个数据时需要移动其后所有数据,而LinkedList只需要修改几个指针即可。

ArrayList和LinkedList的区别

2.ArrayList是怎么扩容的?
发生扩容的条件:根据传入的最小需要容量minCapacity来和数组的容量长度对比,若minCapactity大于或等于数组容量,则需要进行扩容。(如果实际存储数组是空数组,则最小需要容量就是默认容量)

在JDK1.7中,如果通过无参构造的话,初始数组容量为0,当真正对数组进行添加时,才真正分配容量(默认10)。每次按照1.5倍(位运算)的比率通过copeOf的方式扩容。

在JKD1.6中,如果通过无参构造的话,初始数组容量为10.每次通过copeOf的方式扩容后容量为原来的1.5倍加1

2.HashMap是怎样的结构?工作原理是什么?退化成链表解决方法?
答:HashMap的本质仍然是数组,不过数组中存储的不是数据,而是一个链表的头节点。所以准确的说,其实现就是链表数组。HashMap中保存的是一个键值对,插入对象时必须提供一个键对象;查找对象时必须给定一个键对象(因此必须记住键)。键对象时不允许重复的,但是允许null空键的存在。
HashMap插入对象时,根据给定的键key计算hashcode,然后再与数组长度进行求余运算得到数组下标。然后与该位置上的链表中已存储的键进行比较,对于已存在的键,则覆盖;对于不存在的键,则添加到链表尾。

HashMap工作原理:

HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用LinkedList来解决碰撞问题,当发生碰撞了,对象将会储存在LinkedList的下一个节点中。 HashMap在每个LinkedList节点中储存键值对对象。
当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的LinkedList中。键对象的equals()方法用来找到键值对。 key对象相同则覆盖,hashcode相同则添加到链表尾。

退化成链表解决方法?
JDK7中确实会有这样的问题,因为链表法有这样的缺陷。但是在JDK8中,Java会在链表长度超过一个阙值的时候将链表升级为一个平衡二叉树,使用hashcode作为树的分支变量,较大的会插入到右子树中;hashcode相等的情况下,HashMap希望Key对象是实现了Comparable接口的,这样就可以按照顺序插入。
键对象的选择->选择String对象作为键对象最好,因为String具有不可变性。

ConcurrentHashMap总结
Java集合—ConcurrentHashMap原理分析

JAVA集合

  • Map接口:hashMap和treeMap
    • HashMap:Hash表无序,不能放重复键,允许放Null key 和Null value,方法不是Synchronize的要提供外同步
    • TreeMap:数据结构是树,有序
    • 遗留集合:
      • HashTable:不能放重复键,不允许放Null key 和Null value,继承于Dictionary,方法是是Synchronize的
  • Collection接口:List和Set
    • 可添加重复键
    • List接口:ArrayList和linkedList
      • ArrayList:数据结构是数组,在内存中是连续的,可以随机访问,线程不安全,每次长度增长50%
      • LinkedList:数据结构是链表,插入、删除更快
      • Vector:类似ArrayList,线程安全,速度比ArrayList慢,每次长度增长一倍
    • Set接口: HashSet和TreeSet
      • 不可添加重复键,无法随机访问,只能用迭代器遍历
      • HashSet:底层数据结构是哈希链表,保证元素唯一,但不保证元素顺序不变,使用equals()和hashCode()保证元素的唯一性
      • TreeSet:底层数据结构是二叉树,保证元素唯一,并对元素按自然顺序进行排序,继承Comparator接口实现compare()进行排序或继承Comparable接口实现compareTo()实现排序

二、操作系统

1.同步和异步
同步::所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

异步:将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

异步操作例子:为了避免短时间大量的数据库操作,就使用缓存机制,也就是消息队列。先将数据放入消息队列,然后再慢慢写入数据库。

引入消息队列机制,虽然可以保证用户请求的快速响应,但是并没有使得我数据迁移的时间变短(即80万条数据写入mysql需要1个小时,用了redis之后,还是需要1个小时,只是保证用户的请求的快速响应。用户输入完http url请求之后,就可以把浏览器关闭了,干别的去了。如果不用redis,浏览器不能关闭)。

同步操作例子:银行的转账功能

2.什么是进程、什么是线程?进程和线程有什么区别?

  • 进程是某个程序在某个数据集上的一次活动,是系统资源分配的最小单位。
  • 线程是进程的一个实体,是系统进行调度的最小单位;
  • 线程基本不拥有资源,它与其他线程共享进程的资源。

3.什么是死锁?死锁产生的原因?
答:死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。1.系统资源的竞争导致系统资源不足,以及资源分配不当,会导致死锁。2. 进程在运行过程中,请求和释放资源的顺序不当,也会导致死锁。

4.死锁产生的四个必要条件

  • 互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
  • 不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
  • 请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
  • 循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。

以上给出了导致死锁的四个必要条件,只要系统发生死锁则以上四个条件至少有一个成立。事实上循环等待的成立蕴含了前三个条件的成立,似乎没有必要列出然而考虑这些条件对死锁的预防是有利的,因为可以通过破坏四个条件中的任何一个来预防死锁的发生。

线程安全是什么意思?
说出final,finalize,finally的区别?
列举你常用的几个Java工具类。
HashMap与HashSet哪个更快?它们有什么不同?

1.代理模式的适用场景?
答:所谓代理模式,即为一个对象创建一个代理,以控制对这个对象的访问。
使用代理的两种场景:

  • 控制访问权限,不同用户对同一对象拥有不同的访问权限
  • 某个客户端不能直接操作到某个对象,却又必须与其进行交互

Java IO中的设计模式:装饰模式和适配器模式

三、数据库基础

1.事务的四个特性
答:事务,是应用程序中一系列严密的操作,所有操作必须全部完成,否则在每个操作中的更改都会被撤销。也就是说,一个事务中的所有操作要么全部执行,要么全不执行。
四个特性:ACID

  • A:原子性,事务是数据库的逻辑工作单位,事务中包含的操作,要么都做,要么都不做。
  • C:一致性,事务执行的结果必须是使数据库从一个一致性状态到另一个一致性状态。
  • I :隔离性,一个事务的执行不能干扰其他事务。
  • D:持续性,也即永久性,指的是一个事务执行后对数据库数据的更改是永久性的。

2.什么是索引?

3.sql语句in和exists的区别?
如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。

在mapper文件中#{}和${}有什么区别?

四、框架

1.Spring中bean的作用域与生命周期

2.SpringMVC的拦截器和过滤器
过滤器:依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码。

拦截器:依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后

3.SSM框架原理,作用及使用方法

五、JVM

1.Java的垃圾回收机制是怎样的?回收的是什么样的对象?
答:Java垃圾回收器实现对堆内存数据的自动回收,无需程序员显式地调用delete放啊。Java的垃圾自动回收机制有效地避免了因为程序员忘记释放内存而造成的内存溢出错误。
Java使用被称为垃圾收集器的技术来监视Java程序的运行,当对象不再被使用时,即不再被引用时,就会自动释放对象所占用的内存。Java使用一系列软指针来跟踪对象的各个引用,这些软指针并不直接指向对象,而是指向对象的引用。通过软指针,Java的垃圾收集器能够以单独的线程在后台运行,并不时检查每个对象的引用。
调用System的静态方法gc()可以运行垃圾收集器,但是并不能保证立即回收指定对象。(这就是建议回收,不能强迫回收。)
finalize()方法可以终止一个对象来释放资源,调用之后对象不再被引用,就会被回收。

2.GC什么时候开始?
答:GC 经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个 Eden 区和两个 Survivor 区。

首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然有放不下的对象,就将这些对象放入老年代内存里去。因为 Java 大多数对象都是朝生夕灭,所以 Minor GC 非常频繁,而且速度也很快;

Full GC,发生在老年代的 GC,当老年代没有足够的空间时即发生 Full GC,发生 Full GC 一般都会有一次 Minor GC。

大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个;XX:PretenureSizeThreadhold 参数,令大于这个参数值的对象直接在老年代中分配,避免在 Eden 区和两个 Survivor 区发生大量的内存拷贝;

发生 Minor GC 时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次 Full GC,如果小于,则查看 HandlePromotionFailure 设置是否允许担保失败,如果允许,那只会进行一次 Minor GC,如果不允许,则改为进行一次 Full GC。

3.我调用System.gc()能保证GC一定发生吗?
答:System.gc()用于调用垃圾收集器,在调用时,垃圾收集器将运行以回收未使用的内存空间。它将尝试释放被丢弃对象占用的内存。然而System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。

JVM 类加载机制详解
Java类加载器总结
深入理解Java:类加载机制及反射
Java的内存泄漏

4.什么是堆内存?什么是栈内存?有什么区别?
答:Java的内存空间分为堆内存和栈内存。栈内存用于存储定义的基本类型变量、函数返回值、对象的引用等,而堆内存用于存放new出来的一切对象。

5.JVM运行时数据区

  • 虚拟机栈:这是线程私有的,生命周期与线程相同,存储局部变量,动态链接,方法,操作栈等,如果栈操作深度大于虚拟机所允许的深度,将抛出stackOverFlowError,如果栈申请不到足够的内存,将抛出outOfMemory
  • 本地方法栈:与虚拟机栈类似,但是所执行的是native方法(非java语言实现的方法)
  • 方法区:存放已被虚拟机加载后的类信息、常量和静态变量等数据,常量池中存放类的版本、字段、方法、接口等描述信息
  • Java堆:所有线程共享,存放对象实例
  • 程序计数器:当前线程所执行的字节码的行号指示器

IO字节流和字符流相互转换

http://blog.csdn.net/puppylpg/article/details/45620387

JAVA终止线程

http://blog.csdn.net/anhuidelinger/article/details/11746365

堆分区

http://www.cnblogs.com/WJ5888/p/4374791.html

垃圾回收的流程

http://jbutton.iteye.com/blog/1569746

数据库索引

这个问题面试官主要是问应该在什么字段建立索引。
答:在查询时经常使用的字段建立索引

窗口滑动

用于流量拥塞控制,窗口由接收方窗口决定,当接收方窗口大小未0时,已发送但未接收的数据将会被抛弃
TCP三次握手、为什么不是两次

http://blog.csdn.net/whuslei/article/details/6667471/

为什么不是两次握手是防止传送已失效数据
两个栈实现队列及优化

http://www.cnblogs.com/wanghui9072229/archive/2011/11/22/2259391.html

Synchronized和Lock的区别

2、多线程:怎么实现线程安全,各个实现方法有什么区别,volatile关键字的使用,可重入锁的理解,Synchronized是不是可重入锁
  这里我就主要讲了Synchronized关键字,还有并发包下面的一些锁,以及各自的优缺点和区别。volatile关键字我主要从可见性、原子性和禁止JVM指令重排序三个方面讲的,再讲了一下我在多线程的单例模式double-check中用到volatile关键字禁止JVM指令重排优化。
3、集合: HashMap底层实现,怎么实现HashMap线程安全
  我讲了一下HashMap底层是数组加单链表实现,Node内部类,add的过程,Hash冲突解决办法,扩容,三种集合视图。HashMap线程安全的实现方式主要讲了HashTable、ConcurrentHashMap以及Collections中的静态方法SynchronizedMap可以对HashMap进行封装。以及这三种方式的区别,效率表现。

6、HTTP有没有状态,我说无状态,怎么解决HTTP无状态
  怎么解决HTTP无状态其实就是怎么进行会话跟踪,有四种方法:URL重写、隐藏表单域、Cookie、Session。

5.尾递归是怎样的?与递归的比较?
答:尾递归,也即在尾部进行递归的一种递归形式,指的是在一次递归执行完毕,返回上一层之后,不在进行任何操作,也即在回归的过程中不做任何操作,且返回值不属于表达式的一部分。
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。编译器可以做到这点,因为递归调用是当前活跃期内最后一条待执行的语句,于是当这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率会变得更高。

8.什么是优先级队列?优先级队列有什么用?
答:优先级队列,因为一般用二叉堆来实现,因此又称为堆。它的每一个父节点的值都比孩子节点大(或者小)。它的工作是查找或者删除优先队列中的最大值(或最小值)

9.什么是二叉搜索树?
答:二叉搜索树,是一种特殊的二叉树,其每一个父节点的值都大于左孩子节点,且小于右孩子节点。
  
10、讲几个设计模式,哪些地方用到了,为什么要用
  单例模式,jdk中的getRuntime();工厂方法模式,ThreadPoolExcutor用到ThreadFactory;观察者模式:java.util包下面的Observable和Observer。最后主要讲了一下工厂方法模式的使用场景。
11、Mysql优化、索引的实现
  我从数据库设计优化和查询优化两方面讲的。索引B+树实现,InnoDB和MyISAM主键索引的实现区别,一个聚集一个非聚集。

TCP的优点: 可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。 TCP的缺点: 慢,效率低,占用系统资源高,易被攻击 TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

UDP的优点: 快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击…… UDP的缺点: 不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。 基于上面的优缺点,那么: 什么时候应该使用TCP: 当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。 在日常生活中,常见使用TCP协议的应用如下: 浏览器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件传输 ………… 什么时候应该使用UDP: 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。 比如,日常生活中,常见使用UDP协议的应用如下: QQ语音 QQ视频 TFTP ……

有些应用场景对可靠性要求不高会用到UPD,比如长视频,要求速率

小结TCP与UDP的区别:

1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值