面试常见问题总结
一、Javase基础语法
1、&和&& 的区别:&&左边表达式如果是FALSE,则不会判断右边是否成立,&&被称为短路运算。例如判断用户名是否为空username!=null&&!username.equals(""),二者判断顺序都不可颠倒。
2、是否可以继承String :答案是不可以,String是final类,不可以被继承。
3、Java中只支持参数的值传递。
4、重载和重写的区别?
//方法重载的规则: 1、方法名一致,参数列表中的参数个数,类型,个数不相同。 2、重载与方法的返回值没有关系,存在于父类和子类中,同类中。 //方法重写的规则: 1、参数列表必须和重写的方法一致,返回值类型必须完全和被重写方法的返回值类型一致。 2、构造方法不能被重写 3、访问权限不能比父类中被重写方法的访问权限更低。 4、重写的方法能够抛出任何非强制异常。
5、cahr类型的变量中能不能存储一个中文汉字,why?
//答案 char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode,一个char类型占2个字节(16)比特,所以存放一个中文没有问题。
6、抽象类abstract class 和接口 interface的异同点
//相同点: (1)都不能进行实例化; (2)可以将抽象类和接口类型作为引用类型 (3)如果一个类继承类抽象类或者实现了接口,则都需要将抽象方法全部实现,否则这个类还要继续声明为抽象类; //不同点: (1)抽象类可以定义构造器 (2)可以有抽象方法和具体方法 (3)有抽象方法的类一定要声明为抽象类,而抽象类则不一定要有抽象方法 (4)抽象类中可以有静态方法 (5)一个类只能继承一个抽象类 ///////////////////////////// (6)接口中不能定义构造器 (7)接口中的方法全部都是抽象方法 (8)接口中不能有静态方法 (9)一个类可以实现多个接口 ///单继承 多实现
7、==和equals 的区别:
最大的区别就是一个是方法,一个是运算符。 //==:如果比较的是基本类型,则判断其数值是否相同;如果是引用类型,则比较是地址是否相同。 //equals:它用来比较两个对象内容是否相同;
8、break 和 continue 的区别:
//相同点: 都是用来控制循环的语句; break用来结束一个循环,跳出循环体执行循环后面的语句 continue用来跳过本次循环,执行下次循环用的。
9、Java中的多态:
//实现多态的机制是什么: 靠父类或者接口中定义的引用变量指向子类或者具体的实现类的实例对象。
10、异常的分类:
//Java中按照异常的时机分为编译时异常(checkedExce0和运行时异常(RuntimeException)
11、error 和 exception 的区别(父类都是Throwable类)?
//error:一般指和虚拟机相关的问题,例如系统崩溃、虚拟机错误,内存不足,靠程序本身无法恢复和预防。 //exception:表示程序可以处理的异常,可以捕获也可能恢复,
★★所有异常的根类是Thowable,
12、常见的运行时异常有:
//(1)空指针异常 NULLPointException; //(2)指定类找不到异常 ClassNotFoundException //(3)字符串转换为数字异常 NumberFormateException //(4)数组角标越界异常 IndexOutOfBoundsEcception //(5)方法传递错误异常 IllegalArgumentException //(6)方法不存在异常 NoSuchMethodException
13、Thow 和 Thows的区别:
//thow 用在方法体中,表示抛出异常,由方法体内的语句执行 //thows用在方法声明后面,由该方法的调用者来处理;
14、final 和 finally 、finalize
final:修饰属性、方法、类,被它所修饰的都不可被继承修改。
finally:异常处理语句结构的一部分,表示总是执行。
15、数组没有length方法;而是具有length这一个属性。String具有length的方法;举例javaScripe中,获取字符串的长度就是用.length() 这个方法。
16、Java的数据类型
//四类八种:
整型 | byte (1) | short(2) | int(4) | long(8) | |
---|---|---|---|---|---|
浮点 | float(4) | double(8) | |||
字符 | char(2) | ||||
布尔 | boolean(1) | ||||
★★ String不是基本数据类型,是引用类型。
String类常用的方法:
17、集何的安全性问题:
// ArrayList 、 HashSet、HashMap.通过源码可以看出,他们都没有枷锁,显然都是不安全的。在集合中Vector和HashTable倒是安全的。他们在核心方法上都添加了synchronized关键字。 Collections工具类提供了相关的API,让上述三个集合变为安全的。
18、Java的多线程和并发库
传统机制的回顾: (1)传统使用类Thead和接口Runable实现 总结:查看 Thread 类的 run()方法的源代码,可以看到其实这两种方式都是在调用 Thread 对象的 run 方法,如果 Thread 类的 run 方法没有被覆盖,并且为该 Thread 对象设置了一个 Runnable 对象,该 run 方法会调用 Runnable 对象的 run 方法;
18、线程池的作用:
线程池就是限制系统中执行线程的数量。根据系统的环境,可以自动或者手动设置线程数量,达到运行最佳效果。用线程池控制线程数量,其他线程,排队等候,当一个任务完毕,再从队列中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待状态,当一个新任务需要执行时,如果线程池中有等待的工作线程,就可以开始运行工作,否则进入等待队列。
19、为什么要用线程池:
//1、减少创建和销毁线程的次数,每个工作线程都可被重复利用,可执行多个任务。 //2、可以根据系统的承受能力,调整线程池中的线程的数目,防止因为消耗过多的内存,而把服务器累趴下,线程开的越多,消耗的内存就会越大,最后导致死机。
20、Java里面线程池的顶级接口是Excutor,而严格意义上它不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExcutorService.ThreadPoolExcutor是Excutors类的底层实现。
//补充: 在 java 的多线程中,一但线程关闭,就会成为死线程。关闭后死线程就没有办法在启动了。再次启动就会出现 异常信息:Exception in thread "main" java.lang.IllegalThreadStateException。那么如何解决这个问题呢? 我们这里就可以使用 Executors.newSingleThreadExecutor()来再次启动一个线程。
21、线程池的关闭
使用shutdown 和 shutdownNow可以关闭线程池
//两者的区别: shutdown只是将空闲的线程interrupt()了,shutdown()之前提交的任务可以继续执行直到结束 shutdownNow是interrupt所有线程,因此大部分线程将立刻被中断。之所以是大部分,而不是全部,是因为interrupt()方法能力有限。
二、多线程面试题
1、多线程的创建方式:
//继承Thread类:Thread类本质上也是实现了Runnable接口的实例,并且启动线程的唯一方法就是通过它的start()实例方法。start方法是一个native方法,它将启动一个新的线程,并执行run()方法,这种方式实现多线程很简单,通过自己的类直接extend Thread,并重复run方法就可以启动新的线程并执行自己定义的run方法。
//2 第二种创建方式是实现Runnable接口的方式实现多线程,并且实例化Thread,传入自己的Thread实例,调用run方法
1、在Java中wait 和 sleep方法的不同?
最大的不同是在等待时,wait会释放锁,而sleep一直持有锁。wait通常被用于线程间的交互,sleep通常被用于暂停执行。
2、synchronized 和 volatile关键字的作用
// volatile 修饰之后,那么就具备了两层语义 1)不同的线程对这个变量进行操作的可见性,即一个线程修改了某个变量的值,那么其他线程可以立即对修改过的这个变量可以识别。 2)禁止进行指令重排序。volatile 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住
3、叙述一下对线程池的理解:
第一:降低了对资源的消耗。通过重复利用已有创建的线程降低线程创建和销毁造成的消耗。
第二:提高了响应速度。如果有任务的时候,不需要等待线程的创建,直接可以立即执行
第三:提高了线程的可管理性。可以使用线程池进行统一的分配,调优和监控。
4、线程池的启动策略
//线程池刚创建时候,里面没有一个线程。任务队列作为参数传递进来。不过,就算队列有任务,线程池也不会马上执行。 //当调用execute()方法添加一个任务时,线程池会做如下判断: a)如果正在运行的线程数量小于从热PoolSize,那么马上创建线程运行这个任务; b)如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列。 c)c. 如果这时候队列满了,而且正在 运行的线程数量小于maximumPoolSize,那么还是要创建线程运 行这 个任务; d. 如果队列满了,而且正在运行的线程 数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告 诉调用者“我不能再接受任务了”。 3、当一个线程完成任务时,它会从队列中取下一个任务来执行。 4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。