java面试题--基础

集合有哪些?数据结构?初始长度?哪些线程是安全的?hashmap的底层原理?

单列集合:List,Set
双列集合:Map
List是一个有序,可重复的集合
ArraysList:底层数据结构为数组,查询快,增删慢,线程不安全,效率高,初始长度为10,增量0.5倍加 1
Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,初始长度为10,增量1倍
LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全,效率高
Set是一个无序,不可重复的集合
HashSet:底层数据结构是哈希表,都是一个存放链表的数组,线程不安全,效率高,但它不保证存储元素的迭代顺序,HashSet实际上是一个HashMap实例,HashSet中的元素都存放在HashMap的key上面,此类允许使用null元素,HashSet不允许有重复元素,初始容量16,加载因子0.75(超过集合长度值),扩容曾量1;
LinkedHashSet(HashSet的子类):底层数据结构由链表和哈希表组成,链表保证数据中有序,哈希表保证数据唯一
TreeSet:底层数据结构是红黑树(自平衡的二叉树)添加数据通过返回值是否为0来决定数据的唯一性,通过自然排序和比较器排序这两种方式实现集合元素的排列
双列集合:Map数据结构仅仅只针对键有效,与值无关,存储键对形式,键唯一,值可重复
HashMap:底层数据结构是哈希表(数组加链表),线程不安全,效率高,允许有空值和空键,初始容量16,加载因子0.75,扩展增量1,原理:当我们往hashmap中put元素时,首先根据key的hashcode()冲虚计算hash值,根据hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾,如果数组中该位置没有元素,就直接将该元素放到数组的该位置上.JDK1.8以后对HasgMap的实现做了优化,当链表中的节点数据超过八个以后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn),
LinkedHashMap(HashMap的子类):底层数据结构由哈希表和链表组成,哈希表保证数据唯一,链表保证数据有序;
Hashtable:底层数据结构是哈希表,线程安全,效率低;
TreeMap:底层数据结构是红黑树
线程安全:
Vector:就比Arraylist多了个同步化机制(线程安全)
Hashtable:就比HashMap多了个线程安全.contains()
ConcurrentHashMap:是一种高效但是线程安全的集合.
Stack:栈,也是线程安全,继承于Vector

线程的创建?开启?状态?sleep和wait的区别?线程池?死锁?如何保证线程安全?

线程的创建:
实现Runnable接口,重写run();
继承Thread类,重写run();
实现Callable接口,重写call(),利用FutureTask包装Callable,并作为task传入Thread构造函数;
利用线程池创建.
线程的启动:
启动线程的唯一方法就是通过Thread类的start()实例方法.
线程的状态:新建,就绪,运行,阻塞,死亡
sleep和wait的区别:
sleep属于Thread类中的方法,wait属于Object类中的方法
调用sleep方法的线程对象,虽然在指定时间内不会获得CPU的执行权,但是并没有释放对锁的控制权,即当休眠状态的线程获得锁的时候,其他线程不能重新获得锁,但是wait方法是释放锁的,使其他线程可以获得锁而获得资源的控制权;
线程池:主要解决处理器单元内多个线程执行的问题,可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
线程池包括以下四个基本组成部分:
线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
死锁的四个必要条件:
互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源;
请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
环路等待条件:是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系
线程安全:一般说来,确保线程安全的方法有这几个:竞争与原子操作、同步与锁、可重入、过度优化
互斥锁,可以保证线程的原子性,当线程进入方法时,会自动获得一个锁,一旦锁被获得,其他线程必须等待获得锁的线程执行完代码释放锁,会降低程序的执行效率
ThreadLocal为每个线程提供局部变量,解决线程安全问题

==和equals的区别?

== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

对反射的理解?获取class类的方式有哪些?如何用反射取私有属性Filed?

