Java基础(面试)
Java基础 44 道
这是问题(点击右边快速直达答案区)-
解释下什么是面向对象?面向对象和面向过程的区别?
-
面向对象的三大特性?分别解释下?
-
JDK、JRE、JVM 三者之间的关系?
-
重载和重写的区别?
-
Java 中是否可以重写一个 private 或者 static 方法?
-
构造方法有哪些特性?
-
在 Java 中定义一个不做事且没有参数的构造方法有什么作用?
-
Java 中创建对象的几种方式?
-
抽象类和接口有什么区别?
-
静态变量和实例变量的区别?
-
12、short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?
-
Integer 和 int 的区别?
-
装箱和拆箱的区别
-
switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?
-
16、final、finally、finalize 的区别
-
== 和 equals 的区别?
-
两个对象的 hashCode() 相同,则 equals() 也一定为 true 吗?
-
为什么重写 equals() 就一定要重写 hashCode() 方法?
-
& 和 && 的区别?
-
Java 中的参数传递时传值呢?还是传引用?
-
Java 中的 Math.round(-1.5) 等于多少?
-
如何实现对象的克隆?
-
深克隆和浅克隆的区别?
-
什么是 Java 的序列化,如何实现 Java 的序列化?
-
什么情况下需要序列化?
-
Java 的泛型是如何工作的 ? 什么是类型擦除 ?
-
什么是泛型中的限定通配符和非限定通配符 ?
-
List 和 List 之间有什么区别 ?
-
Java 中的反射是什么意思?有哪些应用场景?
-
反射的优缺点?
-
Java 中的动态代理是什么?有哪些应用?
-
怎么实现动态代理?
-
static 关键字的作用?
-
super 关键字的作用?
-
字节和字符的区别?
-
String 为什么要设计为不可变类?
-
String、StringBuilder、StringBuffer 的区别?
-
String 字符串修改实现的原理?
-
String str = "i" 与 String str = new String("i") 一样吗?
-
String 类的常用方法都有那些?
-
final 修饰 StringBuffer 后还可以 append 吗?
-
Java 中的 IO 流的分类?说出几个你熟悉的实现类?
-
字节流和字符流有什么区别?
-
BIO、NIO、AIO 有什么区别?
这是问题(点击右边快速直达答案区)
解释下什么是面向对象?面向对象和面向过程的区别?
面向对象的编程是以对象为中心,以消息为驱动面向对象:是一种基于面向过程的编程思想,是计算机向现实世界模型的自然延伸,说白了就是“万物皆对象”。
在现实世界中任何一种物体都可以归为一类是事物,而每一个个体都是一类事物的实例,这就是"类和实例"。
面向对象编程与面向过程编程的区别:
①编程思路不同:
面向过程以实现功能的函数开发为主,使用函数来实现功能
面向过程要首先抽象出类,类的属性,类的方法,然后通过实例化对象来完成功能
②封装性:
二者都具有封装性,但是面向过程封装的是类,面向过程封装的是函数
③面向过程具有多态和继承性,面向过程没有
面向对象的三大特性?分别解释下?
面向对象的三大特性:"继承"、"封装"、"多态"
封装:是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。通俗来说,就是将一大堆实现逻辑,放在一个盒子里面。我们使用的时候,只需要调用封装好的盒子即可。
封装的优点:
1、良好的封装能减少耦合
2、类内部的结构可以自由修改
3、可以对成员变量进行更精确的控制
4、隐藏信息,实现细节
继承:就是“子类”继承“父类”的特征和行为,使得"子类对象"(实例)具有"父类"的实例域和方法,或"子类"从"父类"继承方法,使得"子类"具有"父类"相同的行为。
多态:同一个行为具有多个不同"表现形式"或"形态的能力"。
多态存在的三个必要条件:
1、继承;
2、重写;
3、父类引用指向子类对象:Parent p = new Child();
JDK、JRE、JVM 三者之间的关系?
JDK: JAVA Development Kit(JAVA开发工具包)
JRE: JAVA Runtime Environment(JAVA运行环境)
JVM: JAVA Virtual Machine(JAVA虚拟机)
三者的包含关系如下图:

JDK包含JRE和JAVA的开发工具
JRE包含JVM和JAVA的核心类库
下列概念图说明了javase的组件关系:

