java基础知识面试题集合

1、字符型常量与字符串常量的区别?

  • 形式上:字符常量是单引号引起的字符,字符串常量是由双引号引起的若干个字符。
  • 含义上:字符常量相当于一个整形的数值,可以参加表达式的运算,字符串常量代表一个地址值(这个值是表示字符串再内存中存放的位置)
  • 占内存的大小:字符常量占2个字节,字符串常量占若干个字节(注意:char在java中占两个字节

2、构造器(Constructor)可否被override?

讲继承的时候说到,父类的私有属性和构造方法不可以被继承,所以说,构造器是不可以被重写,但是可以被重载,所以看一看到一个主类有多个构造器的情况。

3、重载和重写的区别?

  • 重载:发生在同一个类中,方法名可以相同,但是参数类型、参数个数、参数顺序方法的返回值,修饰符可以不同,发生在编译时期。
  • 发生在字符类中,方法名和参数列表必须相同,返回值范围要小于等于父类,抛出的异常范围要小于等于父类,访问修饰符范围要大于或者等于父类,如果父类中的方法修饰符为private那么子类就不可以重写此方法。

4、java面向对象编程的三大特性:继承、封装、多态?

1、封装:

将对象的属性私有化,向外界提供一些可以访问属性的方法,如果属性不想被外界访问,我们大可不提供外界访问的方法,但是如果一个类,没有提供外界访问的方法,那么这个类也就没有什么意义。

2、继承:

继承是通过已经存在的类作为基础来建立一个新的类的过程,新的类可以增加新的功能和数据,也可以使用父类中的功能,但是不可以选择性的继续父类,我们通过继承可以很好的复用以前打代码。
注意
1.子类中拥有父类对象中的所有属性和方法,但是父类中的私有属性和方法子类是无法访问的,只能拥有。
2.子类可以拥有自己的属性和方法,也就是说可以对父类进行扩充。

3、多态:

多态的主要体现就是父类的引用变量可以指向父类,前提是必须存在子父类的关系,可以理解为一个接口可以使用不同的实力来执行不同的操作。
java中的两种形式可以实现多态:继承和接口的实现。

5、String类为什么是不可变的?

String类的值是保存在value数组中,并且被private final修饰的。
private:表示外部类是不可以访问到value的。
final:表示value的引用是不被改变的,也表示该类不被继承,表明方法不可以被重写

6、StringBuffer和StringBulider之间有何区别?

StringBulider和StringBuffer都是继承的AbatractStringBulider类,而在AbstractStringBulider类中也是使用字符数组来保存字符串的,但是没有final来修饰,所以这两个对象是可变的。

1.线程安全问题:

1.String本来是不可变的可以理解为常量,线程安全
2.StringBuffer的公共的父类:定义了一些对字符串的操作方法,,对方法加上了同步锁或者对调用的方法加上了同步锁,所以也是线程安全的
3.而StringBulider没有对方法进行同步加锁,所以线程是非安全的。

性能:

虽然StringBulider要比StringBuffer多15%左右的性能提升,但是要冒着线程不安全的风险。

总结

1.对少量数据进行操作使用String类
2.单线程字符串缓存区下操作大量的数据使用StringBuilder
3.多线程字符串缓存区下操作大量的数据使用StringBuffer.

7、自动装箱的拆箱

1、装箱:使用基本的数据类型使用它们对应的引用类包装起来
2、拆箱:将包装类转化为基本的数据类型。
为什么使用:在一个统用的场景中,调用一个包含Object类型参数的方法中,Object可以支持任意的类型,以便通用。当你需要将一个值注入到容器中的时候就需要装箱了。

8、对象相等与指向它们的引用相等有何不同?

对象相同比较的是内存中存放的内容是否相同,然而指向的引用相等比较的是它们指向的内存地址是否相同。

9、==和equals的比较?

1、==(是java提供的比较运算符)一般来判断两个对象的地址是否相同,也就是说判断两个对象是不是同一个对象(基本数据类型比较的是值,引用数据类型比较的是地址)
2、equals()(是Object类提供的方法):判断两个对象内容是否相同。
注意:如果调用了new关键字,那么会在内存中给你分配一个新的地址

10、hashCode与ecqual()方法

1.hashCode()作用:获取哈希码也叫做散列码,这个码用来确定对象在哈希表中的索引位置,可以通过哈希码快速的检索出对应的值。
2.当把对象加入到hashSet中的时候,会使用hashCode的值来判断对象加入的位置,同时也会和其他已经加入的对象的hsashCode来比较,如果没有发现相同的hashCode那么就会将此对象加入到hashSet中,但是如果发现相同的hashCode那么就会调用ecqual()方法来判断hash对象是否相同,如果相同就不会让其加入,如果不同的话就会重新散列到其他的位置。

11、hashCode()与ecqual()的相关规定

1、如果两个对象相等,但是hashCode也不一定相等
2、如果两个对象相等,那么调用ecqual()方法返回值为true
3、即使两个对象的hashCode相同,两个对象也不一定相等
4、如果ecqual()方法被覆盖过,那么hashCode()方法一定被覆盖

final关键字的一些总结

1、修饰在变量之上:如果是基本数据类型的变量,那么在初始化之后值就不可以被修改,但是如果是引用类型的变量,初始化之后就不可以指向另一个对象。
2、修饰在类上:表明这个类不可以被继承
3、修饰在方法上:将方法锁定以防任何继承类修改它的含义。

java异常类的层次结构

在这里插入图片描述
所有的异常类都有一个共同的祖先throwable类:之后有两个重要的子类:Error和Exception类。
**Error:**是程序无法处理的错误。
**Exception:**是程序本身可以处理的异常。
注意
异常和错误直接的区别:异常时程序可以处理的,然而错误是程序无法处理的。

12、java中序列化的时候如果有些类不想被序列化应该如何处理?

对不想被序列化的变量,使用transient关键字来修饰
作用:阻止实例中那些用此关键字来修饰的变量进行序列化,transient只可以用力啊修饰变量,不可以用来修饰类和方法。

13、什么是线程和进程?

1、进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的,它存在创建,运行,死亡的过程。
在Java中启动main方法就是启动了jvm中的进程,main函数所在的线程是这个进程中的一个线程,也就是主线程。
2、线程与进程相似,但是是一个比进程更小的执行单位,一个进程的执行过程中可以产生多个线程,一个类的多个线程是共享进程的堆和方法区的资源,每一个线程都有自己的程序计数器,虚拟机栈和本地方法栈,所以说各个线程直接切换工作的过程中,负担要不进程小,因此线程也被叫做轻量级的进程。

14、图解进程和线程之间的关系

在这里插入图片描述
图中可以看出一个进程有多个线程,它们共用堆和方法区资源,但是每一个线程都有自己的程序计数器虚拟栈和本地方法栈。

15、程序计数器为什么是私有的?

程序计数器主要有一下的两个功能:
1.字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行,选择,循环、异常处理等等。
2.程序计数器用于记录当前线程执行的位置,从而线程被切换回来之后知道上一次执行的位置是哪里。
主要功能是为了使得线程在切换回来之后知道上一次执行的位置

16、虚拟机栈和本地方法栈为什么是私有的?

java程序在执行的过程中会创建一个栈帧用来存储局部变量表,操作数栈,常量池信息等等,村方法调用直至完成的过程就对应的栈帧在虚拟机栈中掉进栈出栈的过程。
为了保证线程中的局部变量不被别的线程访问到,所以虚拟机栈和本地方法栈是私有的

17、堆和方法区的理解?

堆和方法区都是被线程共享的部分,堆是进程中最大的一块内存,主要存储新创建的对象(所有的对象都在此处来分配内存),方法区主要是存放被加载过的类的信息,常量,静态变量,也就是编译器编译后的代码等数据。

18、并行和并发的区别?

  • 1.并发:同一个时间段,多个任务都在执行(单位时间内不一定在同时执行)
  • 2.并行:单位时间内,多个任务在同时执行。

线程的生命周期和状态?

在这里插入图片描述
线程可能存在的一些状态:线程被新建之后处于NEW(新建状态),调用start()方法之后,此时的线程处于reday(可运行状态),可运行状态获取到CPU的时间片之后就处于runing(运行状态),当线程执行wait()方法之后进入waiting(等待状态) 只有通过其他的线程通知之后才可以进入运作状态,通过sleep()或则wait()方法可以将线程置于time_waiting状态, 在没有获取到锁的情况之下,线程会进入blocked(堵塞状态),在执行完run()方法之后,线程处于terminated(终止状态)

19、什么是上下文切换?

解释:一个CPU的核心在任意的时刻都只可以为一个线程使用,但是线程数一般都是多余CPU核心的个数,所有CPU采取的策列就是通过时间片轮转的新式,一个线程用完一个时间片之后就会处于就绪状态然后等待下一个时间片的执行,这一个过程就是上下文切换。
任务从保存在再次加载的过程就是一次上下文切换

20、什么是线程的死锁,如何避免死锁?

线程的死锁:

多个线程被阻塞时,它们中的多个都在等待某一个资源释放的时候,由于线程被无线的阻塞,此程序不可以被正常的终止。多个线程同时等待,就是处于所谓的线程的死锁。
在这里插入图片描述
产生死锁要必备以下的四个条件
1、互斥条件:该资源在任何时候都只可以被一个线程锁占用
2、请求与保持条件:一个进程因为请求资源而阻塞的时候,对已经获取的资源不会释放。
3、不剥夺条件:一个线程在获取到资源在未使用完毕之前不可以被其他线程强行剥夺,只有自己使用完毕才可以释放资源。
4、循环等待条件:若干个线程形成了一个收尾相接的循环等待资源关系。

21、如何避免线程的死锁?

只要破坏四个条件中的一个就可以了:
1、无法破坏互斥条件,因为锁的目的就是为了实现线程之间的互斥
2、破坏请求以保存条件:一次性申请所有的资源
3、破坏不剥夺条件:占用的部分资源的线程在申请新的资源的时候,如果无法申请,那么就释放自己占有的资源
4、破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。

22、说说 sleep() 方法和 wait() 方法区别和共同点?

  • 主要区别:sleep没有释放锁,而wait方法释放了锁
  • 两者都可以暂停线程的执行
  • wait()方法在执行之后,线程不会自动苏醒,需要别的线程调用同一个notify()方法唤醒,然而sleep()方法执行之后,线程会将自动苏醒。

23、 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?

当创建一个线程处于新建状态的时候,调用start()方法就会使得线程处于就绪状态分配到时间片之后就会执行,start()会执行线程的准备工作,之后会自动调用线程中的run()方法,这才时真正的多线程工作,但是如果直接调用run()方法,相当于将run()方法作为的main方法直下的一个普通方法来执行,并不会在某一个线程中执行它,这并不是多线程的工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值