集合(下)(Set的学习)

本文介绍Java中登录注册系统的实现方法,包括面向对象的设计思路、接口定义与实现,以及集合在用户信息存储中的应用。并通过HashSet和TreeSet的具体案例演示了元素唯一性和排序规则。

在集合的基础上,我们可以做一个登录注册案例

登陆注册案例分析:
利用面向对象的思想,我们必须先找到能完成某个功能的类,接着调用里面的方法完成它

登陆注册案例中的类:
用户类
成员变量:用户名,密码
成员方法:登陆,注册功能

测试类 :就是我们的main方法

登陆注册案例中的类的详细分解:
用户类(User):用户名,密码,邮箱,电话,身份证号。。。。— 标准的java描述类

我们应该把对用户的所有的操作抽取出来形成一个类:
用户操作类:注册,登陆
定义一个接口:就是定义的登陆和注册的功能,
接口本质其实是用来定义规则的


重点
java中的分包:
com.edu.domain — 标准的java描述类
com.edu.dao – 存放的是接口
com.edu.dao.impl – 存放的是接口实现类
com.edu.util – 对对象进行操作的工具类
com.edu.test – 测试类


下面是 代码实现部分,添加了一个 注册成功后可以 玩一个猜数字小游戏的方法
先写一个标准的用户描述类

public class User {
 private String useName;                             
 private String passWord;
 public User() {
  super();
  // TODO Auto-generated constructor stub
 }
 public User(String useName, String passWord) {
  super();
  this.useName = useName;
  this.passWord = passWord;
 }
 public String getUseName() {
  return useName;
 }
 public void setUseName(String useName) {
  this.useName = useName;
 }
 public String getPassWord() {
  return passWord;
 }
 public void setPassWord(String passWord) {
  this.passWord = passWord;
 }


用户的操作类,为了之后代码修改方便,利用借口的方法来实现

import com.edu.domain.User;
public interface UserDao {
 //定义注册的功能
 public abstract void regist(User user);
 //定义一个登陆的功能
 public abstract boolean isLogin(String userName,String passWord );




}

接口的实现类

import java.util.ArrayList;
import com.edu.dao.UserDao;
import com.edu.domain.User;
//创建一个用户操作类
public   class UserDaoImpl implements UserDao {
 ArrayList<User> users = new ArrayList<User>();
    //目前在集合的基础上使用用户注册和登陆的功能,  将用户的信息存储在集合中,登录时拿信息与集合中的信息匹配
 @Override
 public void regist(User user) {
  // TODO Auto-generated method stub
  users.add(user);

 }




