No_16_0316 Java基础学习第十八天

文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.03.16 lutianfei none

[TOC]


集合练习

集合对象的toString()是如何实现
  • 关于System.out.println(c);为什么c输出的不是地址值呢?
    • A:Collection c = new ArrayList();
      • 这是多态,所以输出c的toString()方法,其实是输出ArrayListtoString()
    • B:看ArrayList的toString()
      • 而我们在ArrayList里面却没有发现toString()。以后遇到这种情况,也不要担心,你认为有它却没有,就应该去它父亲里面看看。
代码:
    Collection c = new ArrayList();
    c.add("hello");
    c.add("world");
    c.add("java");
    
    System.out.println(c);

    //toString()的方法源码
    
        public String toString() {
            Iterator<E> it = iterator(); //集合本身调用迭代器方法,得到集合迭代器
            if (! it.hasNext())
                return "[]";
    
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            for (;;) {
                E e = it.next(); //e=hello,world,java
                sb.append(e == this ? "(this Collection)" : e);
                if (! it.hasNext())
                    //[hello, world, java]
                    return sb.append(']').toString();
                sb.append(',').append(' ');
            }
        }


集合版——登录注册(理解)
  • 需求分析:

  • 按照如下的操作,可以让我们更符合面向对象思想

    • A:有哪些类呢?
    • B:每个类有哪些东西呢?
    • C:类与类之间的关系是什么呢?
  • 分析:

    • A:有哪些类呢?
      • 用户类
      • 测试类
    • B:每个类有哪些东西呢?
      • 用户类:
        • 成员变量:用户名,密码
        • 构造方法:无参构造
        • 成员方法:getXxx()/setXxx()
        • 登录,注册
      • 假如用户类的内容比较多,将来维护起来就比较麻烦,为了更清晰的分类,我们就把用户又划分成了两类
      • 用户基本描述类
        • 成员变量:用户名,密码
          
        • 构造方法:无参构造
          
        • 成员方法:getXxx()/setXxx()
          
      • 用户操作类
        • 登录,注册
          
      • 测试类:
        • main方法。
    • C:类与类之间的关系是什么呢?
      • 在测试类中创建用户操作类和用户基本描述类的对象,并使用其功能。
  • 分包:

    • A:功能划分
    • B:模块划分
    • C:先按模块划分,再按功能划分
  • 今天我们选择按照功能划分:

    • 用户基本描述类包 cn.itcast.pojo
    • 用户操作接口 cn.itcast.dao
    • 用户操作类包 cn.itcast.dao.impl
      • 今天是集合实现,过几天是IO实现,再过几天是GUI实现,就业班我们就是数据库实现
    • 用户测试类 cn.itcast.test
  • 项目包情况


  • 第一步添加cn.itcast.pojo包

package cn.itcast.pojo;

/**
 * 这是用户基本描述类
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public class User {
    // 用户名
    private String username;
    // 密码
    private String password;

    public User() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}


  • 第二步:添加cn.itcast.dao包
import cn.itcast.pojo.User;

/**
 * 这是针对用户进行操作的接口
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public interface UserDao {
    /**
     * 这是用户登录功能
     * 
     * @param username
     *            用户名
     * @param password
     *            密码
     * @return 返回登录是否成功
     */
    public abstract boolean isLogin(String username, String password);

    /**
     * 这是用户注册功能
     * 
     * @param user
     *            要注册的用户信息
     */
    public abstract void regist(User user);
}


  • 第三步:添加cn.itcast.dao.impl包
import java.util.ArrayList;
import cn.itcast.dao.UserDao;
import cn.itcast.pojo.User;

/**
 * 这是用户操作的具体实现类(集合版)
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public class UserDaoImpl implements UserDao {
    // 为了让多个方法能够使用同一个集合,就把集合定义为成员变量
    // 为了不让外人看到,用private
    // 为了让多个对象共享同一个成员变量,用static
    private static ArrayList<User> array = new ArrayList<User>();

    @Override
    public boolean isLogin(String username, String password) {
        // 遍历集合,获取每一个用户,并判断该用户的用户名和密码是否和传递过来的匹配
        boolean flag = false;

        for (User u : array) {
            if (u.getUsername().equals(username)
                    && u.getPassword().equals(password)) {
                flag = true;
                break;
            }
        }

        return flag;
    }

    @Override
    public void regist(User user) {
        // 把用户信息存储集合
        // ArrayList<User> array = new ArrayList<User>();
        array.add(user);
    }
}


  • 第四步:添加cn.itcast.test包
import java.util.Scanner;

import cn.itcast.dao.UserDao;
import cn.itcast.dao.impl.UserDaoImpl;
import cn.itcast.game.GuessNumber;
import cn.itcast.pojo.User;

/**
 * 用户测试类
 * 
 * @author 风清扬
 * @version V1.0
 * 
 *          新增加了两个小问题 A:多个对象共享同一个成员变量,用静态
 *          B:循环里面如果有switch,并且在switch里面有break,那么结束的不是循环,而是switch语句
 * 
 */
