关于TreeSet 的equals 和hashcode()问题

John_Tsui 2016-11-03 05:01:56
public class nstring  implements Comparable<nstring>{
public int i;
public nstring(int i){
this.i=i;
}
@Override
public int compareTo(nstring o) {
if(this.i>o.i)
return 1;
else if(this.i==o.i)
return 0;
else
return -1;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.valueOf(i);
}

public static void main(String[] args) {
Set<nstring> set=new TreeSet<nstring>();
set.add(new nstring(4));
set.add(new nstring(2));
set.add(new nstring(3));
set.add(new nstring(2));
System.out.println(set);
}

}


大家能说出答案?
还有我想问一个问题,这个为什么不能插入两个compare相等的对象
...全文
441 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
大隐藏于寺 2016-11-13
  • 打赏
  • 举报
回复
引用 12 楼 John_520 的回复:
[quote=引用 11 楼 u011055132 的回复:]
public class ArrayMarker<T> {
	private Class<T> kind;

	public ArrayMarker(Class<T> ku) {
		super();
		this.kind = ku;
	};
	
	public T[] create(int size){
		return	(T[]) Array.newInstance(kind, size);
	}
	public static void main(String[] args) {
		ArrayMarker<String> sm=new ArrayMarker<String>(String.class);
		String[] strings=sm.create(5);
		System.out.println(Arrays.toString(strings));
	}
}
能帮帮看一下这个问题,解释一下为什么吗。这种类型擦除不会补偿?
没有看明白你要问的最后一个问题.[/quote] 你能不能运行上面的那段代码,解释一下为什么输出是null的数组。 能帮我解答就太感谢你了[/quote] ArrayMarker<T>类的create()方法返回一个数组,这个数组的长度和存储的元素类型都是指定了的.长度由传入creat()方法的整数确定,元素类型由创建对象时传入有参构造的Class类对象确定. 测试类中创建了一个String类型的数组,它的长度是5.听过查看源代码知道第十行的代码调用了Array类的私有方法
private static native Object newArray(Class componentType, int length)
这个方法使用了Native方法,也就是调用了本地的C代码,不能直接从JDK中的src文件中查找到源代码.不过通过结果来看,这个方法创建数组时使用的是动态初始化,因为String是一个类,是引用数据类型,它的默认初始化值就是null. 这里的初始化值与类中成员变量的默认初始化值是一样的.可以看这个链接http://blog.csdn.net/abc5382334/article/details/18254517 1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。 2、单精度浮点型(float)的基本类型变量的默认值为0.0f。 3、双精度浮点型(double)的基本类型变量的默认值为0.0d。 4、字符型(char)的基本类型变量的默认为 “\u0000”。 5、布尔型的基本类型变量的默认值为 false。 6、引用类型的变量是默认值为 null。 7、数组引用类型的变量的默认值为 null。当数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。
John_Tsui 2016-11-12
  • 打赏
  • 举报
回复
引用 11 楼 u011055132 的回复:
public class ArrayMarker<T> {
	private Class<T> kind;

	public ArrayMarker(Class<T> ku) {
		super();
		this.kind = ku;
	};
	
	public T[] create(int size){
		return	(T[]) Array.newInstance(kind, size);
	}
	public static void main(String[] args) {
		ArrayMarker<String> sm=new ArrayMarker<String>(String.class);
		String[] strings=sm.create(5);
		System.out.println(Arrays.toString(strings));
	}
}
能帮帮看一下这个问题,解释一下为什么吗。这种类型擦除不会补偿?
没有看明白你要问的最后一个问题.[/quote] 你能不能运行上面的那段代码,解释一下为什么输出是null的数组。 能帮我解答就太感谢你了
大隐藏于寺 2016-11-10
  • 打赏
  • 举报
