文章目录
-
-
- 一、JavaOOP面试题
- 二、Java集合/泛型面试题
- 三、Java异常面试题
- 总结:面试遇到的问题
-
- 1、static 的用法
- 2、final 用法
- 3、线程
- 4、实现多线程的方法
- 5、什么是线程安全?怎么保证线程安全?
- 6、Volatile
- 7、 int和Integer的区别
- 8、数组有没有length()方法?String有没有length()方法?
- 9、什么是事务的四个特性?
- 10、数据库隔离的四个级别分别是什么
- 11、MYSQL的两种存储引擎区别(事务、锁级别等等),各自的适用场景
- 12、索引的优缺点,什么时候使用索引,什么时候不能使用索引
- 13、InnoDB索引和MyISAM索引的区别
- 14、数据库三范式
- 15、MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?(增量优化)
- 16、如何进行SQL优化
- 17、锁的优化策略
- 18、怎么防止死锁?
- 19、SQL语言包括哪几部分?每部分都有哪些操作关键字?
- 20、完整性约束包括哪些?
- 21、视图的优点
- 22、对于大流量的网站,您采用什么样的方法来解决各页面访问量统计问题?
- 23、如何重写equals() 方法
- 24、**抽象类和接口的区别**
- 25、面向对象特征
- 26、静态变量和实例变量的区别?
- 27、访问修饰符public,private,protected,以及不写(默认)时的区别?
- 28、迭代器 Iterator 是什么?
-
一、JavaOOP面试题
1、short s1 = 1; s1 = s1 + 1;有错吗? short s1 = 1; s1 += 1; 有错吗?
int 占4个字节 4x8=32位 short占用两个字节 2x8=16位
short s1 = 1; s1 = s1 + 1; 有错
s1为short型 s1+1 变量提升为int型,不能显示转换为int型
short s1 = 1; s1 += 1; 没有错
s1+=1; 等价于 s1 = (short)(s1+1)
第一个为简单赋值操作符,第二个为复合赋值操作符
在Java规范中提到,复合赋值(E1 op = E2)等价于简单赋值 E1 = (short)((E1)op (E2))
复合赋值表达式自动将执行的结果—>转化为左侧变量的类型。
假若结果类型与变量类型相同,转型不会造成影响;
然而结果类型比变量类型要宽,复合操作符执行一个窄化原生类型转换 例如:long t1; t1+=1;
2、重载和重写的区别
答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
- 重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;
- 重写发生在子类与父类之间,重写要求子类重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。
重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
重写(Overiide) —> 简单的说:就是子类把父类本身有的方法重新写一遍,子类继承父类原有的方法。
子类可以对父类的方法体进行修改或重写(在方法名,参数列表,返回类型(除了子类方法的返回类型是父类方法返回类型的子类时))
注意:子类函数的访问修饰符权限不能少于父类的
//重写(Overiide)
class Animal{
public void skinColor(){
System.out.println("皮肤有颜色");
}
}
class Dog extends Animal{
public void skinColor(){
System.out.println("皮肤-->黄色");
}
}
- 重写 总结:
1.发生在父类与子类之间
2.方法名,参数列表,返回类型(除子类中方法的返回类型是父类返回类型的子类)必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
重载(Override)
在一个类中,同名方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。
同时重载的返回类型没有要求,但是==不能通过返回类型是否相同来判断重载==。
//重载(Override)
class Animal{
public void skinColor(){
System.out.println("皮肤有颜色");
}
public void skinColor(String skColor){
}
}
3、数组实例化有几种方式?
3.1 静态实例化:创建数组的时候已经指定数组中的元素
int [] a= new int[]{
1 , 3 , 3}
3.2 动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值
int [] a= new int[2];
a[0]=1;//给数组元素赋值
a[2]=2;
3.3 数组的默认初始化
数组是引用类型,他的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化
实例:int a2[]=new int[2];//默认值0,0
boolean[] b=new boolean[2];//默认值 false,false
String[] s=new String[2];//默认值null
4、Java中各种数据默认值(引用类型在堆里,基本类型在栈里。)
- Byte,short,int,long默认是都是0
- Boolean默认值是false
- Char类型的默认值是\u0000
- Float与double类型的默认是0.0
- 对象类型的默认值是null
5、Object类常用方法有哪些?
Equals
Hashcode
toString
wait
notify
clone
getClass
6、java中是值传递引用传递?
Java是值传递。
-
当传的是基本类型时,传的是值的拷贝,对拷贝变量的修改不影响原变量;
-
当传的是引用类型时,传的是引用地址的拷贝,但是拷贝的地址和真实地址指向的都是同一个真实数据,
因此可以修改原变量中的值;
- 当传的是String类型时,虽然拷贝的也是引用地址,指向的是同一个数据,但是String的值不能被修改,因此无法修改原变量中的值。
7、形参与实参区别
7.1 主体不同
- 实参:在调用有参函数时,函数名后面括号中的参数为**“实际参数**”。
- 形参:不是实际存在变量,又称虚拟变量。
7.2 目的不同
- 实参:可以是常量、变量或表达式, 无论实参是何种类型的量,在进行函数调用时,都必须具有确定的值, 以便把这些值传送给形参。
- 形参:定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
7.3 特点不同
- 实参:在调用函数过程中,系统会把实参的值传递给被调用函数的形参。或者说,形参从实参得到一个值。该值在函数调用期间有效,可以参加该函数中的运算。
- 形参:形参的本质是一个名字,不占用内存空间。
8、构造方法能不能重写?能不能重载?
构造方法不可以被重写,因为重写发生在父类和子类之间,要求方法名称相同,而构造方法的名称是和类名相同的,而子类类名不会和父类类名相同,所以不可以被重写
构造方法可以被重载。
9、内部类与静态内部类的区别?
定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明public、protected、private等访问限制,
可以声明 为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。
10、final在java中的作用,有哪些用法?
final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)
10.1 修饰类
- 当用final修饰一个类时,表明这个类不能被继承。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。(尽量不要将类设计为final类)
10.2 修饰方法
-
使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;
-
第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。
但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。即父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。
final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。
此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,
将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,
而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法。)
10.3 修饰变量
-
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
-
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;
如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;
第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
二、Java集合/泛型面试题
1、ArrayList和linkedList的区别
ArrayList的实现是基于数组的数据结构,LinkedList的基于链表的数据结构。这两个数据结构的逻辑关系是不一样,当然物理存储的方式也会是不一样。
LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素
对于随机访问,ArrayList要优于LinkedList。因为LinkedList要移动指针
对于插入和删除操作,LinkedList优于ArrayList。因为ArrayList要移动数据
//参考 https://www.cnblogs.com/huzi007/p/5550440.html
static final int N=50000;
static long timeList(List list){
long start=System.currentTimeMillis();
Object o = new Object();
for(int i=0;i<N;i++) {
list.add(0, o);
}
return System.currentTimeMillis()-start;
}
static long readList(List list){
long start=System.currentTimeMillis();
for(int i=0,j=list.size();i<j;i++){
}
return System.currentTimeMillis()-start;
}
static List addList(List list){
Object o = new Object();
for(int i=0;i<N;i++) {
list.add(0, o);
}
return list;
}
public static void main(String[] args) {
System.out.println("ArrayList添加"+N+"条耗时:"+timeList(new ArrayList()));
System.out.println("LinkedList添加"+N+"条耗时:"+timeList(new LinkedList()));
List list1=addList(new ArrayList<>());
List list2=addList(new LinkedList<>(