主要结构:
JDK=JRE+JAVA的开发工具(javac.exe,java.exe,javadoc.exe等)
JRE=JVM+JAVA核心类库
重载和重写的区别?
一、重载
重载(overloading): 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造方法的重载。
重载是在同一个类中的具有相同方法名,不同参数(个数,类型,顺序)的方法的定义,
构造方法普通方法,抽象方法都可以重载;重写是在子类继承父类的时候重写,
在子类重写的方法必须和父类方法完全相同,可以用@override检查是否是重写方法
重载规则:
被重载的方法必须改变参数列表(参数个数,类型或顺序不一样);
被重载的方法可以改变返回类型;
被重载的方法可以改变访问修饰符;
被重载的方法可以声明新的或更广的检查异常;
方法能够在同一个类中或者在一个子类中被重载。
无法以返回值类型作为重载函数的区分标准。
二、重写
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。
在面向对象原则里,重写意味着可以重写任何现有方法
三、重载与重写的区别
| 区别点 | 重载方法 | 重写方法 |
|---|---|---|
| 参数列表 | 必须修改 | 一定不能修改 |
| 返回类型 | 可以修改 | 一定不能修改 |
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
Java 中是否可以重写一个 private 或者 static 方法?
java中的static方法是不可以被覆盖的,因为方法覆盖是基于运行时的动态绑定的,
而static方法编译时是静态绑定的,static方法类的任何事例都不相关联。
java中也不可以覆盖private权限的方法,因为private修饰变量只能在当前类内部使用,
其他类继承当前类的时候,访问不到private变量,当然不能覆
构造方法有哪些特性?
- 构造方法必须与所在的类具有相同的名字。
- 构造方法没有返回类型,甚至连 void 也没有。
- 构造方法的调用是在创建一个对象时使用 new 操作符进行的。构造方法的作用是初始化
在 Java 中定义一个不做事且没有参数的构造方法有什么作用?
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”
因此,如果⽗类中只定义了有参数的构造⽅法,⽽在⼦类的构造⽅法中⼜没有⽤ super() 来调⽤⽗类中特定的构造⽅法,则编译时将发⽣错误,
因为 Java 程序在⽗类中找不到没有参数的构造⽅法可供执⾏。解决办法是:在⽗类 ⾥加上⼀个不做事且没有参数的构造⽅法。
Java 中创建对象的几种方式?
1.通过 new 关键字创建
最常用的方式,比如 Object obj = new Object();
2.通过Class类的newInstance()方法
这种方式是默认调用类的无参构造方法来创建对象
Person p = (Person) Class.forName("com.hutao.test.Person").newInstance()
3.通过Constructor类的newInstance()方法
和第二种类似,都是通过反射来实现
4.通过clone()方法
clone是Object类的一个方法,通过 对象A.clone()方法会创建一个和A一模一样的对象B
5.反序列化
序列化,即把堆内存中的对象通过某种方式以二进制流的形式把它储存到磁盘文件中或传输给其他网络节点。
而反序列化则是将磁盘中文件的对象数据或网络节点的对象数据恢复成java 对象的过程。
抽象类和接口有什么区别
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类是什么:
抽象类不能创建实例,它只能作为父类被继承。抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类的随意性。
(1) 抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法
(2) 抽象类不能被实例化
(3) 抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类
(4) 具体派生类必须覆盖基类的抽象方法
(5) 抽象派生类可以覆盖基类的抽象方法,也可以不覆盖。如果不覆盖,则其具体派生类必须覆盖它们
接口是什么:
(1) 接口不能被实例化
(2) 接口只能包含方法声明
(3) 接口的成员包括方法、属性、索引器、事件
(4) 接口中不能包含常量、字段(域)、构造函数、析构函数、静态成员
接口和抽象类的区别:
(1)抽象类可以有构造方法,接口中不能有构造方法。
(2)抽象类中可以有普通成员变量,接口中没有普通成员变量
(3)抽象类中可以包含静态方法,接口中不能包含静态方法
(4) 一个类可以实现多个接口,但只能继承一个抽象类。
(5)接口可以被多重实现,抽象类只能被单一继承
(6)如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法
接口和抽象类的相同点:
(1) 都可以被继承
(2) 都不能被实例化
(3) 都可以包含方法声明
(4) 派生类必须实现未实现的方法
静态变量和实例变量的区别?
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于一个对象,必须先创建实例对象,它的实例变量才会被分配空间,才能使用这个实例变量。静态变量则属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
例如,对于下面的程序:
public class VarTest
{
public static int staticVar = 0;
public int instanceVar = 0;
public VarTest ()
{
staticVar++;
instanceVar++;
System.out.println(“staticVar=” + staticVar + ”,instanceVar=” + instanceVar);
}
}
上面程序中的staticVar变量随VarTest类初始化而分配内存、执行初始化的,以后无论创建多少个实例对象,不会再分配staticVar变量,因此用永远只有一个staticVar变量。
但instanceVar变量则是随着VarTest对象初始化而分配内存、执行初始化的,因此每创建一个实例对象,就会分配一个instanceVar,即可以分配多个instanceVar。因此上面程序中每创建一个VarTest对象,staticVar的值就会自加一,但每个VarTest对象的instanceVar最多只自加1。
short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?
先说一下Java的基本数据类型转换规则,大的数据类型转换为小的数据类型需要强制转换,反之可以自动转换。
赋值表达式等号两侧的转换的规则是右侧的向左侧的看齐,即右侧表达式要转换到和左边的类型一样。
第一题:short s1 = 1; s1 = s1 + 1;
错! s1 + 1,s1是short类型,1是int型,s1会自动转换为int型的1,与1相加后,得到int型的2,要向左侧的short类型的s1看齐,即需要通过强制类型转换。正确写法:s1 = (short) (s1 + 1);
第二题:short s1 = 1; s1 += 1;
正确! 执行s1+=1;其实执行的是s1 = (short) (s1 + 1); 其中会有一个强制转换的过程。
第三题:short s1=1,s2=1;short s3=s1+s2;
错误!这里是编译器从数据安全方面考虑,如果s1和s2都是较大的short类型数,可能会导致溢出,所以会要求强制转换到int。
正确写法:short s3 = (int)s1 + s2;
Integer 和 int 的区别?
1、Integer是int提供的封装类,而int是Java的基本数据类型;
2、Integer默认值是null,而int默认值是0;
3、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;
4、Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。
装箱和拆箱的区别
1、概念:装箱是将值类型装换成引用类型的过程;拆箱就是将引用类型转换成值类型的过程;
2、利用装箱和拆箱功能,通过允许值类型的任何值与Object类型的值进行相互转换,将引用 类型与值类型连接起来。
3、注:只有装过箱的对象才能拆箱;
4、装箱/拆箱是什么?
装箱:用于在垃圾回收堆中储存值类型。装箱是值类型到Object类型或到此类型所实现的任 何接口类型的隐式转换。
装箱就是自动将基本数据类型转换为包装器类型(int–>Integer);调用方法:Integer的valueOf(int) 方法。
拆箱:从object类型到值类型或从接口类型到实现该接口的值类型的显示转换。
拆箱就是自动将包装器类型转换为基本数据类型(Integer–>int);调用方法:Integer的intValue方法。
switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?
switch只能是int 或者能转化为int型的byte,short,char, jdk1.7之后String也可以。
在 switch( 表达式)中, 表达式 只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是 int基本类型或 Integer 包装类型,由于byte,short,char 都可以自动转换(隐式转换)为int,所以,这些类型以及这些类型的包装类型也是可以的。
显然, long 和 String 类型都不符合 switch 的语法规定,并且不能被隐式转换成 int类型,所以,它们不能作用于 swtich 语句中。
另外由于 JDK1.7 中引入新特性,所以 swtich 语句可以接收一个 String 类型的值, String 可以作用在 swtich 上。
final、finally、finalize 的区别
- final 用于申明属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承。
- finally 是异常处理语句结构中,表示总是执行的部分。
- finallize
表示是object类一个方法,在垃圾回收机制中执行的时候会被调用被回收对象的方法。允许回收此前未回收的内存垃圾。所有object都继承了finalize()方法
详解请见:https://blog.csdn.net/cristianoxm/article/details/105586122
== 和 equals 的区别?
-
equals 一个是方法,而 == 是运算符。
-
== 如果比较的是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。
-
equals() 用来比较两个对象的内容是否相等。
详解请见:https://blog.csdn.net/weixin_43183107/article/details/114673248
两个对象的 hashCode() 相同,则 equals() 也一定为 true 吗?
这是一道很常见并且很简单的面试题,这道题的结论:
-
两个对象的hashCode()相同,equals()不一定为true;
-
两个对象的equals为true,则两个对象的hashcode一定为true;
详解请见:https://www.zhihu.com/question/316293257/answer/2197536779
为什么重写 equals() 就一定要重写 hashCode() 方法?
1.首先解释equals方法和hashcode方法分别是用来干什么的?
equals()方法:
在Object类源码(如下所示)中,其底层是使用了“==”来实现,也就是说通过比较两个对象的内存地址是否相同判断是否是同一个对象。
public boolean equals(Object obj) { return (this == obj); }
但是在实际应用中,该方法不能满足的我们的需求。因为我们认为两个对象即使不是指向的同一块内存,只要这两个对象的各个字段属性值都相同,那么就认为这两个对象是同一个对象。所以就需要重写equals()方法,即如果两个对象指向内存地址相同或者两个对象各个字段值相同,那么就是同一个对象。
hashCode()方法:
一提到hashcode,很自然就想到哈希表。将某一key值映射到表中的一个位置,从而达到以O(1)的时间复杂度来查询该key值。Object类源码(如下所示)中,hashCode()是一个native方法,哈希值的计算利用的是内存地址。
public native int hashCode();
可以认为利用哈希表也能起到一定的判重的作用,但是现实是可能存在哈希冲突,即使是两个不同的对象,他们的哈希值也可能相同,如何解决哈希冲突,这里就略略略了。总之,我们记住哈希表具有优越的查询性能,并且存在哈希冲突。
hash冲突:
public static void main(String[] args) {
String astring = "Ok"; String bString = new String("Ok");
System.out.println(astring.hashCode());
System.out.println(bString.hashCode());
}
输出:
2556
2556
2.equals()方法和hashCode()方法两者有什么关系?
如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相 同!!!!;
如果两个对象不同(即用equals比较返回false),那么它们的hashCode值可能相同也可能不同;
\3. 如果两个对象的hashCode相同(存在哈希冲突),那么它们可能相同也可能不同(即equals比 较可能是false也可能是true)
4.如果两个对象的hashCode不同,那么他们肯定不同(即用equals比较返回false)
3.最后来看为什么重写equals()就一定要重写hashCode()方法?
对于对象集合的判重,如果一个集合含有100个对象实例,仅仅使用equals()方法的话,那么对于一个对象判重就需要比较4950次,随着集合规模的增大,时间开销是很大的。但是同时使用哈希表的话,就能快速定位到对象的大概存储位置,并且在定位到大概存储位置后,后续比较过程中,如果两个对象的hashCode不相同,也不再需要调用equals()方法,从而大大减少了equals()比较次数。所以从程序实现原理上来讲的话,既需要equals()方法,也需要hashCode()方法。那么既然重写了equals(),那么也要重写hashCode()方法,以保证两者之间的配合关系。
& 和 && 的区别?
一,&与&&的区别
按位与:a&b是把a和b都转换成二进制数然后再进行与的运算;
逻辑与:a&&b就是当且仅当两个操作数均为 true时,其结果才为 true,只要有一个为false,a&&b就为false。
&&进行的是短路判断,即如果左侧的表达式的结果为false,整个的结果就为false,不再计算右侧的表达式的值。
例如:
int main() {
int a = 0, b = 1;
a && b ++; //a为0,即左侧的表示的结果为false,整个的结果就为false,不再计算右侧的表达式
cout<<b;
return 0;
}
输出结果
1
Process returned 0 (0x0) execution time : 0.045 s
Press any key to continue.
二,||与|的区别
1,&&和||是短路运算符,&和|是非短路运算符。
2,&&与&区别:两者都表示“与”运算,但是&&运算符第一个表达式不成立的话,后面的表达式不运算,直接返回。而&对所有表达式都得判断。
3,|| 与|区别:两者都表示“或”运算,但是||运算符第一个表达式成立的话,后面的表达式不运算,直接返回。而|对所有表达式都得判断。
Java基础:Java 中的参数传递时传值呢?还是传引用?
1.Java 的参数是以值传递的形式传入方法中,而不是引用传递。
2.当传递方法参数类型为基本数据类型(数字以及布尔值)时,一个方法是不可能修改一个基本数据类型的参数。
3.当传递方法参数类型为引用数据类型时,一个方法将修改一个引用数据类型的参数所指向对象的值。即使 Java 函数在传递引用数据类型时,也只是拷贝了引用的值罢了,之所以能修改引用数据是因为它们同时指向了一个对象,但这仍然是按值调用而不是引用调用。
由于长度限制后续答案请跳转的如下网址
https://www.cnblogs.com/zhangjuntao520/articles/16171626.html

浙公网安备 33010602011771号