Set集合
Set集合是一个无序不重复的接口,里面有两个实现类HashSet和TreeSet
HashSet类
创建HashSet的语法:
①HashSet 名称=new HashSet(); ②HashSet set1=new HashSet(初始化容量数); ③HashSet set2=new HashSet(初始化容量数 ,负载因子); 负载因子:当数量到达容量的多少时进行扩容,默认75%。
举个例子:
1 public class Test2 { 2 public static void main(String[] args) { 3 //创建一个无参的HashSet对象, 4 HashSet set=new HashSet(); 5 //初始化容器的大小,初始化容量为12 6 HashSet set1=new HashSet(12); 7 //初始化容器的大小,并附上负载因子 8 HashSet set2=new HashSet(12,0.7f); 9 // (这个例子中)负载因子的概念是:当容量超过70%,进行扩容操作 10 } 11 }
添加操作
语法:
boolean add(E e):将指定元素添加到此集合(如果尚未存在)
举个例子:
1 public class Test2 { 2 public static void main(String[] args) { 3 //创建一个无参的HashSet对象, 4 HashSet set=new HashSet(); 5 //添加一个尚未存在的元素时返回true,否则返回false 6 set.add(12); 7 } 8 }
删除操作
语法:
boolean remove(Object o):删除指定的元素
举个例子:
1 public class Test2 { 2 public static void main(String[] args) { 3 //创建一个无参的HashSet对象, 4 HashSet set=new HashSet(); 5 //删除一个指定的元素 6 set.remove(12); 7 } 8 }
遍历操作
HashSet是一个无序不重复的结构,所以没有索引值,只能通过迭代器和增强for循环来实现遍历
①迭代器
1 public class Test2 { 2 public static void main(String[] args) { 3 HashSet set = new HashSet();//生成一个HashSet集合 4 Iterator iterator = set.iterator();//获取迭代器的对象 5 while (iterator.hasNext()) {//判断迭代器是否存在下一个元素 6 //存在下一个元素 7 //获取指定元素并将指针往下移动 8 Object object = iterator.next(); 9 System.out.println(object); 10 } 11 } 12 }
②通过foreach遍历
1 public class Test2 { 2 public static void main(String[] args) { 3 HashSet set=new HashSet();//生成一个HashSet集合 4 for(Object object:set){ 5 //遍历集合内容 6 System.out.println(object); 7 } 8 } 9 }
HashSet底层结构
Set是一个无序不重复的集合,而HashSet作为Set的子实现类,它是如何实现无序不重复的呢?
①底层使用哈希表实现无序
HashSet底层采用哈希表存储数据,哈希表是一种对于增删改查数据性能都比较好的结构,HashSet在存储数据的时候,会根据数组长度和哈希值计算出要存储的位置,从而实现无序结构。
②使用hashcode方法和equals方法实现不重复
HashSet通过hashcode方法计算哈希值,如果两者哈希值都相等,则使用equals方法来判断两者时候是同一个类型。
自定义类对象添加HashSet
1 public class Test2 { 2 public static void main(String[] args) { 3 HashSet<Person> set = new HashSet<>();//生成一个HashSet集合 4 /* 5 * TODO HashSet底层原理: 6 * 将自定义类添加到HashSet中时,会判断hashcode方法计算的哈希值是否相同 7 *如果哈希值不相等,则表示两者不是同一个对象,添加成功 8 * 如果哈希值相等,则比较equals方法,如果equals方法不相等,说明不是同一个对象 ----这种情况为哈希冲突 9 * 如果equals方法相等,则表示两者是同一个对象 10 */ 11 //添加对象 12 set.add(new Person("张三",18)); 13 set.add(new Person("张三",18)); 14 set.add(new Person("李四",14)); 15 set.add(new Person("王五",19)); 16 set.add(new Person("老牛",14)); 17 //遍历对象 18 for (Person person:set) { 19 System.out.println(person); 20 } 21 22 } 23 } 24 class Person{ 25 private String name; 26 private int age; 27 28 29 public Person() { 30 } 31 32 public Person(String name, int age) { 33 this.name = name; 34 this.age = age; 35 } 36 public String getName() { 37 return name; 38 } 39 public void setName(String name) { 40 this.name = name; 41 } 42 43 public int getAge() { 44 return age; 45 } 46 public void setAge(int age) { 47 this.age = age; 48 } 49 50 public String toString() { 51 return "Person{name = " + name + ", age = " + age + "}"; 52 } 53 }
效果展示:
这里发现,对于自定义类中,我想表达的是属性如姓名和年龄两者相等,则是同一个对象才对呀?那为什么会出现两个{张三,18}呢?
那是因为自定义类它使用的hashcode方法是Object类中的hashcode方法,而Object类中的hashcode方法是通过比较两者之间地址值,如果地址值相同表示同一个对象,所以如果我们想表示属性值相同表示同一个对象,需要重写hashcode方法。
重写hashcode语法
@Override public int hashCode() { return Objects.hash(需要比较的属性名,.......,需要比较的属性名);
}
效果展示:
发现为什么重写了hashCode仍然结果一样呢?
那是因为当我们只重写hashCode方法时,HashSet底层会认为{张三,18}这个对象求出的哈希值是相等的,它会比较equals方法,而如果我们没有重写equals方法会直接使用Object类的equals 方法,而Object类的equals方法比较的是两者地址值,如果地址值相等,才代表是同一个对象。
重写equals语法
@Override public boolean equals(Object obj) { //比较两者地址值,如果相等返回true if(obj == this){ return true; } //如果两者是不同类型的返回false if(!(obj instanceof 自定义类)){ return false; } //两者是相同类型 自定义类 对象 = (自定义类) obj; //如果两者属性相同,则表示同一个对象 if(比较对象的属性如果相等){ return true; } return false;
}
效果展示:
发现每个对象是不重复的,这样才能满足我们自己的需求。而String类它也是通过重写hashCode和equals方法来判断是否为同一对象.
TreeSet类
TreeSet底层使用的是二叉树,而TreeSet中元素要求具有排序规则,其它判断元素是否重复与HashSet一样都需要重写hashCode方法和equals方法
创建TreeSet语法:
TreeSet 名称 =new TreeSet(); //调用无参构造器
举个例子:
public class TreeSetTest { public static void main(String[] args) { //调用无参构造器 TreeSet set=new TreeSet(); } }
TreeSet存储的内容是可比较的,那如果是自定义类如何实现对象之间的可比较呢?
Java中提供两种方法来实现
比较的结果返回值:
如果返回0表示两个元素一致。 如果返回大于0,表示添加得元素比容器中得元素大。 如果返回小于0,表示添加得元素比容器中得元素小。
方法一:实现Comparable接口重写里面的方法
语法:
class 类名 implements Comparable<类名>{ // 重写CompareTo方法 @Override public int compareTo(类名 o) { //代码内容
}
举个例子:
1 public class TreeSetTest { 2 public static void main(String[] args) { 3 //调用无参构造器 4 TreeSet set=new TreeSet(); 5 //添加元素 6 set.add(new People("张三",20)); 7 set.add(new People("老王",18)); 8 set.add(new People("老牛",30)); 9 set.add(new People("李四",10)); 10 //遍历元素 11 for (Object o:set) { 12 People people=(People) o; 13 System.out.println(people); 14 } 15 } 16 } 17 class People implements Comparable{ 18 private String name; 19 private int age; 20 21 @Override 22 public int compareTo(People o) { 23 24 //按照年龄进行从小到大排序(根据对象o与本类对象进行比较) 25 return this.age-o.age; 26 } 27 28 public People() { 29 } 30 31 public People(String name, int age) { 32 this.name = name; 33 this.age = age; 34 } 35 public String getName() { 36 return name; 37 } 38 public void setName(String name) { 39 this.name = name; 40 } 41 public int getAge() { 42 return age; 43 } 44 public void setAge(int age) { 45 this.age = age; 46 } 47 public String toString() { 48 return "People{name = " + name + ", age = " + age + "}"; 49 } 50 }
效果展示:
方法二:通过自定义排序方式,通过实现Comparator接口从而调用TreeSet的有参构造方法
语法:
class 类名 implements Compatator<类名>{ //重写接口方法 @Override public int compare(类名 o1,类名 o2){ //代码内容 } }
举个例子:
1 public class TreeSetTest { 2 public static void main(String[] args) { 3 //调用有参构造方法,传入一个实现Comparator接口的类对象 4 TreeSet<People> set=new TreeSet<>(new People()); 5 //添加元素 6 set.add(new People("张三",20)); 7 set.add(new People("老王",18)); 8 set.add(new People("老牛",30)); 9 set.add(new People("李四",10)); 10 //遍历元素 11 for (People people:set){ 12 System.out.println(people); 13 } 14 } 15 } 16 class People implements Comparator<People> { 17 private String name; 18 private int age; 19 20 @Override 21 public int compare(People o1, People o2) { 22 //按照年龄从小到大排序 23 return o1.age-o2.age; 24 } 25 26 public People() { 27 } 28 29 public People(String name, int age) { 30 this.name = name; 31 this.age = age; 32 } 33 public String getName() { 34 return name; 35 } 36 public void setName(String name) { 37 this.name = name; 38 } 39 public int getAge() { 40 return age; 41 } 42 public void setAge(int age) { 43 this.age = age; 44 } 45 public String toString() { 46 return "People{name = " + name + ", age = " + age + "}"; 47 } 48 }
效果展示:
发现有时候这个实现Comparator接口的类只是使用一次就会丢弃,那如果每次都直接生成一个类只使用一次就会导致资源的浪费。
所以这里可以使用匿名实现类的方法来解决这个问题
语法:
Comparator<类名> comparator=new Comparator<类名>() { @Override public int compare(类名 o1, 类名 o2) { //代码内容 } };
举个例子:
1 public class TreeSetTest { 2 public static void main(String[] args) { 3 //生成匿名接口类对象 4 Comparator<String> comparator=new Comparator<String>() { 5 @Override 6 public int compare(String o1, String o2) { 7 return o1.length()-o2.length(); 8 } 9 }; 10 //调用有参构造器,传入自定义排序规则对象 11 TreeSet<String> set=new TreeSet<>(comparator); 12 } 13 }
这种方法也适用于一些已经实现Comparable接口的类,当自己不想用这种排序规则时,便可以使用自定义排序.
标签:set,name,框架,HashSet,age,集合,new,public From: https://www.cnblogs.com/gzyhrc/p/17838051.html