-
可以声明成员变量、方法、类以及本地变量
-
final 成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误
-
final 变量是只读的
-
final 申明的方法不可以被子类的方法重写
-
final 类通常功能是完整的,不能被继承
-
final 变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销
-
final 关键字提高了性能,JVM 和 Java 应用都会缓存 final 变量,会对方法、变量及类进行优化
-
方法的内部类访问方法中的局部变量,但必须用 final 修饰才能访问
String、StringBuffer、StringBuilder
=================================
-
String 是 final 类,不能被继承。对于已经存在的 Stirng 对象,修改它的值,就是重新创建一个对象
-
StringBuffer 是一个类似于 String 的字符串缓冲区,使用 append() 方法修改 Stringbuffer 的值,使用 toString() 方法转换为字符串,是线程安全的
-
StringBuilder 用来替代于 StringBuffer,StringBuilder 是非线程安全的,速度更快
异常处理
====
-
Exception、Error 是 Throwable 类的子类
-
Error 类对象由 Java 虚拟机生成并抛出,不可捕捉
-
不管有没有异常,finally 中的代码都会执行
-
当 try、catch 中有 return 时,finally 中的代码依然会继续执行
| 常见的Error | | |
| — | — | — |
| OutOfMemoryError | StackOverflowError | NoClassDeffoundError |
| 常见的Exception | | |
| — | — | — |
| 常见的非检查性异常 | | |
| ArithmeticException | ArrayIndexOutOfBoundsException | ClassCastException |
| IllegalArgumentException | IndexOutOfBoundsException | NullPointerException |
| NumberFormatException | SecurityException | UnsupportedOperationException |
| 常见的检查性异常 | | |
| IOException | CloneNotSupportedException | IllegalAccessException |
| NoSuchFieldException | NoSuchMethodException | FileNotFoundException |
内部类
===
-
非静态内部类没法在外部类的静态方法中实例化。
-
非静态内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
-
在静态内部类中调用外部类成员,成员也要求用 static 修饰。
-
创建静态内部类的对象可以直接通过外部类调用静态内部类的构造器;创建非静态的内部类的对象必须先创建外部类的对象,通过外部类的对象调用内部类的构造器。
匿名内部类
-
匿名内部类不能定义任何静态成员、方法
-
匿名内部类中的方法不能是抽象的
-
匿名内部类必须实现接口或抽象父类的所有抽象方法
-
匿名内部类不能定义构造器
-
匿名内部类访问的外部类成员变量或成员方法必须用 final 修饰
多态
==
-
父类的引用可以指向子类的对象
-
创建子类对象时,调用的方法为子类重写的方法或者继承的方法
-
如果我们在子类中编写一个独有的方法,此时就不能通过父类的引用创建的子类对象来调用该方法
抽象和接口
=====
-
抽象类不能有对象(不能用 new 关键字来创建抽象类的对象)
-
抽象类中的抽象方法必须在子类中被重写
-
接口中的所有属性默认为:public static final;
-
接口中的所有方法默认为:public abstract;
集合框架
====
- List接口存储一组不唯一,有序(插入顺序)的对象, Set接口存储一组唯一,无序的对象。
HashMap
结构图
- JDK 1.7 HashMap 结构图
- JDK 1.8 HashMap 结构图
HashMap 的工作原理
HashMap 基于 hashing 原理,我们通过 put() 和 get() 方法储存和获取对象。当我们将键值对传递给 put() 方法时,它调用键对象的 hashCode() 方法来计算 hashcode,让后找到 bucket 位置来储存 Entry 对象。当两个对象的 hashcode 相同时,它们的 bucket 位置相同,‘碰撞’会发生。因为 HashMap 使用链表存储对象,这个 Entry 会存储在链表中,当获取对象时,通过键对象的 equals() 方法找到正确的键值对,然后返回值对象。
如果 HashMap 的大小超过了负载因子(load factor)定义的容量,怎么办?
默认的负载因子大小为 0.75,也就是说,当一个 map 填满了 75% 的 bucket 时候,和其它集合类(如 ArrayList 等)一样,将会创建原来 HashMap 大小的两倍的 bucket 数组,来重新调整 map 的大小,并将原来的对象放入新的 bucket 数组中。这个过程叫作 rehashing,因为它调用 hash 方法找到新的 bucket 位置。
为什么 String, Interger 这样的 wrapper 类适合作为键?
因为 String 是不可变的,也是 final 的,而且已经重写了 equals() 和 hashCode() 方法了。其他的 wrapper 类也有这个特点。不可变性是必要的,因为为了要计算 hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的 hashcode 的话,那么就不能从 HashMap 中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个 field 声明成 final 就能保证 hashCode 是不变的,那么请这么做吧。因为获取对象的时候要用到 equals() 和 hashCode() 方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的 hashcode 的话,那么碰撞的几率就会小些,这样就能提高 HashMap 的性能。
HashMap 与 HashTable 对比
HashMap 是非 synchronized 的,性能更好,HashMap 可以接受为 null 的 key-value,而 Hashtable 是线程安全的,比 HashMap 要慢,不接受 null 的 key-value。
HashMap.java
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
···</