public class UserTest {
    public static void main(String[] args) {
        // 为了能够回来
        while (true) {
            // 欢迎界面,给出选择项
            System.out.println("--------------欢迎光临--------------");
            System.out.println("1 登录");
            System.out.println("2 注册");
            System.out.println("3 退出");
            System.out.println("请输入你的选择:");
            // 键盘录入选择,根据选择做不同的操作
            Scanner sc = new Scanner(System.in);
            // 为了后面的录入信息的方便,我所有的数据录入全部用字符接收
            String choiceString = sc.nextLine();

            // switch语句的多个地方要使用,我就定义到外面
            UserDao ud = new UserDaoImpl();

            // 经过简单的思考,我选择了switch
            switch (choiceString) {
            case "1":
                // 登录界面,请输入用户名和密码
                System.out.println("--------------登录界面--------------");
                System.out.println("请输入用户名:");
                String username = sc.nextLine();
                System.out.println("请输入密码:");
                String password = sc.nextLine();

                // 调用登录功能
                // UserDao ud = new UserDaomImpl();

                boolean flag = ud.isLogin(username, password);
                if (flag) {
                    System.out.println("登录成功,可以开始玩游戏了");

                    System.out.println("你玩吗?y/n");
                    while (true) {
                        String resultString = sc.nextLine();
                        if (resultString.equalsIgnoreCase("y")) {
                            // 玩游戏
                            GuessNumber.start();
                            System.out.println("你还玩吗?y/n");
                        } else {
                            break;
                        }
                    }
                    System.out.println("谢谢使用,欢迎下次再来");
                    System.exit(0);
                    // break; //这里写break,结束的是switch
                } else {
                    System.out.println("用户名或者密码有误,登录失败");
                }
                break;
            case "2":
                // 欢迎界面,请输入用户名和密码
                System.out.println("--------------注册界面--------------");
                System.out.println("请输入用户名:");
                String newUsername = sc.nextLine();
                System.out.println("请输入密码:");
                String newPassword = sc.nextLine();

                // 把用户名和密码封装到一个对象中
                User user = new User();
                user.setUsername(newUsername);
                user.setPassword(newPassword);

                // 调用注册功能
                // 多态
                // UserDao ud = new UserDaoImpl();
                // 具体类使用
                // UserDaoImpl udi = new UserDaoImpl();

                ud.regist(user);
                System.out.println("注册成功");
                break;
            case "3":
            default:
                System.out.println("谢谢使用,欢迎下次再来");
                System.exit(0);
                break;
            }
        }
    }
}


  • 第五步:添加cn.itcast.game包
import java.util.Scanner;

/**
 * 这是猜数字小游戏
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public class GuessNumber {
    private GuessNumber() {
    }

    public static void start() {
        // 产生一个随机数
        int number = (int) (Math.random() * 100) + 1;

        // 定义一个统计变量
        int count = 0;

        while (true) {
            // 键盘录入一个数据
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入数据(1-100):");
            int guessNumber = sc.nextInt();

            count++;

            // 判断
            if (guessNumber > number) {
                System.out.println("你猜的数据" + guessNumber + "大了");
            } else if (guessNumber < number) {
                System.out.println("你猜的数据" + guessNumber + "小了");
            } else {
                System.out.println("恭喜你," + count + "次就猜中了");
                break;
            }
        }
    }
}

Set接口

Set接口概述

  • 一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1e2,并且最多包含一个 null 元素。
  • 存储顺序与取出顺序不一致。

Set案例

  • 存储字符串并遍历
import java.util.HashSet;
import java.util.Set;

/*
 * Collection
 *         |--List
 *             有序(存储顺序和取出顺序一致),可重复
 *         |--Set
 *             无序(存储顺序和取出顺序不一致),唯一
 * 
 * HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
 * 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,
 * 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。
 */

