java面试题

1.HashMap为什么是线程不安全的?哪个方法造成的?如何把它变为线程安全的?
2.列举线程池的基本参数有哪些?说说线程池的工作流程
3.spring框架的IOC基本实现原理,BeanFactory和FactoryBean有什么区别?
4.下面是一道阿里巴巴的题目,请问代码输出结果是什么?image.png
答:按照截图去敲,结果就是报错。如果不报错,打印的是子类的move方法。原因就是final修饰的方法是不可继承的,并且父类方法是private的,dog的move方法属于它自己。图片发自简书App
图片发自简书App
5.关于list<?>,list,list,list<? extend Object>以及list<? super T>的区别是什么?
答:?是JAVA泛型中的通配符,它代表JAVA中的某一个类,用来替换老代码的Object,表示不确定类型。list<?>就表示不确定类型的集合。
T表示JAVA类型。list表示类型是T的JAVA类集合。
Object是所有类的根类,是具体的一个类,使用的时候可能需要强制类型转换,list 就表示类型是Object的JAVA类集合。
list<? extend Object>就表示类型Object的子类的集合。
list<? super T>就表示类型T的父类的集合。
其实以上这些都是对JAVA泛型的考察。泛型就是一种通用类型,是JAVA中各种类型的概括。 
6.有一个表t1,列为ABC,现建立索引为AC,现在select xx from table where c=xx a =xx有没有用到索引?
答:没有使用到联合索引,实际上在创建联合索引的时候,也创建了A和C的单列索引,所以这里使用到了单列索引A。
7.手写一个单例模式,并分析过程。
public class SingletonTest {
private static SingletonTest instance;
private SingletonTest() {
}

public static SingletonTest getInstance() {   
    if (instance == null) {   
        synchronized (SingletonTest.class) {   
            if (instance == null) {   
                instance = new SingletonTest();   
            }   
        }   
    }   
    return instance;   
}   

}
上面这个单例的实现使用了双重检查锁(双检锁),是一种高效且线程安全的写法。
8.foreach与正常for循环效率对比哪个高?各自的适应场景是什么?
答:有下标就用for,否则用foreach。需要循环数组结构的数据时使用for循环,因为for循环采用下标访问。需要循环链表结构的数据时使用foreach,因为foreach使用的是迭代器。
9.一张表,里面有ID自增主键,当insert了5条记录之后,删除了第3,4,5条记录后,再把Mysql重启,再insert一条记录,这条记录的ID是6还是3?
答:innoDB表只会把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作都会使最大ID丢失;myisam表会把自增主键的最大ID记录到数据文件里面,重启MySQL后,自增主键的最大ID也不会丢失。所以这个题的答案应该是当使用的引擎是innoDB的时候,MySQL重启后再insert记录,ID应该是3,因为重启后最大的ID丢失了,又是主键自增,所以是3;当使用的引擎是myisam的时候,MySQL重启之后,ID就是6。如果各位觉得这个回答不太认可的话,可以做一下测试来验证此结果。 
10.@Transactional在哪些情况下会导致事务失效?列举出来~
答:1、@Transaction注解只能应用到public可见度的方法上,无法使用中protected、private的方法上;2、如果是无事务的方法调用了注解@Transaction的方法,也会失效;3、数据库的引擎必须是innodb,如果是myisam事务无效;4、可能配置有问题(没有开启注解驱动;没有配置好包名等等)
11.算法题: 给你一串连续的数字,1到10000,随机除去两个数,怎样快速找到这两个数?它的时间复杂度是多少?
答:这道题是个开放型的题目。主要考察算法。提供一个思路:可以使用bitmap,利用二进制来实现。
image.png
原理:任何数异或自己都等于0,任何数异或0都等于它自己。假设原数组为{1,2,3,4,5}现在除去3,就是{1,2,4,5},第一次异或:int res1=124^5;第二次异或:int res2=res112345=03=3 
12.mybatis的xxMapper,只有接口,没有实现类,它是怎么实现具体的查询操作的?原理是什么?
答:1、我们在直接使用xxMapper的时候,mybatis的一个很重要的对象sqlSession是Spring管理的。实际上指定的是sqlSession.getMapper(xxMapper.class)方法;2、通过sqlSession将getMapper(mapper.class)方法委派给Configuration对象执行。3、Configuration对象通过MapperRegistry对象,也就是mapper的注册器。在MapperRegistry最终调用的又是mapperProxyFactory.newInstance(sqlSession)方法,这里工厂对象又会通过MapperProxy对象来生成一个动态代理类;4、MapperProxy对象(它实现了InvocationHandler接口)通过jdk提供的Proxy.newProxyInstance方法生成(注意这个方法只能代理接口,无法代理类),然后就生成了代理对象;5、当比如xxMapper进行insert插入的时候,实际上是通过在代理对象执行的,在mapperProxy的动态代理中会拿到当前的方法,比如insertxx方法,mybatis已经提前封装成了maaperMethod对象(这个对在spring启动的时候就已经根据xml配置封装好了),如何定位是哪个方法呢,这里就用到xml配置的nameSpace和sql中的id了,然后获取方法的参数(动态代理的特点),调用execute方法,其中会传入sqlSession对象,sqlSession会根据sqlCommand和MethodSignature方法执行判断执行insert和update操作;6、最终的数据库操作又交给了sqlSessionProxy代理类,代理类会通过Executor,这里封装了jdbc,调用jdbc获取结果,返回给动态代理的调用,至此一个sql的结果就出来了。
13. mysql的查询,or和in哪个效率更高?为什么?
答:在or和in所在列为主键或者创建了索引的情况下,效率的差别不大;如果没有索引,因为or的时间复杂度为O(n),而in的时间复杂度为O(log2n),当基数越大时,in的查询效率就凸显出来了,这种情况下在查询的时候,mysql会对in里面的数据进行排序,然后用二分法查找数据是否在列表中,而or是全部遍历
14.Java并发编程包中的CountDownLatch类在多线程中有什么作用?
答:作用:发令枪,让当前线程处于阻塞状态,等达到阻塞条件完全开始执行,内部原理通过AQS实现的锁和CAS原子类一直自旋扫描阻塞标记。
使用场景:在调用多个第三方接口时,为提高响应效率,通常会开启多个线程来并发进行,待全部第三方返回结果后统一判断业务逻辑。
15.http和https协议的区别是什么?两种协议分别适合用在哪里?
答:http通信使用明文,可能被窃听,不验证对方身份,可能遭遇伪装,无法证明报文完整性,可能遭遇篡改。默认端口是80
https=http+SSL(TLS)提供加密解密处理并保证了完整性,通过证书确认对方身份。但是https占用CPU和内存资源多,传输慢。默认端口是443
补充: “非对称加密”使用的时候有两把锁,一把叫做“私有密钥”,一把是“公开密钥”,使用非对称加密的加密方式的时候,服务器首先告诉客户端按照自己给定的公开密钥进行加密处理,客户端按照公开密钥加密以后,服务器接收到信息再通过自己的私有密钥进行解密,这样做的好处就是解密的钥匙根本就不会进行传输,因此也就避免了被挟持的风险。就算公开密钥被窃听者拿到了,它也很难进行解密,因为解密过程是对离散对数求值,这可不是轻而易举就能做到的事
16. jvm如何判断一个对象是否可以被回收?垃圾回收算法都有哪些?
答:有计数法和可达性分析算法两种算法判断对象是否可达。但是计数法无法解决对象循环引用的情况,所以都是使用可达性分析算法来判断,垃圾回收算法有标记清除算法,复制算法,标记整理算法,分代垃圾收集算法。新生代都是复制算法,复制算法需要双倍的内存空间,但不需要重复扫描,老年代有标记整理算法的和标记清除算法的,这两种算法是结合使用的,删除标记的,不过会有内存碎片,需要标记压缩把内存碎片清掉,但是效率低。垃圾回收在年轻代回收频繁,老年代回收不频繁。哪些对象可以作为GCROOT?有四种,Java栈引用的对象,本地方法栈引用的对象,方法区常量池引用的对象和方法区静态属性引用的对象,GCROOTS也就是根对象算法。
17.为什么java的分代收集中,年轻代要分为1个eden区和两个surivor区?surivor只有一个可以吗?
答:为了提高GC性能,只有一个surivor的话,会产生内存碎片。
18.ThreadLocal如何解决线程不安全的问题,内部原理是怎样的?它的使用场景有哪些?
答:ThreadLocal实现原理就是在内部维护了一个ThreadLocalMap 可以理解为当前线程是KEY,value就是设置的参数名和参数值,是一个entry节点,然后这个节点是一个弱引用,更有利于垃圾回收。但是在多线程环境下由于线程可以复用,可能会造成OOM,需要手动remove掉变量。我们一般都会用来传参和解决线程安全问题。 
19. 以下代码执行后,会输出什么结果?image.png
答:finally是在return之前执行的。常量是保存在局部变量表里的,i变量是要放到局部变量表的,每次有关于i的运算,都是要把i从局部变量表取出来(可以理解为copy一个副本),比如i += 10,那么需要把i和10都放到操作数栈中进行计算,然后得到一个结果,而这个结果是需要通过retrun语句写回到局部变量表。所以finally里面的i+=10实际上是没有写回局部变量表里的
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果,
因此,即使finally中对变量x进行了改变,但是不会影响返回结果。
它应该使用栈保存返回值。
20.请画出微服务框架dubbo消费者调用生产者的顺序图,并说出它是如何工作的
答:提供者在启动时,根据配置的注册中心地址注册到该注册中心,消费者在启动时根据配置去订阅服务,这时在dubbo后台管理中可以看到每个服务的提供者和消费者,当消费者使用某个服务时,会从所有提供者中随意挑选一个进行访问调用,当服务提供者挂掉时,会抛出异常,当提供者服务发生变更时,重启后会将最新变更同步到注册中心并通知所有订阅者。微服务调用顺序都是一样的。服务的提供者把服务注册到服务注册中心,然后服务的消费者从注册中心订阅这些服务,完成一次调用。dubbo使用的zk服务注册中心类比springcloud的eureka服务注册中心,区别就是zk满足服务的cp而eureka是满足ap。
21. 如图,多线程情况判断,应该选择哪个选项?image.png
答:D。
详解:首先最开始 a=0;
A线程开始执行:isOdd=true; a= 0+1=1;
isOdd =false; a=1+(-2)=-1;
线程B开始执行 isOdd=true: a=0+1=1;
isOdd =false;a=1+(-2)=-1
==输出结果-1=
A线程开始执行:isOdd=true; a= 0+1=1;
线程B开始执行 isOdd=true: a=1+1=2;
isOdd =false; a=2+(-2)=0;
==输出结果0=
A线程开始执行:isOdd=true;i=1 a= 0+1=1;
线程B开始执行 isOdd=true: a=1+(-2)=-1;
线程A开始执行 isOdd=false: i=2 a=-1+1=-0;
线程B开始执行:isOdd =false;i=2 a=0+(-2)=-2;
==输出结果-2=
22. 对于mysql来说,Hash索引的时间复杂度是O(1),而B+树的时间复杂度是log(2N),为什么mysql不选择用Hash作为底层结构?
答:1、Hash只能实现等值查询,而在范围查找中会完全失去自身复杂度为1的优势,比如like查询;
2、在有大量重复数据情况下,哈希索引的效率是极低的,存在哈希碰撞问题(参考HashMap);
3、利用Hash需要把数据全部加载到内存中,如果数据量大,非常消耗内存。而采用B+树,是基于节点分段加载,由此减少内存消耗;
4、无法进行排序,oder by是无法使用Hash的;
5、组合索引可以支持部分索引查询,如(a,b,c)的组合索引,查询中只用到了a和b也可以查询的,如果使用hash表,组合索引会将几个字段合并hash,没办法支持部分索引;
23. 写出你遇到的Exception,并解释他们会在哪些情况下出现?
1、Java.lang.NullPointerExecption --空指针异常
例如:
String s = null;
int size = s.length();
System.out.println(size);
假如‘s’的值为null,当应用程序试图在需要对象的地方使用 null 时,抛出NullPointerException异常。
2、Java.lang.ArithmeticException --数学运算异常
例如:
int a = 5/0;
当一个整数“除以零”时,抛出ArithmeticException异常。
3、java.long.ClassCastException --强制类型转换错误
例如:
Object x = new Integer(0);
System.out.println((String)x);
当试图将对象强制转换为不是实例的子类时,抛出该异常(ClassCastException)
4、java.lang.ArrayIndexOutOfBoundsException --数组越界异常
例如:
java中的数组分配是从0到它的length-1的空间,
比方:
int []a = {1,2,3,4,5};
它分配了5个空间,这样定义跟这样
int [5]a = {1,2,3,4,5}
是一样的,但你不能调用a[5],只能调用到a[4]
结果:a[0]=1,a[1]=2,a[2]=3,a[3]=4,a[4]=5,
但是使用:a[5]=数组越界
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
5、java.long.IllegalArgumentException --传递非法参数异常。
例如:
Date day = new Date();
SimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
String date = df.format(day);
SimpleDateFormat dateFormat= new SimpleDateFormat(“yyyy-MM”);
String format = dateFormat.format(date);
System.out.println(format);
6、FileNotFoundException:文件没有找到异常,如果在定位资源的时候找不到就会报此异常
7、SqlException:sql执行过程中的异常
8、NosuchMethodException:找不到此方法的异常
9、SSLException:https中没有证书的异常
10、ClassNotFoundException:类路径中没有找到相关类
11、RpcException:微服务远程过程调用中出现的异常
12、TimeOutException:远程调用服务超时异常
13、reflactException:反射过程中的异常 
24.解释一下同步和异步,阻塞和非阻塞是什么?并举例说明
答:同步指只能做完当前的事再接着做下一件事,只能一个个来。异步指同时可以做多件事。比如ajax的同步异步,js代码是从上到下执行的,这时有多个调用ajax的函数,从上到下开始执行,一个函数未执行完,下一个函数是不会执行,这是ajax的同步,异步ajax的话,一个函数未执行完,下面一个或多个的函数是可以执行的。阻塞IO和非阻塞IO,阻塞IO如果还没数据传输完,它就会等待,交出CPU,非阻塞IO不会交出CPU。同步异步是相对消息通知(即调用函数返回结果)来说的,同步时会一直等到有返回结果后才接着往下执行,这样可以保证两个任务的成功与否状态一致,而异步的话只需调用方法,不需要等待返回结果,可能会一个任务成功,另一个失败,不能保证一致性。阻塞和非阻塞是在等调用函数返回结果的阶段,其在做什么,如果说在等待返回结果期间什么事都没有干,那就是阻塞,若去干自己的事,那就是非阻塞。同步和异步主要针对接口调用等场景,阻塞和非阻塞概念针对底层IO。
同步就是调用一个函数,必须等被调用函数执行完才能返回;异步是调用函数后不等被调函数执行完,就直接返回,被调函数执行结果通过回调函数通知调用者。
阻塞是请求操作系统内核从网络读取数据,必须等网络数据到达了,才返回给程序;非阻塞是请求操作系统从网络读数据,如果数据没到,内核返回一个异常给程序,程序先去执行其他代码,过一会向内核发起轮询,直到读到数据返回。
同步与异步
同步和异步关注的是消息通信机制。
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待调用的结果。
而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
 阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