反射:就是程序在运行过程中能够获取自身的信息,即能获取java中反射类的字节码,在java中只要给定类的名字就能通过反射机制获取该类的所有信息;
获取class的方式:
Class class = Class.forName("被获取类的全限定类名")
Class class = 类名.class
Class class=类对象(this).getClass()
如何用反射获取私有属性Filed
反射获取类对象,获取私有属性和方法集合,然后取消访问检查setAccessible(true),最后调用私有属性或方法。
Field[] fields=s.getClass().getDeclaredFileds();
修改私有属性:
追加:fields.setAccessible(true);
获取对象:
Student s=(Student)class.getConstructor().newInstance();(初始化无参构造方法加强转)

常用的设计模式有哪些?项目中哪里有用到?单例中懒汉饿汉优缺点?

常用设计模式:
创建类(创建一个对象):单例模式,工厂模式,抽象工厂模式
结构性(将几个对象组织成一个结构):桥接模式,外观模式,代理模式
行为型(多个对象间的通讯):观察者模式,策略模式
项目中用到:
数据库连接池,线程池,网站访问计数器,mybatis中的SqlSessionFactory,spring容器中的bean对象默认使用到了单例模式;
spring中的AOP用到了代理模式
jdbc连接数据库用到了桥接模式
懒汉饿汉优缺点:
饿汉:在加载类时就构建,预先加载;
优点:线程安全,在类加载的同时就创建好了静态对象,调用时反应速度快;
缺点:资源效率不高
懒汉式:在使用该类的对象时才会产生实例化对象;延迟加载(不会第一时间new对象来占用内存,而是什么时候get什么时候new);线程安全(在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的)
优点:资源利用率高
缺点:第一次加载不够快,多线程使用不必要的同步开销大
restful设计风格:Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

jdk1.8新特性有哪些?

原来的HashMap集合底层是数组加链表,1.8以后引入了红黑树,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入 ;1.8之后链表新进元素加到末尾
Lambda表达式
Optional类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中
等…

session的实现原理?session的生命周期?session如何储存数据?

session的实现原理:客户向服务器端发送请求后,服务端创建session,会把session对象的id以cookie形式返回给客户端,当下次发送请求时,会把session的id传给服务器,服务器根据session的id来为用户提供相应的服务。
session的生命周期:存储数据计时是滚动计时方式,等到默认时间后,自动销毁;
session如何存储数据:
session.setAttribute(String attrName,Object attrValue)--往session域中添加一个域属性,属性名只能是字符串类型,属性值可以是任意类型
session.getAttribute(String attrName)--根据属性名获取域中的属性值,返回值是一个Object类型

类加载机制?代码块的执行顺序?

加载过程:加载,验证,准备,解析,初始化,使用,卸载;
代码块的执行顺序:
在主类中定义的静态代码块会优先于主方法(main)执行;
静态块优先于构造块执行;
构造块优先于构造方法执行,每产生一个新对象就调用一次构造块,构造块可以进行简单的逻辑操作;
有继承关系的话,在main方法里new子类,则先调用父类,再调用子类;

cookie和session的区别?

cookie数据存放在客户的浏览器上,session存放在服务器上;
cookie不安全(因为存放在浏览器上,可以操作本地的cookie数据),session安全
cookie储存为String数据,session储存为Object类型数据
cookie可以长时间保存一些数据,session随着会话结束,销毁数据;

Java中字符串的方法有哪些?string、stringbuild、stringbuffer的区别?

String 类的常用方法:
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
string、stringbuild、stringbuffer的区别:
String:不可变的字符串序列
StringBuffer:可变字符串序列、效率低、线程安全(不能同步访问);
StringBuilder:可变字符串序列、效率高、线程不安全;

jvm调优和垃圾回收机制?

jvm调优:
使用JDK提供的内存查看工具,如JConsole和Java VisualVM;
控制堆内存各个部分所占的比例;
采用合适的垃圾收集器.
垃圾回收机制:
判断是否为垃圾(引用计数算法,可达性算法)
垃圾回收(标记清除、标记整理、标记复制)

