java se基础(五)字符串数组,异常处理以及object

1. String、StringBuffer、StringBuilder以及对String不变性的理解

1.String、StringBuffer、StringBuilder

  • 都是 final 类, 都不允许被继承;
  • String 长度是不可变的, StringBuffer、StringBuilder 长度是可变的;
  • StringBuffer 是线程安全的, StringBuilder
    不是线程安全的,但它们两个中的所有方法都是相同的,StringBuffer在StringBuilder的方法之上添加了synchronized修饰,保证线程安全。
  • StringBuilder比StringBuffer拥有更好的性能。
  • 如果一个String类型的字符串,在编译时就可以确定是一个字符串常量,则编译完成之后,字符串会自动拼接成一个常量。此时String的速度比StringBuffer和StringBuilder的性能好的多。

2.String不变性的理解

  • String 类是被final进行修饰的,不能被继承。
  • 在用+号链接字符串的时候会创建新的字符串。
  • String s = new String(“Hello world”); 可能创建两个对象也可能创建一个对象。如果静态区中有“Hello
    world”字符串常量对象的话,则仅仅在堆中创建一个对象。如果静态区中没有“Hello world”对象,则堆上和静态区中都需要创建对象。
  • 在 java 中, 通过使用 “+” 符号来串联字符串的时候, 实际上底层会转成通过 StringBuilder 实例的 append()
    方法来实现。

2. String有重写Object的hashcode和toString吗?如果重写equals不重写hashcode会出现什么问题?

  • String有重写Object的hashcode和toString吗?
    String重写了Object类的hashcode和toString方法。
  • 当equals方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规协定,该协定声明相对等的两个对象必须有相同的hashCode

object1.euqal(object2)时为true, object1.hashCode() == object2.hashCode() 为true
object1.hashCode() == object2.hashCode() 为false时,object1.euqal(object2)必定为false
object1.hashCode() == object2.hashCode() 为true时,但object1.euqal(object2)不一定定为true

  • 重写equals不重写hashcode会出现什么问题

在存储散列集合时(如Set类),如果原对象.equals(新对象),但没有对hashCode重写,即两个对象拥有不同的hashCode,则在集合中将会存储两个值相同的对象,从而导致混淆。因此在重写equals方法时,必须重写hashCode方法。

3. 如果你定义一个类,包括学号,姓名,分数,如何把这个对象作为key?要重写equals和hashcode吗

需要重写equals方法和hashcode,必须保证对象的属性改变时,其hashcode不能改变.

4. 字面量

在编程语言中,字面量(literal)指的是在源代码中直接表示的一个固定的值。

八进制是用在整数字面量之前添加“0”来表示的。

十六进制用在整数字面量之前添加“0x”或者“0X”来表示的

Java 7中新增了二进制:用在整数字面量之前添加“0b”或者“0B”来表示的。

在数值字面量中使用下划线 在Java7中,数值字面量,不管是证书还是浮点数都允许在数字之间插入任意多个下划线。并且不会对数值产生影响,目的是方便阅读,规则只能在数字之间使用。

public class BinaryIntegralLiteral {
    public static void main(String[] args) {
        System.out.println(0b010101);
        System.out.println(0B010101);
        System.out.println(0x15A);
        System.out.println(0X15A);
        System.out.println(077);
        System.out.println(5_000);
        /**
         * 输出结果
         * 21 
         * 21 
         * 346 
         * 346 
         * 63
         * 5000
         */
    }
}

5.常见异常分为那两种(Exception,Error),常见异常的基类以及常见的异常

  • Throwable是java语言中所有错误和异常的超类(万物即可抛)。它有两个子类:Error、Exception。
  • 异常种类

