Java面试题---基础篇
经常阅读一些牛人的基础博以及相关个人经历,你才发现自己真的不够努力,人生路漫漫,希望本人以及看客能走出一条自己不后悔的人生路,骚年 加油!!!
回归正题
一 java基础知识点
1)java面向对象的思想?
Java是一门纯粹的面向对象语言,万物皆对象,类是面向对象中重要概念,是具有相同属性和行为的对象的抽象
类具有三个基本特征
封装:隐藏类的实现细节,提供对外访问接口
继承:是对原有累的扩展,子类可以重写父类的方法
多态:是建立的继承的基础之上的.父类对象的引用指向子类对象,也就是说,同一种类型的对象执行相同的方法可以表现出不同的行为
2) Java中重载和覆盖的区别
覆盖(Override):是子类对父类方法的重写,而且抛出的异常更少,访问权限更大
重载(Overload):表示一个类中可以有多个方法名相同,参数列表不同的方法,参数列表不同可以是参数类型,参数个数以及参数顺序不同
3)接口和抽象类的区别
①:抽象类中可以没有抽象的方法,接口中普通方法必须是抽象方法,Java8中default关键字修饰的方法可以写方法的实现,以及static也是的
②:抽象类中可以有普通的成员变量,接口中变量必须是static final类型,必须被初始化
③:抽象类只能单继承,接口可以实现多个
4) Java和C++的区别
①:都是面向对象的语言,都支持封装 继承 和多态
②:指针:Java中不提供指针直接访问内存,程序更加安全
③:Java是单继承,而C++支持多继承
④:Java有自动内存管理机制,不需要程序员释放无用的内存
5)Java中的值传递和引用传递
Java中只存在值传递,当然这是文字游戏,有人也认为存在引用传递
值传递:形参接收的值是实参的原始值的copy,此时内存存在两个相同的基本数据类型,方法中的操作是对copy值得修改,不影响实际参数
引用传递:传的是地址,实际参数的引用被传递给方法中形参,方法接收的是原始值的内存地址,所以修改会改变的源数据
6)JDK 中常用的包有哪些?
答:java.lang java.util java.io java.net java.sql
7)JDK JRE 和JVM的联系和区别
JDK是java的开发工具包,是java开发环境的核心组件,并提供编译,调试和运行一个java程序所需的所有工具,可执行java文件和而二进制文件
JRE是java运行的环境,是JVM的实现,提供java程序的平台,不包含编译器和调试器
JVM是java的虚拟机,JVM负责将字节码转换特定的机器码,JVM提供内存管理/垃圾回收和安全机制
二 java中常见的集合
1)说说常见的集合有哪些?
Map接口和Collection接口是所有的集合框架的父接口
①:Collection接口的子类包括Set接口和List接口
②:Map接口的实现类主要有:HashMap TreeMap Hashtable ConcurrentMap以及Properties等
③:Set接口实现类主要有HashSet TreeSet LinkedHashSet等
④:List 接口主要的实现类有:ArrayList,LinkedList,Stack以及Vector
2)HashMap和Hashtable的区别有哪些?
①:HashMap没有考虑同步,是线程不安全的;Hashtable使用synchronized的关键字,是线程安全的,性能低
②:前者允许null作为key;后者不允许null作为key
3)HashMap底层的实现原理
在java 8之前,其底层使用数组+链表,java8中使用数组+链表/红黑树
4)ConcurrentHashMap和Hashtable的区别?
ConcurrentHashMap结合HashMap和Hashtable二者的优势,HashMap没有考虑同步,Hashtable考虑同步的问题,但是每次执行时都要锁住整个结构,ConcurrentHashMap锁的方式是稍微细粒度的,ConcurrentHashMAp将hash表分成16个桶(默认值),诸如get put remove操作只锁当前桶即可
具体ConcurrentHashMap的实现细节
① 该类有两个静态内部类HashEntry和Segment.前者用来封装映射表的键值对,后者充当锁的角色
② Segment是一种可重入的锁ReetrantLock,每一个Segment守护一个HashEntry数组的元素,当对HashEntry数组的数据进行修改时,必须获得对应的Segment锁
5)HashMap的长度为什么是2的幂次方?
① 通过将key的hash值与length -1进行&运算,实现当前Key的定位,2的幂次方可以减少冲突(碰撞)的次数,提高HashMap查询的效率
② 如果length为2的次幂 则length-1 转化为二进制必定是11111……的形式,在于h的二进制与操作效率会非常的快,而且空间不浪费;如果length不是2的次幂,比如length为15,则length-1为14,对应的二进制为1110,在于h与操作,最后一位都为0,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能存放元素了,空间浪费相当大,更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。
6)List 和Set的区别?
List元素是有序的,可以重复;Set元素是无序的,不可以重复
7)List,Set 和Map的初始容量
① List
ArrayList的初始容量10;加载因子为0.5;扩容增量,原容量的0.5倍+1;一次扩容的长度为16
Vector初始容量为10 加载因子是1,扩容增量是1倍 ,一次扩容的容量20
② Set
HashSet,初始容量为16,加载因子为0.75; 扩容增量:原容量的 1 倍; 如 HashSet的容量为16,一次扩容后容量为32
③ Map
HashMap,初始容量16,加载因子为0.75; 扩容增量:原容量的 1 倍; 如 HashMap的容量为16,一次扩容后容量为32
8)java集合的快速失败"fail-fast"
是java集合错误检测机制,当多个线程对集合结构上的改变操作时,有可能产生fail-fast机制
三 高并发编程包(JUC)
在java 5.0 提供java.util.concurrent(简称JUC),在此包中增加并发编程的常用的实用工具类,用于定于线程的自定义的子系统,包括线程池,异步io 和轻量级任务框架
1) 多线程和单线程的区别和联系
① 在单核CPU中,将CPU分成很小的时间片,在每一个时刻只能有一个线程在执行,是一种微观上的轮流占用CPU的机制
② 多线程会存在线程上下文切换,会导致程序执行速度变慢,即采用一个拥有两个线程的进程执行所需的时间比一个线程的进程执行两次所需的时间要多一些,但是对用户而言,可以减少用户的响应时间
2)线程和进程的区别?
①:进程是一个"执行中的程序",是系统进行资源分配和调度的一个独立单位
② 线程是进程的一个实体,一个进程中拥有多个线程,线程之间共享地址空间和其他资源
③ 线程之间上下文切换比进程上下文切换要快的多
进程切换时,涉及到当前进程的CPU环境的保存和新被调度进程的CPU环境的设置
线程切换仅需要保存和设置少量的额寄存器的内容,不涉及存储管理方面的操作
3)多线程产生死锁的4个必要条件
① 互斥条件:一个资源每次只能被一个线程使用
② 请求与保持条件 一个线程因请求资源而阻塞时,对以获取的资源保持不放
③ 不剥夺条件 进程已经获得的资源,在未使用完,不能强行剥夺
④ 循环等待条件 若干线程之间形成一种头尾相接的循环等待资源关系
那如何避免死锁?
避免一个线程同时获取多个锁
避免一个线程在锁内同时占用多个资源,保证每个所占用一个资源
尝试使用定时锁,使用lock.tryLock来代替使用内置锁
4)sleep() 和wait()的区别?
sleep():是Thread类的静态方法,睡眠不释放锁
wait():是Object类的方法,必须与synchronized关键字一起使用,线程进入阻塞状态,当notify或者notifyAll()调用,会自动解除阻塞,睡眠时会释放锁
5)synchronized关键字
当进入时,执行monitorenter,将计数器+1,释放锁monitorexit,计数器-1
当一个线程判断计数器为0,则当前锁空闲,可以占用;反之,当前线程进入等待
monitor机制
Synchronized实在加锁,加的是对象锁,对象锁是一种重量级(monitor),synchronized的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程),轻量级(多个线程访问synchronized区域),对象锁,自旋锁
6)volatile关键字
保证可见性但不保证原子性
① 主内存和工作内存,直接与主内存产生交互,进行读写操作,保证可见性
② 禁止JVM进行指令重排
7)Threadlocal(线程局部变量)关键字
① 当使用ThreadLocal维护一个类似HashMap的对象,称之为ThreadLocalMap,里面包含若干个Entry(k-V键值对),相应的线程被称之为这些Entry的属主线程
② Entry的key是一个ThreadLocal实例,Value是一个线程特有的对象.Entry的作用即是:为其属主线程建立一个ThreadLocal实例与线程持有的特定对象之间对应关系
③ Entry对key的引用时弱引用;Entry对Value的引用时强引用
8)Atomic关键字
可以使基本数据类型以原子的方式实现自增自减等操作
9)线程池有了解吗?
java.util.concurrent.ThreadPoolExecutor类就是一个线程,客户端调用ThreadPoolExecutor.submit(Rannable task)提交任务,线程池内部维护的工作线程的数量就是线程大小
当前线程的大小:表示线程池中实际工作这线程的数量
最大线程大小(maxinumPoolSize):表示线程池中允许的存在线程的数量的上限
核心线程大小(corePoolSize):表示一个不大于最大线程的工作线程的数量的上限
①:当运行的线程数量少于corePoolSize是,则Executor始终首选添加新的线程,而不进行排队
② 当运行的线程等于或者多余corePoolSize,则Executro始终首选请求加入队列,而不是添加新的线程
③ 如果无法将请求加入队列,即表示队列已经满了,,则创建新的线程,除非创建新的线程超出maxinumPolSize.在这种情况下,任务将被拒绝