面试经java菜鸟的职场技术站

又到了实习生如涛涛巨浪般的涌入废品回收站(相对于大多数人),而那些回收站就缺我们这样的菜鸟,为什么,因为我们菜啊,因为菜而骄傲,但不能跌了身份啊!!!!

  话不多说 ,上实战经验

  1.站在面试官之上回答问题 ,自我介绍一下 ,不要怂,虽然我不是985 ,我也不是211.但是我是实习生,你缺的那种人,别隐藏了,从我进门起你就想要我 ,因为我是实习生,大胆介绍自己,获得奖学金 获得荣誉证书 四六级 大胆说出来,这就是你加薪的好机会,不要太长 三分钟,最后别忘了介绍你是一名实习生,表明你的目的,你是为了实习而来(谁不是为了钱而来)目的高尚一点。

2.开始问问题了

 2.1 又是老生长谈的问题 ,可能你看都看腻了

接口和抽象类的区别 。。。。。。从类的单继承和接口的多实现多继承,主体说完说方法 抽象类不仅有抽象方法还有普通方法,拜托能不能有点条理性

相同点:

1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。

2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

不同点:

1 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。
2 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。
3 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
4 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。
5 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承不足。、

这样回答才稍微符合面试官的心意,为什么说稍微 ,一看你就是背我的,麻烦你自己组织一下语言,ok!

接下来再问三个S的问题,String ,StringBuffer StringBuilder的区别

先说String ,再说后两个

因为String用的最多,并且和后面两个有一致性的区别

  1. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
  2. String最慢的原因:

 String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

记住String的不断赋值,只是不断在创建新的对象,老的对象被GC回收,不要误认为是一个对象

3.再来说线程安全

StringBuilder线程不安全 ,Buffer线程安全的 ,为什呢 ,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,那么你平时是怎么使用的呢

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

举个例子吧。

我平时使用常量时会经常使用,会这样写定义一个接口

在接口里在这样定义常量 interface mmm{

String xx = "xx";

String cc = "cc";}

这样是为了这个常量可能会被多次调用,也可能被别人调用方便,让别人很容易读懂你的代码,那就说到了为什么String 是常量呢?

因为他被final修饰 ,是最终类,又说到了final

final关键字可以修饰类、方法、字段。修饰类时,这个类不可以被继承;修饰方法时,这个方法就不可以被覆盖(重写),在JVM中也就只有一个版本的方法--实方法;修饰字段时,这个字段就是一个常量。

java.lang.String 这样説的

/**
 * The String class represents character strings. All string literals in Java programs, such as "abc",
 * are implemented as instances of this class.
*/
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
   ...
}"The String class represents character strings"意思是String类表示字符串;String类被关键字final修饰,可以说明它不可被继承;从"private final char value[]"可知,String本质上是一个char数组。

        String类的成员字段value是一个char[]数组,而且也是用final关键字修饰,被final关键字修饰的字段在创建后其值是不可变的,但也只是value这个引用地址不可变,可是Array数组的值却是可变的,Array数组数据结构如下图所示:

从图中可以看出,Array变量只是栈上(stack)的一个引用,数组中的数据存储在堆上(heap)。String类里的value是用final修饰,只能说在栈上(stack)这个value的引用地址不可变,可没说堆里的Array本身数据不可变。看下面这个例子:

final int[] value = {1,2,3,4,5};
int otherValue = {6,7,8,9,10};
value = otherValue;//编译报错value是被final关键字修饰的,编译器不允许把value指向堆另外一个地址;但如果直接对数组元素进行赋值,就允许;如下面这个例子:

final int[] value  = {1,2,3,4,5};
value[0] = 0;
        所以说String是不可变,在后面所有的String方法里没有去动Array中的元素,也没有暴露内部成员字段。private  final char value[],private的私有访问权限的作用都比final大。所以String是不可变的关键都是在底层实现的,而不是一个简单的final关键字。

然后这些问完了,再来集合吧

map list set 懂多少 如实招来 ,其实也不懂啥 就知道用了就new嘛

可是面试 又不是写代码改需求 比如说给你一个list给我展成树结构 我会简单的告诉你两层for嵌套循环搞定 或者两层for循环不嵌套,第一层找根,第二层找儿子,递归解决,可是面试官不会问的,他要问三个区别,管你怎么用 ,那你就吹吧

list和set是实现了collection接口的。

List:1.可以允许重复的对象。

         2.可以插入多个null元素。

        3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。

       4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

 Set:1.不允许重复对象

          2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。

         3. 只允许一个 null 元素

         4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。、

Map:

1.Map不是collection的子接口或者实现类。Map是一个接口。

2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。

3. TreeMap 也通过 Comparator  或者 Comparable 维护了一个排序顺序。

4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。

5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)


1.如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。

但是注意的是你在末尾增删数据未必这样选,可以自己尝试一些两者的速度

毕竟你要明白

ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构(双链表)。 

ArrayList内部是使用可増长数组实现的,所以是用get和set方法是花费常数时间的,但是如果插入元素和删除元素,除非插入和删除的位置都在表末尾,否则代码开销会很大,因为里面需要数组的移动。
LinkedList是使用双链表实现的,所以get会非常消耗资源,除非位置离头部很近。但是插入和删除元素花费常数时间。


2.如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。


3.如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。


4.如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。

再说一下hashTable和hashMap的区别吧

HashTable

  • 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
  • 初始size为11,扩容:newsize = olesize*2+1
  • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

  • 底层数组+链表实现,可以存储null键和null值,线程不安全
  • 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
  • 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
  • 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
  • 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
  • 计算index方法:index = hash & (tab.length – 1)

 

HashMap的初始值还要考虑加载因子:

  •  哈希冲突:若干Key的哈希值按数组大小取模后,如果落在同一个数组下标上,将组成一条Entry链,对Key的查找需要遍历Entry链上的每个元素执行equals()比较。
  • 加载因子:为了降低哈希冲突的概率,默认当HashMap中的键值对达到数组大小的75%时,即会触发扩容。因此,如果预估容量是100,即需要设定100/0.75=134的数组大小。
  • 空间换时间:如果希望加快Key查找的时间,还可以进一步降低加载因子,加大初始大小,以降低哈希冲突的概率。

HashMap和Hashtable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性:

  • 容量(capacity):hash表中桶的数量
  • 初始化容量(initial capacity):创建hash表时桶的数量,HashMap允许在构造器中指定初始化容量
  • 尺寸(size):当前hash表中记录的数量
  • 负载因子(load factor):负载因子等于“size/capacity”。负载因子为0,表示空的hash表,0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时比较慢)

除此之外,hash表里还有一个“负载极限”,“负载极限”是一个0~1的数值,“负载极限”决定了hash表的最大填满程度。当hash表中的负载因子达到指定的“负载极限”时,hash表会自动成倍地增加容量(桶的数量),并将原有的对象重新分配,放入新的桶内,这称为rehashing。

HashMap和Hashtable的构造器允许指定一个负载极限,HashMap和Hashtable默认的“负载极限”为0.75,这表明当该hash表的3/4已经被填满时,hash表会发生rehashing。

“负载极限”的默认值(0.75)是时间和空间成本上的一种折中:

  • 较高的“负载极限”可以降低hash表所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作(HashMap的get()与put()方法都要用到查询)
  • 较低的“负载极限”会提高查询数据的性能,但会增加hash表所占用的内存开销

程序猿可以根据实际情况来调整“负载极限”值。

ConcurrentHashMap

  • 底层采用分段的数组+链表实现,线程安全
  • 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
  • Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
  • 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
  • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

 

Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

HashMap基于哈希思想,实现对数据的读写。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来存储值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞时,对象将会储存在链表的下一个节点中。HashMap在每个链表节点中储存键值对对象。当两个不同的键对象的hashcode相同时,它们会储存在同一个bucket位置的链表中,可通过键对象的equals()方法来找到键值对。如果链表大小超过阈值(TREEIFY_THRESHOLD,8),链表就会被改造为树形结构。

在HashMap中,null可以作为键,这样的键只有一个,但可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中没有该key,也可以表示该key所对应的value为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个key,应该用containsKey()方法来判断。而在Hashtable中,无论是key还是value都不能为null。

Hashtable是线程安全的,它的方法是同步的,可以直接用在多线程环境中。而HashMap则不是线程安全的,在多线程环境中,需要手动实现同步机制。

Hashtable与HashMap另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。

先看一下简单的类图:

看到别的笔友画好直接拿来用了

从类图中可以看出来在存储结构中ConcurrentHashMap比HashMap多出了一个类Segment,而Segment是一个可重入锁。

ConcurrentHashMap是使用了锁分段技术来保证线程安全的。

锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。 

ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。

ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。

到此基本问完了

再说说事务啥的 直接跟他说我都是用的Spring注解@Transactional异步方法经常用@Aysnc 最简单的例子我要执行job 但是执行会需要时间,为了让页面继续能工作 我直接将执行状态改变 改为我可以工作的状态,好了下次再说吧 ,面试还早 我要早点休息

大保健开始咯!!!晚安  菜鸟们

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值