回复
引用 10 楼 John_520 的回复:
[quote=引用 9 楼 u011055132 的回复:] [quote=引用 7 楼 John_520 的回复:] [quote=引用 1 楼 a6877321 的回复:] 234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一
为什么不是用equals 判断唯一性[/quote] 你可以查看TreeSet源代码知道TreeSet不是使用的equals()方法判断唯一性,而是使用的 compareTo(Object obj)和compare(T o1 , T o2)两种方法.源代码在JDK的安装路径下的src.zip文件里面.比如我已经解压了这个文件,文件路径就为D:\develop\Java\jdk1.7.0_72\src\java\util\TreeSet.java 里面有如下注释
A {@link NavigableSet} implementation based on a {@link TreeMap}.
 * The elements are ordered using their {@linkplain Comparable natural
 * ordering}, or by a {@link Comparator} provided at set creation
 * time, depending on which constructor is used.
[/quote]
public class ArrayMarker<T> {
	private Class<T> kind;

	public ArrayMarker(Class<T> ku) {
		super();
		this.kind = ku;
	};
	
	public T[] create(int size){
		return	(T[]) Array.newInstance(kind, size);
	}
	public static void main(String[] args) {
		ArrayMarker<String> sm=new ArrayMarker<String>(String.class);
		String[] strings=sm.create(5);
		System.out.println(Arrays.toString(strings));
	}
}
能帮帮看一下这个问题,解释一下为什么吗。这种类型擦除不会补偿?[/quote] 没有看明白你要问的最后一个问题.
John_Tsui 2016-11-09
  • 打赏
  • 举报
回复
引用 9 楼 u011055132 的回复:
[quote=引用 7 楼 John_520 的回复:] [quote=引用 1 楼 a6877321 的回复:] 234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一
为什么不是用equals 判断唯一性[/quote] 你可以查看TreeSet源代码知道TreeSet不是使用的equals()方法判断唯一性,而是使用的 compareTo(Object obj)和compare(T o1 , T o2)两种方法.源代码在JDK的安装路径下的src.zip文件里面.比如我已经解压了这个文件,文件路径就为D:\develop\Java\jdk1.7.0_72\src\java\util\TreeSet.java 里面有如下注释
A {@link NavigableSet} implementation based on a {@link TreeMap}.
 * The elements are ordered using their {@linkplain Comparable natural
 * ordering}, or by a {@link Comparator} provided at set creation
 * time, depending on which constructor is used.
[/quote]
引用 9 楼 u011055132 的回复:
[quote=引用 7 楼 John_520 的回复:] [quote=引用 1 楼 a6877321 的回复:] 234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一
为什么不是用equals 判断唯一性[/quote] 你可以查看TreeSet源代码知道TreeSet不是使用的equals()方法判断唯一性,而是使用的 compareTo(Object obj)和compare(T o1 , T o2)两种方法.源代码在JDK的安装路径下的src.zip文件里面.比如我已经解压了这个文件,文件路径就为D:\develop\Java\jdk1.7.0_72\src\java\util\TreeSet.java 里面有如下注释
A {@link NavigableSet} implementation based on a {@link TreeMap}.
 * The elements are ordered using their {@linkplain Comparable natural
 * ordering}, or by a {@link Comparator} provided at set creation
 * time, depending on which constructor is used.
[/quote]
public class ArrayMarker<T> {
	private Class<T> kind;

	public ArrayMarker(Class<T> ku) {
		super();
		this.kind = ku;
	};
	
	public T[] create(int size){
		return	(T[]) Array.newInstance(kind, size);
	}
	public static void main(String[] args) {
		ArrayMarker<String> sm=new ArrayMarker<String>(String.class);
		String[] strings=sm.create(5);
		System.out.println(Arrays.toString(strings));
	}
}
能帮帮看一下这个问题,解释一下为什么吗。这种类型擦除不会补偿?
大隐藏于寺 2016-11-09
  • 打赏
  • 举报
