1、面向对象的特征
面向对象特征主要有:封装、继承、多态与抽象
封装
封装是隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的结构,同时也保护了数据。对于外界而言,它的内部细节是隐藏的,暴露给外界的只是它的方法。
继承
继承就是在已存在的类的基础上定义一个新类,新类的定义可以增加新的属性和方法,也可以使用父类的属性和方法
抽象
抽象就是找出一些事务的相似和共性之处,然后将这些事务归为一个类,这个类只考虑这些事务的相似和共性之处
多态
父类引用指向子类对象,在运行时,调用方法时会调用子类的实现而不是父类的实现,这种在运行时的动态绑定就是多态
多态实现的必要条件:
封装、继承、父类引用指向子类对象
多态的种类:
继承多态、接口多态
2、final, finally, finalize 的区别
final关键字可以用来修饰属性、方法和类,分别表示属性不可变、方法不可被覆盖、类不可以被继承
finally是异常处理的一部分,被用于try catch语句中并且附带一个语句块,表示不管异常是否发生,程序最终都会执行
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时其他资源的回收,JVM不保证此方法总会被调用。
3、反射机制及使用场景
Java反射是指在运行状态中,对于任意一个类,我们都可以知道这类的所有属性和方法,对于任一一个对象,我们都可以对它的方法和属性进行调用,这种动态获取对象信息和调用方法的功能称之为反射机制。
优点:
运行期类型的判断,动态类加载
缺点:
反射相当于一些列解释操作,通知JVM要做的事情,性能比直接的Java代码慢很多
用途:
在运行时,判断一个对象所属的类
在运行时,获取任意对象的所有属性和方法
在运行时,任意构造一个类的对象
生成动态代理
4、==和equals区别
==比较基本类型时,比较的是值是否相等,比较引用对象时,比较两个对象的内存地址是否相同
equals一般用来比较两个对立对象的内容是否相同,在没有重写Object的equals方法时,使用equals方法默认就是使用==来比较两个对象是否是同一对象
5、String、StringBuffer和StringBuilder的区别
String是字符串不可变类,String对象一旦创建并初始化后便不能再改变。
StringBuffer和StringBuilder是字符串可变类,可以动态构造字符数据,区别就是StringBuilder是非线程安全的,而StringBuffer 是线程安全的,所有的方法都被synchronized所修饰。
6、单线程下StringBuffer和StringBuilder有区别么?单线程和多线程下StringBuffer的区别呢?
在单线程下,在未达到一定数量级的情况下,二者的效率其实差不多,在达到一定数量级的情况下StringBuilder效率要稍高一些,因为在JDK1.6及以后,在单线程下synchronized关键字默认加的的是偏向锁。
在Java对象头的Mark Word中存在四种状态的锁:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。偏向锁就是在大多数情况下,锁总是由同一线程多次获得,不存在多线程竞争。所以偏向锁的目标是在只有一个线程执行同步代码块时能够提高性能。
当一个线程访问同步代码块并获取锁时,会在Mark Word中存储锁偏向的线程ID,在线程进入和退出同步块时不再通过CAS操作来加锁和解锁,而是检测Mark Word中是否存储着指向当前线程的偏向锁。
在多线程情况下,synchronized采用锁升级的优化方式,即先使用偏向锁,优先同一线程获取锁,如果获取锁失败,则升级为轻量级锁通过CAS方式来获取锁,成功表示获取锁,失败会进行CAS自旋方式来获取锁,如果CAS释放锁失败,则表示存在线程竞争,则升级为重量级锁。
7、String为什么是不可变的
在Java中String不可变的原因主要是基于设计、效率及安全性三大方面考虑的。
String类是由final修饰的,避免了被继承后破坏,而且String类的所有属性都是由private final修饰的,并且没有提供修改方法。
intern()方法
intern用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。否则,在常量池中加入该对象,然后返回引用。
String被设计为不可变主要有以下几个原因:
字符串常量池的需要,提高效率和减少内存分配
出于安全性考虑,防止被意外修改(例如HashSet存储的值如果是可变的String,则破坏了唯一性;不可被写所以线程安全)
作为散列型数据结构key的必要,因为JVM底层很容易在缓存String对象的时候缓存其hashcode,这样在执行效率上会大大提升。
8、servlet的生命周期
servlet生命周期包括:加载、创建、初始化、处理客户端请求及销毁
加载:
容器通过类加载器使用servlet对应的文件来加载servlet
创建:
容器启动后,通过调用servlet构造方法来创建servlet实例
初始化:
通过调用init方法来完成初始化工作
处理客户端请求:
servlet一旦创建后,就可以为客户端提供服务了,每当有新的请求到来,容器都会创建一个线程来处理当前请求,接着会调用servlet的service方法来完成客户端请求,当然service方法会根据请求参数的不同来决定调用doPost方法还是doGet方法
销毁:
容器在卸载servlet之前会调用destroy方法,让其自己释放其占用的系统资源
9、什么是Java序列化,如何实现Java序列化
Java对象序列化
就是将对象转换为字节流的过程,可以将其保存在磁盘空间或者通过网络发送给其他程序。
反序列化
就是将字节流转换为对象的过程,通过实现java.io.Serializable接口实现序列化
10、static关键字的作用
static关键字可以修饰变量、方法、代码块、内部类
静态变量
static修饰的变量为静态变量,静态变量与非静态的变量的区别就是,静态变量被所有对象所共享,在内存中只有一个副本,只有在类首次加载的时候才初始化;而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响
静态方法
static修饰的方法是静态方法,静态方法可以不需要依赖任何对象就可以访问,但是在静态方法中不能访问非静态变量或非静态方法
静态代码块
static修饰的代码块是静态代码块,静态代码块里的代码只会被执行一次,并且只在初始化类的时候执行,在编译阶段虚拟机会自动将类中所有类变量的赋值和静态代码块合并收集到()方法中,在主动触发了类的初始化方法之后就会被虚拟机调用执行这个方法
静态内部类
static一般是不可以修饰类的,如果有static修饰的一个类,这个类一定是静态内部类
11、transient关键字的作用
被transient关键字修饰的变量,可以不会被序列化,换句话说这个字段的生命周期仅存于调用者的内存中,而不会被持久化到磁盘中
12、java -jar如何找到主类
在jar包中的META-INFO目录下有一个MENIFEST.MF文件,这个文件包含了Main-Class这个主类信息
13、什么是泛型,泛型的好处是什么
在JDK1.5之前,我们知道,在集合中存储元素并在使用前进行类型转换是多么的不方便,泛型就防止了这种情况的发生。它提供了编译期的类型安全,确保你只能把正确类型的对象放到集合中,避免了在运行时出现ClassCastException异常。
泛型是如何工作的 ,什么是类型擦出
泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型的相关信息,所以在运行时不存在任何类型相关的信息。
泛型中的限定通配符和非限定通配符
限定通配符: extends T>和 super T>
非限定通配符:>
14、重载和重写的区别
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 子类重新定义了父类非私有的方法,子类的覆盖方法与父类被覆盖的方法有相同的方法名,返回值和参数列表,访问修饰符范围大于等于父类
15、什么是自动装箱和自动拆箱
自动装箱就是Java编译器在基本数据类型和对应的封装类型之间的转换,比如int转Integer,double转Double,反之则是自动拆箱。
16、cookie和session区别
session主要用于服务器,cookie主要用于客户端浏览器
session的运行依赖session_id,并且session_id一般是存放在cookie中的,如果客户端浏览器禁用cookie,那么session也就会失效
cookie不是很安全,别人可以分析本地cookie进行cookie欺骗,因此考虑到安全使用session
session会在一定时间内保存在服务器上。当访问量增多时,会比较占用服务器性能。因此考虑性能要使用cookie。
单个cookie保存的数据不超过4k,很多浏览器都限制一个站点最多保存20个cookie。
17、Error和Exception区别
Error表示恢复不是不可能,但很困难的一种情况,一般是指虚拟机层面的错误,不可能指望程序来处理这样的错误。
Exception表示一种设计或实现问题,可以通过Java异常处理机制来处理。
Exception又分为CheckedException(受检异常)和UncheckedException(不受检异常)
受检异常,发生在编译阶段,必须用try...catch进行捕获,否则编译不通过
不受检异常,发生在运行期,具有不确定性,即运行时异常。 throw和throws有什么区别
throw用来在程序中明确抛出异常
throws表示方法不能处理异常