public class SetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        Set<String> set = new HashSet<String>();

        // 创建并添加元素
        set.add("hello");
        set.add("java");
        set.add("world");
        set.add("java");
        set.add("world");

        // 增强for
        for (String s : set) {
            System.out.println(s);
        }
    }
}


HashSet类

HashSet类概述

  • 不保证 set 的迭代顺序
  • 特别是它不保证该顺序恒久不变。
  • HashSet如何保证元素唯一性
    • 底层数据结构是哈希表(元素是链表的数组)
    • 哈希表依赖于哈希值存储
    • 添加功能底层依赖两个方法:
      • int hashCode()
      • boolean equals(Object obj)
HashSet集合的add()方法的原码解析
interface Collection {
    ...
}

interface Set extends Collection {
    ...
}

class HashSet implements Set {
    private static final Object PRESENT = new Object();
    private transient HashMap<E,Object> map;
    
    public HashSet() {
        map = new HashMap<>();
    }
    
    public boolean add(E e) { //e=hello,world
        return map.put(e, PRESENT)==null;
    }
}

class HashMap implements Map {
    public V put(K key, V value) { //key=e=hello,world
    
        //看哈希表是否为空,如果空,就开辟空间
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }

        //判断对象是否为null
        if (key == null)
            return putForNullKey(value);

        int hash = hash(key); //和对象的hashCode()方法相关

        //在哈希表中查找hash值
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            //这次的e其实是第一次的world
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
                //走这里其实是没有添加元素
            }
        }

        modCount++;
        addEntry(hash, key, value, i); //把元素添加
        return null;
    }

    transient int hashSeed = 0;

    final int hash(Object k) { //k=key=e=hello,
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode(); //这里调用的是对象的hashCode()方法

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}


hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");


HashSet 存储字符串并遍历
import java.util.HashSet;

/*
 * HashSet:存储字符串并遍历
 * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
 * 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。
 * 步骤:
 *         首先比较哈希值
 *         如果相同,继续走,比较地址值或者走equals()
 *         如果不同,就直接添加到集合中    
 * 按照方法的步骤来说:    
 *         先看hashCode()值是否相同
 *             相同:继续走equals()方法
 *                 返回true:    说明元素重复,就不添加
 *                 返回false:说明元素不重复,就添加到集合
 *             不同:就直接把元素添加到集合
 * 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。
 * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
 */
public class HashSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        HashSet<String> hs = new HashSet<String>();

        // 创建并添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");

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


存储对象元素并遍历
  • Student类不再写,注意添加hashCode和equals方法。

  • 哈希表结构



  • HashSetDemo类

import java.util.HashSet;

/*
 * 需求:存储自定义对象,并保证元素的唯一性
 * 要求:如果两个对象的成员变量值都相同,则为同一个元素。
 * 
 * 目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。
 * 而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。
 * 这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。
 */
public class HashSetDemo2 {
    public static void main(String[] args) {
        // 创建集合对象
        HashSet<Student> hs = new HashSet<Student>();

        // 创建学生对象
        Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("柳岩", 22);
        Student s3 = new Student("王祖贤", 30);
        Student s4 = new Student("林青霞", 27);
        Student s5 = new Student("林青霞", 20);
        Student s6 = new Student("范冰冰", 22);

        // 添加元素
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);
        hs.add(s6);

        // 遍历集合
        for (Student s : hs) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}


LinkedHashSet类

LinkedHashSet类概述

  • 元素有序唯一
  • 链表保证元素有序
  • 哈希表保证元素唯一
import java.util.LinkedHashSet;

/*
 * LinkedHashSet:底层数据结构由哈希表和链表组成。
 * 哈希表保证元素的唯一性。
 * 链表保证元素有序。(存储和取出是一致)
 */
 
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        LinkedHashSet<String> hs = new LinkedHashSet<String>();

        // 创建并添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");
        hs.add("java");

        // 遍历
        for (String s : hs) {
            System.out.println(s);
        }
    }
}


TreeSet类

TreeSet类概述

  • 使用元素的自然顺序对元素进行排序

  • 或者根据**创建 set 时提供的 Comparator **进行排序

  • 具体取决于使用的构造方法

  • TreeSet是如何保证元素的排序和唯一性的

    • 底层数据结构是红黑树(红黑树是一种自平衡的二叉树)
  • TreeSet集合保证元素排序和唯一性的原理

    • 唯一性:是根据比较的返回是否是0来决定。
    • 排序:
      • A:自然排序(元素具备比较性)
        • 让元素所属的类实现自然排序接口 Comparable
      • B:比较器排序(集合具备比较性)
        • 让集合的构造方法接收一个比较器接口的子类对象 Comparator

