HashTable和HashMap的区别面向对象==和equalsfinalString、StringBuffer、StringBuilder重载和重写接口和抽象类List和Sethashcode和equalsArrayList和linkedList字节码Java中的异常体系GC如何判断对象可以被回收线程的生命周期及状态sleep和waityield和join守护线程并发和并行
HashTable和HashMap的区别- 线程安全方面:HashTable是线程安全的,HashMap线程不安全,因为在HashTable中的函数大部分都是以synchronized关键字修饰的,不过也因此HashTable的效率要低于HashMap.(所以要兼顾线程安全和效率的话可以选择ConturrentHashMap.继承的父类不同:HashTable继承的是Dictionary类;HashMap继承的是AbstractMap类初始容量、初始化数组时机、一次性扩容量不同:HashTable的初始容量为11,在构造函数的时候就初始化数组了,一次扩容为原来的2倍+1(因为源码中是左移1位+1);HashMap的初始容量为16,初始化是在第一次put值的时候而不是构造函数时候,一次扩容为原来的2倍(源码中是左移1位),且在HashMap中取下标index的方式是hash值和length(数组长度)-1做与运算,所以要保证length-1总是1111…这种形式出现,就必须保证数组长度为2的次幂,所以无论初始化传的值为什么值,HashMap中有个函数会将其转为最近的2的次幂的值作为数组长度,可能这也是为什么扩容要扩容2倍的原因吧。允不允许key,value为nullHashTable不允许key,value为null,原因如下图,value为null会报空指针异常,而key为null的时候如果调用hashcode函数也会报空指针异常。
HashMap允许key,value为null,原因如下图,首先value可以为null,其次在计算key的hash时候,如果key为null,则它的hash值就为0,否则按后面的计算来。
面向对象三大特征是封装、继承、多态
- 封装:封装就是将具有相同属性、行为的物体抽象成一个类 ,或者就是将具有相同功能的代码封装成一个函数继承:继承就是在父类的基础上,可以重写父类的函数,拓展属于子类的属性或方法,也算是对父类相同属性、方法的复用(Java是单继承)多态:我理解的多态可能就是函数的重载
如果比较的是基本数据类型,比较的是值如果是引用数据类型,比较的是引用对象的地址
为什么String类型的equals是比较值呢,因为其equals函数重写了,重写之前内核也是使用==来比较
final
final修饰的类不能被继承final修饰的函数不能被重写final修饰的变量一旦赋值就不可以修改
1.成员变量:如果final修饰的是static成员变量,则需要在静态代码块或者在生命变量时就给其赋值;如果final修饰的是非static成员变量,则就在非静态代码块、声明时或者构造函数中赋值即可。
2.局部变量:局部变量需要自己进行初始化操作,可以定义时赋值或者后面再赋值,但无论什么时候赋值,只能赋值一次。
3.引用类型:final修饰基本数据类型之后其值不可改变,但是如果修饰的是应用类型数据,其地址是不可改变,但其地址对应的值是可以改变的。局部内部类、匿名内部类只能够访问final类型的变量,因为这两种类在类内部,编译时会生成2个.class文件,外面类在使用结束之后则会被回收掉,而内部类使用其变量的方法就是复制一份到自己类中,而如果这个变量不是final类型的话,如果值发生改变,则就会产生不一样的结果,所以要保证值不变,就只能使用final修饰的变量
String、StringBuffer、StringBuilder
String底层实现的char数组是final修饰的,不可变,每次操作之后会产生一个新的String对象,如果声明的字符串不经常改变的话可以是用StringStringBuffer是在原对象上进行操作,是线程安全的,方法都是加synchronized修饰的StringBuilder是线程不安全的
性能方面StringBuilder>StringBuffer>String
重载和重写重载:重载是在同一个类中,方法名需要相同、返回值相不相同都可以、参数列表需要不相同(如参数类型、参数个数等)重写:重写是指父类子类间的,子类继承父类之后,对其中的函数进行重写,方法名、参数列表必须相同 接口和抽象类
抽象类中可以有实现的函数,而接口中全部为抽象方法抽象类更像是is something,即是某种类型的东西,偏向于功能复用,因为可以把已知可以公用的函数在抽象类中实现,剩余未实现的抽象函数让子类去根据自我需求实现;而接口更偏向于has a function,即具有某种功能,这也更能体现出Java中只能够单继承而可以多实现(即某一个类只能is something,而可以has many functions,物种是唯一的,具有的能力是多种多样的)抽象类只能继承一个,接口可以实现多个抽象类中的成员变量可以为各种类型,而接口中的成员变量必须为public static final 类型的 List和Set
List:有序、可以重复、允许多个null对象,可以使用iterator迭代器去遍历取值也可以使用get(index)取值。Set:无序、不可以重复、只允许一个null对象,只能用iterator迭代器取值。 hashcode和equals
hashcode相同,equals不一定为trueequals为true,hashcode一定相同重写equals函数后,一定要重写hashcode,因为hashSet在存值时,会以其hashcode值来判断对象加入的位置,看该位置是否有值,如果没值,则会假设没有重复元素,将其放入这里,有值则会再去看equals是否为true,如果为true则不会让其加入,不为true则会散列到其他位置,而如果重写了equals让其比较的是对象值是否相同,这时候hashcode不同,而equals为true,导致hashSet存了相同的值,就会出现错误。 ArrayList和linkedList
ArrayList是以动态数组实现,linkedList是以链表实现的ArrayList在进行查询时优于linkedList,但是在进行插入、删除操作时要劣于linkedListArrayList的扩容机制,因为是数组,长度固定,扩容是新建一个数组,将老数组数据拷贝到新数组,然后用新数组替换老数组。ArrayList默认初始容量为0,不给定其数组容量大小的话,首次存入时扩容至10,如果给定该参数,则扩容至该参数大小,后面扩容时是每次扩容1.5倍(源码中是newCapacity=oldCapacity+(oldCapacity>>1),右移一位表示除以2,所以为1.5倍) 字节码
Java相关字节码就是Java代码被编译器编译成的字节码,字节码可以被JVM识别,不受限于操作系统,因此Java语言具有跨平台的特性,可以一处编译处处运行。
Java中的异常体系Java中所有的异常都来自于顶级父类Throwable,它有两个子类,一个是Error一个是Exception,Error是程序无法处理的错误,会直接终止程序,而Exception则是异常不会终止程序,Exception又有RuntimeException和CheckedException,一个是运行时错误,一个是编译时检查错误。
GC如何判断对象可以被回收引用计数法:每个对象有个引用计数器,新增一个引用+1,释放一个引用-1,为0时判断为不可用,会被回收(Java 不用该方法)可达性分析:从GC ROOTS向下找,探索过的路程为引用链,如果一个对象不在引用链上,则说明其不可用,会被回收
GC ROOTS有如下
- 虚拟机栈中引用的对象方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中引用的对象
当对象第一次可达性分析不可用之后,并不会立即被回收,而是还有一次机会,首先会判断该对象有没有重写finalize函数,如果没有重写该函数,则会立即被回收;如果重写了,则会判断其是否已经执行过该重写后的函数,如果未执行则会执行,执行完成后再次执行可达性分析,如果还不可达则回收,如果可达则复活。
finalize函数一个对象只能执行一次,而且消耗很大,不建议使用。
线程是程序运行的最小单元,一个进程可以拥有多个线程(最少有一个).
Java默认有两个线程,一个是main线程,一个是GC垃圾回收线程
线程的状态:
NEW,新创建的线程还未变成可以被执行状态RUNNABLE,可以被执行状态BLOCKED,阻塞状态WAITING,等待(一直等)TIMED_WAITING,超时等待(到指定时间就不等待了)TERMINATED,终止状态
Java创建线程:Thread、Runnable、Callable
Java无法开启线程,线程开启是由本地方法开启的(c++)
sleep和waitwait是Object类的方法,sleep是Thread类的方法wait能够释放锁,而sleep无法释放锁(可以想象为抱着锁睡着了)wait只能在同步代码块使用,sleep则没有限制 yield和join
yield是礼让的意思,线程调用该函数时,该线程会进入就绪状态,即它和别的就绪线程一样也可能被CPU调度从而继续执行。join是加入的意思,在主线程中如果有子线程调用join函数,则主线程进入阻塞队列,需要等待子线程中断或者结束,主线程才能够继续执行。 守护线程
守护线程在其他线程没有要执行的之后就会自动结束,常见的守护线程有GC线程
并发和并行并发:多个线程操作统一资源,并行:多个线程同时执行并发编程的意义:充分地利用CPU资源



