java基础
1、Java的数据类型有哪些?
Java的数据类型有:
(1)基本数据类型:byte,short,int,long,float,double,char,boolean
(2)空类型:void
(3)引用数据类型:数组、类、接口、枚举、注解等
2、变量的三要素是什么?变量使用有什么要求?
变量的三要素:
数据类型、变量名、变量值
变量使用要求:
变量必须先声明再使用;
变量必须初始化,其中成员变量有默认值;
局部变量有作用域,同一个作用域中变量不能重复声明;
给变量赋值时要求值的类型<=变量声明的类型;
3、基本数据类型变量和引用数据类型变量有什么区别?
基本数据类型的变量:存储数据值,数据类型不同,宽度不同
引用数据类型的变量:存储地址值
4、Java的运算符+有几种意思?
(1)作为一元运算符:表示正号
(2)当+左右两边有字符串出现时,表示拼接
(3)其他情况表示求和
5、Java的自增、自减运算符在自增变量前后有什么区别?
首先,
自增运算符++,表示自增变量自增1,
自减运算符--,表示自增变量自减1。
其次,以自增为例
(1)如果自增表达式直接加;构成语句,自增运算符在自增变量前后没有区别
a++; 和 ++a; 没区别
(2)如果自增表达式 和其他运算符一起运算,或者自增表达式作为实参使用时,则有区别。
自增运算符在前:表示先自增,再取自增变量的值运算,
自增运算符在后:表示先取自增变量的值,然后自增变量再自增1,计算用的是自增之前取的值。
6、Java的与运算符& 和 && 的区别?
&:
逻辑与,按位与,不会发生短路现象
&&:
逻辑与,会发生短路现象,也称为短路与。
当&&左边是false,右边就不看了。
7、Java的运算符| 和 || 的区别?
|:
逻辑或,按位或,不会发生短路现象
||:
逻辑或,会发生短路现象,也称为短路或。
当||左边是true,右边就不看了。
8、Java的运算符<<,>>,>>>的区别?
<<:
称为左移,左移几位相当于乘以2的n次方。
可能发生正变负,负变正的情况。
>>:称为右移,右移几位相当于除以2的n次方。
不会发生正变负,负变正的情况。
>>>:无符号右移
正数的右移,和>>一样。
负数的右移,直接变正数。
9、Java的分支结构if..else和switch...case有什么区别?
(1)if...else适用于任何条件的判断,
switch...case只适用于byte,short,char,int,String,枚举类型的常量判断。
即能够使用switch...case的都可以使用if...else,反过来不可以。
(2)if...else不会发生分支贯穿/穿透的现象,
switch...case可能发生分支贯穿/穿透的现象。
10、Java的循环有几种情况?
Java的循环有3种形式:
for,while,do...while
11、Java的普通for循环和增强for循环的区别?
普通for循环:
任何需要重复执行某些代码的场景都可以使用它。
增强for循环:
只能用于遍历数组,或实现了java.lang.Iterable接口的集合。
增强for循环遍历数组时,本质上底层是用普通for循环。
增强for循环遍历集合时,本质上底层是用Iterator迭代器遍历。
12、关键字break、continue、return的区别?
break:
用于switch或循环,表示提前结束当前switch或循环。
continue:
用于循环,表示提前结束本次循环体的执行。
return:
用于方法体中,结束当前方法体的执行。
return;表示直接结束当前方法体的执行。
return 结果;表示结束当前方法的执行,并返回结果。
13、类和对象的关系?
类是创建对象的模板。
对象是类的实例。
14、类的成员有哪些?
类的成员:
成员变量
成员方法
构造器
代码块
成员内部类
15、静态变量、实例变量、局部变量的区别?
-
局部变量:
- 声明在方法、构造器、代码块里面,没有默认值,必须手动初始化,在栈中分配内存,有严格的作用域,只能加final修饰。
-
实例变量:
- 声明在类中,其他成员外面,有默认值,也可以在声明后面手动初始化,或者使用非静态代码块和构造器初始化,在堆中分配内存,每一个对象的实例变量都是独立的,可以加public,protected,private,transient,final等修饰符。
-
静态变量:
- 声明在类中,其他成员外面,必须有static修饰,有默认值,也可以在声明后面手动初始化,或者使用静态代码块初始化,在方法区中分配内存,每一个类的静态变量是所有对象共享的,可以加public,protected,private,transient,final等其他修饰符。
16、构造器的特点?
-
构造器的名字必须和类名相同
-
构造器没有返回值类型
-
构造器的首行必须是this() 或 this(输出列表)或super()或super(实参列表),如果这4句都没写,默认是super()
-
构造器不会被继承,但是子类构造器一定会调用父类的构造器
-
如果一个类没有编写任何构造器,那么编译器将会给这个类自动添加默认的无参构造器
-
构造器只能加权限修饰符public,protected,缺省,private
- 枚举类和单例类的构造器一定是私有化的
-
构造器的调用必须用new关键字
17、方法重载和重写的区别?
- 方法的重载:在同一个类中,或父子类中,出现方法名相同,形参列表不同的两个或多个方法称为方法的重载。和返回值类型、修饰符等无关。
- 方法的重写:在父子类、接口和实现类中,出现方法名相同,形参列表相同的两个方法称为方法的重写。方法的重写对返回值类型、修饰符、抛出的异常列表等都有严格的要求。
- 方法名相同,形参列表必须相同
- 返回值类型:如果是基本数据类型必须相同,如果是引用数据类型必须<=的关系
- 权限修饰符:必须子类可见,必须>=的关系
- 其他修饰符:不能是static和final修饰
- 抛出的异常列表:被重写方法没有throws受检异常/编译时异常,重写时也不能throws受检异常/编译时异常。如果被重写方法throws受检异常/编译时异常,重写方法时,要么不throws,要是throws的异常类型满足<=的关系。关于非受检异常/运行时异常不做限制。
Overload方法重载 | Override方法重写 | |
---|---|---|
方法名 | 必须相同 | 必须相同 |
形参列表 | 必须不同 | 必须相同 |
返回值类型 | 不看 | 基本数据类型和void:必须相同 引用数据类型:<= |
权限修饰符 | 不看 | >=,并且要求被重写方法在子类可见 |
抛出的异常列表 | 不看 | 被重写方法没有throws受检异常/编译时异常,重写时也不能throws受检异常/编译时异常。 如果被重写方法throws受检异常/编译时异常,重写方法时,要么不throws,要是throws的异常类型满足<=的关系。 关于非受检异常/运行时异常不做限制。 |
位置 | 同一个类 父子类中 |
父子类中,实现类和接口中 |
18、可变参数是什么意思?
可变参数:
参数类型后面出现...形式,就称为可变参数。
在声明可变参数的方法中,可变参数就是数组。
在调用时,可变参数可以传入对应类型的数组,或者传入0~n个对应类型的元素。
19、什么是递归?
方法出现自己调用自己就是递归。
20、静态代码块和非静态代码块的区别?
静态代码块:
有static修饰的代码块。是给静态变量初始化的。在类初始化时执行,一个类的静态代码块只会执行一次。
非静态代码块:
没有static修饰的代码块。是给实例变量初始化的。在实例初始化时执行,每次new对象时,都会执行。
21、静态方法和非静态方法有什么区别?
静态方法:
在本类中的任意成员中都可以被调用。
父类的静态方法可以被子类继承,但不能被重写。
父接口的静态方法不会被实现类继承,也不能被重写。
非静态方法:
只能在本类的非静态成员中被调用。
非final修饰的非静态方法,只要子类、实现类可见,就可以选择重写。
22、抽象方法和非抽象方法的区别?
抽象方法:
有abstract修饰,没有方法体,不能由private,static,final,native修饰。
在子类或实现类中需要重写。
抽象方法只能出现在抽象类或接口中。
非抽象方法:
没有abstract修饰,有方法体。
23、关键字class、interface、enum的区别
class:
声明类
interface:
声明接口
@interface:声明注解(这个可选)
enum:
声明枚举类
24、继承的关键字是什么?
extends
25、实现接口的关键字是什么?
implements
26、extends关键字的作用
extends:
表示子类继承父类,子接口继承父接口
<泛型变量>的上限指定,<T extends Object & Comparable>
<泛型通配符?>的上限指定,<? extends Comparable>
27、包的作用是什么
(1)避免类的重名
(2)限制某些类或成员的可见性范围
(3)组织管理不同主题的类
28、package和import的区别
package:
声明包
必须在.java文件的首行
import:
导包
在package语句和类定义之间
29、this和super的意思
this:当前对象
super:引用父类/父接口中声明的成员
30、this和super的用法
this:
(1)可以单独使用
(2)this.成员变量:
可以通过this.成员变量,访问当前对象的成员变量,这个成员变量可以是当前类声明的,也可以是从父类继承的,如果要使用父类声明的成员变量,要求当前类没有重名的成员变量。
当局部变量和成员变量重名时,可以在成员变量前面加this.成员变量进行区别。
(3)this.成员方法
可以通过this.成员方法,调用当前对象的成员方法,这个方法可以当前类声明的,也可以是从父类继承的,如果要使用父类声明的成员方法,要求当前类没有重写该方法。
this.成员方法,加不加this完全相同。
this.虚方法时,执行时要看this对象的运行时类型是否重写过虚方法,如果重写了,一定执行重写的代码。
(4)this()或this(实参列表)
表示调用本类其他的构造器
(5)外部类.this.成员
在非静态内部类中使用,引用外部类的成员。
super:
(1)不能单独使用
(2)super.成员变量
可以通过super.成员变量引用父类声明的成员变量,特别是当前类有与父类重名的成员变量时,通过super.成员变量可以区别。
(3)super.成员方法
可以通过super.成员方法引用父类声明的成员方法,特别是当前类有重写父类的方法时,通过super.成员方法可以方法被重写的方法体
(4)super()或super(实参列表)
表示调用父类的构造器
(5)父接口.super.方法
在实现类中调用父接口的默认方法,当默认方法有冲突时使用
31、如何理解面向对象的3个基本特征
封装:
为了体现高内聚、低耦合的开发原则。
为了安全、隐藏类的内部实现细节,提高代码的复用性。
继承:
为了提高代码复用性、便于代码扩展。
为了表示is-a的事物关系。
多态:
为了代码编写更灵活,可以实现虚方法的动态绑定。
32、如何理解多态性?
对象的多态性
(1)一个类可以引用本类对象,也可以引用各种子类对象
(2)一个对象可以让编译器按照本类处理,也可以按照父类或父接口类型,但是运行时类型不变
33、什么是基本数据的自动类型转换和强制类型转换?
当把数据类型小的数据赋值给数据类型大的变量时,就会发生自动类型提升。
byte->short->int->long->float->double
char->
当byte、short、char三个类型在计算时,就会自动升级为int。
当数据类型小的数据与数据类型大的数据混合计算时,数据类型小的数据会自动类型提升。
当把数据类型大的数据赋值给数据类型小的变量时,就要强制类型转换。
double->float->long->int->short->byte
->char
当希望某个数据类型小的数据按照某个大的类型计算时,也可以使用强制类型转换。
34、什么是向上转型和向下转型?
向上转型:
把子类对象赋值给父类的变量。
把实现类的对象赋值给父接口的变量。
向下转型:
把父类变量赋值给子类的变量。
可能发生ClassCastException,最好向下转型之前加instanceof判断
35、使用接口有什么好处?
(1)避免单继承
(2)表示has-a的关系
36、枚举类有什么特点?
枚举类的对象是固定的有限的几个常量对象。
枚举类有固定的直接父类java.lang.Enum类,也不能有子类,构造器私有化了。
37、包装类有什么作用?
当必须使用对象时,基本数据类型就会自动装箱为包装类对象。
当对包装类进行计算时,可以自动拆箱为基本数据类型。
38、int,Integer,BigInteger的区别?
int:基本数据类型
Integer:包装类
BigInteger:任意大小的整数
39、final、finally、finalize的区别
final:修饰符
final修饰类,表示不能被继承
final修饰方法,表示不能被重写
final修饰变量,表示不能修改值
finally:
和try...catch结构一起使用,
表示无论是否有异常,是否可以捕获异常,是否有return语句,都要执行的finally块。
finalize:
finalize是Object类的一个方法,由GC调用,在对象被回收时调用,适用于释放JVM之外的内存。
40、受检异常和非受检异常的区别?
受检异常:
称为编译时异常,编译器检测到某个代码可能发生受检异常,就会强制要求编写try...catch或throws。
非受检异常:
称为运行时异常,无论是否真的会发生运行时异常,编译器都不会提示你编写try...catch或throws。
但是无论受检异常还是非受检异常,只要发生了,没有用try...catch处理,就一定会导致程序崩溃。
41、两种实现多线程的方式?
继承Thread类或实现Runnable接口
42、String、StringBuffer、StringBuilder的区别
String:
字符串对象不可变,字符串常量可以共享。
StringBuffer和StringBuilder:
可变字符序列。
StringBuffer:线程安全
StringBuilder:线程不安全
43、ArrayList和Vector的区别
ArrayList:
线程不安全的动态数组,数组初始化长度为0,默认扩容为1.5倍。
Vector:
线程安全的动态数组,数组初始化长度为10,默认扩容为2倍。
44、ArrayList、Vector和LinkedList的区别
ArrayList、Vector:动态数组
需要扩容。
非末尾位置增加、删除元素,需要移动元素。
ArrayList、Vector实现List接口。
LinkedList:双向链表
不需要扩容和移动元素。
LinkedList实现List、Queue、Deque接口。
45、Stack和LinkedList的区别
Stack:
是Vector的子类,是顺序栈,底层是数组。
LinkedList:
是链式栈,底层是双向链表。
46、List和Set的区别
List:
元素有序:元素的存储和添加顺序一致。
元素可重复。
Set:
元素存储和添加顺序无关。
元素不可重复。
47、Collection和Map的区别
Collection:
存储一组对象
Map:
存储键值对
48、Hashtable和HashMap的区别
Hashtable:
线程安全的,不允许key和value为null
HashMap:
线程不安全的,允许key和value为null
49、Hashtable和HashMap、TreeMap的底层实现
Hashtable:
数组+链表
HashMap:
JDK1.8之前:数组+链表
JDK1.8及之后:数组+链表/红黑树
TreeMap:
红黑树
50、哈希表的底层数组长度为什么是2的n次方
因为2的n次方-1的二进制值是前面都0,后面几位都是1,这样的话,与hash进行&运算的结果就能保证在[0,table.length-1]范围内,而且是均匀的。
如果手动指定为一个非2的n次方的数组长度,HashMap是否接收呢?如果不接收怎么处理呢?
会纠正为>=手动指定的长度的最近的一个2的n次方值。
51、哈希表的数组的元素类型
java.util.Map$Entry接口类型。
JDK1.7的HashMap中有内部类Entry实现Entry接口
JDK1.8的HashMap中有内部类Node和TreeNode类型实现Entry接口,并且TreeNode是Node的子类。
52、哈希表的键值对如何计算存储位置
hash & table.length-1
53、哈希表要用链表或红黑树?
为了解决hash和[index]冲突问题
(1)两个不相同的key的hashCode值本身可能相同
(2)两个不相同的key的hashCode值不同,但是经过hash()运算,结果相同
(3)两个hashCode不相同的key,经过hash()运算,结果也不相同,但是通过 hash & table.length-1运算得到的[index]可能相同
那么意味着table[index]下可能需要存储多个Entry的映射关系对象,所以需要链表或红黑树
54、HashMap的数组什么时候扩容?
JDK1.7版:当要添加新Entry对象时发现(1)size达到threshold(2)table[index]!=null时,两个条件同时满足会扩容
JDK1.8版:当要添加新Entry对象时发现(1)size达到threshold(2)当table[index]下的结点个数达到8个但是table.length又没有达到64。两种情况满足其一都会导致数组扩容
而且数组一旦扩容,不管哪个版本,都会导致所有映射关系重新调整存储位置。
55、如何计算阈值threshold
threshold = table.length * loadfactor
56、loadfactor的默认值是多少
0.75
57、JDK1.8的HashMap什么时候树化?为什么要树化?
当table[index]下的结点个数达到8个但是table.length已经达到64
因为当table[index]下的结点个数超过8个后,查询效率就低下了,修改为红黑树的话,可以提高查询效率
58、JDK1.8的HashMap什么时候反树化?为什么要反树化?
当table[index]下的树结点个数少于等于6个
(1)当继续删除table[index]下的树结点,最后这个根结点的左右结点有null,或根结点的左结点的左结点为null,会反树化
(2)当重新添加新的映射关系到map中,导致了map重新扩容了,这个时候如果table[index]下面还是小于等于6的个数,那么会反树化
因为当table[index]下树的结点个数少于6个后,使用红黑树反而过于复杂了,此时使用链表既简洁又效率也不错
59、请问已经存储到HashMap中的key的对象属性是否可以修改?为什么?
如果该属性参与hashCode的计算,那么不要修改。因为一旦修改hashCode()已经不是原来的值。
而存储到HashMap中时,key的hashCode()-->hash()-->hash已经确定了,不会重新计算。用新的hashCode值再查询get(key)/删除remove(key)时,算的hash值与原来不一样就不找不到原来的映射关系了。
60、如何key是null,在哈希表中如何存储
会存在table[0]中
61、两个字符串比较用什么方法
eqauls方法
如果要忽略大小写,用equalsIgnoreCase方法
62、TCP/UDP协议有什么区别
TCP:面向连接的可靠的基于字节流的传输控制协议
UDP:非面向连接的不可靠的基于用户数据报的协议
63、线程安全问题是什么,如何解决
当多个线程使用共享数据时,就会有线程安全问题。
可以加同步synchronized解决。
同步代码块或同步方法。
同步代码块:手动选择同步锁对象。
同步方法:静态方法的同步锁对象是当前类的Class,非静态方法的同步锁对象是this
64、IO流的四个抽象基类是什么
InputStream:字节输入流
OutputStream:字节输出流
Reader:字符输出流
Writer:字符输出流
65、如何实现对象序列化?
对象序列化需要用ObjectOutputStream的writeObject方法,对象的反序列化需要用ObjectInputStream的readObject方法。
对象的类型需要实现java.io.Serializable接口,并加序列化版本ID
加transient和static修饰的成员变量都不序列
66、Class类对象如何获取
类型名.class
对象.getClass
Class.forName(类型全名称)
类加载器对象.loadClass(类型全名称)
67、反射的作用
实现Java语言的动态性。
在运行时动态获取类信息,动态创建对象,动态操作属性,动态调用方法。
68、什么是函数式接口
只有一个抽象方法的接口,即SAM接口(Single Abstract Inteface)
69、什么是Lambda表达式?
Lambda表达式是一种实现函数式接口的新语法。
70、举几个函数式接口的例子
java.lang.Runnable
java.util.Comparator
java.util.function.Consumer
java.util.function.Predicate
java.util.function.Supplier
java.util.function.Function
70、Comparable和Comparator的区别
Comparable:自然比较接口
Comparator:定制比较接口
71、Iterable和Iterator的区别
Iterable:可迭代接口,实现它的集合就可以支持foreach循环遍历
Iterator:迭代器接口
72、sleep() 和 wait() 有什么区别?
sleep和wait都会导致当前线程进入阻塞状态,被挂起。
sleep不释放锁,睡眠时间到自动醒来,回到就绪状态
wait是会释放锁,要通过notify()或notifyAll()唤醒,回到就绪状态
sleep是在Thread类中声明的一个静态方法,Thread.sleep(毫秒)
wait是在Object类中声明的非静态的方法,必须锁对象调用
73、请解释Java异常处理机制相关的5个关键字
try:尝试执行可能发生异常的代码。
catch:尝试捕获try部分发生的异常。可以存在多个catch,如果多个catch的异常类型有继承关系,那么遵循子上父下。
finally:不管是否发生异常都要执行的代码放在finally块中。
throws:方法声明时显示抛出异常,指定该方法可能抛出的异常类型列表。
throw:手动抛出异常,可以抛出系统预定异常,也可以抛出用户自定异常,而且用户自定义异常必须用throw语句抛出,可以代替return语句结束方法运行。
74、访问修饰符的作用范围由大到小,及各自的范围是什么?可以修饰什么?
修饰符的作用范围由大到小:public、protected、缺省、private
本类 | 本包的所有类 | 其他包的子类 | 其他包的非子类 | |
---|---|---|---|---|
private | √ | |||
缺省(不写) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
这些权限修饰符可以修饰的角色:
class(外部类) | 成员变量 | 成员方法 | 成员内部类 | |
---|---|---|---|---|
private | √ | √ | √ | |
缺省(不写) | √ | √ | √ | √ |
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
75、请列出一些常用的类、接口、包,各至少5个
注意答案不固定
常用类:String,Math,ArrayList,HashMap,System,Arrays,LocalDate,Thread,HashSet,LinkedList等
常用接口:Comparable,Comparator,Runnable,Serializable,Collection,Map,List,Set,Iterator,Consumer,Predicate等
常用包:java.lang, java.util,java.io,java.net,java.text,java.lang.reflect,java.time,java.util.function,java.math等