- final关键字简记
(1)final修饰类,表示类不可变,不可继承
比如,String不可变性
(2)final修饰方法,表示该方法不可重写
(3)final修饰变量,这个变量就是常量
(4)注意:修饰的是基本数据类型,这个值本身不能修改
*修饰的是引用数据类型,引用的指向不能修改
*例子:final student student = new Student(1,"aa"); student.setName("bb");
这样是可以修改的,但不能对student重新赋值新的引用,因为它已经是最终的引用了。 - String、StringBuffer、StringBuilder区别
(1)String跟其它两个类的区别是:
String是final类型,每次声明都是不可变对象,所以每次操作都会产生新的String对象,然后将指针指向新的String对象。
(2)StringBuffer、StringBuilder都是在原有的对象上进行操作所以,如果需要经常改变字符串的内容,则应该使用StringBuffer和StringBulider比较好。
(3)StringBuffer 与 StringBulider的区别:
*前者是线程安全的,后者是线程不安全的。
*线程不安全性能更高,但安全性没有后者好。
*在高并发、多线程需要线程之间共享资源的时候考虑使用线程安全的StringBuffer,在单线程的时候优先考虑性能更高的StringBulider。 - 区分多继承、多重继承、多实现:
*多重继承:A->B->C(爷孙三代的关系)
*多实现: Person implements IRunable,IEatable (通过实现多个接口 进行多重实现 符合多项国际化标准)
*多继承: 接口可以多继承,类只支持单继承。 - 方法的重写和重载的区别:
*重载发生在一个类里面,方法名相同,参数列表不同(混淆点:跟返回类型没有关系)
* 例子:一些构不成重载public double add(int a,int b) public int add(int a,int b)
*重写:发生在子类里面,方法名相同,参数列表相同。 - ArrayList 和 LinkedList的区别
(1)底层数据结构的差异:
*ArrayList,数组,连续的一块内存空间
*LinkedList ,双向链表,不是连续的内存空间
(2)简单见解:
*ArrayList,查找速度快,因为是连续的空间,方便寻址,但是删除,插入慢,因为删除插入需要发生数据迁移。
*LinkedList,查找比较慢,因为需要通过指针一个个寻找,但是删除,插入比较快,因为只需改变前后节点的指针指向即可
(3)ArrayList细节分析:
*扩容:如果空间不够了,ArrayList会先创建一个新的数组,新的数组是原数组的1.5倍是通过位运算进行扩容的,然后再将原数组的数据迁移到新数组的数据中。 - HashSet存储原理
(1)HashSet最底层其实用了HashMap来实现存储,其值作为HashMap的key。
(2) - HashMap细节再说
(1)第一,为什么采用Hash算法?有什么优势?解决了什么问题?
*解决的问题是唯一性
*存储数据,底层采用的是数组
*如何判定数组是唯一?
解决方法:
1.采用遍历的方式,逐个比较,但是这种效率极低。
2.采用hash算法,通过计算存储对象的hashcode,然后再跟数组长度-1做位运算,得到我们要存储在数组的那个下标下,如果此时计算机的位置没有其他元素,直接存储,不用比较。此处,我们只会用到hashcode,随着元素不断添加,就可能出现“哈希冲突”,不同对象计算出来的hash值是相同的,这个时候,我们就需要比较,才需要用到equals方法,如果equals相同,则不插入,如果不相等,则形成链表。
*哈希表的本质就是一个数组,而数组的元素是链表。 - ArrayList 与 Vector 区别
(1)ArrayList线程不安全,效率高,常用
(2)Vector 线程安全,效率低 - Hashtable 、HashMap 、ConcurrentHashMap的区别
(1) HashTable:线程安全的对象,内部有上锁的控制synchronized,会阻塞,效率低。
(2) HashMap : 线程不安全对象,不会阻塞,效率高,如果有多个线程同时操作这个hashmap,可能出现线程不安全的情况,甚至会出现死锁。
(3)ConcurrentHashMap :分段锁,将锁粒度变小,兼顾两者,保证线程安全和性能。
(4) 三者在开发中一般优先选择hashmap,当然得在不是多个线程访问同一个资源的情况下,优先选择hashmap,局部变量,不是全局变量。多线程访问同一资源下,选择ConcurrentHashMap比较好一点,既保证了性能也保证了安全。。 - IO流的分类及选择
(1)分类:
*按方向分:输入流(以程序为主角 读取文件) 、输出流(程序写入文件)
*按读取单位分:字节流(任何文件,二进制文件)、字符流(文本文件)
*按处理的方式分:节点流、处理流
*IO流的4大基类:InputStream、OutputStream、Reader、writer - java异常
常见异常:算数异常、空指针、类型转化异常、数组越界、数字格式转化异常 - 创建线程的方式:
(1)继承Thread
(2)实现Runable接口
(3)实现Callable接口(可获取线程执行之后的返回值)
(4)Runnable与Callable的区别是,后者是有返回型的,而且是一个泛型
//如何正确开启线程
public class MyThread extends Thread {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// myThread.run();//调用方法,并非开启新线程
myThread.start();//这才是开启线程
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+": running....");
}
}
public class MyTask2 implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
return null;
}
}
//这个是可执行任务,需要其他开启
public class MyTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Runnable");
}
}
- 什么时候使用线程安全:
(1)多个线程访问同一资源的时候
(2)资源是有状态的时候需要线程安全 - 线程中Sleep和wait的区别
(1)所属类不同
*sleep方法是定义在Thread上
*wait方法是定义在object上
(2)对锁的资源处理方式不同
*sleep不会释放锁
*wait会释放锁
(3)使用范围
*sleep可以使用在任何的代码块
*wait必须在同步方法中或同步代码块中执行
(4)与wait配置使用方法
*void notify()
*void notifyAll()