java基础面试题
1. Java有哪些数据类型?
Java中有 8 种基本数据类型,分别为:6 种数字类型 (四个整数形,两个浮点型):byte、short、int、long、float、double,1 种字符类型:char,1 种布尔型:boolean。 2.什么是自动装箱拆箱? 装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。 3.基本数据类型和包装类型的区别? 1. 声明方式不同:基本类型不使用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间; 2. 存储方式及位置不同:基本类型是直接将变量值存储在栈中,而包装类型是将对象放在堆中,然后通过引用来使用; 3. 初始值不同:基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null; 4. 使用方式不同:基本类型直接赋值直接使用就好,而包装类型在集合如Collection、Map时会使用到。 4.final 在 Java 中有什么作用? final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。 特征:凡是引用final关键字的地方皆不可修改! (1)修饰类:表示该类不能被继承; (2)修饰方法:表示方法不能被重写; (3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。 5.static都有哪些用法? 1、所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享. 2、除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作。 3、最后一种用法就是静态导包,即 import static .import static是在JDK 1.5之后引入的新特性,可以用来指 定导入某个类中的静态资源,并且不需要使用类名,可以直接使用资源名 6.== 和 equals 的区别是什么? 对于基本类型和引用类型 == 的作用效果是不同的,如下所示: 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同; equals equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。 总结 == 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。 7.面向对象的特征 封装: 把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。 继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。 多态: 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定(比如:向上转型,只有运行才能确定其对象属性)。方法 覆盖和重载体现了多态性。 8. 多态现实意义理解: 现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。 Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。 1. 多态体现为父类引用变量可以指向子类对象。 2. 前提条件:必须有子父类关系。 9.Java创建对象有几种方式? java中提供了以下四种创建对象的方式: 1.new创建新对象 2.通过反射机制 3.采用clone机制 4.通过序列化机制 10.Java 中操作字符串都有哪些类?它们之间有什么区别? 1.操作字符串的类有: String 、 StringBuffer 、 StringBuilder 。 2.String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象。 3.而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。 4.StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。 11. String 类的常用方法都有那些? indexOf():返回指定字符的索引。 charAt():返回指定索引处的字符。 replace():字符串替换。 trim():去除字符串两端空白。 split():分割字符串,返回一个分割后的字符串数组。 getBytes():返回字符串的 byte 类型数组。 length():返回字符串长度。 toLowerCase():将字符串转成小写字母。 toUpperCase():将字符串转成大写字符。 substring():截取字符串。 equals():字符串比较。 12.ArrayList和LinkedList区别? 1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的双向环形列表数据结构。 2. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 3. 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 13.ArrayList和Vector的区别 1.相同点: 两个类都实现了List接口(List接口继承了 Collection 接口),他们都是有序集合,即存储在这两个集 合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素, 并且其中的数据是允许重复的,这是与 HashSet 之类的集合的最大不同处, HashSet 之类的集合不可以 按索引号去检索其中的元素,也不允许有重复的元素。 2.区别: a.Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList ,因为它不考 虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector ,因为不需要我们自己再去考虑和编写线程安全的代码b.ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增 加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增 长为原来的1.5倍)。 ArrayList 与 Vector 都可以设置初始的空间大小, Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。 总结:即Vector增长原来的一倍, ArrayList 增加原来的0.5倍。 14.HashMap和Hashtable的区别 1.HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于 HashMap 允许空(null)键值(key),由于非线程安全,在只有一个线程访问的情况下,效率要高于 Hashtable 。 2.HashMap 允许将null作为一个entry的key或者value,而 Hashtable 不允许。 3.HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey 。因为contains方法容易让人引起误解。 4.Hashtable 继承自 Dictionary 类,而 HashMap 是Java1.2引进的Map interface的一个实现。 5.最大的不同是, Hashtable 的方法是 Synchronize 的,而 HashMap 不是,在多个线程访问 Hashtable时,不需要自己为它的方法实现同步,而 HashMap 就必须为之提供同步。 15.HashMap的实现原理 1.原理 简单讲解下HashMap的原理:HashMap基于Hash算法,我们通过put(key,value)存储,get(key)来获取。当传入key时,HashMap会根据key.hashCode()计算出hash值,根据hash值将value保存在bucket里。当计算出的hash值相同时怎么办呢,我们称之为Hash冲突,HashMap的做法是用链表和红黑树存储相同hash值的value。当Hash冲突的个数比较少时,使用链表,否则使用红黑树。 2.jdk1.8中,HashMap使用了一个内部类Node< K, V>来存储数据, 可以看见Node类中除了键值对(key-value)以外,还有额外的两个数据:hash : 这个是通过计算得到的散列值next:指向另一个Node,这样HashMap可以像链表一样存储数据因此可以知道,HashMap的结构大致如下:我们可以将每个横向看成一个个的桶,每个桶中存放着具有相同Hash值的Node,通过一个list来存放每个桶。 3.put操作 put函数大致的思路为: 1. 对key的hashCode()做hash,然后再计算index; 2. 如果没碰撞直接放到bucket里; 3. 如果碰撞了,以链表的形式存在buckets后; 4. 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树; 5. 如果节点已经存在就替换old value(保证key的唯一性) 6. 如果bucket满了(超过load factor*current capacity),就要resize。 注意:在Java 8以前,每次产生hash冲突,就将记录追加到链表后面,然后通过遍历链表来查找。如果某个链表中记录过大,每次遍历的数据就越多,效率也就很低,复杂度为O(n); 在Java 8中,加入了一个常量TREEIFY_THRESHOLD=8,如果某个链表中的记录大于这个常量的话,HashMap会动态的使用一个专门的treemap实现来替换掉它。这样复杂度是O(logn),比链表的O(n)会好很多。 4。get操作 在理解了put之后,get就很简单了。大致思路如下: 1. bucket里的第一个节点,直接命中; 2. 如果有冲突,则通过key.equals(k)去查找对应的entry 3. 若为树,则在树中通过key.equals(k)查找,O(logn); 4. 若为链表,则在链表中通过key.equals(k)查找,O(n)。 5.HashMap的自动扩容 如果在初始化HashMap中没有指定初始容量,那么默认容量为16,但是如果后来HashMap中存放的数量超过了16,那么便会有大量的hash冲突;在HashMap中有自动扩容机制,如果当前存放的数量大于某个界限,HashMap便会调用resize()方法,扩大HashMap的容量。当hashmap中的元素个数超过数组大小loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,也就是说,默认情况下,数组大小为16,那么当hashmap中元素个数超过160.75=12的时候,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。 HashMap的capacity必须满足是2的N次方,如果在构造函数内指定的容量n不满足,HashMap会通过下面的算法将其转换为大于n的最小的2的N次方数。 16.hashCode()和equals()方法有何重要性? HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两 个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和 equals()去查找重复,所以正确实现它们非常重要。equals()和hashCode()的实现应该遵循以下规则: (1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。 (2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。 17.我们能否使用任何类作为Map的key? 我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点: (1)如果类重写了equals()方法,它也应该重写hashCode()方法。 (2)类的所有实例需要遵循与equals()和hashCode()相关的规则。请参考之前提到的这些规则。 (3)如果一个类没有使用equals(),你不应该在hashCode()中使用它。 (4)用户自定义key类的最佳实践是使之为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了。 比如,我有一个类MyKey,在HashMap中使用它。 //传递给MyKey的name参数被用于equals()和hashCode()中 MyKey key = new MyKey('Pankaj'); //assume hashCode=1234 myHashMap.put(key, 'Value'); // 以下的代码会改变key的hashCode()和equals()值 key.setName('Amit'); //assume new hashCode=7890 //下面会返回null,因为HashMap会 尝试查找存储同样索引的key,而key已被改变了,匹配失败,返回null myHashMap.get(newMyKey('Pankaj')); 那就是为何String和Integer被作为HashMap的key大量使用。
标签:面试题,java,HashMap,ArrayList,基础,equals,hashCode,链表,key From: https://www.cnblogs.com/yangyanga/p/17103661.html