Javase基础小结

117 阅读9分钟

1. Object有哪些公用方法

clone 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

equals 在Object中与==是一样的,子类一般需要重写该方法。

hashCode 该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

getClass final方法,获得运行时类型

wait 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。 调用该方法后当前线程进入睡眠状态,直到以下事件发生

1、其他线程调用了该对象的notify方法。 2、其他线程调用了该对象的notifyAll方法。 3、其他线程调用了interrupt中断该线程。 4、时间间隔到了。 5、此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

notify 唤醒在该对象上等待的某个线程。

notifyAll 唤醒在该对象上等待的所有线程。

toString 转换成字符串,一般子类都有重写,否则打印句柄。

2.Java的四种引用,强弱软虚

1、强引用: 最普遍的一种引用方式,如String s = "abc",变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。

2、软引用(SoftReference): 用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。

3、弱引用(WeakReference): 弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

4、虚引用(PhantomReference): 就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。

3.为什么重载hashCode方法?

一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?

如果你重写了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。

这样,当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。

为什么equals()相等,hashCode就一定要相等,而hashCode相等,却不要求equals相等?

1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。 2、HashMap获取一个对象是比较key的hashCode相等和equal为true。

之所以hashCode相等,却可以equal不等,就比如ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。

为什么需要hashCode?

1、通过hashCode可以很快的查到小内存块。 2、通过hashCode比较比equal方法快,当get时先比较hashCode,如果hashCode不同,直接返回false。

4. ArrayList、LinkedList、Vector的区别

List的三个子类的特点

ArrayList:

  • 底层数据结构是数组,查询快,增删慢。

  • 线程不安全,效率高。 Vector:

  • 底层数据结构是数组,查询快,增删慢。

  • 线程安全,效率低。

  • Vector相对ArrayList查询慢(线程安全的)。

  • Vector相对LinkedList增删慢(数组结构)。

LinkedList

  • 底层数据结构是链表,查询慢,增删快。
  • 线程不安全,效率高。

5.String、StringBuffer与StringBuilder的区别

String:适用于少量的字符串操作的情况。 StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况。StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况。 StringBuilder:是线程不安全的,而StringBuffer是线程安全的。

这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

6.Map、Set、List、Queue、Stack的特点与用法

Map

  • Map是键值对,键Key是唯一不能重复的,一个键对应一个值,值可以重复。
  • TreeMap可以保证顺序
  • HashMap不保证顺序,即为无序的。
  • Map中可以将Key和Value单独抽取出来,其中KeySet()方法可以将所有的keys抽取成一个Set。而Values()方法可以将map中所有的values抽取成一个集合。

Set

  • 不包含重复元素的集合,set中最多包含一个null元素。
  • 只能用Lterator实现单项遍历,Set中没有同步方法。

List

  • 有序的可重复集合。
  • 可以在任意位置增加删除元素。
  • 用Iterator实现单向遍历,也可用ListIterator实现双向遍历。

Queue

  • Queue遵从先进先出原则。
  • 使用时尽量避免add()和remove()方法,而是使用offer()来添加元素,使用poll()来移除元素,它的优点是可以通过返回值来判断是否成功。
  • LinkedList实现了Queue接口。
  • Queue通常不允许插入null元素。

Stack

  • Stack遵从后进先出原则。
  • Stack继承自Vector。
  • 它通过五个操作对类Vector进行扩展,允许将向量视为堆栈,它提供了通常的push和pop操作,以及取堆栈顶点的peek()方法、测试堆栈是否为空的empty方法等。

用法

  • 如果涉及堆栈,队列等操作,建议使用List。
  • 对于快速插入和删除元素的,建议使用LinkedList。
  • 如果需要快速随机访问元素的,建议使用ArrayList。

String最慢的原因

String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

再来说线程安全

在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

7.JDK7与JDK8中HashMap的实现

JDK7中的HashMap

HashMap底层维护一个数组,数组中的每一项都是一个Entry。

transient Entry<K,V>[] table;

JDK8中的HashMap

JDK8中采用的是位桶+链表/红黑树(有关红黑树请查看红黑树)的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值的时候,这个链表就将转换成红黑树。

JDK8中,当同一个hash值的节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树(上图中null节点没画)。这就是JDK7与JDK8中HashMap实现的最大区别

8.为什么HashMap是线程不安全的

HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。

9.try?catch?finally,try里有return,finally还执行么

肯定会执行。finally{}块的代码。 只有在try{}块中包含遇到System.exit(0) 。 之类的导致Java虚拟机直接退出的语句才会不执行。

当程序执行try{}遇到return时,程序会先执行return语句,但并不会立即返回——也就是把return语句要做的一切事情都准备好,也就是在将要返回、但并未返回的时候,程序把执行流程转去执行finally块,当finally块执行完成后就直接返回刚才return语句已经准备好的结果。

10. Excption与Error包结构。OOM你遇到过哪些情况,SO F你遇到过哪些情况

堆内存溢出 OutOfMemoryError(OOM)

除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能。

Java Heap 溢出。 一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess。 java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。

运行时异常RuntimeException

定义 : RuntimeException及其子类都被称为运行时异常。 特点 : Java编译器不会检查它 也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。

例如,除数为零时产生的ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常,fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常。

堆栈溢出 StackOverflow (SOF)

StackOverflowError 的定义: 当应用程序递归太深而发生堆栈溢出时,抛出该错误。 因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。

栈溢出的原因:

递归调用。 大量循环或死循环。 全局变量是否过多。 数组、List、map数据过大。