一、Java基础面试
1.Java基础知识
1.1面向对象的特征?
面向对象的特征:封装、继承、多态、抽象。
封装:就是把对象的属性和行为(数据)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节,就是把不想告诉或者不该告诉别人的东西隐藏起来,把可以告诉别人的公开,别人只能用我提供的功能实现需求,而不知道是如何实现的。增加安全性。
继承:子类继承父类的数据属性和行为,并能根据自己的需求扩展出新的行为,提高了代码的复用性。
多态:指允许不同的对象对同一消息做出相应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。封装和继承几乎都是为多态而准备的,在执行期间判断引用对象的实际类型,根据其实际的类型调用其相应的方法。
抽象:表示对问题领域进行分析、设计中得出的抽象的概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。在 Java 中抽象用 abstract 关键字来修饰,用abstract 修饰类时,此类就不能被实例化,从这里可以看出,抽象类(接口)就是为了继承而存在的。
1.2& 和 && 的区别?
&运算符有两种用法:
按位与;
逻辑与。
&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是 true 整个表达式的值才是 true。
&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行 运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为
username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会产生NullPointerException 异常。
注意:逻辑或运算符(|) 和短路或运算符(||)的差别也是如此。
1.3Java 的基本数据类型有哪些?
1.4简述 Java 中的值传递和引用传递?
1.值传递
在方法的调用过程中,实参把它的实际值传递给形参,此传递过程就是将实参的值复制
一份传递到函数中,这样如果在函数中对该值(形参的值)进行了操作将不会影响实参的值。 因为是直接复制,所以这种方式在传递大量数据时,运行效率会特别低下。
2、引用传递
引用传递弥补了值传递的不足,如果传递的数据量很大,直接复过去的话,会占用大量
的内存空间,而引用传递就是将对象的地址值传递过去,函数接收的是原始值的首地址值。
在方法的执行过程中,形参和实参的内容相同,指向同一块内存地址,也就是说操作的其实都是源数据,所以方法的执行将会影响到实际对象
结论:
基本数据类型传值,对形参的修改不会影响实参;
引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象。String, Integer, Double 等 immutable 的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。
1.5char 型变量中能不能存储一个中文汉字,为什么?
类型可以存储一个中文汉字,因为 Java 中使用的编码是 Unicode(不选择任何特定的
编码,直接 使用字符在字符集中的编号,这是统一的唯一方法),一个 char 类型占 2 个字节(16 比特),所以放一个中 文是没问题的。
1.6重载和重写的区别?
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类, 访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
1.7==与equals的区别?
对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;如果作用于引用类型的变量,则比较的是所指向的对象的地址。
对于equals方法,注意:equals方法不能作用于基本数据类型的变量;
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
1.8String、StringBuffer、StringBuilder 的区别?
String 是不可变的对象,每次对 String 类型进行改变的时候其实是产生了一个新的 String 对象,然后指针指向新的 String 对象;
StringBuffer 是线程安全的可变字符序列,需要同步,则使用。
StringBuilder 线程不安全,速度更快,单线程使用。
(String 是一个类,但却是不可变的,所以 String 创建的算是一个字符串常量, StringBuffer 和 StringBuilder 都是可变的。所以每次修改 String 对象的值都是新建一个对象再指向这个对象。而使用 StringBuffer 则是对 StringBuffer 对象本身进行操作。所以在字符串 j 经常改变的情况下,使用 StringBuffer 要快得多。)
对于三者使用的总结:
1. 操作少量的数据 = String
2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffffer
1.9final 关键字的一些用法?
final关键字主要用在三个地方:变量、方法、类。
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。
使用final方法的原因有两个:
第一个原因是把方法锁定,以防任何继承类修改它的含义;
第二个原因是效率。
在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为fianl。
1.10Object类是一个特殊的类,是所有类的父类。
它主要提供了以下11个方法:
public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass()
== x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。
public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数, 这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作
1.11接口和抽象类的区别是什么?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
1.12什么是单例模式?有几种?
单例模式:某个类的实例在 多线程环境下只会被创建一次出来。
单例模式有饿汉式单例模式、懒汉式单例模式和双检锁单例模式三种。
饿汉式:线程安全,一开始就初始化。
懒汉式:非线程安全,延迟初始化。
双检锁:线程安全,延迟初始化。
1.13final、finally、finalize 的区别?
1) final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不可继承。
2) finally:异常处理语句结构的一部分,表示总是执行。
3)finalize:Object 类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法 提供垃圾收集时的其他资源回收,例如关闭文件等。该方法更像是一个对象生命周期的临终方法,当该方法 被系统调用则代表该对象即将“死亡”,但是需要注意的是,我们主动行为上去调用该方法并不会导致该对 象“死亡”,这是一个被动的方法(其实就是回调方法),不需要我们调用。
1.14throw 和 throws 的区别?
throw:
1)throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
2)throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是
抛出了某种异常。
throws:
1)throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的
处理。
2)throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异
常的类型。
3)throws 表示出现异常的一种可能性,并不一定会发生这种异常。
1.15请写出你最常见的 5 个 RuntimeException?
下面列举几个常见的RuntimeException。
1)java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
2)java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
3)java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
4)java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
5)java.lang.IllegalArgumentException 方法传递参数错误。
6)java.lang.ClassCastException 数据类型转换异常。
7)java.lang.NoClassDefFoundException 未找到类定义错误。
8)SQLException SQL 异常,常见于操作数据库时的 SQL 语句错误。
9)java.lang.InstantiationException实例化异常。
10)java.lang.NoSuchMethodException方法不存在异常。
1.16java 异常处理机制?
Java 对异常进行了分类,不同类型的异常分别用不同的Java 类表示,所有异常的根类为 java.lang.Throwable, Throwable 下面又派生了两个子类:Error 和 Exception,Error 表示应用程序本身无法克服和恢复的一种严重问题。 Exception 表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让 软件系统继续运行或者让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常
(ClassCastException);普通异常是运行环境的变化或异常所导致的问题,是用户能够克服
的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。
java 为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须
try..catch 处理或用 throws 声明继 续抛给上层调用方法处理,所以普通异常也称为
checked 异常,而系统异常可以处理也可以不处理,所以,编译器不 强制用 try..catch 处理或用 throws 声明,所以系统异常也称为 unchecked 异常。
1.17error 和 exception 的区别?
Error 类和 Exception 类的父类都是 Throwable 类,他们的区别如下。
Error 类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类 错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
Exception 类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复 运行,而不应该随意终止异常。
Exception 类又分为运行时异常(Runtime Exception)和受检查的异常(Checked
Exception ),运行时异 常;ArithmaticException,IllegalArgumentException,编译能通
过,但是一运行就终止了,程序不会处理运行时异常, 出现这类异常,程序会终止。而受检查的异常,要么用 try。。。catch 捕获,要么用 throws 字句声明抛出,交给它 的父类处理,否则编译不会通过。