J2SE基础~2
开心一刻:不要羡慕别人,幸福其实就是一碗白开水,你每天都在喝,不要羡慕别人喝的饮料有各种颜色,其实未必有你的白开水解渴!有这么一则寓言:“猪说假如让我再活一次,我要做一头牛,工作虽然累点,但名声好,让人爱怜;牛说加入让我再活一次,我要做一头猪,吃罢睡,睡罢吃,不出力,不流汗,活得赛神仙;鹰说假如让我再活一次,我要做一只鸡,渴了有水,饿了有米,有房住,还受人保护;鸡说假如让我再活一次,我要做一只鹰,可以翱翔天空,云游四海,任意捕兔杀鸡”。幸福如人饮水,冷暖自知。你不是我,怎知我走过的路?怎知我心中的苦与乐?所以,真的不必去羡慕别人。明白自己所拥有的,想清楚自己真正想要的,才会真正快乐。扯了这么多还是看文章吧,想必你来这里也不是看我扯淡的,哈哈~ ~ !
下面正式进入干货区,喜欢的话、双击、评论、转发,动一动你的小手让更多的人知道!关注帅比~杨
-
HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
-
TreeMap、HashMap、LindedHashMap的区别。
-
Collection包结构与Collections的区别。
-
try catch finally,try里有return,finally还执行么?
-
Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
-
Java面向对象的三个特征与含义。
-
Override和Overload的含义及区别。
-
interface与abstract类的区别。
-
static class 与non static class的区别。
-
java多态的实现原理。
-
实现多线程的两种方法:Thread与Runable。
-
线程同步的方法:sychronized、lock、reentrantLock等。
-
锁的等级:方法锁、对象锁、类锁。
-
写出生产者消费者模式。
-
ThreadLocal的设计理念与作用。
-
ThreadPool用法与优势。
-
Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
-
wait()和sleep()的区别。
-
foreach与正常for循环效率对比。
-
Java IO与NIO。
-
反射的作用与原理。
-
泛型常用特点,List能否转为List。
-
解析XML的几种方式的原理与特点:DOM、SAX、PULL。
-
Java与C++对比。
-
Java1.7与1.8新特性。
-
设计模式:单例、工厂、适配器、责任链、观察者等等。
-
JNI的使用。
1. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀计算index方法:index = hash & (tab.length - 1)ConcurrentHashMap底层采用分段的数组+链表实现,线程安全通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
2. TreeMap、HashMap、LindedHashMap的区别。
Map: 在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。这就是我们平时说的键值对。
HashMap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null,且不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力。
LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。 注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。
TreeMap 不仅可以保持顺序,而且可以用于排序;HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap。
3. Collection包结构与Collections的区别。
Collection是集合类的上级接口,子接口主要有Set 和List。
Collections是针对集合类的一个帮助类,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作
Collections常用方法:
- sort(Collection)方法的使用(含义:对集合进行排序)。
- binarySearch(Collection,Object)方法的使用(含义:查找指定集合中的元素,返回所查找元素的索引)。
- max(Collection),max(Collection,Comparator)方法的使用(前者采用Collection内含自然比较法,后者采用Comparator进行比较)。
- min(Collection),min(Collection,Comparator)方法的使用(前者采用Collection内含自然比较法,后者采用Comparator进行比较)。
- indexOfSubList(List list,List subList)方法的使用(含义:查找subList在list中首次出现位置的索引)。
- lastIndexOfSubList(List source,List target)方法的使用(含义:查找target在list中最后出现位置的索引)。
- reverse()方法的使用(含义:反转集合中元素的顺序)。
- rotate(List list,int m)方法的使用(含义:集合中的元素向后移m个位置,在后面被遮盖的元素循环到前面来)。
感兴趣可以来这里看些小demo:
4. try catch finally,try里有return,finally还执行么?
这个说实话真的看基本功了,相信平时工作认真的小伙伴应该也答得出来,这里我贴上代码。细节决定成败你们赞同吗?
try {
System.out.println("try");
return;
} catch (Exception e) {
System.out.println("catch");
}finally{
System.out.println("finally");
}
想必验证这个问题是个很简单的问题,但你刚刚认为对了吗?
*ps: *只有在try里面调用System.exit(0)来退出JVM的情况下finally块中的代码才不会执行。
5. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
Exception
(1) 可以是可被控制(checked) 或不可控制的(unchecked)。
(2) 表示一个由程序员导致的错误。
(3) 应该在应用程序级被处理。
Error
(1) 总是不可控制的(unchecked)。
(2) 经常用来用于表示系统错误或低层资源的错误。
(3) 如何可能的话,应该在系统级被捕捉
出现OOM的场景:
- 加载对象过大
- 相应资源过多,来不及加载。
解决方案:
- 内存引用上做一些处理,常用的有软引用。
- 内存中加载图片直接在内存中做处理(如边界压缩)这个Glide\Fresco 图片框架可能封装好了
- 优化Delivk虚拟机的堆内存分配、自定义堆内存大小
- 合适的场景动态回收内存
SOF
程序中一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过默认大小而导致溢出。
栈溢出的原因:
- 递归调用
- 大量循环或死循环
- 全局变量是否过多
- 数组、List、map数据过
总结:Error 表示系统级的错误和程序不必处理的异常,是一种很严重的问题无法通过程序修复,比如内存溢出,不可能指望程序能处理这样的情况; Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题,它表示如果程序运行正常从不会发生的情况。而OOM和SOF大都是由于编码不当造成的程序内存占用过高导致的问题,所以为了避免程序少出问题养成一个好的编程习惯是很重要的这个就需要大家多多总结和实践了。
感兴趣的小伙伴可以来这里看看:https://developer.android.com/topic/performance/memory.html
6. Java面向对象的三个特征与含义。
封装、继承、多态
封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已经定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
继承:
继承是子对象继承父对象的属性和行为,亦即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为。这非常类似大自然中的物种遗传(孩子跟父亲是很像的,且也可以有自己的独立行为)。
多态:
多态是同一个行为具有多个不同表现形式或形态的能力,代码中就是同一个接口使用不同的实例而执行不同操作。
一张图看明白多态:
yangke.pngps:打印机根据产物可以分为彩色和黑色打印机。他们都具有打印的作用,但是产物类似却不同。彩色打印机打印效果:彩色;黑白打印机打印效果:黑白色;其实这就是多态。
7. Override和Overload的含义及区别。
Overload 是重载的意思,Override 是覆盖的意思,也就是重写。
Overload(重载) 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数、类型或顺序不同)。
Override(重写) 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。(ps:子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法 是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。)
8. interface与abstract类的区别。
简单来说,接口(interface)是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的,另外,实现接口一定要实现接口里定义的所有方法,而实现抽象类(abstract)可以有选择地重写需要用到的方法。一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。
9. static class 与non static class的区别。
static class
- 静态内部类不需要有指向外部类的引用;
- 静态类只能访问外部类的静态成员,不能访问外部类的非静态成员;
non static class
- 非静态内部类需要持有对外部类的引用;
- 非静态内部类能够访问外部类的静态和非静态成员;
- 一个非静态内部类不能脱离外部类实体被创建;
- 一个非静态内部类可以访问外部类的数据和方法;
10. java多态的实现原理。
上面“6. Java面向对象的三个特征与含义”已经进行多态的解释。实现原理大致是:程序在运行期间编译器会去查找函数所对应的具体对象,不同的对象相同的函数可以运行出不同的结果。(ps:我与小伙伴共同进步,哪里有问题或者您觉得自己的理解更全面欢迎拍砖留下脚印!)
未完待续~~~
喜欢有帮助的话、双击、评论、转发,动一动你的小手让更多的人知道!关注 帅比-杨
网友评论