java面试总结之基础

0、java语法

0.1 ==与equals的区别

对于字符串来说equals比较的是值,==比较的是地址
例如String str1 = "123";
String str2 = new String("123");
则str1.equals(str2)为true;而str1==str2为false
int a=1;int b=1;则a==b为true

0.2 iterator与listiterator的区别?

  • 相同点
    都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用。

  • 不同点
    1.使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。

    2.ListIterator有add方法,可以向List中添加对象,而Iterator不能。

    3.ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。

    4.ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

    5.都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator不能修改。

一、集合相关

1.1、HashMap相关

  • HashMap实现原理
    HashMap实际上是数组和链表的结合体,底层就是一个数组结构,数组中的每一项又是一个链表。
    HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。
    当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标), 如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
    在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。

简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,再根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,
也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

  • HashTable和ConcurrentHashMap
    它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。

  • HashMap和Hashtable有什么区别?
    HashMap允许键和值是null,而Hashtable不允许键或者值是null。
    Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
    HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。
    一般认为Hashtable是一个遗留的类。

  • 遍历HashMap的几种方式?
    https://blog.csdn.net/tolcf/article/details/38471493

2、ArrayList与LinkedList

ArrayList和LinkedList都实现了List接口
ArrayList是基于索引的数据接口,它的底层是数组。
相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
ArrayList查询快,LinkedList增删快。

3、Java集合类框架的基本接口

Collection:代表一组对象,每一个对象都是它的子元素。
Set:无序,不重复
List:有序,可重复
Map:可以把键(key)映射到值(value)的对象,键不能重复。

4、HashSet和TreeSet有什么区别?

HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间复杂度是O(1)。
TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是O(logn)。

二、面向对象相关

1、接口和抽象类

  • 接口与抽象类的区别
    抽象类和接口都不能直接实例化
    接口可继承接口,并可多继承接口,但类只能单继承
    接口方法,访问权限必须是公共的 public

  • 什么时候使用抽象类和接口

    • 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类
    • 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以 实现多个接口。因此你就可以使用接口来解决它
    • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类
  • Java8中的默认方法和静态方法

    Oracle已经开始尝试向接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。现在,我们可以为接口提供默认实现的方法了并且不用强制子类来实现它。

  • 接口与抽象类中能不能有静态方法
    抽象类中可以有静态的普通方法,但不能有静态的抽象方法。
    接口中的方法也只能是 public abstract修饰的,不能加上static,即接口中不能有静态的抽象方法。

三、设计模式相关

3.1、动态代理的两种方式,以及区别。
一般而言,动态代理分为两种,一种是JDK反射机制提供的代理,另一种是CGLIB代理。
JDK代理,必须提供接口,而CGLIB则不需要提供接口
3.2、单例的特点:

  • 单例类只能有一个实例;
  • 单例类必须自己创建自己的唯一实例;
  • 单例类必须给所有其他对象提供这一实例。
1、饿汉式单例:在类初始化时,已经自行实例,
在类创建的同时,就已经创建好一个静态的对象供系统使用,以后不再改变。
public class Singleton { 
 private Singleton(){    
  } 
  private static final Singleton sin = new Singleton();    
  public static Singleton init(){ 
    return sin; 
  } 
} 
2、懒汉式单例
在第一次调用的时候实例化自己
public class Singleton { 
  private Singleton(){    
    } 
   private static  Singleton sin = null;    
  public static synchronized Singleton init(){ 
     if(sin==null){
       sin=new Singleton();
     }
    return sin; 
  } 
} 

四、java语法相关

1、传值和传引用的区别

“传值”传递的是一个值,而“传引用”传递的是指向一个另一块内存空间的地址;
“传值”实际是将一个值的拷贝传递至方法内部,这个值的原始数据是不会改变的,无论你内部进行的是何种操作,都不会改变这个源数据的值;而“传引用”传递进去的则是指向一个对象的地址,那么在方法内部进行实际操作的时候,就很可能会改变该对象的属性值(当然具体是否改变,还需要结合具体的业务)。

五、JVM相关

1、Java 内存模型

JVM内存结构分为:方法区(method),栈内存(stack),堆内存(heap),本地方法栈(java中的jni调用)。

  • 方法区——存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(Permanet Generation)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。
  • 栈内存——在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。
  • 堆内存——堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。

2、类加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称链接。
加载:通过一个类的名字获取此类的二进制字节流,生成一个Class对象
验证:验证语法错误
准备:为静态类变量分配内存并设置初始值。
解析:将常量池内的符号引用替换为直接引用。
初始化:执行类中的java程序代码,执行java类的构造方法。

3.垃圾回收解决三个问题:

哪些内存需要回收?
什么时候回收?
如何回收?
垃圾回收关注的是堆内存(heap);
常见的垃圾收集算法:标记-清除算法、复制算法、标记-整理算法、分代收集算法

六、java多线程

1、synchronized修饰方法和synchronized修饰代码块

修饰代码块效率比修饰方法要高,因为修饰代码块的时候其它非synchronized修饰的代码块是异步的。

2、产生死锁的四个必要条件

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

3、lock与synchronized

七、spring相关

7.1事务

  • 事务的特性:ACID——原子性、一致性、隔离性和持久性
  • @transactional注解在什么情况下会失效,为什么。

service类标签(一般不建议在接口上)上添加@Transactional,可以将整个类纳入spring事务管理,在每个业务方法执行时都会开启一个事务,不过这些事务采用相同的管理方式。
@Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。
默认情况下,spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。

7.2scope的singleton与prototype的区别:

singleton:当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。
prototype:每一次请求(将其注入到另一个bean中,或者以程序的方式调用 容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作。
详情请参考:
https://blog.csdn.net/mastermind/article/details/1932787

7.3Autowired与Resource的区别

相同点:两者都可用于依赖注入,都可以用在字段和setter方法上。
不同点:

  • @Autowired为Spring提供的注解,@Resource 是JDK1.6支持的注解。
  • @Autowired注解按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:
public class TestServiceImpl {
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao; 
}
  • @Resource注解默认按照ByName自动注入,通过name属性进行指定,当找不到与名称匹配的bean时才按照类型进行装配。
    7.3ApplicationContext通常的实现是什么?
    ApplicationContext cxt = new ClassPathXmlApplicationContext ("applicationContext.xml");

八、数据库相关

1、数据库优化

  • 设计合适的尽量短的字段,比如邮政编码使用char(6)就够了,varchar也是不必要的
  • 将字段设置为not null的,这样执行查询时可以不必去比较null值
  • 使用join来代替子查询
  • 使用索引
    在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,使用索引性能提高更为明显。
    索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。最好是在相同类型的字段间进行比较的操作。在建有索引的字段上尽量不要使用函数进行操作。

2、数据库常见连接池

常用的主流开源数据库连接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等,其中阿里的Druid最好用。

  • Druid的主要配置
    DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池(据说是目前最好的连接池,不知道速度有没有BoneCP快)。
    和其它连接池一样DRUID的DataSource类为:com.alibaba.druid.pool.DruidDataSource,基本配置参数如下:
    name:配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this)。
    jdbcUrl:
    username:
    password:
    maxActive:最大连接池数量,默认值为8。

九、servlet与jsp

9.1

  • session.getMaxInactiveInterval():获得session的最大存活时间,默认是1800秒!
    可以在web.xml 配置文件中添加如下内容(单位为分钟,只针对该项目起作用)

    60

你可能感兴趣的:(java面试总结之基础)