回复
引用 7 楼 John_520 的回复:
[quote=引用 1 楼 a6877321 的回复:] 234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一
为什么不是用equals 判断唯一性[/quote] 你可以查看TreeSet源代码知道TreeSet不是使用的equals()方法判断唯一性,而是使用的 compareTo(Object obj)和compare(T o1 , T o2)两种方法.源代码在JDK的安装路径下的src.zip文件里面.比如我已经解压了这个文件,文件路径就为D:\develop\Java\jdk1.7.0_72\src\java\util\TreeSet.java 里面有如下注释
A {@link NavigableSet} implementation based on a {@link TreeMap}.
 * The elements are ordered using their {@linkplain Comparable natural
 * ordering}, or by a {@link Comparator} provided at set creation
 * time, depending on which constructor is used.
大隐藏于寺 2016-11-09
  • 打赏
  • 举报
回复
引用 6 楼 John_520 的回复:
[quote=引用 5 楼 u011055132 的回复:] 你说的equals() 和hashCode()方法是HashSet集合使用来判断元素是否相同的.HashSet集合使用的是哈希表数据结构来存储集合元素的.这为了提高存储效率,首先会调用元素的hashCode()方法来与集合中的元素进行比较,首先声明接下来讲的都是保存同一个类的情况,hashCode()方法返回值不同的对象也不同相同时再使用equals()方法判断元素属性是否相同.
你回答的很好,很仔细。我之前是看编程思想477页(中文4版)中介绍的Set接口:存入set 的每个元素都必须是唯一的,必须定义equals()方法以确保唯一性,所以我发现TreeSet并不是用equals确保唯一性。应该是用CompareTo() hashSet 用hashcode()确保唯一性?[/quote] TreeSet是使用compareTo(Object obj)(自然排序)和compare(T o1 , T o2)(定制排序)两种方法的返回值来判断保证元素唯一的,这两个函数的返回值是int类型,等于0时表示元素相等,还有负数与正数,表示了元素不相等及他们大小关系. HashSet使用的是equals()方法来判断两个元素是否相等,当使用equals()比较相等的两个元素,使用hashCode()方法的到的两个返回值也是相等的.
John_Tsui 2016-11-08
  • 打赏
  • 举报
回复
引用 1 楼 a6877321 的回复:
234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一
为什么不是用equals 判断唯一性
John_Tsui 2016-11-08
  • 打赏
  • 举报
回复
引用 5 楼 u011055132 的回复:
你说的equals() 和hashCode()方法是HashSet集合使用来判断元素是否相同的.HashSet集合使用的是哈希表数据结构来存储集合元素的.这为了提高存储效率,首先会调用元素的hashCode()方法来与集合中的元素进行比较,首先声明接下来讲的都是保存同一个类的情况,hashCode()方法返回值不同的对象也不同相同时再使用equals()方法判断元素属性是否相同.
你回答的很好,很仔细。我之前是看编程思想477页(中文4版)中介绍的Set接口:存入set 的每个元素都必须是唯一的,必须定义equals()方法以确保唯一性,所以我发现TreeSet并不是用equals确保唯一性。应该是用CompareTo() hashSet 用hashcode()确保唯一性?
大隐藏于寺 2016-11-06
  • 打赏
  • 举报
回复
你说的equals() 和hashCode()方法是HashSet集合使用来判断元素是否相同的.HashSet集合使用的是哈希表数据结构来存储集合元素的.这为了提高存储效率,首先会调用元素的hashCode()方法来与集合中的元素进行比较,首先声明接下来讲的都是保存同一个类的情况,hashCode()方法返回值不同的对象也不同相同时再使用equals()方法判断元素属性是否相同.
大隐藏于寺 2016-11-06
  • 打赏
  • 举报
