Java面试前知识点总复习
方法的重载与覆盖
重载:
一个类中可以定义多个方法名相同,但参数不同的方法。调用时,会根据不同的参数自动匹配对应的方法。
重载的方法,实际是完全不同的方法,只是名称相同而已
方法重载条件:形参的类型,形参的参数,形参的顺序不同。
覆盖(重写):
子类通过重写父类的方法,可以用自身的行为替换父类的行为。
方法的重写是实现多态的重要条件。
方法重载条件:
- 方法名,形参列表相同
- 返回值类型和声明异常类型,子类小于父类
- 访问权限,子类小于父类
toString()方法
Object类中定义有 public String toString() 方法,源码如下:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
默认会返回 类名 + @ + hashCode。
在打印对象对象时,会自动调用该对象的toString()方法。
==、equals()方法、hashCode()方法
==
== 代表比较双方是否相同。如果是基本类型则比较值是否相等。如果是引用类型则比较地址是否相等,即是否是同一个对象。
equals()方法
equals()方法在Object类中的定义如下:
public boolean equals(Object obj) {
return (this == obj);
}
很明显是对两个对象的地址进行比较。
而String,Integer,Double这些封装类在使用equals()方法时,已经覆盖了Object类的equals()方法,进行内容的比较。
当equals()方法被覆盖时,hashCode()也要被覆盖。
hashCode()方法
- 在一个Java应用执行期间,如果一个对象提供给equals()方法做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个hashcode值。
- 如果两个对象根据equals()方法是相等的,那么调用两个对象各自的hashCode()方法必须产生同一个hashcode值。
- 不要求根据equals()方法不相等的两个对象,调用各自的hashCode()方法一定产生不同的hashcode值。
hashcode作用
想要明白hashcode的作用,必须先知道Java中的集合。Java中的集合有两类,一类是List,一类是Set。前者集合内是有序的,元素可以重复;后者元素无序,但元素不可以重复。
判断元素是否重复需要用equals()方法,但是元素过多时,需要多次调用equals()方法。会降低效率。
此时先计算hashcode定位一个位置,如果这个位置没有元素,它就可以直接储存在这个位置,不用再进行比较;如果有元素,就调用它的equals()方法与新元素比较,相同就不存了。这样实际调用equals()方法的次数就大大降低了。
简而言之:在集合查找时,hashcode能大大降低对象比较次数,提高查找效率。
equlas()方法结果为true的对象必须有相同的hashcode
如果两个对象A和B的equals()为true,但结果不同,则A和B存入HashMap时计算的HashMap内部数组的索引位置可能不能。那么A和B可能同时存入HashMap,而HashMap中不允许存放重复元素。
String、常量池、StringBuffer、StringBuilder
String
String类又称不可变字符序列
- 为了节省内存,JVM专门用一片特殊的区域存储String,如果存在的话直接引用,避免浪费内存,因此必须保证这个具体的常量不能变。
- String类里边是一个 private final char value[].
String对象的两种创建方式
String str1 = "abcd"; String str2 = new String("abcd"); System.out.println(str1==str2);//false
- 第一种方式是在常量池中拿对象
- 第二种方式是直接在堆内存空间中创建一个新对象
String常量池
- 直接用双引号声明的String对象会直接存储在常量池中
如果不是双引号声明的对象,可以调用该对象的String.intern()方法。
- 如果常量池中已经包含一个等于此String对象内容的字符串,则返回该常量池引用
- 如果常量池中没有,则在常量池中新创建,并返回新创建的引用
- String s = new String("abc");创建了两个对象,一个在常量池,一个在堆内存。
StringBuffer和StringBuilder
- 都是可变字符序列
- StringBuffer:线程安全,执行速度慢;多线程
- StringBuilder:线程不安全,执行速度快;单线程
通用的分代垃圾回收机制
不同的对象的生命周期是不一样的,所以不同的对象可以采取不同的回收算法,以便提高效率。对象分为年轻代、年老代、持久代。JVM将堆内存划分为Eden,Survivor和Tenured空间。
- Minor GC:用于清理年轻代区域。Eden区满了会触发一次Minor GC,清理无用对象,将有用对象复制到Survivor1,Survivor2区中(这两个区大小空间相同,同一时刻只有一个再用,另一个为空)
- Major GC:用于清理年老代区域
- Full GC:用于清理年轻代,年老代区域。成本较高会对系统性能产生影响。
垃圾回收过程
- 新创建的对象,绝大多数都会存储在Eden中
- 当Eden满了不能创建对象后,会触发垃圾回收Minor GC,将无用对象清理掉,然后将剩余对象复制到某个Survivor1中,同时清空Eden区
- 当Eden区再次满了,会将Survivor1中不能清理的对象复制到Survivor2中,同时将Eden中不能清空的对象也复制到Survivor2中,保证Eden和Survivor1都被清空
- 重复15次后,Survivor中还没有被清理的对象,则会被复制到年老代Tenured区中
- 当Tenured区满了,会触发一次完整的垃圾回收Full GC
包装类的缓存问题
整形、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,目的是提高效率。
缓存原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱发生时(或者调用valueOf方法时),就会先判断数据是否在该区间,如果在直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
Integer类相关源码如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
1、IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用
2、一般情况下 IntegerCache.low 为-128, IntegerCache.high 为127, IntegerCache.cache 为内部类的一个静态属性,代码如下
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
由上面的源码可以看到,静态代码块的目的就是初始化cache数组的,这个过程会在类加载时完成。
HashMap和HashTable
- HashMap采用哈希算法实现,是Map接口最常用的实现类。要求键不能重复,如果发生重复,新的键值会替换旧的键值。
- HashTable和HashMap用法几乎一样,底层实现几乎一样。只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率低。
区别
- HashMap:线程不安全,效率高,允许Key或Value为null
- HashTable:线程安全,效率低,不允许Key或Value为null
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。