TreeSet的add()方法

interface Collection {...}

interface Set extends Collection {...}

interface NavigableMap {

}

class TreeMap implements NavigableMap {
     public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
}

class TreeSet implements Set {
    private transient NavigableMap<E,Object> m;
    
    public TreeSet() {
         this(new TreeMap<E,Object>());
    }

    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
}

真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。
所以,你要想重写该方法,就必须实现 Comparable接口。这个接口表示的就是自然排序。


TreeSet 案例

TreeSet自然排序
import java.util.TreeSet;

/*
 * TreeSet:能够对元素按照某种规则进行排序。
 * 排序有两种方式
 * A:自然排序
 * B:比较器排序
 * 
 * TreeSet集合的特点:排序和唯一
 * 
 * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        // 自然顺序进行排序
        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 i : ts) {
            System.out.println(i);
        }
    }
}


TreeSet 存储自定义对象
  • Eg1:
/*
 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
 */
public class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student() {
        super();
    }

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    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 int compareTo(Student s) {
        // return 0 相等;
        // return 1 大于;
        // return -1小于;

        // 这里返回什么,其实应该根据我的排序规则来做
        // 按照年龄排序,主要条件
        int num = this.age - s.age;
        // 次要条件
        // 年龄相同的时候,还得去看姓名是否也相同
        // 如果年龄和姓名都相同,才是同一个元素
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }
}
import java.util.TreeSet;

/*
 * TreeSet存储自定义对象并保证排序和唯一。
 * 
 * A:你没有告诉我们怎么排序
 *      自然排序,按照年龄从小到大排序
 * B:元素什么情况算唯一你也没告诉我
 *      成员变量值都相同即为同一个元素
 */
public class TreeSetDemo2 {
    public static void main(String[] args) {
        // 创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>();

        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);

        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}


  • Eg2:
//学生类,除此方法其他与上相同。测试类遍历方法也与上相同。
    @Override
    public int compareTo(Student s) {
        // 主要条件 姓名的长度
        int num = this.name.length() - s.name.length();
        // 姓名的长度相同,不代表姓名的内容相同
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
        int num3 = num2 == 0 ? this.age - s.age : num2;
        return num3;
    }


TreeSet比较器排序
  • TreeSetDemo类
import java.util.Comparator;
import java.util.TreeSet;

/*
 * 需求:请按照姓名的长度排序
 * 
 * TreeSet集合保证元素排序和唯一性的原理
 * 唯一性:是根据比较的返回是否是0来决定。
 * 排序:
 *      A:自然排序(元素具备比较性)
 *          让元素所属的类实现自然排序接口 Comparable
 *      B:比较器排序(集合具备比较性)
 *          让集合的构造方法接收一个比较器接口的子类对象 Comparator
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
        // public TreeSet(Comparator comparator) //比较器排序
        // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
        
        // 方法一:TreeSet<Student> ts = new TreeSet<Student>(new MyComparator())
        // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
        // 而匿名内部类就可以实现这个东西
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 姓名长度
                int num = s1.getName().length() - s2.getName().length();
                // 姓名内容
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
                        : num;
                // 年龄
                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
                return num3;
            }
        });

        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);
        Student s8 = new Student("linqingxia", 29);

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);

        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
  • Student类不需要改动。

  • MyComparator类

package cn.itcast_07;

import java.util.Comparator;

public class MyComparator implements Comparator<Student> {

    @Override
    public int compare(Student s1, Student s2) {
        // int num = this.name.length() - s.name.length();
        // this -- s1
        // s -- s2
        // 姓名长度
        int num = s1.getName().length() - s2.getName().length();
        // 姓名内容
        int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
        // 年龄
        int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
        return num3;
    }

}


Set集合练习

练习1
  • 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
import java.util.HashSet;
import java.util.Random;

/*
 * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
 * 
 * 分析:
 *      A:创建随机数对象
 *      B:创建一个HashSet集合
 *      C:判断集合的长度是不是小于10
 *          是:就创建一个随机数添加
 *          否:不搭理它
 *      D:遍历HashSet集合
 */
