问题:上面的算法根据什么确定容器中对象的“大小”顺序?
所有可以“排序”的类都实现了
java.lang.Comparable
接口,
C
omparable
接口中只有一个方法
Publicint compareTo(Object obj)
返回
0
:表示
this==obj
返回正数:表示
this>obj
返回负数:表示
this
<
obj
实现了
C
omparable
接口的类通过实现
comparaTo
方法从而确定该对象的排序方式
要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
1.
如果两个对象相同,那么它们的hashCode值一定要相同
;
2.如果两个对象的hashCode相同,它们并不一定相同(这里说的对象相同指的是用eqauls方法比较)。
如不按要求去做了,会发现相同的对象可以出现在Set集合中,同时,增加新元素的效率会大大下降。
3.
equals()相等的两个对象,hashcode()一定相等
;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。
在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;
在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。
以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。
hashCode()方法被用来获取给定对象的唯一整数。这个整数被用来确定对象被存储在HashTable类似的结构中的位置。默认的,Object类的hashCode()方法返回这个对象存储的内存地址的编号。 hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。
如果我们不重写这两个方法,将几乎不遇到任何问题,但是有的时候程序要求我们必须改变一些对象的默认实现。
举例说明:
[java]
view plain
print
-
public
class
TestString{
-
public
static
void
main(String[] args){
-
String s1=
"Hello"
;
-
String s2=
"World"
;
-
String s3=
"Hello"
;
-
System.out.println(s1 == s3);
-
-
s1=
new
String(
"hello"
);
-
s2=
new
String(
"hello"
);
-
System.out.println(s1 == s2);
-
System.out.println(s1.equals(s2));
-
-
-
}
-
}
以上的正确执行是因为我们已经默认重写了String类的equals()方法和hashCode()方法。但是如果是Object类呢?
-
import
java.util.HashSet;
-
import
java.util.Set;
-
-
public
class
TestEquals1{
-
public
static
void
main(String[] args){
-
Cat cl=
new
Cat(
1
,
2
,
3
);
-
Cat c2=
new
Cat(
1
,
2
,
3
);
-
System.out.println(cl==c2);
-
System.out.println(cl.equals(c2));
-
-
}
-
}
-
-
class
Cat{
-
-
int
color,height,weight;
-
public
Cat(
int
color,
int
height,
int
weight){
-
-
this
.color=color;
-
this
.height=height;
-
this
.weight=weight;
-
}
-
-
}
-
public
class
TestEquals{
-
public
static
void
main(String[] args){
-
Cat cl=
new
Cat(
1
,
2
,
3
);
-
Cat c2=
new
Cat(
1
,
2
,
3
);
-
System.out.println(cl==c2);
-
System.out.println(cl.equals(c2));
-
}
-
}
-
-
class
Cat{
-
-
int
color,height,weight;
-
public
Cat(
int
color,
int
height,
int
weight){
-
-
this
.color=color;
-
this
.height=height;
-
this
.weight=weight;
-
}
-
public
boolean
equals(Object obj){
-
if
(obj==
null
)
return
false
;
-
else
{
-
if
(obj
instanceof
Cat){
-
Cat c=(Cat)obj;
-
if
(c.color==
this
.color && c.height==
this
.height && c.weight==
this
.weight){
-
return
true
;
-
}
-
}
-
}
-
return
false
;
-
}
-
}
以上这些都是针对容器来说的(如何判断set中不重复,如何判断list中的顺序),当然最主要的是解释为什么重写equals()方法必须要重写hashCode()方法的问题。
根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。
所以只要重写了equals(),一定要重写hashCode,否则Hash表都会失效,工作不正常。即便你用equals方法比较得到两个对象是相等的结论那你也得不到相同的哈希码
即如果cat类只重写了equals(),hashcode没有被重写,加入元素时使用的hashcode()是继承于set<-collection<-object的,所以计算的hashcode值不同,存储位置不同,则认为元素不相同,也就能明白为什么上面的判断是否存在(System.out.println(cat.contains(newCat(1,2,3))))时输入的结果为false了。
Java
系列之:
比较
两个list中的内容,返回list1中有但list2中没有的数据,当list1和list2数据相同时返回空的list
方法主要用于返回list1中有但list2中没有的数据
当list1和list2数据相同时返回空的list
import
java
.util.*;
public class CompareList {
//方法主要用于返回list1中有的数据,而list2没有的
//当list1和list2数据相同时返回空的list
public stati
1. 场景描述通过
java
代码从外围接口中获取数据并落地,已经存在的不落地,不存在的落地,因有部分字段变化是正常的,只需比对3个字段相同即为相同。2. 解决方案设置定时任务(
三
个标签完成springboot定时任务配置),比对接口中获取的数据和本地落地的数据是否相同。2.1 真实代码@Scheduled(cron = "0 10 2 * * ? ")public void execAppUser(...
集合
框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了: Comparble和Comparator两种方式。
1. Comparble是默认的内部
比较
方式,如果用户插入自定义类型
对象
时,该类
对象
必须要
实现
Comparble接口,并覆写compareTo方法
2. 用户也可以选择使用
比较
器
对象
,如果用户插入自定义类型
对象
时,必须要提供一个
比较
器类,让该类
实现
Comparator接口并覆写compare方法。
Java
的
集合
框架从整体上可以分为两大家族。
1、 Collection(接口)家族。该接口下的所有子孙均存储的是单一
对象
。 Add(s)
2、 Map(接口)家族。该接口下的所有
Collections和Collection的
区别
:
Collections是
java
.utils下面的类,含有许多
集合
的相关操作的静态方法
Collections是
java
.utils下面的接口,是许多
集合
的上级接口
2.Collections的sort方法
sort方法用于对数据
集合
进行大小排序
* 使用给定的
比较
器对给定的列表
笔者之前做项目的时候,写过一个小算法,用来
实现
两张表的数据同步。因为移动端的数据量一般也就几千条,所以便没有关注性能问题。最近开始面试,由于没做过性能测试,只能根据经验判断,想了想还是靠数据说话
比较
好。
集合
A 是新
集合
,
集合
B 是老
集合
,现需要筛选出
集合
A 中的新增元素、已更新元素以及
集合
B ...
实现
了Seriazable,所以可用于json的序列化操作
Iterator:进行轮训的时候尽量使用轮询的方法,,内部优化了非空判断,以及异常处理,for循环遍历有风险,可读,不要用于其他方面
优点:尾插效率高,支持随机访问
在add方法里面了,首先会判断容量大小,如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值, ensureExpl...
Jaccard coefficient:A,B分别代表符合某种条件的
集合
:两个
集合
交集的大小/两个
集合
并集的大小,交集=并集意味着2个
集合
完全重合。
Ochiai coefficient:A,B分别代表符合某种条件的
集合
:两个
集合
的交集大小/两个
集合
大小的几...
1 List
集合
: 被
比较
的
对象
要重写equals()方法, 调用List中contains()方法,就是用equals()方法
比较
的.
List
集合
(允许
重复
元素,允许空值)
2 HashSet
集合
(不允许
重复
元素,允许空值): 被
比较
的
对象
要重写hashCode()方法和重写equals()方法, 两个都要.
3 TreeSet
集合
.(不允许重...
在项目中,我们常常用到两个
集合
的数据比对,找到其中
不同
的数据,在Android里面基本上数据量也不会太大,往往大家都是直接用for循环嵌套搞定,大家有没有想过 当数据量很大的时候,使用for循环嵌套找出不一样的
对象
,需要多久。本文将为大家介绍一下如果进行高效的数据比对,以及一些特殊场景的应用,收藏起来,你会用到的。
测试耗时会因为设备性能
不同
而
不同
,以下为测试设备的硬件
创建...