Java中锁的种类和基本原理?

锁就是限制多线程中同时只有一个线程访问到这个锁对应的对象,其他线程要等待这个线程将锁释放了才能获取到这个锁,其实锁,它锁住的并不是要访问的对象,而是代码,假如多个线程访问一个对象,一个线程获取到了这个对象的锁,但是其他线程仍然可以访问这个对象并进行修改,只是获取不到锁
锁种类和原理:
公平锁:指的是按照申请的顺序来获取锁
非公平锁:线程不一定按照申请锁的顺序来获取锁
独享锁:一次只能被一个线程访问,如:写锁
共享锁:可以被多个线程所持有,如:读锁
乐观锁:对一个数据的操作并发,是不会发生修改的。在更新数据时会采用不断重入的方式更新数据.
悲观锁:对于同一个数据的并发操作,是一定会发生修改的。因此对于同一个数据的并发操作,悲观锁采用加锁的方式。悲观锁认为不加锁会出事.
分段锁:并发操作就是分段锁,其思想就是为了让锁的粒度变小;
偏向锁:指的是一段同步代码一直被一个线程访问,那么该线程就会自动获取锁,降低取锁的代价.

collection和collections的区别?

Collection是一个接口,它是Set、List等容器的父接口.
Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等

java如何跳出循环?

continue:中止本次循环,继续下次循环。continue以后的循环体中的语句不会继续执行,下次循环继续执行,循环体外面的会执行;
break:直接结束一个循环,跳出循环体。break以后的循环体中的语句不会继续执行,循环体外面的会执行
return:return的功能是结束一个方法。 一旦在循环体内执行return,将会结束该方法,循环自然也随之结束

排序有哪些?原理是什么?

冒泡排序:从第一个数开始,相邻元素两两对比,小的数放前面。(每循环一次,最后一个数都会被确定下来,为每轮的最大数)
选择排序:从第一个数开始,循环一圈找最小的数交换位置。(每循环一圈,第一个数都会被确定下来,为每轮最小的值)
插入排序:从第二个数开始,跟前一个数比较,若比前一个数小,则交换位置,接着跟前一个数比较,直到比前一个数大为止。(从第一张开始整理扑克牌,小的往前插)(可能会出现一个数从最后比较到最前面,比较费时)
希尔排序属于插入类排序,是将整个有序序列分割成若干个小的子序列分别进行插入排序。
归并排序:归并排序有两种实现方法:自上而下的递归;自下而上的迭代。
将原数组用二分法一直分到两个数为一组,然后通过比较将较小的数放到前面(通过一个中间数组排序);然后一层层向上排序。
快速排序:先找到一个基准点(一般指数组的中部),然后数组被该基准点分为两部分,依次与该基准点数据比较,如果比它小,放左边;反之,放右边。 左右分别用一个空数组去存储比较后的数据。最后递归执行上述操作,直到数组长度<=1。
堆排序:堆逻辑上是一棵完全二叉树。
计数排序:计数排序是一种不基于比较的排序算法,主要思想是计算出待排序序列的最大值 maxValue 与 最小值 minValue,开辟一个长度为 maxValue - minValue + 1 的额外空间,统计待排序序列中每个元素的数量,记录在额外空间中,最后遍历一遍额外空间,按照顺序把每个元素赋值到原始序列中。
基数排序:将整数按位数切割成不同的数字,然后按每个位数分别比较。
桶排序:假定有1-100个编号的桶(既定义一个长度为100的整型一维数组),每输入一个数字·就在对应的桶上插一个小旗(也就是对应下标的桶加1次),如果这个数字出现了n次就在对应桶上插n个小旗,当所有数输入完毕时,只需要从下标1开始找那些数字是1,如果是1就打印1次,是2就打印2次,是多少就打印多少次。

什么是堆栈?什么是内存溢出?有垃圾回收机制了为什么还会出现内存溢出的情况?

