复习day2
一 .面向对象
1. 你怎么理解面向对象?
面对对象就是:
把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。
对象即为人对各种具体物体抽象后的一个概念,人们每天都要接触各种各样的对象,如手机就是一个对象。
在面向对象的编程方式中,对象拥有多种特性,如手机有高度、宽度、厚度、颜色、重量等特性,这些特性被称为对象的属性。对象还有很多功能,如手机可以听音乐、打电话、发信息、看电影等工作功能,这些功能被称为对象的方法,实际上这些方法是一种函数。而对象又不是孤立的,是有父子关系的,如手机属于电子产品,电子产品属于物体等,这种父子关系称为对象的继承性。在编程中,把所有的问题看做对象,以人的思维方式解决。这种方式非常人性化,对象实际上就是一组数据的集合,并且数据都已经命名。这些数据根据就是对象的属性,可以被程序访问。对象还包括很多函数,这些函数被称为对象的方法,也可以被程序访问。不过在外部访问对象内的属性或方法,必须先引用对象,然后用点号访问对象的属性和方法
2. 面向对象有什么特征?
(1)封装
概念:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:将变化隔离;便于使用;提高重用性;安全性。
封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。
(2)继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。
好处:a.提高了代码的复用性。
b.让类与类之间产生了关系,提供了另一个特征多态的前提。
坏处:
继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在 缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构。(3)多态
体现:父类引用或者接口的引用指向了自己的子类对象。//Animal a = new Cat();
多态的好处:提高了程序的扩展性。
多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)
多态的前提:
a. 必须要有关系,比如继承、或者实现。
b. 通常会有重写操作。
3. Java的访问修饰符有哪些?
public:使用public修饰,对所有类可以访问。
protected:使用protected修饰,对同一包内和所有子类可以访问。
缺省:不使用任何修饰符,在同一包内可以访问。
private:使用private修饰,在同一类内可以访问。
4. 重载(overload)和重写(override)的区别?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表
(参数类型不同、参数个数不同或者二者都不同)则视为重载;
重写
(1)在继承关系中;
(2)、修饰符:(子类的不能比父类更严格)子类中的修饰符只能和父类中方法的修饰符相同或者更宽;
(3)、返回值:子类中的方法的返回值只能是父类中方法返回值类型的子类或者相同; 对于基本类型必须完全一致;
(4)、方法名:必须相同;
(5)、参数列表:必须相同;
(6)、异常:子类中方法抛出异常只能是父类中方法抛出异常的子类或者相同。 子类中的方法可以不抛出任何异常。
5. 接口和抽象类的区别是什么?(能讲多少讲多少)
应用方面的区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。
抽象类在代码实现方面发挥作用,可以实现代码的重用。
(理解示例,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码。)
语法方面的区别:
(1)抽象类和接口都不能直接实例化,如果要实例化,抽象类对象必须指向实现所有抽象方法的子类对象, 接口对象必须指向实现所有接口方法的类对象。
(2)抽象类要被子类继承,接口要被类实现。
(3)接口中有全局常量与抽象方法,静态方法,default关键字来定义普通方法;
抽象类中可以有抽象方法,允许存在构造方法,普通属性,普通方法,可以有类变量与实例变量
(4)接口可继承接口,并可多继承接口;但抽象类只能单继承
类变量和实例变量的区别在于:类变量是所有对象共有,其中一个对象将它值的改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象;
补充:
接口的好处:
- 接口代表一种行为,顾名思义
- 屏蔽实现,方便维护。实现可以随便改,入参和返回值和约定一致就可以,大项目对接时比较方便
- 方便扩展,多继承
- 简单、规范性:如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)
- 方便使用。接口有多个实现时,通过接口可以屏蔽硬编码实现类,可读性好
- 减少耦合;安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些
- 制定标准,屏蔽底层
6. Java 支持多继承么?
不支持,Java 不支持多继承。每个类都只能继承一个类,但是可以实现多个接口。
7.Java 中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,
而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,
也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法
8. String,StringBuffer的和StringBuilder的区别?
String: 字符串不可变,适用于字符串内容不经常发生改变的时候
StringBuilder: 字符串可变,适用于字符串内容经常发生改变的时候,适用于单线程(线程不安全),在单线程中,执行效率较高
StringBuffer:字符串可变,适用于字符串内容经常发生改变的时候,适用于多线程(线程安全)
详细分析:
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做
在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同.
9. 写出String类常见的5个方法,并详细解释?
indexOf(String str)获取str在字符串对象中第一次出现的索引
startsWith()判断该字符串是否以指定字符开始
concat() 将指定字符串连接在该字符串的结尾
length()返回字符串的长度charAt(int index) 获取指定索引处的字符
subString(int start,int end)从start开始截取字符串,到end结束,包括start,但不包括end
isEmpty()判断字符串是否为空
10. Java中的泛型是什么 ? 使用泛型的好处是什么?
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
11. Error和Exception有什么区别?
Error和Exception都是继承于Throwable。
Error一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类错误,Java编译器不去检查他们。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和预防,遇到这样的错误,建议让程序终止。
Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
12 . try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
a) finally: 用于释放资源,节省内存,语法上无论是否有异常,都会执行
b) return : 方法结束
c) 先执行return ,再执行finally
13. 在finally中,修改return 的返回值变量,最后返回值究竟有没有发生改变?
若返回值类型是:基本数据类型,finally 中修改返回值变量,返回值不会改变【值传递】
若返回值类型是:引用数据类型,finally 中修改返回值变量,返回值会改变【引用传递】
14. 列出一些你常见的运行时异常?(至少五个)
ArithmeticException
ClassCastException
IllegalArgumentException
IndexOutOfBoundsException
NullPointerException
SecurityException
15. final, finally, finalize 的区别?
final:修饰符有三种用法:
(1)修饰类:表示该类不能被继承,即不能有子类
(2)修饰方法:表示方法不能被重写;
(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
finally:用在异常结构中
通常放在try…catch的后面构造总是执行代码块,可以将释放外部资源的代码写在finally块中,即finally的作用是释放资源,节省内存。补充(
System.exit (0)
可以阻断 finally 执行。)finalize:Object类中GC相关的方法
Object类中的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
补充:一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用 finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize 了,进而产生问题,因此不推荐使用 finalize 方法。
16. ==与equals的区别
(1)基本数据类型比较,用双等号(==),比较的是他们的值。
(2)引用数据类型比较,
a. 使用==比较,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,比较后的结果为true,否则结果为false。( JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。–这部分帮助理解)
b. 使用equals比较,若没有重写Object类的equals方法,比较还是内存地址(==理解);若重写Object类的equals方法,equals比较的是堆中内容是否相等,即两个对象的内容是否相同。
17. 自动装箱与拆箱
装箱:将基本类型—转换成—对应的包装类;
拆箱:将包装类型—转换成—基本数据类型;
Java使用自动装箱和拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率,由编译器来完成,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。
18. Java中按值传递和引用传递区别
按值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
按引用传递:引用传递就是直接把内存地址传过去,操作的其实都是源数据,这样的话修改有时候会冲突,记得用逻辑弥补下就好了。具体的数据类型就比较多了,比如Object,二维数组,List,Map等除了基本类型的参数都是引用传递。
19. 什么是反射API?它是如何实现的?
反射是指在运行时能查看一个类的状态及特征,并能进行动态管理的功能。这些功能是通过一些内建类的反射API提供的,比如Class,Method,Field, Constructors等。使用的例子:使用Java反射API的getName方法可以获取到类名。
20. 类加载器工作机制
1.装载:将Java二进制代码导入jvm中,生成Class文件。
2.连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用
3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。
双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。
21. 编程题:写一个 Singleton 单例模式
在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:Spring的Bean标签,数据库连接池等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是单例模式(Singleton)。
/*第一种生成singleton优点:简单,缺点:生成的资源浪费*/
class singleton1{
private singleton1(){};
private static singleton1 s1=new singleton1();
public static singleton1 getSingleton(){
return s1;
}
}
/*第二种优点:不占用资源,缺点:不是完全的线程安全,如果在if语句执行过后转移到另一线程执行,在转移回来的时候将不进行判断,又生成一次*/
class singleton2{
private singleton2(){
}
private static singleton2 s2=null;
public static synchronized singleton2 getSingleton(){
if(s2==null)
s2=new singleton2();
return s2;
}
22. 单例模式-线程安全
(1)多线程安全单例模式实例一(不使用同步锁)
public class Singleton {
private static Singleton sin=new Singleton(); ///直接初始化一个实例对象
private Singleton(){ ///private类型的构造函数,保证其他类对象不能直接new一个该对象的实例
}
public static Singleton getSin(){ ///该类唯一的一个public方法
return sin;
}
}
上述代码中的一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 。现在流行的设计都是讲“延迟加载”,我们可以在第一次使用的时候才初始化第一个该类对象。所以这种适合在小系统。
(2) 多线程安全单例模式实例二(使用同步方法)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance(){ //对获取实例的方法进行同步
if (instance == null)
instance = new Singleton();
return instance;
}
}
上述代码中的一次锁住了一个方法, 这个粒度有点大 ,改进就是只锁住其中的new语句就OK。就是所谓的“双重锁”机制。
(3)多线程安全单例模式实例三(使用双重同步锁)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance(){ //对获取实例的方法进行同步
if (instance == null){
synchronized(Singleton.class){
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
23. 面向对象和面向过程的区别?
面向过程:
- 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
- 缺点:没有面向对象易维护、易复用、易扩展。
面向对象:
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。
- 缺点:性能比面向过程低。
24. Static关键字
为什么要用static关键字?
通常来说,用new创建类的对象时,数据存储空间才被分配,方法才供外界调用。但有时我们只想为特定域分配单一存储空间,不考虑要创建多少对象或者说根本就不创建任何对象,再就是我们想在没有创建对象的情况下也想调用方法。在这两种情况下,static关键字,满足了我们的需求。
”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
static静态方法能不能引用非静态资源?
不能,new的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。
static静态方法里面能不能引用静态资源?
可以,因为都是类初始化的时候加载的,大家相互都认识。
非静态方法里面能不能引用静态资源?
可以,非静态方法就是实例方法,那是new之后才产生的,那么属于类的内容它都认识。
java静态变量、代码块、和静态方法的执行顺序是什么?
基本上代码块分为三种:Static静态代码块、构造代码块、普通代码块
代码块执行顺序静态代码块——> 构造代码块 ——> 构造函数——> 普通代码块
继承中代码块执行顺序:父类静态块——>子类静态块——>父类代码块——>父类构造器——>子类代码块——>子类构造器
25. 类加载器(哪三个,各自作用,本身过程:线程安全)
我们所说的类加载过程即是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程。
举个通俗点的例子来说,JVM在执行某段代码时,遇到了class A, 然而此时内存中并没有class A的相关信息,于是JVM就会到相应的class文件中去寻找class A的类信息,并加载进内存中,这就是我们所说的类加载过程。
由此可见,JVM不是一开始就把所有的类都加载进内存中,而是只有第一次遇到某个需要运行的类时才会加载,且只加载一次。
类加载器是指:通过一个类的全限定性类名获取该类的二进制字节流叫做类加载器;类加载器分为以下四种:
- 启动类加载器(BootStrapClassLoader):用来加载java核心类库,无法被java程序直接引用;
负责加载<JAVA_HOME>\lib目录,或-Xbootclasspath指定目录下的jar。 特殊说明:JVM认为合理的jar文件名才会被加载,例如:rt.jar、tools.jar,文件名不符合的jar即使放在上述目录下也不会被加载。
- 扩展类加载器(Extension ClassLoader):用来加载java的扩展库,java的虚拟机实现会提供一个扩展库目录,该类加载器在扩展库目录里面查找并加载java类;
负责加载<JAVA_HOME>\lib\ext目录,或java.ext.dirs指定目录下的jar。 特殊说明:Java9以后引入了模块化机制,此加载器被此机制取代。
- 应用程序类加载器(AppClassLoader):它根据java的类路径来加载类,一般来说,java应用的类都是通过它来加载的;
负责加载用户类路径(ClassPath)上的jar包
- 自定义类加载器:由java语言实现,继承自ClassLoader;
类加载过程是线程安全的
26. 重写hashCode(),equals()两种方法
介绍下hashCode()?
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
为什么要有 hashCode?
以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。
但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
hashCode(),equals()两种方法是什么关系?
要弄清楚这两种方法的关系,就需要对哈希表有一个基本的认识。其基本的结构如下:
对于hashcode方法,会返回一个哈希值,哈希值对数组的长度取余后会确定一个存储的下标位置,如图中用数组括起来的第一列。
不同的哈希值取余之后的结果可能是相同的,用equals方法判断是否为相同的对象,不同则在链表中插入。
则有hashCode()与equals()的相关规定:
- 如果两个对象相等,则hashcode一定也是相同的;
- 两个对象相等,对两个对象分别调用equals方法都返回true;
- 两个对象有相同的hashcode值,它们也不一定是相等的;
如果不被重写(原生)的hashCode和equals是什么样的?
- 不被重写(原生)的hashCode值是根据内存地址换算出来的一个值。
- 不被重写(原生)的equals方法是判断一个对象是否相等的方法(object1 == object2,判断的是引用)。
为什么需要重写equals和hashCode方法?
判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。如果只重写了equals方法,而不重写hashcode的方法,会造成hashcode的值不同,而equals()方法判断出来的结果为true。
在Java中的一些容器中,不允许有两个完全相同的对象,插入的时候,如果判断相同则会进行覆盖。这时候如果只重写了equals()的方法,而不重写hashcode的方法,Object中hashcode是根据对象的存储地址转换而形成的一个哈希值。这时候就有可能因为没有重写hashcode方法,造成相同的对象散列到不同的位置而造成对象的不能覆盖的问题。
hashCode主要用于提升查询效率,来确定在散列结构中对象的存储地址;
重写equals()必须重写hashCode(),二者参与计算的自身属性字段应该相同;
hash类型的存储结构,添加元素重复性校验的标准就是先取hashCode值,后判断equals();
equals()相等的两个对象,hashcode()一定相等;
反过来:hashcode()不等,一定能推出equals()也不等;
hashcode()相等,equals()可能相等,也可能不等。
27. 简单工厂模式
优点:
将对象的创建和对象使用进行分离