Java后台开发常见面试题
八种基本数据类型的大小,以及他们的封装类
创新互联建站是专业的连江网站建设公司,连江接单;提供成都网站制作、做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行连江网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
整数型: byte 1个字节 -128~127 封装类:Byte short 2个字节 -32768~32767 Short Int 4个字节 -2147483648~2147483647 Integer long 8个字节 -2的63方~2的63次方-1 Long 浮点型: float 4个字节 单精度 Float Double 8个字节 双精度 Double 布尔类型: boolean 4个字节 true或false Boolean 字符类型: char 2个字节 Character
引用数据类型:
分为3种,类、接口和数组Switch能否用String做参数
在jdk7以前,switch只支持byte、int、short、char或者对应的包装类和枚举。
equals和==的区别
a) 对象类型不同 equals是超类Object的方法,而==是操作符 b) 比较类型不同 equals用来检测两个对象是否相同,即两个对象的内容是否相等,==比较引用数据类型和基本数据类型时具有不同的功能。==比较的是变量(栈)内存中存放的对象的内存地址,用来判断两个对象的地址是否相同,即是否指向同一对象,比较的是真正意义上的指针操作,而equals用来比较的是两个对象的内容是否相同,适用于所有对象。 c) 注意:如果没有对该对象进行覆盖的话,调用的仍然是超类Object的方法,而Object中的equals方法返回的是==的判断。
自动拆装箱和常量池
a) Java自动将原始数据类型值转换成对应的对象,比如将int类型的变量转换成Integer类型,自动装箱时调用valueOf将原始数据类型转换成对应的对象。 b) 反之,将Integer对象装换成int类型值,这个过程叫拆箱,自动拆箱通过调用类似intValue、doubleValue这类的方法将对象转换成对应的原始数据类型。 c) Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 i. 静态常量池:即.*class文件中的常量池,class文件中的常量池不仅仅包含字符串,还包含类、方法的信息,占用class文件绝大部分空间。 ii. 而运行时常量池:则是jvm虚拟机在完成类装载过程后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池就是指方法区中的运行时常量池。
Object中有哪些公用方法?
a) Clone:实现对象的浅复制,只有实现了cloneable接口才可以调用此方法,否则会抛出CloneNotSupportedException异常。 b) Equals:在Object中和==是一样的,子类一般需要重写此方法。 c) Hashcode:该方法用于哈希查找,重写了equals方法一般都要重写hashcode方法,这个方法在一些具有哈希功能的collection中用到。 d) getClass:获得运行时的类型。 e) wait:是当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是说具有该对象的锁! f) Notify:唤醒在对象上等待的某个线程。 g) notifyAll:唤醒该对象上等待的所有线程。 h) toString:转换成字符串,一般子类都要重写此方法,否则打印句柄。
Java的四种引用,强弱软虚。
a) 强引用:最常见,把一个对象赋给引用数据类型则为强引用。如果内存中不足,java虚拟机将会跑出OutOfMemoryError错误,从而将程序异常停止强引用的对象是不可以gc回收的,不可以随意回收具有强引用的对象来解决内存不足的问题。在java中,强引用是一种默认的状态,除非Java虚拟机停止工作。 b) 软引用:如果一个对象具有软引用,内存空间足够,垃圾回收就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序继续使用。软引用用来实现内存敏感的高速缓存,比如网页缓存或图片缓存,使用软引用能防止内存泄露,增强程序的健壮性。 c) 弱引用:用来描述非必需对象的,当jvm进行垃圾回收的时候,无论内存是否充足,都会回收被弱引用关联的对象。 d) 虚引用:他不影响对象的生命周期,如果一个对象与虚引用关联,则跟没有与之关联一样,在任何时候都可能被垃圾回收器回收。
hashcode的作用
比较两个对象是否相等,重写的equals方法一般比较全面,比较复杂,效率比较低,而采用hashcode方法进行对比,只需要生成一个hashcode进行比较就可以了!
Hashmap中的hashcode的作用
a) Hashcode的存’用于查找的快捷性,如hashtable、hashmap等,hashcode是在散列结构中确定对象的地址。 b) 如果两个对象相同,就是适用equals方法,那么这两个对象的hashcode一定要相同。 c) 如果对象的equals方法被重写,那么对象的hashcode也尽量重写,并且产生hashcode使用的对象,一定要和equals放法使用的一致,否则会违反上面的第二点。 d) 两个对象的hashcode相同,并不代表这两个对象就相同,也就是不一定适用equals方法,只能说明这两个对象在散列存储结构中,如hashtable,他们“存放在同一个篮子里”。
为什么重载hashcode方法?
一般不需要重载hashcode方法,只有当类放在hshtable、hashmap、hashset等hash结构的集合时,才会重载hashcode。就hashmap来说,好比hashmap就是一个大内存块,里面有许多小内存块,小内存里面就是一系列的对象,可以利用hashcode查找小内存块,,所以当equals相等时,hashcode必需相等,而且如果是Object对象,必须重载hashcode和equals方法。
Arraylist、linkedlist和vector的区别?
a) Arraylist:底层数据结构是数组,查询快、增删慢,线程不安全。 b) Liskedlist;底层数据结构是链表,查询慢、增删块,线程不安全。 c) Vector:底层是数组,查询慢、增删慢,线程安全。
String、stringbuffer与stringbulder的区别?
a) String是不可变的对象,因此每次对string类型进行改变的时候,就等于生成了一个新的对象,然后蒋指针指向一个新的string的对象,因此经常改变内容的字符串最好不用string,因为每次生成对象都会对系统性能产生影响,特别是当内存中无引用对象过多时,jvm的gc就会开始工作,那么速度一定会非常慢。 b) 而stringbuffer结果就完成不一样了,每次结果都会对stringbuffer本省进行操作,而不是生成新的对象,再改变对象的引用。是线程安全的。 c) Stringbuildere是jdk5以后新增的,其用法和stringbuffer完全一致,但它是线程不安全的,在单线程中是最佳的,因为不需要维护线程的安全。
Map、set、list、queue、stack的特点与用法。
a) Map是键值对,键key是唯一不能重复的,一个键对应一个值,值可以重复,treemap可以保证顺序,hashmap不保证顺序,即是无序的,map可以把key和value单独抽取出来,其中keyset()方法可以将所存的key抽取成一个set。而valuses方法可以将map中所有的value抽取成一个集合。 b) Set:不包含重复元素,且最多包含一个null元素,只能用iterater实现单向遍历, set没有同步方法。 c) List:有序的可重复集合,可以在任何位置增加和删除元素。用Iterator实现单向遍历,也可以用listIterator实现是双向遍历。 d) Queue:遵从先进先出原则,使用时尽量避免add()和remove()方法,而只是使用offer()来添加元素,使用poll来移除元素,它的优点是可以通过返回值来判断是否成功,LinkedList实现Queue接口,Queue通常不允许插入null元素。 e) Stack:遵从先进后出原则,stack继承自vector,它通过五个操作对类vector进行扩展,允许将向量视为堆栈,它提供push和pop操作,以及取堆栈顶点的peek()方法,测试堆栈是否为空的empty()方法等。 f) 用法:如果涉及堆栈、队列等操作,建议使用list,对于快速插入和删除元素,建议使用linkedlist,如果,快速随机访问元素,建议使用ArrayList。
Hashmap和hashtable的区别?
a) 都是map接口的实现类,都是基于hash表的实现类。
b) Hashmap集合线程不安全的类,不同步,执行效率高,允许键和值是null。
c) Hashtable集合是线程安全的类,同步,执行效率低,不允许键和值为null。
Jdk7和jdk8中的hashmap的实现。
a) Jdk7:hashmap底层维护一个数组,数组中的每一项都是一个entry,我们向hashmap中放置的对象实际上存储在该数组中,map中的key和value则以entry的形式存放在数组中,而这个key放在数组的哪一个位置上,是通过key的hashcode来计算的。 b) Jdk8:采用(位桶+链表)红黑树的方式,也是非线程安全的。
Hashmap和hashConcurrentHashmap的区别,hashmap的底层源码。
Hashmap是线程非安全的,效率比较高,hashtable和ConcurrentHashmap是线程安全的,效率比hashmap差一点,但ConcurrentHashmap采用了更高级的分段锁机制,具体可以理解为把hashmap拆分为n个小的hashtable,根据key。Hashcode()来决定把key放到哪个hashtable中,在concurrenthashmap中,就是把map分为n个segment,put和get时,都是key.hashcode()算出放到哪个segment中。
接口和继承的区别?接口内可以定义常量吗?继承可以继承父类的那些东西?
a) 区别: i. 标识符不同,interface和extends ii. 接口支持多继承,而不支持继承的继承 iii. 接口中只能定义全局变量和抽象变量,而继承中可以定义属性、方法、常量、变量等。 iv. 某接口被实现,在类中一定要实现接口所有的方法,而继承只需要用哪一个就调用哪一个。 b) 接口不可以定义常量。 c) 继承可以继承父类所有的东西(成员方法、成员变量、包括私有)。
如何修改父类中以private关键字修饰的变量?
如果父类中有public的set方法,就可以通过set方法修改父类中以private修改的变量。
Java中public、private 、protect、default的区别?
a) Public:java中访问限制最宽的修饰符,即公共的,被修饰的类、属性、方法允许跨类访问,甚至可以跨包访问。 b) Private:是java中访问限制最窄的修饰符,被private修饰的类、属性、方法只能被本类的对象进行访问,其子类不能访问,更不允许跨包访问。 c) Protec:介于public和private之间的一种访问修饰符,一般称受保护的,被其修饰的类、方法、属性只能被本类和子类进行访问,即使子类不在同一个包下。 d) Default:意为默认的,即不加修饰符,该模式下只能同一个包下进行访问。
数据库锁的问题?如何上锁?是不是行锁?
a) 当多个用户同时对数据库进行操作时,会带来数据不一致的问题,所以锁主要是用于多用户环境下保证数据库完整性和一致性. b) 锁分类:从数据库系统来看:排它锁、悲观锁、更新锁 从程序员角度来看:一种是乐观锁,一种是悲观锁。 i. 悲观锁:很悲观,每次去拿数据的时候,都以为别人会修改,所以在每次拿数据的时候,都会上锁,这样别人拿这个数据就会block,直到它合锁。具有强烈的排他性和独占性,悲观锁的实现依靠数据库提供的机制,也只有数据库底层提供的机制才能保证数据访问的排他性。传统的关系型数据库用到了很多这同样的机制,比如行锁、表锁、读锁、写锁等,都是在操作前加上锁。 ii. 乐观锁:很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。悲观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write—condition机制的其实都是提供的乐观锁。
c) 按作用性质分:
i. 共享锁:也叫读锁,用于所有只读操作,不能同时增删改,可以查。
例如:select * from 表 lock in share mode;
ii. 排它锁:也叫读锁,表示对数据进行写操作,一个事务对象施加了排它锁,其他事务就不能加锁了。
例如:查询时加排它锁,别人不能加共享锁和排它锁。
Select * from 表 for update;
仅允许一个事务封锁此表,其他事务必须等到此锁被释放才能访问。
排它锁(x锁)一直到事务结束才能释放。
iii. 更新锁:允许其他事务读,但不允许在施加x锁和u锁,当要被读取的对象要被更新的时候,则升级为x锁,防止死锁,如果一个数据在修改前直接申请更新锁,在修改时再升级为排它锁,就可以避免死锁。
d) 按范围分:
i. 行锁:锁的范围是行级别,数据能够确定哪些行需要锁的情况下使用行锁(inodb),如果在不知道会影响到哪些数据的时候就会使用表锁
例如:一个用户表有主键id和birthday。
Update …where id=? 行锁
Update … where birthday=? 表锁
ii. 表锁:锁的范围是整张表。 MyISAM
22.事务的隔离性
a) 隔离性级别越低,并发性越好,但数据库的一致性就越差。
隔离级别越高,并发性越差,但数据库的一致性高。
b) 由低到高
读未提交<读提交<可重复读(默认)<序列化读
c) 错误的级别由低到高:
脏读、不可重复读、幻读
脏读:两个事物,一个事务先修改,另一个事务读,结果是修改前的结果。
不可重复读:两个事物,一个先读是一个结果,一个后修改,再读,又是一个结果。
幻读:第一个事务表中有10、20、30、40几个部门,第二个事务插入表中50的部门,然后提交,第一个事务插入50部门,主键冲突。
23.能否用一个sql语句解决库存判断问题(非查询语句)。
用if语句:if(exper1,exper2,exper3)
如果exper1的值是true,则返回是exper2的值,如果exper1的值是false,则返回exper3的值。
例如:id name number
1 苹果 300
2 梨 100
Update fruit set number=if(number>200,number,0)where if=’1’;
即如果苹果的数量大于200,就不变,否则,number改为0,即就可以判断内存是否充足。
24.红黑树
a) 特性:
i. 每个节点都是黑色或者红色。
ii. 根节点是黑色。
iii. 定义null为黑色。
iv. 如果某个子节点是红色,那么它的两个儿子都是黑色,且父节点一定是黑色。
v. 对于任意节点,它到叶子节点的每一条路径都包含相同数目的黑色节点
性质5称之为黑高。
b) 相对平衡:
i. 若H(left)>=H(right),则H(left)=2*H(right)+1
ii. 但BH(left)=BH(right),H(left)
c) 在调整节点p之前,必需保证p的左子树left、右子树right都已经是rbt。
i. 多个子问题成立->某个总问题成立
ii. 插入调整:删除调整均是由底向上
d) Rbt的插入调整(默认是红色)
i. 无需调整
- X为根节点,将x由红染黑
- 父亲节点是黑色
ii. 仅仅考虑父亲节点p是红色,由于性质4,爷爷节点必定是黑色,分为3中:
1. Case1:y为黑色,x可左可右;p、y染黑,g染红;x回溯至g
2. Case2:y为黑色,x为右孩子,左旋p,x指向p,转为case3
3. Case3:y为黑色,x为左孩子,p染黑,g染红,右旋g结束。
Rbt的插入调整最多2次
右旋转:逆时针旋转两个节点,使父亲节点被右孩子取代,而自己变成左孩子。
左孩子:顺时针旋转两个子节点,使父亲节点被左孩子取代,自己变成右孩子。
25.Session是什么?和cookie的区别?
a) Cookie通过客户端记录信息确认身份,session是通过服务端的信息确认身份。
b) 客户端浏览器访问服务器的时候,服务端把客户端的信息以某种形式记录在服务器上,这就是session,用户与服务器建立连接的同时,服务器自动分配一个sessionid。
c) 区别:cookie不×××全,别人可以分析本地存在的cookie并进行cookie欺骗,考虑到安全应当使用session。
有哪些排序算法?说一下堆排序?时间复杂度是多少?
a) 直接插入排序:第一个元素已经排序,第二个与第一个元素进行比较,第一个大,第一个则与第二个交换位置,第三个分别于第一个和第二个比较,以此类推。 时间复杂度:O(n*n) b) 希尔排序:按步长grep进行分组,然后将每组元素利用直接插入排序的方法进行排序;每一次结束后再将步长grep减半,循环上述操作,直到步长grep=1,利用直接插入排序,完成排序。 时间复杂度:O(log n) c) 简单选择排序:首先在未排序序列中找到最小(或最大)的元素,放在排序序列的起始位置,然后再从未排序序列中找到最小(最大)的元素,放在已排序序列的后面。 时间复杂度:O(n*n) d) 堆排序:堆排序过程就是将待排序序列构造成一个堆,选出堆中最大的移走,再把剩下的整成堆,找出最大的在移走,重复直至有序。 i. 每次将根节点与左右节点最大的进行交换,直到根节点最大,然后把根节点放在最后一个位置,然后再次执行循环,找到最大值放在长度-1的位置。 ii. 时间复杂度:O(n log n) e) 冒泡排序:每次比较两个元素,把小的放在前面。 时间复杂度:O(n*n) f) 快速排序:把一个序列分为两个子序列,步骤可分为: i. 从数列中选出一个元素,作为基准。 ii. 重新排序数列,所有比基准序列小的元素放在基准前面,所有比基准大的元素放在基准后面,相同的放在任意一边,在这个分区结束后,该基准处于中间位置。 iii. 递归将小于基准的子序列和大于基准的子序列排序。 iv. 即:先对大序列进行排序,大序列分为两个子序列,然后递归调用方法对这两个序列进行排序。 g) 归并排序:将两个或两个以上的有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列都是有序的,然后再把整个序列合并成整体有序序列。 时间复杂度:O(nlogn) h) 基数排序:将所有待比较的数(正整数统一为同样的数位长度),数位数不足的前面补0,然后从低位开始,依次进行一次排序,这个序列从最低位排序一直到最高位排序完成以后,数列将变成一个有序序列。 时间复杂度:O(d*(n+r)) D为位数,r为基数,n为数据个数
27.Statement和preparestatement的区别?
a) 代码的可读性和可维护性preparestatement更好。
b) Preparestatement尽最大可能提高性能。
c) 提高安全性,preparestatement防止sql注入。
28.NIO和IO到底有什么区别?有什么关系?
a) NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式去写入和读出的,肯定NIO的效率比IO的效率高出好多。
b) NIO不是和IO一样用Ouputstream和Inputstream输入流形式来处理数据,但是基于这种流的形式,而是采用通道和缓冲流的形式来处理数据的。
c) NIO通道可以是双向的,IO中的流只能是单向的。
d) 还有就是NIO的缓冲区(其实也是一个字符数组)还可以进行分片,可以建立只读缓冲区、直接缓冲区和间接缓冲区,只读缓冲区很明显就字面意思,直接缓冲区是为了加快I/O速度,而以一种特殊的方式分配其内存的缓冲区。
29.数据库索引的分类,索引底层的实现,说一下b+树,b-树?
a) 索引的作用:
i. 提高查询速度
ii. 确保数据的唯一性
iii. 可以加快表与表之间的连接,实现表和表之间的完整性。
iv. 使用分组和排序字句进行数据检查时,可以减少分组和排序的时间。
v. 全文检索字段进行搜索优化。
b) 分类;
i. 主键索引(PRIMAY_KEY):确保数据记录的唯一性,一个表只有一个。
ii. 唯一索引(UNIQUE):避免一个表中某些数据列中的值重复。可以有多个。
iii. 常规索引(INDEX):快速定位特定数据。
iv. 全文索引(FULLTEXT):快速定位特定数据,只能用于MyISAM类型的数据表。
c) 索引底层实现:把平衡树当做数据表默认的索引数据结构,平衡树也就你、b+tree或者b-tree。
d) B-tree:适用于外查找的树,是平衡树的多叉树。
i. 一个m阶b树是一颗平衡的m路搜索树,它或者是空树,或者满足下列性质:
1. 定义任意非叶子节点最多有m个儿子,且m>=2;
2. 根节点的儿子数[2,m];
3. 除根节点以外的叶子节点的儿子数{m/2,m};
4. 每个节点存放m/2-1(向上取整)和至多m-1个关键字(至少2个)。
5. 非叶子节点的关键字个数=指向儿子的指针个数-1;
6. 非叶子节点的关键字:k[1]、k{2}…k[m-1],且k{i}
ii. B-树的特性:
1. 关键字集合分布在整棵树中。
2. 任何一个关键字出现且只出现一个节点中。
3. 搜索可能在非叶子节点结束。
4. 其搜索性能等价于在在关键字全集中做一次二分查找。
5. 自动层次控制。
e) B+树:
i. B+树的定义:
1. 其定义与b-树基本相同,除了:
2. 非叶子节点的子树指针与关键字个数相同。
3. 非叶子节点的子树指针p[i],指向关键字属于k[i],k[i+1]的子树。
4. 为所有关键字增加一个键指针。
5. 所有关键字在叶子节点出现。
ii. B+树的特性:
1. 所有关键字都出现叶子节点的链表中(稠密索引)且链表中的关键字恰好是有序的。
2. 不可能在非叶子节点命中。
3. 非叶子节点相当于叶子节点的索引(稀疏索引),叶子节点相当于存储数据(关键字)的数据层。
4. 更适合文件索引系统。
30.java类加载的过程。
类从被加载到jvm中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
其中类加载的过程包括加载、验证、准备、解析、初始化五个阶段。
类加载的任务是根据一个类的全限定名来读取此类的二进制字节流到jvm中,此后转换为一个与目标类对应的java.lang.Class对象实例。
bootstrapclassloader、extclassloader和appclassloader defineclass方法将字节码的byte数组转换为一个类的class对象实例,如果此类被记载到jvm时就被链接,那么就可以调用resolveclass方法
自定义类加载器需要继承抽象类classloader,实现findclass方法,该方法会在classloader调用的时候被调用,findclass默认会抛出异常。
findclass方法表示根据类名查找类对象。
loadclass方法根据类名进行双亲委托模型进行类加载并返回类对象。
defineclass方法根据类的字节码转换为类对象。
双亲委托模型:当一个类接受到一个类加载的任务时,不会立即展开加载,而是将加载任务委托给它的父类加载器去执行,每一层的类都会采用相同的方法,直到委托给最顶层的启动类加载器为止。如果父类加载器无法加载委托给它的类,便将类的加载任务退回给下一级类加载器去执行加载。
双亲委托模型的工作过程是:如果一个类加载器收到类加载的请求,它不会自己尝试去加载这个类,而是把这个请求委托给父类加载器去完成,每一层次的类加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有父类加载器反馈自己无法加载这个加载请求时,子加载器才会尝试自己去加载。
使用双亲委托模型的好处:能够确保一个类的全局唯一性,当程序中出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的某一个类。
31.Object如果不重写hashcode()的话,hashcode()如何计算出来的?
Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法直接返回对象的 内存地址。
32.java8新特性。
(1)Lambda表达式
Lambda表达式可以说是Java 8最大的卖点,她将函数式编程引入了Java。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。
一个Lambda表达式可以由用逗号分隔的参数列表、–>符号与函数体三部分表示。例如:
Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e -> System.out.println( e ) );
(2)接口的默认方法与静态方法
我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现。例如:
public interface DefaultFunctionInterface {
default String defaultFunction() {
return "default function";
}
}
(3)方法引用
1)通常与Lambda表达式联合使用,可以直接引用已有Java类或对象的方法。一般有四种不同的方法引用:
2)构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;
3)静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;
4)特定类的任意对象方法引用。它的语法是Class::method。要求方法是没有参数的;
5)特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数,与不同的地方在于,3是在列表元素上分别调用方法,而4是在某个对象上调用方法,将列表元素作为参数传入;
(4)重复注解
在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次。Java 8引入重复注解,这样相同的注解在同一地方也可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。
(5)扩展注解的支持
Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。
(6)Optional
Java 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。
(7)Stream流
Stream API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!
(8)Date/Time API (JSR 310)
Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。
(9)JavaScript引擎Nashorn
Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。
(10)Base64
在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与×××。
33.说说lambda的优缺点。
优点:
1. 简洁。
2. 非常容易并行计算。
3. 可能代表未来的编程趋势。
4. 结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。
缺点:
1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势,并行计算目前对 Collection 类型支持的好,对其他类型支持的一般)
2. 不容易调试。
3. 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。
4. 在 lambda 语句中强制类型转换貌似不方便,一定要搞清楚到底是 map 还是 mapToDouble 还是 mapToInt
34.一个十进制的数在内存中是怎么存的?
以二进制补码形式存储,最高位是符号位,正数的补码是它的原码,负数的补码是它的反码加1,在求反码时符号位不变,符号位为1,其他位取反。
35.为啥有时候会出现4.0-3.6=0.40000001这种现象?
2进制的小数无法精确的表达10进制小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算,这个过程中出现了误差。
36.什么是值传递和引用传递?
值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;
在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
37.数组(Array)和列表(ArrayList)有什么区别?什么时候使用Array而不是ArrayList?
Array:它是数组,申明数组的时候就要初始化并确定长度,长度不可变,而且它只能存储同一类型的数据,比如申明为String类型的数组,那么它只能存储S听类型数据
ArrayList:它是一个集合,需要先申明,然后再添加数据,长度是根据内容的多少而改变的,ArrayList可以存放不同类型的数据,在存储基本类型数据的时候要使用基本数据类型的包装类
当能确定长度并且数据类型一致的时候就可以用数组,其他时候使用ArrayList
38.你了解大O符号(big-O notation)么?你能给出不同数据结构的例子吗?
大O符号表示当数据结构的元素增加的时候,算法规模或者性能在最坏场景下有多好。
大O符号也可以用来描述其他行为,比如说内存消耗。因为集合实际上就是一种数据结构,我们一般用大O符号基于时间、性能、内存消耗来选择最好的实现。
大O符号可以对大量数据的性能给出一个很好的说明
39.Integer 类和 int 的区别
1)、Integer 是 int 包装类,int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)
2)、Integer 是类,默认值为null,int是基本数据类型,默认值为0;
3)、Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。
40.&和&&的区别?
Java中&&和&都是表示与的逻辑运算符,都表示逻辑运输符and,当两边的表达式都为true的时候,整个运算结果才为true,否则为false。
&&的短路功能,当第一个表达式的值为false的时候,则不再计算第二个表达式;&则两个表达式都执行。
&可以用作位运算符,当&两边的表达式不是Boolean类型的时候,&表示按位操作。
41.java中如何跳出多重嵌套循环?
方法一:可以在需要的循环语句前定义一个标号,
然后在里层循环体的代码中使用带有标号的break语句,即可跳出外层循环
方法二:可以在需要的循环条件内加入一个boolean类型的判断,需要的时候将此变量值反转,再break当前循环即可跳出。
建议:推荐使用方法一,方便灵活,且代码可读性好。示例如下:
public static void main(String[] args) {
method1();
method2();
}
/**
* 利用标签
*/
public static void method1(){
tag:for (int i=0;i<9;i++){
for (int j=0;j<9;j++){
System.out.println(i+"*"+j+"="+i*j);
if (i==8&&j==7){
break tag;
}
}
}
}
/**
* 增加循环条件判断
*/
public static void method2(){
boolean flag=true;
for (int i=0;i<9&flag;i++){
for (int j=0;j<9;j++){
System.out.println(i+"*"+j+"="+i*j);
if (i==8&&j==7){
flag=false;
break;
}
}
}
}
42.我们在web应用开发过程种经常遇到输出某种编码的字符,如iso8859-1等,如何输出某种编码的字符串?
public String translate (String str) {
String tempStr = "";
try {
tempStr = new String(str.getBytes("ISO-8859-1"), "GBK");
tempStr = tempStr.trim();
}catch (Exception e) {
System.err.println(e.getMessage());
}
return tempStr;
}
44.你能比较一下java和JavaScript吗?
java:面向对象;需要编译,再进行运行;强类型.
javascript:基于对象和事件驱动;解释型语言;弱类型!
45.简述正则表达式及用途?
在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
46.java中是如何支持正则表达式操作的?
Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作,例如:
面试题: - 如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写?
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExpTest {
public static void main(String[] args) {
String str = "北京市(朝阳区)(西城区)(海淀区)";
Pattern p = Pattern.compile(".*?(?=\\()");
Matcher m = p.matcher(str);
if(m.find()) {
System.out.println(m.group());
}
}
}
47.请你说说java和php的区别?
PHP暂时还不支持像Java那样JIT运行时编译热点代码,但是PHP具有opcache机制,能够把脚本对应的opcode缓存在内存,PHP7中还支持配置opcache.file_cache导出opcode到文件.第三方的Facebook HHVM也支持JIT.另外PHP官方基于LLVM围绕opcache机制构建的Zend JIT分支也正在开发测试中.在php-src/Zend/bench.php测试显示,PHP JIT分支速度是PHP 5.4的10倍. PHP的库函数用C实现,而Java核心运行时类库(jdk/jre/lib/rt.jar,大于60MB)用Java编写(jdk/src.zip), 所以Java应用运行的时候,用户编写的代码以及引用的类库和框架都要在JVM上解释执行.
Java的HotSpot机制,直到有方法被执行10000次才会触发JIT编译, 在此之前运行在解释模式下,以避免出现JIT编译花费的时间比方法解释执行消耗的时间还要多的情况. PHP内置模板引擎,自身就是模板语言.而Java Web需要使用JSP容器如Tomcat或第三方模板引擎. PHP也可以运行在多线程模式下,比如Apache的event MPM和Facebook的HHVM都是多线程架构.不管是多进程还是多线程的PHP Web运行模式,都不需要PHP开发者关心和控制,也就是说PHP开发者不需要写代码参与进程和线程的管理,这些都由PHP-FPM/HHVM/Apache实现.PHP-FPM进程管理和并发实现并不需要PHP开发者关心,而Java多线程编程需要Java开发者编码参与.PHP一个worker进程崩溃,master进程会自动新建一个新的worker进程,并不会导致PHP服务崩溃.而Java多线程编程稍有不慎(比如没有捕获异常)就会导致JVM崩溃退出.对于PHP-FPM和Apache MOD_PHP来说,服务进程常驻内存,但一次请求释放一次资源,这种内存释放非常彻底. PHP基于引用计数的GC甚至都还没发挥作用程序就已经结束了。
48.介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰了成员方法,锁住了什么?
在synchronized里面,包含有三种常见的锁状态:
对于普通的同步方法:
锁是当前的对象
对于静态函数的同步方法:
锁是指引用当前类的class对象
对于同步方法块的内容:
锁是指Synchonized括号里配置的对象
49.介绍一下volatile?
volatile作为java中的关键词之一,用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile会禁止指令重排 volatile具有可见性、有序性,不具备原子性。 注意,volatile不具备原子性,这是volatile与java中的synchronized、java.util.concurrent.locks.Lock最大的功能差异。
50.说一下sychronized和lock?
1)来源:
lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;
2)异常是否释放锁:
synchronized在发生异常时候会自动释放占有的锁,因此不会出现死锁;而lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生。(所以最好将同步代码块用try catch包起来,finally中写入unlock,避免死锁的发生。)
3)是否响应中断
lock等待锁过程中可以用interrupt来中断等待,而synchronized只能等待锁的释放,不能响应中断;
4)是否知道获取锁
Lock可以通过trylock来知道有没有获取锁,而synchronized不能;
5)Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)
6)在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
7)synchronized使用Object对象本身的wait 、notify、notifyAll调度机制,而Lock可以使用Condition进行线程之间的调度,
51.讲一讲java里面的final关键字怎么用?
在java中,final的含义在不同的场景下有细微的差别,但总体上来说,它指的是“这是不可变的”。下面,我们来讲final的四种主要用法。
1)修饰数据
在编写程序时,我们经常需要说明一个数据是不可变的,我们称为常量。在java中,用final关键字修饰的变量,只能进行一次赋值操作,并且在生存期内不可以改变它的值。更重要的是,final会告诉编译器,这个数据是不会修改的,那么编译器就可能会在编译时期就对该数据进行替换甚至执行计算,这样可以对我们的程序起到一点优化。不过在针对基本类型和引用类型时,final关键字的效果存在细微差别。
2)修饰方法参数
前面我们可以看到,如果变量是我们自己创建的,那么使用final修饰表示我们只会给它赋值一次且不会改变变量的值。那么如果变量是作为参数传入的,我们怎么保证它的值不会改变呢?这就用到了final的第二种用法,即在我们编写方法时,可以在参数前面添加final关键字,它表示在整个方法中,我们不会(实际上是不能)改变参数的值。
3)修饰方法
第三种方式,即用final关键字修饰方法,它表示该方法不能被覆盖。这种使用方式主要是从设计的角度考虑,即明确告诉其他可能会继承该类的程序员,不希望他们去覆盖这个方法。这种方式我们很容易理解,然而,关于private和final关键字还有一点联系,这就是类中所有的private方法都隐式地指定为是final的,由于无法在类外使用private方法,所以也就无法覆盖它。
4)修饰类
了解了final关键字的其他用法,我们很容易可以想到使用final关键字修饰类的作用,那就是用final修饰的类是无法被继承的。
52.wait方法底层原理?
导致当前线程等待,直到该对象的notify或notifyAll被执行。换句话说,这个方法行为效果完全与简单调用wait(0)一样。当前线程必须拥有对象监视器。线程释放对象监视器的所有权,等待直到另一个线程通过调用notify或notifyAll来通知等待对象监视器的线程们并唤醒。然后,当前线程等待重新获取对象监视器并继续执行。因为在一个参数的版本中,中断与伪唤醒是可能的,这个方法应该通常在一个循环中使用:
synchronized (obj) {
while ()
obj.wait();
... // Perform action appropriate to condition
}
该方法必须同步执行的,否则会抛出IllegalMonitorStateException。
53.java有哪些特性,举个多态的例子。
java有3个特性:继承、多态、封装。
多态的定义:指允许不同类的对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
比如有动物(Animal)之(Class),而且由动物继承出类别鸡(Chicken)和类别狗(Dog),并对同一源自类别动物(父类别)之一消息有不同、的响应,如类别动物有“叫()”之动作,而类别鸡会“啼叫()”,类别狗则会“吠叫()”,则称之为多态。。
54.为啥String不可变?
关于为什么String对象不可变,可以看看它的设计源码。
public final class String
implements java.io.Serializable, Comparable, CharSequence{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0
可以看出String对象本质上就是一个字符数组,这也和数组就是对象相符,也可以解释了String.charAt()等方法的原理。value[]就是这个字符数组,offset是在数组中的起始位置,count是字符数组的长度即字符串的长度,而hash是这个String对象的hash值缓存。value[],offset和count这三个变量都是private而且没有setter方法,这也是String对象不可变的本质原因。
55.类和对象的区别?
面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型。
它们的关系是,对象是类的实例,类是对象的模板。对象是通过new className产生的,用来调用类的方法;类的构造方法
56.重载和重写的区别?相同参数不同返回值能重载吗?
方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
不能重载
新闻标题:Java后台开发常见面试题
文章源于:http://pwwzsj.com/article/jcdcii.html