堆栈(两种不同的数据结构):
堆:顺序随意
栈:先进后出
实例对象,实例变量存在堆中
局部变量,参数放在栈中
方法,静态变量存在方法区中
内存溢出:
内存溢出(out of memory),是指程序在申请内存时,没有足够的内存空间供其使用,出现内存溢出。
内存泄露最终也会导致内存溢出。
有垃圾回收机制(内存满了就回收垃圾再分配空间)了为什么还会内存溢出:
垃圾回收机制只能回收没有引用的对象,也就是说只能回收没有“指针”的对象,对于非引用类对象,垃圾回收机制就不能起作用,比如说打开过多的数据库连接,ArrayList死循环,就不能被回收可能会造成内存溢出的情况

内存模型的理解?

为了解决多线程通信,变量共享的并发问题并且保障跨平台行,Java定义了自己的内存模型.内存模型描述了程序中各个变量之间的关系,以及操作系统将变量存储到内存以及从内存中取出变量这样的细节.此处的变量不包括局部变量与方法参数,后者是线程私有的,不会被共享.所以说JMM帮助屏蔽了操作系统底层的细节,保障了程序的正确性.

泛型的理解

用于指定添加到集合的类型
好处:
类型参数化,通用、可以像方法一样的参数一样传递,非常实用。
安全、编译时检查类型是否正确,降低类型强转报错率。
提高代码重用率。

Java的基本类型有哪些?int占几个字节?byte占几个字节?

image.png

常见的异常有哪些?异常处理的方式有哪些?

Exception:需要进行处理,用于用户程序可以捕获到异常情况;
error:程序对此无能为力,不显式的处理,定义了不期望被用户捕捉到的异常
异常处理方式:
在方法声明处,显式的使用throws+异常类型
try{处理方式1}catch{处理方式2}finally{一定要执行的代码}
定义异常,继承Exception(受检查异常)或者RuntimeException(非受检查异常)
image.png

枚举的了解?

枚举类是一种特殊的类,它和普通的类一样,有自己的变量、方法和构造器。它的构造器只能使用private访问修饰符,所以无法从外部调用构造器,构造器只能在构造枚举值时被调用
一个java源文件中只能有一个public类型的枚举类,而且该原文件的名字也必须和该枚举类的名字一致。也就是在一个文件中只能有一个public修饰的枚举类。这里不包括内部类哈,指的是公共访问的.java文件的入口。
枚举类和class,interface地位是等同的,枚举也能实现接口。
枚举类的对象是有限且固定的,常用于状态、类型
枚举类默认集成了java.lang.Enum 类,并实现了java.lang.Seriablizable 和 java.lang.Comparable两个接口
所有的枚举值都默认是public static final的,不用重复声明,而且枚举值应该显式的在枚举类第一行列出,否则无法产生实例,非抽象的枚举类不能再派生子类。
枚举值列举的时候也可以实现该枚举类实现的接口方法。

final、finally、finalize关键字的区别?volatile关键字的了解?

final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。
volatile关键字:
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
禁止进行指令重排序。

在一个list中存放string类型的字符串,如何实现把所有带“王”的字符串从list中去除?

遍历集合for(String s:list)
判断遍历的对象中是否含有“王”if(s.indexOf(“王”)!=-1)
执行删除list.remove(s)

如何序列化和反序列化?序列化的目的?

序列化是指将Java对象转换为字节序列的过程,而反序列化则是将字节序列转换为Java对象的过程。
实现序列化:实现Serializable、Externalizable接口(没有任何方法,只是作为一种标记)
实现反序列化:即反向进行序列化的过程,需要将一个InputStream封装在ObjectInputStream对象内,然后调用readObject()方法,获得一个对象引用(它是指向一个向上转型的Object),然后进行类型强制转换来得到该对象。
目的:
实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(如:存储在文件里),实现永久保存对象。
利用序列化实现远程通信,即:能够在网络上传输对象。

你可能感兴趣的:(java,基础,面试)