面向对象的三个特性及五大原则:
三大特性:封装,继承,多态
封装:把一个类中不需要让别的类知道得到属性或者方法封闭,仅留有接口供外部调用。
继承:子类从父类中得到父类允许被子类得到的方法或者属性。
多态:一个方法有不同的实现逻辑或者不同的输入参数。
五大原则:单一职责原则,开放封闭原则,里氏替换原则,依赖倒置原则,接口隔离原则
单一职责原则:一个类尽量只做一种事情。
开发封闭原则:对类中数据修改封闭,对类的扩展开发。
里氏替换原则:子类可以替换父类。
依赖倒置原则:具体依赖抽象,而不能抽象依赖具体。
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,类不应该依赖那些它不需要的接口。
八大基础类型及其封装类:
八大基础类型:byte,short,int,long,char,float,Boolean,double.
八大封装类:除了int变为Integer,char变为Character,其余首字母大写。
基础类型可以自动装箱成封装类,封装类可以自动拆箱成基础类型。
装箱是调用包装器类的Valueof,拆箱是调用包装器类的xxxValue()。
例如:int通过valueOf()装箱成Integer,Integer通过intValue()方法拆箱成int
String有那些方法:
equals():判断两个字符串是否相等。
length():字符串的长度。
charAt():获取下标对应的字符。
indexOf():获取字符对应的下标。
trim():忽略前后端空白。
split():根据字符或者正则表达式的匹配拆分字符。
replace():替换字符(仅替换一个)。
replaceAll():替换所有匹配的字符。
toCharArray():将字符串转换成一个新的字符组。
String,Stringbuffer,Stringbuilder区别:
String:不可改变对象的值,每次重新赋值实际上都是新建了一个对象,把引用指向新对象。
Stringbuffer:可变对象,线程安全,方法由synchronized修饰,均公开。
StringBuilder:可变对象,线程不安全,适合单线程。
==和equals的区别:
:作用于对象比较的是地址,作用于基本类型比较的值
equals:如果没有重写object类中的equals方法那么其底层就是==,如果重写了例如String,Date那么可以比较地址中的值。
常用的集合有那些:
List,set,map
ArrayList,LinkedList,vector(线程安全)
HashSet,TreeSet
HashMap,HashTable
ArrayList,LinkedList区别
一个是数组,一个是链表
ArrayList查找和遍历比LinkedList快
一般认为删除和添加操作LinkedList比较快(也不一定,要是在最后删除增加,可能Arraylist比较快)
HashMap和HashTable的区别
HashMap线程不安全,HashTable线程安全。
HashMap允许键值为空,HashTable不允许。
扩容方式不同:HashMap每次扩容2倍,HashTable每次扩容2倍+1。
HashMap数据结构是啥:
JDK1.7是数组+链表 头插法
JDK1.8是数组+链表+红黑树 尾插法
HashMap初始大小为16,在链表元素(链表深度)大于8(数组长度大于64)时变成红黑树,在红黑树节点小于6时变成链表
HashMap线程安全吗,为啥:
Hashmap线程不安全,主要发生在扩容期间(put期间也有),两个线程同时对其扩容会导致死循环。
可以使用hashtable或ConcurrentHashMap。
ConcurrentHashMap为啥是线程安全的,原理是啥:
1.7是Segment分段锁
1.8是CAS (自旋锁)+ synchronized
创建线程的四种方式:
继承thread类,重现run方法;实现runnable接口;实现callable接口;线程池创建。
线程的run()和start()方法
run()方法是Runnable接口定义的,start方法是Thread类定义的。
真正启动线程的是start(),run()只是由main的主线程区调用run()方法。
单独调用run()方法,是同步执行;通过start()调用run()是异步执行。
创建线程池的四种方式:
定长线程池,可缓存线程池,单例线程池,定长延时线程池。
创建线程池的七个参数:
核心线程的大小,最大线程数量,线程工厂,空闲线程存活时间,空闲线程存活时间单位,工作队列和拒绝策略。
线程池的状态:
Running,ShutDown,Stop,Tidying,Terminated
如何保证多线程的运行安全:
线程安全在三个方面体现:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作。(atomic,synchronized)
可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile)
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序。
多线程锁的升级原理是什么?
在Java中,锁共有四种状态,级别从低到高依次为:无状态锁,偏向锁,轻量级锁,重量级锁状态。
死锁的定义及四个必要条件
死锁是指两个或者两个以上的进程在执行过程中,由于资源不足,导致的相互循环等待对方资源。
四个必要条件:
互斥条件
请求和保持条件
环路等待条件
不可剥夺条件
synchronized的底层实现原理
synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入临界区,同时它还可以保证共享变量的内存可见性。
普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步代码块,锁是括号里面的对象
synchronized和volatile的区别是什么?
volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取;
Synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞。
volatile仅能使用在变量级别;synchronized则可以使用在变量,方法,和类级别的。
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
synchronized和Lock有什么区别?
synchronized是Java内置关键字,在jvm层面,Lock是个Java类;
synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
synchronized会自动释放锁,Lock需在finally中释放锁,否则容易造成死锁;
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
synchronized和ReentrantLock区别是什么?
Synchronized是和if,else,for,while一样的关键字,ReentrantLock是类,这是两者的本质区别。两者的锁机制不同,ReentrantLock底层调用的是Unsafe的park方法的加锁,synchronized操作的应该是对象头中mark word.
反射
在运行状态中,对于任意一个类,都能知道这个类所有的属性及方法,对于任意一个对象都能调用它任意一个方法和属性。
序列化
Java提供的一种保存在内存中的各种对象的状态(实例变量,不是方法),并且可以把保存的对象再读出来的机制。
动态代理是什么?有哪些应用?
动态代理:给实现了某个接口的类中的方法,加一些额外的处理,比如说加日志,加事务等。可以给这个类创建一个代理,就是创建一个新的类,这个类不仅包括原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动态代理的应用:
Spring的AOP
加事务
加权限
加日志