Java面试前知识点总复习

方法的重载与覆盖

重载:

一个类中可以定义多个方法名相同,但参数不同的方法。调用时,会根据不同的参数自动匹配对应的方法。

重载的方法,实际是完全不同的方法,只是名称相同而已

方法重载条件:形参的类型,形参的参数,形参的顺序不同。

覆盖(重写):

子类通过重写父类的方法,可以用自身的行为替换父类的行为。

方法的重写是实现多态的重要条件。

方法重载条件:

  1. 方法名,形参列表相同
  2. 返回值类型和声明异常类型,子类小于父类
  3. 访问权限,子类小于父类

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空间。
image.png

  • Minor GC:用于清理年轻代区域。Eden区满了会触发一次Minor GC,清理无用对象,将有用对象复制到Survivor1,Survivor2区中(这两个区大小空间相同,同一时刻只有一个再用,另一个为空)
  • Major GC:用于清理年老代区域
  • Full GC:用于清理年轻代,年老代区域。成本较高会对系统性能产生影响。

垃圾回收过程

  1. 新创建的对象,绝大多数都会存储在Eden中
  2. 当Eden满了不能创建对象后,会触发垃圾回收Minor GC,将无用对象清理掉,然后将剩余对象复制到某个Survivor1中,同时清空Eden区
  3. 当Eden区再次满了,会将Survivor1中不能清理的对象复制到Survivor2中,同时将Eden中不能清空的对象也复制到Survivor2中,保证Eden和Survivor1都被清空
  4. 重复15次后,Survivor中还没有被清理的对象,则会被复制到年老代Tenured区中
  5. 当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

韩二愣子
7 声望0 粉丝

天南越国镜州青牛镇五里沟人氏,小名二愣子,天南地域燕族人。