 @Override
 public boolean isLogin(String userName, String passWord) {
  boolean flag = false;
  for(User user:users){
   if(userName.equals(user.getUseName())&&passWord.equals(user.getPassWord())){
    flag = true;

   }
  }
  return  flag;



 }





}

测试类

import java.util.Scanner;
import com.edu.dao.impl.UserDaoImpl;
import com.edu.domain.User;
public class Test {
 public static void main(String[] args) {
   int real =  (int) (Math.random()*100+1);
  UserDaoImpl udi = new  UserDaoImpl();
  //先创建一个用户操作类对象,来完成一定的操作
  //UserDaoImpl udi = new  UserDaoImpl();
  while(true){
  System.out.println("欢迎来到登录注册页面");
  System.out.println("1:注册");
  System.out.println("2:登录");
  System.out.println("3:退出系统");
  Scanner sc = new Scanner(System.in);
    String line = sc.nextLine();
//注意这里接受数字选择的时候,要用字符串类型来接,因为如果用int类型来接受的话,后面用的是String类型接受,这样会导致程序运行时发生错误,而且编译的时候不会报错,所以一定要切记



  switch(line){
  case "1" :
      System.out.println("欢迎来到注册页面");
         System.out.println("请输入你的用户名");
         String userName = sc.nextLine();
         System.out.println("请输入你的密码");
         String passWord = sc.nextLine();
         User user = new User(userName,passWord);
         udi.regist(user);
         System.out.println("注册成功");
         break;
  case "2":System.out.println("欢迎来到登录页面");
         System.out.println("请输入你的用户名");
         String intputuserName = sc.nextLine();
         System.out.println("请输入你的用户密码");
         String intputpassWord = sc.nextLine();
         boolean flag = udi.isLogin(intputuserName, intputpassWord);
         if(flag){
          System.out.println("等录成功");
          System.out.println("你现在可以玩一个猜数字小游戏了");
          while(true){
          System.out.println("请输入你猜的一个在1到100之间的数字");
             int guess = sc.nextInt();
             if(real>guess){
              System.out.println("你猜的数字偏小");
             }else if(guess>real){
              System.out.println("你猜的数字偏大");
             }else if(guess==real){
              System.out.println("恭喜你答对了");break;
             }

         }
         }else{
          System.out.println("登录失败,请确保你的用户信息正确");
         }



         break;
  case "3":  System.out.println("系统即将退出");System.exit(0);
   default:  System.out.println("您输入有误,系统将自动退出,请重新启动");System.exit(0);




  }
 }




}
}




集合3_Set
1.Set
1.常用方法:直接查看api
2.HashSet
元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
案例:创建一个HashSet集合,添加元素(String元素),测试唯一性,无序性

package com.edu_01;

import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
    public static void main(String[] args) {
        //创建一个HashSet集合
        HashSet<String> set = new HashSet<String>(); 

        //给集合中添加元素
        set.add("hello");
        set.add("java");
        set.add("world");
        set.add("c++");
        set.add("php");
        set.add("hello");

        //遍历集合
        /**
         * HashSet集合特点:
         * 1.元素无序
         * 2.元素唯一
         */
        for (String string : set) {
            System.out.println(string);
        }
        //为什么在String类型中不用重写HashCode()和equals()方法
        //因为String类型中,本来就包含了HashCode()和equals()方法
    }

}

2.2如何保证元素的唯一性的呢?
* ,我们知道HashSet集合保证元素的唯一性和add()方法相关。
* 看add()方法的源码,看它的底层依赖什么内容?
* if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {…}
*
* 左边:e.hash == hash
* 比较对象的哈希值。
*
* 右边:((k = e.key) == key || key.equals(k))
* 左边:(k = e.key) == key
* 比较对象的地址值。
*
* 右边:key.equals(k)
* 比较的是对象的内容是否相同。默认情况下比较的是地址值

结论:
底层数据结构是哈希表。
哈希表依赖两个方法:hashCode()和equals()

执行流程:
首先判断哈希值是否相同,如果不同,就直接添加到集合。
如果相同,继续执行equals(),看其返回值,
如果是false,就直接添加到集合。
如果是true,说明元素重复不添加。

使用:
如果你看到哈希结构的集合,就要考虑可能需要重写这两个方法。
如果真要重写,自动生成即可。

**哈希表结构:是一个元素为链表的数组结构
元素的哈希码值作为索引,元素本身的值作为数组的值存入到数组中
所以在存储过程中,先比较元素的哈希码值是否相同,如果不同,则直接添加,通过重写HashCode()方法,如果元素的哈希码值相同,在通过重写的equals()方法比较元素的地址值或者内容,如果有一个相同则该元素不能够存储**

知识点demo
1.存储String类型的元素,说明元素无序且唯一
2.分析add()方法,保证唯一性的原理(底层依赖于hashCode()和equals()方法,保证了元素的唯一性)
3.存储自定义对象,如何保证元素的唯一性?(存储相同元素,发现无法保证元素的唯一性)
hashcode()方法保证了字符串的哈希码值相同,equals()保证了字符串的地址值和内容相同

public class HashSetDemo {
 public static void main(String[] args) {
  //创建一个HashSet集合
  HashSet<String> set = new HashSet<String>(); 

  //给集合中添加元素
  set.add("hello");
  set.add("java");
  set.add("world");
  set.add("c++");
  set.add("php");
  set.add("hello");

  //遍历集合
  /**
   * HashSet集合特点:
   * 1.元素无序
   * 2.元素唯一
   */
  for (String string : set) {
   System.out.println(string);
  }

 }




}



3.TreeSet
3.1 元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序(比较器排序),
具体取决于使用的构造方法。
3.2 底层算法:二叉树
3.3 元素要求, 加入自定义JavaBean

