面试——java基础篇,带个人题目理解

java基础篇:

  1. 集合有哪些?数据结构?初始长度?扩容机制?哪些线程是安全的?hashmap的底层原理?
    1.单列集合;1:List(有序,可重复);
    1.ArrayList:底层数据结构为数组,查询快,增删慢,线程不安全,效率高,初始长度10,增量0.5倍加1;
    2.Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,初始长度10,增量1倍;
    3.LinkedList:底层数据结构是链表,查询慢,增删块,线程不安全,效率高;
    2:Set(无序,唯一);
    1.HashSet:底层数据结构是哈希表(哈希表依赖两个方法hashCode()和eauals()),执行顺序为首先判断hashCode()的返回值哈希值是否相同,是则继续执行equals()判断地址是否相同,是则不添加,否则添加;初始容量16,加载因子0.75(超过集合长度值),扩容增量1;
    2.LinkedHashSet(HashSet的子类):底层数据结构由链表和哈希表组成,链表保证数据有序,哈希表保证数据唯一;
    3.TreeSet:底层数据结构是红黑树(自平衡的二叉树),添加数据通过返回值是否为0来决定数据的唯一性,通过自然排序(元素要具备比较性,让元素所属的类实现Comparable接口)和比较器排序(集合具备比较性,让集合接收一个Comparable的实现类对象)这两种方式实现集合元素的排列;
    2.双列集合;3.Map(Map集合的数据结构仅仅只针对键有效,与值无关;储存键值对形式,键唯一,值可重复);
    1.HashMap:底层数据结构是哈希表(数组加链表),线程不安全,效率高,调用put(),get()方法存储,获取对象,调用put()方法存储时,会先调用键对象的hashCode()方法来计算哈希值,然后找到bucket位置来储存对象,获取对象时,通过键对象的equals方法找到正确的键值对,返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。HashMap在每个链表节点中储存键值对对象,当两个不同键值对对象的哈希值相同会储存在同一个bucket位置的链表中,键对象的equals方法用来找到键值对;初始容量16,加载因子0.75,扩容增量1;
    2.LinkedHashMap(HashMap的子类):底层数据结构由哈希表和链表组成,哈希表保证数据唯一,链表保证数据有序;
    3.Hashtable:底层数据结构是哈希表,线程安全,效率低;
    4.TreeMap:底层数据结构是红黑树

2.线程的创建?开启?状态?sleep和wait的区别?线程池?死锁?如何保证线程安全?
线程的创建:
无返回:
1.实现Runnable接口,重写run();
2.继承Thread类,重写run();
有返回:
1.实现Callable接口,重写call(),利用FutureTask包装Callable,并作为task传入Thread构造函数;
2.利用线程池
线程的启动:
启动线程的唯一方法就是通过Thread类的start()实例方法。
线程的状态:新建,就绪,运行,阻塞,死亡
sleep和wait的区别:
1.所属对象不同:
sleep属于Thread类中的方法,wait属于Object类中的方法
2.对锁的控制权不同:
调用sleep方法的线程对象,虽然在指定时间内不会获得CPU的执行权,但是并没有释放对锁的控制权,即当休眠状态的线程获得锁的时候,其他线程不能重新获得锁,但是wait方法是释放锁的,使其他线程可以获得锁而获得资源的控制权;
线程池:服务器完成一个线程的时间:T1创建线程时间+T2线程执行任务所需时间+T3线程销毁时间;如果T1+T3要远大于T2,这个时候就可以采用线程池;提高服务器的性能;线程池技术正是关注如何缩短和调整T1,T3时间的技术,从而提高服务器性能的。它把T1,T3分别安排在服务器程序启动和结束的时间段或者一些空闲的时间段,这样在进行处理客户请求时就不会有T1,T3的开销了;
线程池构成:
1.线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务
2.工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可循环的执行任务;
3.任务接口(Task):每个人物必须实现的接口,以供工作线程调度任务的执行,他主要规定了任务的入口,任务执行完后的收尾工作,任务执行状态等;
4.任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
死锁:是指两个或者两个以上的进程在执行过程中,由于资源竞争或者彼此通信造成的阻塞现象
线程安全:一般说来,确保线程安全的方法有这几个:竞争与原子操作、同步与锁、可重入、过度优化

3.==和equals的区别?
:对于基本类型比较值,对于引用类型比较内存地址
equals:它是object类中的方法,该方法如果没有被重写过默认也是“
”,只能用于引用类型的比较;

4.对反射的理解?获取class类的方式有哪些?如何用反射取私有属性Filed?
反射:就是程序在运行过程中能够获取自身的信息,(即能获取java中反射类的字节码,)在java中只要给定类的名字就能够通过反射机制获取该类的所有信息;
获取class类的方式:
1.Class class=Class.forName(“被获取类的全限定类名”)
2.Class class=类名.class
3.Class class=类对象(this).getClass()
如何用反射取私有属性Filed:
Field[] fields=s.getClass().getDeclaredFileds();
修改私有属性:
追加:fields.setAccessible(true);
获取对象:
Student s=(Student)class.getConstructor().newInstance();(初始化无参构造方法加强转)

