**Object类**
Object类是java默认提供的类。Java中除了Object类,所有的类都是有继承关系的。默认会继承Object类,即所有的对象都可以用Object进行接收
Object类位于java.lang包中,该包中包含着Java最基础和核心的类,在编译时会自动导入。
Object类是参数的最高统一类型。
1.toString()的核心目的在于取得对象信息。
String作为信息输出的重要数据类型,在java中所有数据类型只要遇到String并且执行了“+”操作,那么都要求先将其变为字符串后再连接,而所有的对象要想变成字符串默认采用toString()方法。
2.对象比较pubulic boolean equals(Object obj)
所有的类均可以按照自己的需要对equals方法进行覆写,即这个方法可用来比较两个对象是否“相等”,至于什么才叫“相等”,各个类可以根据自己的情况与需要自行定义。如String,就是要求两个对象所代表的字符串值相等,而对于一个自定义的Per类,则可能是要求姓名、年龄等一样才算是“相等”。
尽管不同的类有不同的规则,但都遵循同一条规则,即如果两个对象是“一样”的,那么它们必然是“相等”(equals)的。那么我们又将什么视为是一样的呢:即a和b指向同一个对象。Object类中的equals方法实施的就是这一条比较原则,对任意非空的指引值a和b,当且仅当a和b指向同一个对象时才返回true。
hash方法
1.1 Hash的定义
散列(哈希)函数
把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值,是一种压缩映射。
或者说一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
1.2 Hash函数特性
h(k1)≠h(k2)则k1≠k2,即散列值不相同,则输入值即预映射不同
如果k1≠k2,h(k1)=h(k2) 则发生碰撞;
如果h(k1)=h(k2),k1不一定等于k2;
HashCode的作用
减少查找次数,提高程序效率
例如查找是否存在重复值
h(k1)≠h(k2)则k1≠k2
首先查看h(k2)输出值(内存地址),查看该内存地址是否存在值;
如果无,则表示该值不存在重复值;
如果有,则进行值比较,相同则表示该值已经存在散列列表中,如果不相同则再进行一个一个值比较;而无需一开始就一个一个值的比较,减少了查找次数。
Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。 equals方法可用于保证元素不重复,但是,如果每增加一个元素就检查一次,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。
哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。
这样一来,当集合要添加新的元素时,先调用这个元素的HashCode方法,就一下子能定位到它应该放置的物理位置上。
(1)如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;
(2)如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;
(3)不相同的话,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同HashCode的对象放到这个单链表上去,串在一起(很少出现)。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
如何理解HashCode的作用:
从Object角度看,JVM每new一个Object,它都会将这个Object丢到一个Hash表中去,这样的话,下次做Object的比较或者取这个对象的时候(读取过程),它会根据对象的HashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。若HashCode相同再去调用equal。
clone方法
class obj2 implements Cloneable{ //实现接口
private int a =0;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public void changeA(int b){
this.a=b;
}
//重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class JavaCloneEq {
public static void main(String[] args) {
obj2 a = new obj2();
obj2 b = null;
try {
b = (obj2) a.clone(); //克隆a
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
b.changeA(5); //改变b对象中的值
System.out.println("a :" + a.getA());
System.out.println("b :"+ b.getA());
}
}
使用clone()方法的步骤:
1.实现clone的类首先需要实现Cloneable接口。Cloneable接口实质上是一个标识接口
2.在类中重写Object类中的clone方法
3.在clone方法中调用super.clone()。无论clone类的继承结构是什么,super.clone会直接或间接调用java.lang.Object类的clone()方法。
4.把浅复制的引用指向原型对象新的克隆体。
String,StringBuilder,Stringbuffer。
可变性的区别:
String是字符串常量,是不可变的对象:String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
线程安全性:
AbstractStringBuilder是StringBulider和StringBuffer的父类,其中定义了很多公共方法。StringBuffer对这些方法加了同步锁,所以是线程安全的,但是StringBuilder没加,所以是线程不安全的;String是不可变的,所以是线程安全的;
性能:
执行速度:StringBuilder (没同步锁,不安全,所以最快)>StringBuffer(有同步锁,安全)>String(不可变性,安全)
原因:
每次对String类型进行改变的时候,都是新生成了一个新的String对象,然后将指针指向新的对象。
StringBuffer是对对象本身进行操作,StringBulider比StringBuffer快10%-15%,但是却冒着多线程不安全的风险;
StringBuilder没有同步锁,所以最快;
单线程下操作字符串缓冲区,选择StringBuilder最快;
多线程下操作字符串缓冲区,选择StringBuffer最好;
如果是少量数据,用String就够了;