案例演练:
1.创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24),分析如何保证元素唯一性,以及排序的规则。
二叉树根据compareTo()方法的返回值来确定要存入元素的安放位置)
这里写图片描述
**二叉树结构存储数据的规则:
1.当存入第二个元素的时候会与第一个元素做减法,如果差值为负,说明你存的这个元素比之前的小往左边放
2.如差值为正,说明比之前存的值大,往右边放;
3:如果值为0,说明相等则不存储

**

import java.util.TreeSet;
public class TreeSetDemo {
 public static void main(String[] args) {
  /**
   * 1.创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24),
   * 分析如何保证元素唯一性,以及排序的规则。二叉树
    *(首先讲解二叉树数据结构是怎么存入元素的,根据compareTo()方法的返回值来确定要存入元素的安放位置)
    *
   */
  //创建一个TreeSet集合
  /**
   * TreeSet集合特点:
   * 1.元素唯一
   * 2.元素有序
   */
  TreeSet<Integer> ts = new TreeSet<Integer>();

  //给集合中存储元素
  //(20,18,23,22,17,24,19,18,24)
  ts.add(20);
  ts.add(18);
  ts.add(23);
  ts.add(22);
  ts.add(17);
  ts.add(24);
  ts.add(19);
  ts.add(18);
  ts.add(24);

  //遍历集合
  for (Integer integer : ts) {
   System.out.println(integer);
  }

 }




}









2.存储字符串并遍历(字母a-z排序)
import java.util.TreeSet;
public class TreeSetDemo2 {
 public static void main(String[] args) {
  /**
   *  2.存储字符串并遍历(字母a-z排序)
   */
  //创建一个TreeSet集合
  //当存入字符串的时候,按照字典顺序进行排序
  TreeSet<String> ts = new TreeSet<String>();

  //存入字符串
  ts.add("linzhiling");
  ts.add("amu");
  ts.add("bigbang");
  ts.add("guodegang");

  //遍历集合
  for (String string : ts) {
   System.out.println(string);
  }

 }




}