回复
现在来说第一个问题,TreeSet的排序方法上面已经提到了,只有两种自然排序定制排序.和你说的equals和hashCode()方法没有关系. 自然排序 当一个自定义对象要想添加到TreeSet集合中,该类对象就一定要实现Comparable接口,实现接口中的compareTo()方法,否则会提示ClassCastException异常.具体的说是当你想保存一个以上的没有实现Comparable接口的同类对象时,执行到第二个元素添加语句会提示这个错误.因为添加元素时,TreeSet都会调用添加的这个元素的compareTo()方法与已有元素进行比较.添加第一个对象时,集合里面没有元素,可以添加进去,当添加第二个对象时,TreeSet调用第二个对象的compareTo()方法去比较,由于该类没有实现Comparable接口,没有comparaTo()方法,就提示ClassCastException异常了.你可以查看一下Comparable接口的Api文档,就知道哪些类已经实现了这个接口了.基本数据类型的包装类,String,Date,File等类都实现了这个接口了,所以我们可以直接使用TreeSet集合进行字符串的排序,数字的排序. 定制排序 如果需要实现降序排列或者不去重排列,可以使用定制排序.到1.8版本,可以使用实现Comparator接口的子类或者Lambda表达式两种方法,Lambda表达式是1.8新增的特性.Comparator接口中有一个compare()方法,可以自定义如何比较,当两个对象属性值相同,而我们又需要同时保存这两个对象时,让compare()返回值不为0即可,因为TreeMap的采用的是红黑数(或者二叉树)数据结构来存储集合元素的,0代表相同不保存,-1代表小于集合中元素,放在左边,1代表大于的元素放在右边.而使用Lambda表达式只需要将Comparator接口的匿名内部类中的方法重写就可以了,作用类似.
大隐藏于寺 2016-11-06
  • 打赏
  • 举报
回复
package com.test;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;


public class nstring  implements Comparable<nstring>{
	public int i;
	public  nstring(int i){
		this.i=i;
	}
	@Override
	public int compareTo(nstring o) {
		if(this.i>o.i)
			return 1;
		else if(this.i==o.i)
			return 0;
		else 
			return -1;
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return String.valueOf(i);
	}
	
	public static void main(String[] args) {
		Set<nstring> set=new TreeSet<nstring>(new Comparator<nstring>() {

			@Override
			public int compare(nstring n1, nstring n2) {
				int num = n1.i - n2.i;
				return  num == 0 ? 1 : num; //这里的1也可以改成-1结果是一样的,因为就算你添加元素时有先后,但是结果都是有两个相同元素
			}
			
		} );
		set.add(new nstring(4));
		set.add(new nstring(2));
		set.add(new nstring(3));
		set.add(new nstring(2));
		System.out.println(set);
	}
	
}
输出结果为:[2, 2, 3, 4],这里有两个2. 先用这个例子说明以下你的第二个问题吧.你问为什么不能插入两个用compareTo()比较相等的对象,其实是可以的,看代码在创建TreeMap对象时使用了定制排序,也就是上面代码中的第29行,这里我传入了一个Comparator接口的匿名内部类,重写了比较方法,当添加的对象的i属性相同时,返回值num不是0而是1,这样就避免去掉用comparaTo()方法比较相同的对象. [color=#FF6600]TreeSet只有两种排序方法:自然排序和定制排序.默认情况下使用自然排序,但是创建TreeSet对象时传入了Comparator的匿名内部类时就使用的定制排序,要不然我们把它传进去干什么?[/color]
RYCookie 2016-11-04
  • 打赏
  • 举报
回复
还有,这里的set集合是无序的,treeset也是一样的,这里的序指的是输入123,那么输入就是正序123,逆序321这样的下标可以检索的序
RYCookie 2016-11-04
  • 打赏
  • 举报
回复
234,set集合的特性就是无序且不能重复,你每次插入一个值,这个值就会调用compare方法与集合中的元素进行比较,找到适合的位置插入,如果相等的话他就不会插入。但是有些元素不具备有自然的比较顺序或者我们不想使用它们的自然比较顺序,这时我们可以重写compareto方法或者传入比较器来实现元素的排序和唯一

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