目录

Java修炼指南:高频源码解析

目录

使用java.lang包下的所有类,都不需要手动导入。至于原因,因为用得多,提前加载了该包文件,且节省了资源。

Java中的两种导包形式:

1)单类型导入(single-type-import),例如import java.util.Date。需要什么类便导入什么类,这种方式是导入指定的public类或者接口。

2)按需类型导入(type-import-on-demand),例如import java.util.∗。程序员会以为是导入java.util包下的所有类,其实并不是这样,Java会根据名字知道是按照需求导入,并不是导入整个包下的所有类。

Java编译器会从启动目录(bootstrap)、扩展目录(extension)和用户类路径去定位需要导入的类,而这些目录仅给出了类的顶层目录,编译器的类文件定位方法大致可以理解为如下公式:

顶层路径名 \ 包名 \ 文件名.class=绝对路径

编译器找到java.io.File类之后并不会停止下一步的寻找,而要把所有的可能性都查找完以确定是否有类导入冲突。如果在查找完成后,编译器发现了两个同名的类,那么就会报错。

按需类型导入是绝对不会降低Java代码的执行效率的,但会影响到Java代码的编译速度。所以在编码时最好是使用单类型导入,这样不仅能提高编译速度,也能避免命名冲突。

一个类必须要有一个构造器,如果没有显示声明,那么系统会默认创造一个无参构造器,在JDK的Object类源码中,是看不到构造器的,系统会自动添加一个无参构造器。

在Java规范中,对equals方法的使用必须遵循以下几个原则

实际上用instanceof关键字是达不到对称性的要求的。这里推荐做法是用getClass()方法取代instanceof运算符。

对于使用instanceof和getClass()运算符有如下建议

一个完美的equals方法的建议

请注意,无论何时重写此方法,通常都必须重写hashCode方法,以遵循hashCode方法的一般约定。

用native修饰的方法是由操作系统帮忙实现的,该方法的作用是返回一个对象的运行时类,通过这个类对象可以获取该运行时类的相关属性和方法。也就是Java中的反射,各种通用的框架都是利用反射来实现的

1.1 JDK中所有类的基类——Object类

  • class是一个类的属性,能获取该类编译时的类对象,而getClass()是一个类的方法,它是获取该类运行时的类对象。
  • 如果集合中有10000个元素了,当新加入一个元素时,那就需要进行10000次equals方法的调用,这显然效率很低。
  • 于是,Java的集合设计者就采用了哈希表来实现。哈希算法也称为散列算法,是将数据依特定算法产生的结果直接指定到一个地址上。
  • 发生了哈希冲突,这时候由于最先插入了A,在插入B的时候,发现B是要插入A所在的位置,而A已经插入了,这时候就通过调用equals方法判断A和B是否相同,如果相同就不插入B,如果不同则将B插入A后面的位置。
  • 如果用自定义对象作为key,那么一定要重写equals方法和hashCode方法,不然会产生错误。
  • hashCode()和equals()使用的注意事项
  • 所以如果想把编写的对象放进hashSet,并且发挥hashSet的特性(即不包含一样的对象),就要重写自定义类的hashCode()和equals()方法。
  • 如果只想对比两个对象是否一致,则只重写一个equals(),然后用equals()去对比即可。
  • notify()/notifyAll()/wait()方法是用于多线程之间的通信方法
  • 该方法用于垃圾回收,一般由JVM自动调用
  • 静态代码块是一个类在初始化过程中必定会执行的内容,所以在类加载的时候会执行该方法,并通过该方法来注册本地方法。

1.2 Java的深拷贝和浅拷贝 | Java修炼指南:高频源码解析

  • 关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。
  • 创建对象的5种方式:new Class.newInstance() Constructor.newInstance() clone() 反序列化!
  • 用native修饰的方法就是告诉操作系统去实现。
  • 基本类型也称为值类型,分别是字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。
  • 引用类型则包括类、接口、数组、枚举等。
  • 基本类型直接在栈中存储数值,而引用类型是将引用放在栈中,实际存储的值是放在堆中,通过栈中的引用指向堆中存放的数据。
  • 调用对象的clone方法,必须要让类实现Cloneable接口,并且重写clone方法。
  • 也就是说,对象Person的属性Address经过clone之后,其实只是复制了其引用,它们指向的还是同一块堆内存空间,当修改其中一个对象的属性Address时,另一个也会跟着变化
  • 浅拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的,则复制引用但不复制引用的对象。
  • 深拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都复制独立的一份。当用户修改其中一个对象的任何内容时,都不会影响另一个对象的内容。
  • 既然引用类型不能实现深拷贝,那么将每个引用类型都拆分为基本类型,分别进行浅拷贝。
  • 有多少个引用类型,就要重写多少次,如果存在很多引用类型,那么代码量显然会很大,所以这种方法不太合适。
  • 序列化是将对象写到流中便于传输,而反序列化则是把对象从流中读取出来。
  • 注意每个需要序列化的类都要实现Serializable接口,如果有某个属性不需要序列化,可以将其声明为transient,即将其排除在克隆属性之外。
  • 因为序列化产生的是两个完全独立的对象,所有无论嵌套多少个引用类型,序列化都是能实现深拷贝的。

1.3 最常用的引用类——Integer类 | Java修炼指南:高频源码解析

Integer类在JDK 1.0的时候就有了,它是一个类,是int基本数据类型的封装类