举个栗子,假如我现在准备预订饭店里的座位,我给服务员打电话的场景(调用过程),服务员我要查看一下当前还有没有座位。
同步:我一直在等待,没有挂断电话,直到服务员告诉我结果。(一直等待)
异步:我直接挂断电话,服务员有了结果,他再打电话通知我(不等结果,直接返回)
阻塞:在等待的过程中,我就专心只等待服务员告诉我结果(线程挂起)
非阻塞:在等待的过程中,我还在看电影(线程可以多开做其他事情)
25. 以下代码输出什么?java是值传递还是引用传递,两者区别是什么?image.png
答:1.test ok 2.good 3.gbc 4.1 java是按值传递的,比如基本数据类型的传递,这个int a,作为参数传递给这个change方法,实际上是把int a这个存储空间中的1这个值传递给change方法中的int b,int b分配空间保存这个1这个值,之后在change方法中无论怎么操作这个int b,也只是针对这个int b的存储空间,main方法中的int a的值是不会发生变化的;引用类型传递的是对象在堆内存的开辟存储空间的地址,change方法通过这个地址可以修改里面的值,但是这个内存地址的值不会变。String虽然是对象,但是由于String是不可变的,虽然str和str1都指向了"good",在给str1赋值为"test ok"时,并不会去改变str1指向的内存地址中的值,而是在内存中重新创建一个"test ok"对象,并让str1指向它(此时,str1和str不再指向同一个对象),所以str所指向空间存的值不会被改变,但是如果不是String这种不可变对象,通过这种方式,其值是会被改变的。值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;简单来讲,值传递就是传递参数的一个复制的值,改变形参不影响原值;引用传递过程中传递的是内存的地址,改变形参的值,影响原值
26. 队列适用于哪些开发场景,什么时候你会考虑使用队列?常见的队列,你会如何选择

  • Spring里用到了哪些常见的设计模式?请详述使用场景。
  • java的引用强度都有哪些类型?在GC过程中都是如何表现的?
  • 详解TCP三次握手,四次挥手的过程?并解释为什么握手需要三次,挥手却需要四次?
  • 为什么 Java 中的 String 类是不可变的?使用final有什么好处?
  • java中i++和++i满足原子性吗,为什么?如果不是,怎么保持其原子性
  • 同步方法和同步代码块的区别是什么?
  • String对象的intern()方法作用是什么?实现原理是什么?
  • 事务的隔离级别有哪些,分别会引起哪种异常读取?
  • 以下代码输出什么?并分析原因~[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RhyoL58N-1576203964759)(https://upload-images.jianshu.io/upload_images/9535644-d503fdc693ad3e4e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
  • Http状态码有哪些,分别表示什么含义?
  • mysql的like语法和Locate函数哪个效率更高?为什么?
  • redis是单线程的,使用它需要加锁吗?为什么它依然那么快?
  • 后端如何防止前端的重复请求,如何保证请求的幂等?
  • 使用随机算法产生一个数,要求将1-1000W之间这些数全部生成出来。(考察高效率,解决产生冲突的问题)
  • spring中如何解决循环依赖问题?
  • CAS的原理是什么?适用场景有哪些?有什么优点和缺点?
  • 说一说Nio为什么要比IO流快,它的底层原理是什么?
  • 编程实现:删除单链表中的元素。
    Example:
    input:1->2->6->3->4->5->6,val=6
    output:1->2->3->4->5
    /**
  • Definition for singly-linked list.
  • public class ListNode {
  • int val;
    
  • ListNode next;
    
  • ListNode(int x) { val = x; }
    
  • }
    /
    public class Solution {
    /
    *
    • @param head a ListNode

    • @param val an integer

    • @return a ListNode
      */
      public ListNode removeElements(ListNode head, int val) {
      // Write your code here
      if (null == head)
      return head;

      ListNode p = head;
      ListNode pre = null;

      while (null != p) {
      if (p.val == val) {
      ListNode del = p;
      p = p.next;
      if (null != pre) {
      pre.next = p;
      } else {
      head = p;
      }

       } else {
           pre = p;
           p = p.next;
       }
      

      }
      return head;
      }
      }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值