[Java 基础]
1.== 和 equals 的区别是什么?
答:==是比较内存地址,只有在常量池或基本数据类型的比较时采用==,它所比较的是内存地址,equals是比较两个对象的值是否相等。
2.java 中的 Math.round(-1.5) 等于多少?
答:-1。
3.数组有没有length()方法?String有没有length()方法?
答:数组没有leng()方法,数组只有length值;String有length()方法。
4.java 中操作字符串都有哪些类?它们之间有什么区别?
答:操作字符串的常用类有StringBuffer、StringBuilder类,StringBuffer是线程安全的,它的底层其实是一个字符数组,用synchronized关键字修饰来保证它在多线程情况下是线程安全的,StringBuilder类非线程安全的,它的速度远在StringBuffer之上,因为它未加锁来形成阻塞。
5.List、Set、Map 之间的区别是什么?
答:List和Set都是继承于Collection接口,而Map是一个独立的接口,
List是一个有序队列,默认容量是10,每次add的时候进行扩容,容量加1,它允许有有重复的数据, 为了保证执行速度,数据是动态增长的,它是非线程安全的,如果要在多线程情况下保证线程安全,我们使用CopyOnWriteArrayList类;
Set是一种不包含重复数据的集合,它的子类HashSet底层就是一个HashMap,它的初始容量是集合的size/负载因子(0.75)+1, 它的值作为map的key存储,value则是一个常量值,非线程安全的,保证线程安全使用CopyOnWriteHashSet类;
Map是一个键值对,它的初始容量为16,默认的负载因子为0.75,它在每次调用put方法时计算容量,判断是否需要扩容,适合存储键值对数据,非线程安全的,保证线程安全使用ConcurrentHashMap类。
6.线程的基本状态以及状态之间的关系
答:线程的状态分为:1)、创建 2)、准备就绪 3)、运行 4)、消亡 5)阻塞
在创建线程后通过start方法来启动线程,将其线程进入就绪状态,然后获取cpu的执行权进入运行状态,运行状态结束后就进入消亡状态,当调用sleep方法或wait方法时进入阻塞状态,sleep设置指定时间让进程自动唤醒,而wait方法需要手动调用notify方法进行唤醒。
7.说一下 runnable 和 callable 有什么区别?
答:Runnable是java.lang包下的一个接口,它是没有返回值的,而Callable是有返回值的,它可以配合FutureTask获取异步执行的返回结果,在多线程的异步编排就可以使用此种方式。
8.说一下数据库的事务隔离?
答:1)、可重复读
两个人更新同一条记录,第一个更新未提交,第二个更新提交后,第一个更新提交时读取的是第二个更新提交之后的值,从而避免了幻读。它采用了MVCC类似与乐观锁的并发版本控制的方式,它是mysql默认事务隔离级别。
2)、读已提交
先更新,事务还未提交,去读取数据的时候,不能读取到已更新的值,避免了脏读。
3).读未提交
事务还未提交就读到已更新的数据。
4)、串行化
9.说一下 mysql 常用的引擎?
答:myisam和innodb,myisam不支持事务,innodb支持事务,支持行级锁,索引会单独生成文件。
10.说一下乐观锁和悲观锁?
答:乐观锁通过版本号来控制,每次更新的时候增加一个版本号,如果版本号是上次的,更新成功,如果版本好不一致,更新失败,允许并发操作,但同一时间只有一人成功。
悲观锁是一个行级锁,每次更新就将此条记录锁定,其他人不能操作,for update的方式,只有一人能操作,其他人只有等当前操作完成后才能操作。
11.redis 支持的数据类型有哪些?
答:String,List,Set,Sorted Set, Hash。其中Set可以用来过滤重复数据,ZSet可以做实时排行榜,Hash可以存储键值对,这在多层级场景下非常有效,比如购物车的使用。
12.队列和栈是什么?有什么区别
答:队列就相当于我们平常排队一样,一个入口进入,一个出口出来,先进先出;
栈就相当于一个子弹夹,先进去的压到栈底,最后进去的在栈顶,最后进去的相反第一个弹出,后进先出。
13.说出下面代码的运行结果
class A extends Exception {}
class B extends A {}
public class Test {
public static void main(String[] args) throws Exception {
try {
try {
throw new B();
}
catch (A a) {
System.out.println("Caught A");
throw a;
}
}
catch (B b) {
System.out.println("Caught B");
return ;
}
finally {
System.out.println("Hello World!");
}
}
Caught A
Caught B
Hello World!
14.说出下面代码的运行结果
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A {
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) {
A ab = new B(); 1a2b 静态代码块启动时初始化一次
ab = new B(); 2b
}
1a2b2b
12
[JAVA 编程题]
15.打印输出当前时间,格式要求如下 2020-05-05 10:10:10
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String curTime = "";
try {
curTime = sdf.format(d);
} catch (Exception e) {
e.printStackTrace();
}
System.out.print("curTime = " + curTime);
JDK1.8新增日期类
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("curTime:" + df.format(ldt));
16.创建以下二叉树,并实现遍历(先序,中序,后序任选一种)
import java.util.HashMap;
class BinaryTree {
public static void main(String[] args) {
int pre[] = {10,9,20,15,35};
int in[] = { 35,15,20,9,10};
BinaryTree binaryTree = new BinaryTree();
// 利用前序和中序,创建二叉树
TreeNode treeNode = binaryTree.reConstructBinaryTree(pre, in);
// 前序遍历二叉树
binaryTree.preorderTraversa(treeNode);
System.out.println();
// 中序遍历
binaryTree.inorderTraversa(treeNode);
System.out.println();
// 后序遍历
binaryTree.postorderTraversa(treeNode);
}
// 左右根
public void postorderTraversa(TreeNode node) {
if (node == null) {
return;
}
postorderTraversa(node.left);
postorderTraversa(node.right);
}
// 根左右
public void preorderTraversa(TreeNode node) {
if (node == null) {
return;
}
preorderTraversa(node.left);
preorderTraversa(node.right);
}
// 左根右
public void inorderTraversa(TreeNode node) {
if (node == null) {
return;
}
inorderTraversa(node.left);
inorderTraversa(node.right);
}
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
if (pre == null || in == null) {
return null;
}
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
for (int i = 0; i < in.length; i++) {
hashMap.put(in[i], i);
}
return preIn(pre, 0, pre.length - 1, in, 0, in.length - 1, hashMap);
}
// 根据前序和中序还原二叉树
public TreeNode preIn(int[] p, int pi, int pj, int[] n, int ni, int nj,
HashMap<Integer, Integer> map) {
if (pi > pj) {
return null;
}
TreeNode head = new TreeNode(p[pi]);
int index = map.get(p[pi]);
// 根据前序遍历知道根节点,根据中序遍历知道根左边的为左子树,右边的为右子树
head.left = preIn(p, pi + 1, pi + index - ni, n, ni, index - 1, map);
head.right = preIn(p, pi + index - ni + 1, pj, n, index + 1, nj, map);
System.out
.println("head =" + (head != null ? head.val : " ")
+ " head.left ="
+ (head.left != null ? head.left.val : " ")
+ " head.right ="
+ (head.right != null ? head.right.val : " "));
return head;
}
}