1.Error:Error为错误,是程序无法处理的,如OutOfMemoryError、ThreadDeath等,出现这种情况你唯一能做的就是听之任之,交由JVM来处理,不过JVM在大多数情况下会选择终止线程。
2.Exception:Exception是程序可以处理的异常。它又分为两种CheckedException(受捡异常),一种是UncheckedException(不受检异常)。

  • 受检异常(CheckException):发生在编译阶段,必须要使用try…catch(或者throws)否则编译不通过。
  • 非受检异常 (UncheckedException):是程序运行时错误,例如除 0 会引发 Arithmetic
    Exception,此时程序奔溃并且无法恢复。
    (发生在运行期,具有不确定性,主要是由于程序的逻辑问题所引起的,难以排查,我们一般都需要纵观全局才能够发现这类的异常错误,所以在程序设计中我们需要认真考虑,好好写代码,尽量处理异常,即使产生了异常,也能尽量保证程序朝着有利方向发展。
  • 常见异常的基类(Exception)

IOException
RuntimeException

  • 常见的异常
  • 这里写图片描述

6. 以下为Object中的通用方法

以下为Object中的通用方法

public final native Class<?> getClass()

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

public final native void notify()

public final native void notifyAll()

public final native void wait(long timeout) throws InterruptedException

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait() throws InterruptedException

protected void finalize() throws Throwable {} // JVM内存回收之finalize()方法

equals()
1. equals() 与 == 的区别

对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
对于引用类型,== 判断两个实例是否引用同一个对象,而 equals() 判断引用的对象是否等价。

Integer x = new Integer(1);
Integer y = new Integer(1);
System.out.println(x.equals(y)); // true
System.out.println(x == y);      // false
  1. 等价关系

(一)自反性

x.equals(x); // true

(二)对称性

x.equals(y) == y.equals(x); // true

(三)传递性

if (x.equals(y) && y.equals(z))
    x.equals(z); // true;

(四)一致性

多次调用 equals() 方法结果不变

x.equals(y) == x.equals(y); // true

(五)与 null 的比较

对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

x.euqals(null); // false;

3 . 实现
- 检查是否为同一个对象的引用,如果是直接返回 true;
- 检查是否是同一个类型,如果不是,直接返回 false;
- 将 Object 实例进行转型;
- 判断每个关键域是否相等。

public class EqualExample {
    private int x;
    private int y;
    private int z;

    public EqualExample(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EqualExample that = (EqualExample) o;

        if (x != that.x) return false;
        if (y != that.y) return false;
        return z == that.z;
    }
}

hashCode()
hasCode() 返回散列值,而 equals() 是用来判断两个实例是否等价。等价的两个实例散列值一定要相同,但是散列值相同的两个实例不一定等价。

在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个实例散列值也相等。

下面的代码中,新建了两个等价的实例,并将它们添加到 HashSet 中。我们希望将这两个实例当成一样的,只在集合中添加一个实例,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个实例的散列值是不同的,最终导致集合添加了两个等价的实例。

EqualExample e1 = new EqualExample(1, 1, 1);
EqualExample e2 = new EqualExample(1, 1, 1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size());   // 2

理想的散列函数应当具有均匀性,即不相等的实例应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来,可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。

一个数与 31 相乘可以转换成移位和减法:31*x == (x<<5)-x,编译器会自动进行这个优化

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + x;
    result = 31 * result + y;
    result = 31 * result + z;
    return result;
}

toString()
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。

public class ToStringExample {
    private int number;

    public ToStringExample(int number) {
        this.number = number;
    }
}
ToStringExample example = new ToStringExample(123);
System.out.println(example.toString());
ToStringExample@4554617c

clone()

  1. cloneable

clone() 是 Object 的 protect 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

public class CloneExample {
    private int a;
    private int b;
}
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'

重写 clone() 得到以下实现:

public class CloneExample {
    private int a;
    private int b;

    @Override
    protected CloneExample clone() throws CloneNotSupportedException {
        return (CloneExample)super.clone();
    }
}
CloneExample e1 = new CloneExample();
try {
    CloneExample e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
java.lang.CloneNotSupportedException: CloneTest

以上抛出了 CloneNotSupportedException,这是因为 CloneTest 没有实现 Cloneable 接口。

public class CloneExample implements Cloneable {
    private int a;
    private int b;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

参考资料:
【必读】搞懂 Java equals 和 hashCode 方法 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值