Java基础知识(三)

240 阅读6分钟

1、对象相等、引用相等

  • 对象相等指的是内存中的内容相等
  • 引用相等指的是指向的内存地址相等

2、==、equals

  • ==:判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
  • equals():它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
  • 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象;
  • 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
  • 这里有一个比较有意思的例子:
public class test {
    public static void main(String[] args) {
        String s1 = new String("sss");
        String s2 = new String("sss");
        String s3 = "sss";
        String s4 = "sss";
        if (s1 == s2) { //true
            System.out.println("s1 == s2");
        }
        if (s3 == s4) { //false
            System.out.println("s1 == s2");
        }
        if (s3.equals(s4)) {    //true
            System.out.println("s3 equal s4");
        }
        if (9 == 9.0) { //true
            System.out.println("true");
        }
    }
}
/*
String中的equals方法是被重写过的,基类Object的equals方法是比较两者内存地址是否相等,
而String的equals方法是比较内存中内容的值是否相等。
创建String类型时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,
如果有就把它赋值给当前引用。如果没有就在常量池再新建一个。
*/

3、hashCode、equals

为什么重写equals时必须重写hashCode方法

hashCode()介绍 hashCode()的作用时获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在Object.java中,这就意味着Java中任何类都包含有hashCode()函数。散列表存储的是键值对,它的特点是能根据键快速检索出对应的值。

为什么要有hashCode 以HashSet为例,当你把对象加入HashSet时,它会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashCode值作比较,如果没有相符的hashcode,HashSet会假设没有重复出现,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会加入。这样大大减少了equals的次数,提高了性能。

hashCode()和equals()相关规定

  • 如果两个对象相等,则hashcode一定也是相同的
  • 两个对象相等,对两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashcode值,它们也不一定是相等的
  • equals覆盖,则hashCode方法也必须被覆盖
  • hashCode()默认行为是对堆上的对象产生独特值。如果没有重写,则该类的两个对象无论如何都不会相等,即使他们有相同的数据

4、线程、程序、进程及其关系

  • 线程:与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
  • 程序:含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码
  • 进程:程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程独自占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。

5、线程有哪些基本状态

状态名称 状态说明
NEW 初始状态,线程被构建
RUNNABLE 运行状态,java把操作系统中的就绪和运行笼统地称为‘运行中’
BLOCKED 阻塞状态,线程阻塞于锁
WAITING 等待状态,线程需要等待其他线程做出一些特地的动作才能够返回到运行状态
TIME_WAITING 超时等待状态,该通知不同于WAITING,它是可以在指定时间自行返回的
TERMINATED 终止状态,表示当前线程已经执行完毕

6、Java 中的异常处理

Throwable: 有两个重要的子类:Exception(异常) 和 Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类

异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。

Throwable类常用方法

  • public string getMessage():返回异常发生时的详细信息
  • public string toString():返回异常发生时的简要描述
  • public string getLocalizedMessage():返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
  • public void printStackTrace():在控制台上打印Throwable对象封装的异常信息

异常处理

  • try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
  • catch 块:用于处理try捕获到的异常。
  • finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。

4种特殊情况,finally不会执行

  • 在finally语句块第一行发生了异常。 因为在其他行,finally块还是会得到执行
  • 在前面的代码中用了System.exit(int)已退出程序。若该语句在异常语句之后,finally会执行
  • 程序所在的线程死亡。
  • 关闭CPU

7、获取键盘输入

  • Scanner
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
  • BufferedReader
BufferedRead input = new BufferedRead(new InputStreamReader(System.in));
String s = input.readLine();