- hashCode()和equals()的关系
hashCode()用于获取对象的哈希码,而equals()用于比较两个对象。
– 两个对象相同,它们的哈希码一定相同
– 哈希码相通的两个对象,它们不一定相同 - 为什么需要重写hashCode()和equals()
Object类中的equals()方法默认是用 == 判断两个对象的,双等号 判断对象时,如果是基本数据类型,则比较对象的值,如果是引用数据类型则判断对象的内容,一般情况下都是判断对象的内容是否相等,这与实际开的情况不同,所以一般都要重写equals()方法。而hashCode()方法与equals()方法具有一定的联动作用,所以重写equals()方法时,也需要重写hashCode()方法,维持hashCode()和equals()的约定。 - = = 与 equals()的区别
==:
– 基本数据类型:默认比较的是对象的内容
– 引用数据类型:默认比较的是两个对象是否相等
equals():
– 默认采用 ==比较两个对象
– 重写后的equals()比较的是两个对象的值 - String的常用方法
– char charAt(int index):返回指定索引字符
– String subString(int beginIndex, int endIndex)):从字符串中截取一部分
– void trim():消除前导和后置空格
– int indexOf(String str):返回指定字符在字符串中首次出现的索引
– int lastIndexOf(String str);返回指定字符在字符串中最后出现的索引
– String [] spilt(String regex);将字符串根据指定规则分割成数组
– String toUpperCase():将字符串转换为大写
– String toLowerCase():将字符串转换为小写
– replace(char oldChar , char newChar):替换字符串中的指定字符
String类中的方法很多,不需要全部记住,记住几个常用的就行了 - String类能否被继承
不能,String类被final关键字修饰,不能被继承。
String类被设计成不可变类的原因主要有四点:- 字符串在Java程序中广泛使用,经常会用来存储账号,密码等敏感数据,所以需要保证其安全性
- 在多线程之中,因为String类不可变,因此在其他线程中修改了字符串的值,也只是会产生一个新的对象,对其他的线程产生不了副作用。
- 由于字符串 hashcode 属性不会变更,保证了唯一性,使得类似 HashMap,HashSet 等容器才能实现相应的缓存功能。由于 String 的不可变,避免重复计算 hashcode,只要使用缓存的 hashcode 即可,这样一来大大提高了在散列集合中使用 String 对象的性能。
- 当字符串不可变时,字符串常量池才有意义字符串常量池的出现,可以减少创建相同字面量的字符串,让不同的引用指向池中同一个字符串,为运行时节约很多的堆内存。
如果String类没有被final关键字修饰,那么创建一个子类继承String类,子类就可以强行修改String类中的数据了,这就违背了String类的设计初衷了
-
String与StringBuffer的区别
Sting类是不可变的,对象创建的字符序列也是不可变的,直到对象被销毁
StringBuffer类是可变的,当StringBuffer类对象被创建后,可利利用StringBuffer类中提供的append(),insert()等方法改变对象的字符序列,在得到想要的字符串后,调用toString()方法将其转为一个String对象。 -
StringBuffer与StringBuilder的区别
二者都是可变字符串的对象,他们都继承自AbstractStringBuilder类
二者的区别在于StringBuilder类是非线程安全的,StringBuffer是线程安全的,所以StringBuilder类的性能比StringBuffer类高一些。在不涉及到多线程时,优先考虑使用StringBuilder类 -
new与直接赋值的区别
使用 new 时,JVM会先让常量池管理字符串直接量,然后再创建一个String对象指向这个字符串直接量,新创建的String对象放在堆内存之中。
使用""直接赋值时,JVM会让常量池来管理该字符串
可以看出,使用new时比使用“”多创建的一个对象,所以在开发中应优先使用“” -
字符串拼接
– + 运算符,拼接的是字符串直接量时,优先使用+号拼接
– StringBuffer:在考虑线程安全情况下,优先使用StringBuffer
– StringBuilder:在不考虑线程安全的情况下,优先使用StringBuilder
– String类的concat()方法:如果是两个字符串拼接,且其中包含变量,则可以使用concat()方法 -
字符串相加是如何实现的
如果拼接的是字符串直接量,则编译时编译器会将其直接优化为一个完整的字符串,和你直接写一个完整的字符串是一样的。
如果拼接的字符串中包含变量,则在编译时编译器采用StringBuilder对其进行优化,即自动创建StringBuilder实例并调用其append()方法,将这些字符串拼接在一起。 -
接口与抽象类的区别
从设计目的:
接口体现的是一种规范。当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。
抽象类体现的是一种模板式设计。抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能,但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同方式。从使用方式:
接口里只能包含抽象方法、静态方法、默认方法和私有方法;抽象类则完全可以包含普通方法。接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以 定义静态常量。
接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
接口里不能包含初始化块;但抽象类则完全包含初始化块。一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。
-
接口中能有构造方法吗
不能,接口定义的是一种规范,因此接口里不能包含构造器和初始化块定义。但接口中可以包含成员变量(只能是静态常量)、方法(只能是抽象实例方法、类方法、默认方法或私有方法)、内部类(包括内部接口、枚举)定义。