基础
1, static 关键字 表明在没有所属类的实例变量的情况下被访问。
static方法就是没有this的方法。在static方法内部不能调用非静态方法。
静态变量被所有的对象所共享,在内存中只有一个副本,它只在类初次加载时会被初始
不能被覆盖。
2, 覆盖方法是基于运行时动态绑定的,static 是编译时静态绑定的。
3, java 运行时环境(jre),包括java虚拟机,java核心类库和支持文件
4, java 开发工具(jdk) , 完整的java软件包, 包含jre, 编译器, 其他工具javaDoc, 调试器等
序列化
序列化就是把对象转化为0和1二进制编码,有两个作用1.用于网络传输。2.可以存储到硬盘中,用来保存。
使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;
所有需要保存到磁盘的java对象都必须是可序列化的。
对象相等
equals
Object类中的equals方法和“==”是一样的,没有区别,即俩个对象的比较是比较他们的栈内存中存储的内存地址。
当需要判断对象是否相等时(如对象作map的key,唯一),需重写equals
如果不重写equals()方法,相同的内容不同引用的对象会被当做不同的对象被使用
重写equals方法的要求:
1、自反性:对于任何非空引用x,x.equals(x)应该返回true。
2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
5、非空性:对于任意非空引用x,x.equals(null)应该返回false。
注意:1、重写equals必须重写hashCode方法 因为是先比较两个对象的hash值是否相等在判断值
2、equals() 和 hashCode() 的定义必须兼容 如果 x.equals(y) 则x , y 的hashCode必须相等,
3、x , y 的 hashCode相等,x , y 不一定相等
hashCode
什么是哈希码?就是一套算法算出来的一个值,且这个值对于这个对象相对唯一。在Java应用程序执行期间,在对同一对象(未修改)多次调用 hashCode 方法时,必须一致地返回相同的整数。
1如果散列表中存在和散列原始输入K相等的记录,那么K必定在f(K)的存储位置上
2不同关键字经过散列算法变换后可能得到同一个散列地址,这种现象称为碰撞
3如果两个Hash值不同(前提是同一Hash算法),那么这两个Hash值对应的原始输入必定不同
可以理解为K多对一 Hash,因为f(K)不会有俩个计算结果hash, 而有可能f(K1)=f(K2)=Hash
hashCode的作用,用来查找 对象在内存中的位置。 如 把K的hashCode % 9,算出的结果则为内存的结果,有数据了则取决于算法去加1或者链表。
查找的时候,对比对象是否相同时候,则先对比hashCode,如果不同则不同,相同则在对比equals。
String就是一个对象,本质是个char[] ,自己重写了equals和hashCode, 遍历char数组中的每个字符来实现equals和hashCode。
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
使用String的 char 数组的数字每次乘以 31 再叠加最后返回,因此,每个不同的字符串,返回的 hashCode 肯定不一样。
在名著《Effective Java》第 42 页就有对 hashCode 为什么采用 31 做了说明:
之所以使用31, 是因为他是一个奇素数。如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算(低位补0)。使用素数的好处并不很明显,但是习惯上使用素数来计算散列结果。 31 有个很好的性能,即用移位和减法来代替乘法,可以得到更好的性能: 31 * i == (i << 5) - i, 现代的 VM 可以自动完成这种优化。这个公式可以很简单的推导出来。
集合
Collection
├List (有序集合,允许相同元素和null)
│├LinkedList (非同步,允许相同元素和null,遍历效率低插入和删除效率高)
│├ArrayList (非同步,允许相同元素和null,实现了动态大小的数组,遍历效率高,用的多)
│└Vector(同步,允许相同元素和null,效率低)
│ └Stack(继承自Vector,实现一个后进先出的堆栈)
└Set (无序集合,不允许相同元素,最多有一个null元素)
|-HashSet(无序集合,不允许相同元素,最多有一个null元素)
Map (没有实现collection接口,key不能重复,value可以重复,一个key映射一个value)
├Hashtable (实现Map接口,同步,不允许null作为key和value,用自定义的类当作key的话要复写hashCode和eques方法,)
├HashMap (实现Map接口,非同步,允许null作为key和value,用的多)
└WeakHashMap(实现Map接口)
泛型的定义:在程序中我们将一个对象放入集合中,但是集合不会记住对象的类型,当我们在次使用对象的时候,对象变为Object类型,而程序中还是原来的类型,我们必须要自己转换其类型,为了解决这个问题,则提出泛型。
Java中数组是对象,父类是Object,每个数组都实现了接口Cloneable and java.io.Serializable
有自己的类名,如int[]的类名是 [I
Arrays
Arrays类位于 java.util 包中,主要包含了操纵数组的各种方法, 有搜索,排序,填充,复制等。
Arrays.asList(T… data)
注意:该方法返回的是Arrays内部静态类ArrayList,而不是我们平常使用的ArrayList,,该静态类ArrayList没有覆盖父类的add, remove等方法,如果直接调用,会报异常。
hashMap
Key常用String ,string已经重写了hashCode
HashMap中定位到桶的位置 是根据Key的hash值与数组的长度取模来计算的。getNode() 方法中
p = tab[i = (n - 1) & hash]
可以理解为,将hash的 bit 位截取到 (n - 1) 的 bit 位长度。并找到该字节对映的 node 数组坐标中的值。所以数组的长度都要为2^n。
hash方法:return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
可以看成是hashCode高位 和 地位 的异或计算得到的hash值。
可以真正的动一位则动全身。不论高位还是低位,只要有一位不同,计算存储位置相同的概率就会大幅度降低(但是还是有的)。