5.常用设计模式有哪些?项目中那里有用到?单例中懒汉饿汉优缺点?
常用设计模式:Singleton(单例模式)、Factory(工厂模式)、Proxy(代理模式)、Adapter(适配器模式)、Strategy(策略模式)、Template(模板模式);
哪里用到:
1.数据库连接池,线程池,网站访问计数器,mybatis中的SqlSessionFactory,spring容器中的bean对象默认使用到了单例模式;
2.spring中的aop用到了代理模式
3.jdbc连接数据库用到了桥接模式
懒汉饿汉优缺点:
饿汉:在加载类时就构建,预先加载;
优点:线程安全,在类加载的同时就创建好了静态对象,调用时反应速度快;
缺点:资源效率不高,
懒汉:单例实例在第一次被使用时被构建,延时加载(在单线程使用没有问题,但在多线程就可能会出现两个或者多个Singleton2实例情况,虽然后面的Singleton2会覆盖之前的单最好避免,改进方式就是加锁synchornized:双重检测,一般采用饿汉式单例模式,若对内部静态资源比较在意可以采用静态内部类,不建议采用懒汉单例模式);
优点:资源利用率高
缺点:第一次加载不够快,多线程使用不必要的同步开销大
restful设计风格:Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

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

7.session的实现原理?session的生命周期?session如何储存数据?
session的实现原理:客户向服务器端发送请求后,session创建在服务器端,返回session给客户端浏览器保存在本地,当下次发送请求时,在请求头中传递sessionId获取服务器上的对应的session;session存放在服务器,关闭浏览器session不会消失;
session生命周期:等到默认时间后,自动销毁;
session如何储存数据:httpSession.setAttribute(键值对);

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

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

10.Java中字符串的方法有哪些?string、stringbuild、stringbuffer的区别?
String的方法:
1.equals,只比较字符串里面的内容;
2.charAt(0),寻找对应ascii码对应的字符(47-58对应0-9)
3.concat方法就是连接字符串
4.contains方法 是否包含某个字符串
5.replace方法用新的字符串来代替旧的字符串
6.toCharArry就是将字符串转化为字符数组
7.trim方法 是去掉前后的空格等…
string、stringbuild、stringbuffer:
string的值是不可变的,但是stringbuild、stringbuffer可以被多次修改;
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
String:不可变的字符串序列
StringBuffer:可变字符串序列、效率低、线程安全;
StringBuilder:可变字符串序列、效率高、线程不安全;

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

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

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

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

15.排序有哪些?原理是什么?
1.比较排序:
1.冒泡排序:每次对相邻的两个元素进行比较,若前者大于后者则进行交换,如此一趟下来最后一趟的就是最大元素,重复以上的步骤,除了已经确定的元素;
2.选择排序:选择排序改进了冒泡排序,每次遍历列表只做一次交换,为了做到这一点,一个选择排序在遍历时寻找最大的值,并在完成遍历后,将其放到正确的地方。第二次遍历,找出下一个最大的值。遍历n-1次排序n个项,最终项必须在n-1次遍历之后
3.插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
4.归并排序:归并排序是一种递归算法,不断将列表拆分为一半,如果列表为空或有一个项,则按定义进行排序。如果列表有多个项,我们分割列表,并递归调用两个半部分的合并排序。一旦对两半排序完成,获取两个较小的排序列表并将它们组合成单个排序的新列表的过程
5.堆排序:堆逻辑上是一棵完全二叉树。
6.快速排序:先定义两个指针,一个在最前面,一个在最后面,第一次要对数组进行划分,先找出一个中间数,一般默认把第一个数作为中间数,然后从后往前找比中间数小的,把他放在前一个指针的位置,在从前往后找比中间数大的,找到后把它放在第二个指针的位置,直到前面和后面的指针指向同一个位置,我们就把中间值放在这里即可,这样根据中间数,把整个需要排序的数组分为两部分,前一部分都小于中间数,后一部分都大于中间数,此时这两部分的数还是无序的,最后递归调用排序方法,对两部分分别进行排序即可。
2.非比较排序:
1.计数排序:计数排序是一种不基于比较的排序算法,主要思想是计算出待排序序列的最大值 maxValue 与 最小值 minValue,开辟一个长度为 maxValue - minValue + 1 的额外空间,统计待排序序列中每个元素的数量,记录在额外空间中,最后遍历一遍额外空间,按照顺序把每个元素赋值到原始序列中。
2.基数排序:将整数按位数切割成不同的数字,然后按每个位数分别比较。
3.桶排序:假定有1-100个编号的桶(既定义一个长度为100的整型一维数组),每输入一个数字·就在对应的桶上插一个小旗(也就是对应下标的桶加1次),如果这个数字出现了n次就在对应桶上插n个小旗,当所有数输入完毕时,只需要从下标1开始找那些数字是1,如果是1就打印1次,是2就打印2次,是多少就打印多少次。

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

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

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

19.Java的基本类型有哪些?int占几个字节?byte占几个字节?
Java的基本数据类型(8位位1字节):
1.byte:1字节,8位
2.short:2字节,16位
3.int:4字节,32位
4.long:8字节,64位
5.float:4字节,32位
6.double:8字节,64位
7.char
8.boolean

20.常见的异常有哪些?异常处理的方式有哪些?
异常:
(1) Error: jvm 监管范围外的,可以捕获,但是无法解决
(2) Exection:既可以捕获,也可以解决(Exception:编译异常,强制处理,RuntimeException:运行时异常,不强制处理)
处理方式:
1.捕获
2.抛出

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

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

23.在一个list中存放string类型的字符串,如何实现把所有带“王”的字符串从list中去除?
1.遍历集合for(String s:list)
2.判断遍历的对象中是否含有“王”if(s.indexOf(“王”)!=-1)
3.执行删除list.remove(s)

24.string a=“123”;string b=“123”;a+=b;生成了几个对象?
3

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值