public class HashSetDemo {
    public static void main(String[] args) {
        // 创建随机数对象
        Random r = new Random();

        // 创建一个Set集合
        HashSet<Integer> ts = new HashSet<Integer>();

        // 判断集合的长度是不是小于10
        while (ts.size() < 10) {
            int num = r.nextInt(20) + 1;
            ts.add(num);
        }

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


练习2
  • 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
    • Student类
    public class Student {
    // 姓名
    private String name;
    // 语文成绩
    private int chinese;
    // 数学成绩
    private int math;
    // 英语成绩
    private int english;
    
    public Student(String name, int chinese, int math, int english) {
        super();
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
    }
    
    public Student() {
        super();
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getChinese() {
        return chinese;
    }
    
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }
    
    public int getMath() {
        return math;
    }
    
    public void setMath(int math) {
        this.math = math;
    }
    
    public int getEnglish() {
        return english;
    }
    
    public void setEnglish(int english) {
        this.english = english;
    }
    
    public int getSum() {
        return this.chinese + this.math + this.english;
    }
    

}

```
* TreeSetDemo类
```java
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

/*
 * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
 * 
 * 分析:
 *      A:定义学生类
 *      B:创建一个TreeSet集合
 *      C:总分从高到底如何实现呢?      
 *      D:键盘录入5个学生信息
 *      E:遍历TreeSet集合
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建一个TreeSet集合
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 总分从高到低
                int num = s2.getSum() - s1.getSum();
                // 总分相同的不一定语文相同
                int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
                // 总分相同的不一定数序相同
                int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
                // 总分相同的不一定英语相同
                int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
                // 姓名还不一定相同呢
                int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
                        : num4;
                return num5;
            }
        });

        System.out.println("学生信息录入开始");
        // 键盘录入5个学生信息
        for (int x = 1; x <= 5; x++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第" + x + "个学生的姓名:");
            String name = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的语文成绩:");
            String chineseString = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的数学成绩:");
            String mathString = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的英语成绩:");
            String englishString = sc.nextLine();

            // 把数据封装到学生对象中
            Student s = new Student();
            s.setName(name);
            s.setChinese(Integer.parseInt(chineseString));
            s.setMath(Integer.parseInt(mathString));
            s.setEnglish(Integer.parseInt(englishString));

            // 把学生对象添加到集合
            ts.add(s);
        }
        System.out.println("学生信息录入完毕");

        System.out.println("学习信息从高到低排序如下:");
        System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
        // 遍历集合
        for (Student s : ts) {
            System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
                    + s.getMath() + "\t" + s.getEnglish());
        }
    }
}

```


Collection集合总结

  • Collection
    • List 有序,可重复
      • ArrayList
        • 底层数据结构是数组查询快,增删慢
        • 线程不安全,效率高
      • Vector
        • 底层数据结构是数组查询快,增删慢
        • 线程安全,效率低
      • LinkedList
        • 底层数据结构是链表查询慢,增删快
        • 线程不安全,效率高
    • Set 无序,唯一
      • HashSet
        • 底层数据结构是哈希表
        • 如何保证元素唯一性的呢?
          • 依赖两个方法:hashCode()和equals()
          • 开发中自动生成这两个方法即可
        • LinkedHashSet
          • 底层数据结构是链表哈希表
          • 由链表保证元素有序
          • 由哈希表保证元素唯一
      • TreeSet
        • 底层数据结构是红黑树
        • 如何保证元素排序的呢?
          • 自然排序
          • 比较器排序
        • 如何保证元素唯一性的呢?
          • 根据比较的返回值是否是0来决定
  • 针对Collection集合我们到底使用谁呢?

    • 唯一吗?
      • 是:Set
        • 排序吗?
          • 是:TreeSet
          • 否:HashSet
        • 如果你知道是Set,但是不知道是哪个Set,就用HashSet
      • 否:List
        • 要安全吗?
          • 是:Vector
          • 否:ArrayList或者LinkedList
            • 查询多:ArrayList
            • 增删多:LinkedList
        • 如果你知道是List,但是不知道是哪个List,就用ArrayList
    • 如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
    • 如果你知道用集合,就用ArrayList。
  • 在集合中常见的数据结构(掌握)

    • ArrayXxx:底层数据结构是数组查询快,增删慢
    • LinkedXxx:底层数据结构是链表查询慢,增删快
    • HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()equals()
    • TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序比较器排序
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,587评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,795评论 0 11
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,046评论 0 4
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,214评论 0 2
  • 导读:事实上,麻醉的历史非常久远,伴随着人类社会的发展走到今天,人们为了缓解疼痛使出了各种办法。 大约20年前,当...
    岚逸筠篁阅读 1,214评论 0 5