3.存入学生对象(姓名,年龄),1.按年龄排序,2.姓名排序(自然排序实现Comparable接口,并重写comparaTo()


 import java.util.TreeSet;

 public class Student implements Comparable<Student>{
 private String name;
 private int age;
 public Student(String name, int age) {
  super();
  this.name = name;
  this.age = age;
 }
 public Student() {
  super();
  // TODO Auto-generated constructor stub
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 @Override
 public String toString() {
  return "Student [name=" + name + ", age=" + age + "]";
 }

 //实现Comparable接口的同时必须实现这个比较法
 @Override
 public int compareTo(Student s) {
  //就是写的是元素的比较规则,由你自己去动手写出
  //按照学生的年龄进行排序
  /**
   * 两个对象进行比较:
   * s
   * this
   */
  int num = this.age - s.age;
  //判断年龄是否相同,如果相同比较姓名
  /**
   * 写这个比较规则的时候注意两点:
   * 1.他有主要条件,先按照主要条件进行排序
   * 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较
   */

  int num2 = num==0?this.name.compareTo(s.name):num;
  return num2;
 }

/**
* java.lang.ClaastException:类型转换异常
* 有俩种式* 1.集合中的对象所属的类实现一个Comparable接口
* 2.为集合指定相应的比较器
* TreeSet集合有两种排序方式:至于哪两种排序方式,取决于他的构造器
*
* 自然排序:无参构造public TreeSet()
*
* 比较器排序(Comparator):
*
*
*/

import java.util.TreeSet;

public class TreeSetDemo {
 public static void main(String[] args) {
  //创建TreeSet集合,存储自定义对象
  TreeSet<Student> ts = new TreeSet<Student>();

  //给集合中添加Student对象
  Student s = new Student("guodegang", 50);
  Student s6 = new Student("liuyifei", 50);
  Student s2 = new Student("zhangxueyou", 55);
  Student s3 = new Student("amu", 45);
  Student s4 = new Student("tf-boys", 18);
  Student s5 = new Student("wangfeng", 49);

  ts.add(s);
  ts.add(s2);
  ts.add(s3);
  ts.add(s4);
  ts.add(s5);
  ts.add(s6);

  //遍历集合
  for (Student student : ts) {
   System.out.println(student);
  }




 }




}




4.创建set集合的时候,传入Comparator(

比较器排序)进行排序,进行排序(比较器排序)

public class Student{
 private String name;
 private int age;
 public Student(String name, int age) {
  super();
  this.name = name;
  this.age = age;
 }
 public Student() {
  super();
  // TODO Auto-generated constructor stub
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 @Override
 public String toString() {
  return "Student [name=" + name + ", age=" + age + "]";
 }

}




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




public class TreeSetDemo {
 public static void main(String[] args) {
  //创建集合,参数是一个接口,实际需要的是接口的实现类对象
  //TreeSet<Student> ts = new TreeSet<Student>(new ComparatorImpl());

  //使用匿名内部类来进行改进
  TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
   @Override
   public int compare(Student s1, Student s2) {
    int num = s1.getAge() - s2.getAge();
    int num2 = num==0?s1.getName().compareTo(s2.getName()):num;
    return num2;
   }
  });

  //创建对象存入集合
  Student s = new Student("guodegang", 50);
  Student s6 = new Student("liuyifei", 50);
  Student s2 = new Student("zhangxueyou", 55);
  Student s3 = new Student("amu", 45);
  Student s4 = new Student("tf-boys", 18);
  Student s5 = new Student("wangfeng", 49);

  ts.add(s);
  ts.add(s2);
  ts.add(s3);
  ts.add(s4);
  ts.add(s5);
  ts.add(s6);

  //遍历集合
  for (Student student : ts) {
   System.out.println(student);
  }


 }




}




4.Set的遍历
4.1Iterator:创建迭代器进行遍历
4.2foreach:利用增强for进行遍历

5.HashSet与TreeSet的相同点与不同点
相同点:
单列集合,元素不可重复
不同点
1. 底层存储的数据结构不同
HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储
2.存储时保证数据唯一性依据不同
HashSet是通过重写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的
3.有序性不一样
HashSet无序,TreeSet有序

  • 这种情况的数据,属于一一对应的映射关系。这种关系的集合在java叫Map。
  • Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

  • Map接口中的方法概述(创建集合测试方法):

  • A:删除功能
  • void clear():移除集合中的所有键值对元素
  • V remove(Object key):根据键移除键值对元素,并返回值
  • B:判断功能
  • boolean containsKey(Object key):判断集合中是否包含指定的键
  • boolean containsValue(Object value):判断集合中是否包含指定的值
  • boolean isEmpty():判断集合是否为空
  • C:获取功能
  • Set
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;




public class MapDemo {
 public static void main(String[] args) {
  //创建一个Map集合
  //键是学号--值是姓名
  Map<Integer,String> map = new HashMap<Integer,String>();

  //V put(K key,V value):集合添加键值对
  map.put(1, "周杰伦");
  map.put(2, "郭德纲");
  map.put(3, "刘德华");
  map.put(4, "张学友");

  //void clear():移除集合中的所有键值对元素
  //map.clear();

  //V remove(Object key):根据键移除键值对元素,并返回值
  //String remove = map.remove(1);
  //System.out.println(remove);


  //boolean containsKey(Object key):判断集合中是否包含指定的键
  //boolean containsKey = map.containsKey(2);
  //System.out.println(containsKey);

  //boolean containsValue(Object value):判断集合中是否包含指定的值
  //boolean containsValue = map.containsValue("周杰伦");
  //System.out.println(containsValue);

  //boolean isEmpty():判断集合是否为空
  //System.out.println(map.isEmpty());

  //int size():键值对对数。
  //System.out.println(map.size());

  //Collection<V> values():获取所有的值
  /*
  Collection<String> values = map.values();
  Iterator<String> it = values.iterator();
  while (it.hasNext()) {
   System.out.println(it.next());
  }*/


  //Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,
     //利用getKey(),getValue()取出键和值(理解即可)
  Set<Entry<Integer,String>> entrySet = map.entrySet();
  for (Entry<Integer, String> entry : entrySet) {
   System.out.println(entry.getKey()+"  "+entry.getValue());
  }

  System.out.println("--------------------");
  //Set<K> keySet():获取所有的键
  Set<Integer> keys = map.keySet();
  for (Integer key : keys) {
   //V get(Object key):根据键获取值
   System.out.println(key+"  "+map.get(key));
  }

 }




}

2.HashMap
2.1元素顺序:元素顺序不可预测
2.2底层算法:哈希算法
2.3对键没有要求(仅仅相对于TreeMap来说) 知识点demo演练:
1.存入(String,String)主要讲解遍历方式,键:丈夫 值:妻子

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;




public class HashMapDemo {
 public static void main(String[] args) {
  // 1.存入(String,String)主要讲解遍历方式,键:丈夫  值:妻子
  HashMap<String, String> hm = new HashMap<String,String>();

  //给键值对集合存入元素
  hm.put("文章", "马伊琍");
  hm.put("黄晓明", "baby");
  hm.put("汪老师", "章子怡");
  hm.put("周杰伦", "昆凌");
  //hm.put("文章", "姚笛");,当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替

  //遍历,通过建找值
  Set<String> keys = hm.keySet();
  for (String key : keys) {
   System.out.println(key+"  "+hm.get(key));
  }

  System.out.println("-------------");
  //通过找到结婚证,来分别找到丈夫和妻子
  Set<Entry<String,String>> entrySet = hm.entrySet();
  for (Entry<String, String> entry : entrySet) {
   System.out.println(entry.getKey()+"  "+entry.getValue());
  }

 }




}















  1. 练习 存入(String,Student
    )键:String(国籍) 值:Student
public class Student{
 private String name;
 private int age;
 public Student(String name, int age) {
  super();
  this.name = name;
  this.age = age;
 }
 public Student() {
  super();
  // TODO Auto-generated constructor stub
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 @Override
 public String toString() {
  return "Student [name=" + name + ", age=" + age + "]";
 }

}
import java.util.HashMap;
import java.util.Set;




public class HashMapDemo {
 public static void main(String[] args) {
  // 2.存入(String,Student)键:String(国籍)  值:Student
  HashMap<String, Student> hm = new HashMap<String, Student>();

  //创建学生对象
  Student s1 = new Student("杰克逊", 60);
  Student s2 = new Student("孙楠", 50);
  Student s3 = new Student("权志龙", 30);

  //将对象存入集合
  hm.put("美国", s1);
  hm.put("中国", s2);
  hm.put("韩国", s3);

  //同过键找值
  Set<String> keys = hm.keySet();
  for (String key : keys) {
   System.out.println(key+"  "+hm.get(key));
  }

 }




}









3.存入(Student,String),键是同一个对象的时候要把之前存入的元素挤出去,想要实现这样
的效果的话,
需要重写javabean里面的hashCode()和equals()方法

 public class Student{
 private String name;
 private int age;
 public Student(String name, int age) {
  super();
  this.name = name;
  this.age = age;
 }
 public Student() {
  super();
  // TODO Auto-generated constructor stub
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 @Override
 public String toString() {
  return "Student [name=" + name + ", age=" + age + "]";
 }
 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + age;
  result = prime * result + ((name == null) ? 0 : name.hashCode());
  return result;
 }
 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Student other = (Student) obj;
  if (age != other.age)
   return false;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
 }



}
import java.util.HashMap;
import java.util.Set;




public class HashMapDemo {
 public static void main(String[] args) {
  // 3.存入(Student,String)
  //创建一个Map集合
  HashMap<Student, String> hm = new HashMap<Student, String>();

  //创建学生对象
  Student s1 = new Student("杰克逊", 60);
  Student s2 = new Student("孙楠", 50);
  Student s3 = new Student("权志龙", 30);
  Student s4 = new Student("权志龙", 30);

  //将对象存入集合
  hm.put(s1, "美国");
  hm.put(s2, "中国");
  hm.put(s3, "韩国");
  hm.put(s4, "中国");

  //遍历集合
  Set<Student> keys = hm.keySet();
  for (Student s : keys) {
   System.out.println(s+"  "+hm.get(s));
  }

 }



}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值