java基础面试题
1.面向对象的特征
封装,继承,多态,抽象
封装:是将对象的属性和数据结合在一起,成为一个独立的整体,把可以展现别人的展现出来,不可以展现给别人的进行隐藏,别人不知道你是怎么实现的,从而提高了代码的安全性!
继承:是出现在父子类中,孩子继承了爸爸的属性和行为,还可以根据自身的需求来扩展自己的业务,从而提高了代码的复用性!
多态:是多个对象对同一的消息做出的响应。换句话说就是同一消息可以根据发送的对象不同而采用不同的行为方式!封装和继承就是为多态而准备的。
抽象:用abstract关键字修饰的类,不可被实例化!此类叫抽象类!就是用关键字abstract来修饰
2.JDK,JRE,JVM区别
JDK:整个java运行的核心内容,是java的开发工具包,包含了java的运行环境JRE,Java运行工具,java的基础类库
JRE:是java运行时所需要的环境的集合,其中包含了虚拟机和java程序的一些基础类库
JVM:是虚拟机的缩写,是整个java实现跨平台的重要部分,能够运行java语言写作的软件程序。
3.重写和重载的区别
重写:发生在父子类中,方法名和参数列表必须相同,抛出的异常小于等于父类,返回值小于等于父类,访问修饰符大于等于父类,如果父类中的方法修饰符为private,则子类不能重写该方法。
重载:发生在同一个类中,方法名不同,参数列表不同,参数类型不同,个数不同,顺序不同,方法返回值和访问修饰符不同,发生在编译时。
4.java中==和equals的区别
==基本类型比较的是具体内容,引用类型比较的是地址值
equals引用类型默认情况下比较的是地址值,除一些特定的String,Integer等在类库中equals被重写,比较的是具体内容!
面试常问,在字符串比较中,==和equals()的区别是什么
在字符串比较中,==比较的是内存地址(hashcode)值是否相同,属于地址值的比较
而equals()比较的是字符串的具体内容,所以属于内容的比较
5.String,StringBuffer,StringBuilder三者的区别是什么?
String是字符串的常量
StringBuffer是字符串的变量属于线程安全类型
StringBuilder是字符串的变量,属于现成非安全类型
String中的String类型想要保存字符数组需要使用final关键字来修饰,被final关键字修饰的常量是属于不可变的,属线程安全类型的
AbstractStringBuffer是StringBuffer和StringBuilder的公共父类。
StringBuffer是对方法或者对调用的方法添加了同步锁的机制,属于线程安全类型的
StringBuilder是对方法没有进行同步锁添加的机制,属于线程不安全的类型
6.接口类和抽象类的区别
抽象类是 采用继承的方式,子承父的方式,用extends来继承
接口类是采用实现的方式,用implement来实现
构造方法:抽象类可以有构造方法,接口类不能有构造方法
main方法:类可以实现多个接口,确只能继承一个抽象类
访问修饰符:接口中的方法默认使用的是public,而抽象类中可以是任何的访问修饰符
7.String常用的方法名
indexOf():返回指定字符串的索引
charAt():返回指定索引处的字符串
replace():字符串的替换
trim():去掉收尾的空白处
split():分割字符串,返回个分割后的字符串的数组
8.单例模式的介绍和分类
单例模式:就是某一个类的实例在多线程的环境下会被创建一次出来
单例模式分为:懒汉式单例模式,饿汉式单例模式,双检索式单例模式
饿汉式单例模式:就是一开始就被初始化出来,属于线程安全的类型,其代码如下所示:
public class test{
private static Singleton sing = new Singleton(); 创建一个Singleton对象
private singleton(){} 构造方法
public static Singleton getInstance(){ 创建一个静态的Instance方法
return instance; 返回一个instance
}
}
懒汉式单例模式:线程非安全的类型,而且延迟初始化
双检索单例模式:线程安全的类型,延迟初始化
9.反射
Java中的反射首先要获取到Java中要反射的字节码,其方式有三种,如下:
类名.class
this.getclass()
Class.ForName(className)
在Java的反射机制是指Java的运行状态中,对于任意一个类都能够知道这个类的方法和属性,并且对于任意一个对象,都可以调用其任何一个方法,这种动态获取属性值或者方法的方式就是Java的反射机制。
10.Java的异常
Java异常是Java提供的一种识别以及消息响应错误的一种方式。
Throwable:是Java中语言错误和异常的超类,分为如下两类异常
Error和Exception两种
Error是JVM所侦测到无法预期的错误,这个错误可能是因为jvm层次的错误,这个错误是无法采取任何的恢复方式的,只能显示一个错误信息
Exception异常是可恢复异常,分为运行时异常和非运行时异常
运行时异常表示在运行时才会出现的异常,是RuntimeException类及其子类,如空指针异常,数组下标越界异常等,这些都是可以选择捕获处理,及时不处理,他们也会在编译时通过
非运行时异常也叫编译时异常,即我们在编译期间会出现的异常,这些异常是必须处理的,如果不进行处理,那么编译不通过。
11.BIO,AIO,NIO的区别
BIO:即block IO ,同步阻塞式IO,他的特点就是方式简单,使用方便,处理并发能力低
NIO:即new IO,同步非阻塞 IO,是传统IO的升级,客户端与服务端通过channel通讯,实现了多路的复用
AIO:即AsynchronousIO,是NIO的升级,也叫NIO2,实现了异步非阻塞IO,异步IO的操作基于事件和回调机制。
12.Threadloal的原理
Threadloal:为共享变量在每个线程中创建一个副本,也就是说每个线程都可以访问自己的副本变量。通过Threadloal来保证线程的安全。
在Threadloal类中有一个内部类,这个静态内部类是ThreadlocalMap,在这个ThreadlocalMap类中,存储的是键值对形式的线程的变量副本,Threadlocal中的元素key是当前Threadlocal对象,value为键值对形式的线程变量副本。
在使用完Threadlocal之后,记得调用remove方法,在不使用线程池的情况下,也可以不调用remove方法,线程的变量副本也会被系统的gc回收掉。
13.同步锁,死锁,乐观锁,悲观锁
同步锁:就是多个线程访问同一个数据时,很容易出现问题,那么为了避免这种情况的发生,就使用了同步锁的机制,表示同一时间只允许有一个线程进入访问共享数据,Java中可以通过synchronized关键字来取得同一对象的同步锁
死锁:就是多个线程同时阻塞,他们中的某一个或者全部在等待某个资源被释放
乐观锁:就是假设总是最好的情况,每次去拿数据都认为别人不会更改数据,所以不上锁,但是会在更新的时候判断一下别人是否更新过数据。
悲观锁:就是假设总是最坏的情况,每次去拿数据都认为别人会更新数据,所以每次都拿数据的时候,都会上锁,别人想拿这个数据会被阻塞,直到拿到锁为止。
14.说一说syncharonized的底层原理
synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法进入临界区,同时他还可以保证共享变量的可见性。
Java中每一个队形都可以作为锁,这是synchronized的实现同步的基础:
普通的同步方法:锁是当前实例的对象
静态的同步方法:锁是当前类的class对象
同步方法块,锁是括号里面的对象
15.synchroized和volatile的区别是什么?
volatile的本质还是在告诉jvm当前变量的工作内存中的值不确定,需要我们从主存中去读取,而synchronized则是锁定了当前的变量,只有当前线程可以访问该变量,其他线程被阻塞住了
volatile是仅能使用变量级别的,而synchronized则可以使用变量,方法和类级别的
volatile仅能实现变量的修改可见性,不能保证原子性,而synchronized则可以保证变量的修改可见性和原子性
volatile不会对线程造成阻塞,synchronized可能会对线程造成阻塞
volatile标记的变量不会被编译器优化,synchronized标记的变量可以被编译器优化
16.手写冒泡排序
以下是一段手写的冒泡排序
public class Sort{
public static void sort(){
Scanner input = new Scanner (System.in);
int sort[ ] = new int[10]
int temp;
System.out.println("请输入10个排序的数据:");
for(int i = 0;i<sort.length;i++){
sort[i] = input.nextInt();
}
for(int i = 0; i < sort.length - 1;i++){
for(int j = 0; j< sort.length - 1; j++){
if(sort[ j ] < sort[ j + 1 ]{
temp = sort[ j ];
sort[ j ] = sort[ j + 1];
sort[j + 1 ] = temp;
}
}
}
System.out.println("排列后的顺序为");
for(int i = 0;i<sort.length;i++){
System.out.println(sort[ i ] + “==========");
}
}
public static void main (String[ ] args){
sort();
}
}