再新建一個包 cn.itcast.dao.impl
============分割線=================
package 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
UserTest.java

==========分割線====================
package 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,而且是
JDK1.7以及以后才能用,因為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;
}
}
}
}
===============分割線===================
3.Set集合概述及特點
Collection
* |--List
* 有序(存儲順序和取出順序一致),可重復
* |--Set
*
無序(存儲順序和取出順序不一致),
唯一
*
* HashSet:它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。
* 注意:雖然Set集合的元素無序,但是,作為集合來說,它肯定有它自己的存儲順序,
* 而你的順序恰好和它的存儲順序一致,這代表不了有序,你可以多存儲一些數據,就能看到效果。
4.HashSet集合的add()方法的
源碼以及解析
HashSet:存儲字符串並遍歷
* 問題:為什么
存儲字符串的時候,
字符串內容相同的只存儲了一個呢?
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");
總結:通過查看add方法的源碼,我們知道這個方法底層依賴 兩個方法:hashCode()和equals()。
* 步驟:
* 首先比較哈希值
* 如果相同,繼續走,比較地址值或者走equals()
* 如果不同,就直接添加到集合中
* 按照方法的步驟來說:
* 先看hashCode()值是否相同
* 相同:繼續走equals()方法
* 返回true: 說明元素重復,就不添加
* 返回false:說明元素不重復,就添加到集合
* 不同:就直接把元素添加到集合
*
如果類沒有重寫這兩個方法,默認使用的Object()。一般來說不會相同。
*
而String類重寫了hashCode()和equals()方法,所以,它就可以把內容相同的字符串去掉。只留下一個。
以下兩個重寫都在學生類Student類中修改
重寫hashCode方法
重寫equals方法

需要手動重寫的代碼如下
@Override
public int hashCode() {
// return 0;
//
因為成員變量值影響了哈希值,所以我們把成員變量值相加即可
// return this.name.hashCode() + this.age;
// 看下面
// s1:name.hashCode()=40,age=30
// s2:name.hashCode()=20,age=50
// 盡可能的
區分,我們可以把它們乘以一些整數(乘上整數
擴大分差把細微差別放大避免偶爾誤差)
return this.name.hashCode()
+ this.age
* 15;
}
@Override
public boolean equals(Object obj) {
//
System.out.println(this + "---" + obj);//測試比較順序以及比較次數的代碼,測試后注釋掉
if (this == obj) {
return true;
}
if (!(obj
instanceof Student)) {
return false;
}
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
優化測試截圖(優化前hashCode默認返回值是0.也就是所有的元素哈希值都一樣)
優化前,比較次數比較大
優化后(哈希值不再一樣,通過哈希值與成員變量相加來重寫hashCode方法避免不必要的比較)

但實際上,一般不自己想寫這么麻煩,可以用代碼自動生成功能來實現


以后解決HashSet 存儲自定義對象時元素不唯一問題就可以用重寫hashCode()方法和equals()方法解決


5.HashSet集合存儲自定義對象並遍歷
注意了:
* 你使用的是HashSet集合,這個集合的底層是哈希表結構。
* 而哈希表結構底層依賴:hashCode()和equals()方法。
* 如果你認為對象的成員變量值相同即為同一個對象的話,你就應該重寫這兩個方法。
* 如何重寫呢?不同擔心,自動生成即可。
import java.util.HashSet;
public class DogDemo {
public static void main(String[] args) {
HashSet<Dog> hs = new HashSet<Dog>();
Dog d1 = new Dog("網", 27, "綠色", '男');
Dog d2 = new Dog("隨", 27, "綠色", '男');
Dog d3 = new Dog("王", 27, "綠色", '男');
Dog d4 = new Dog("網", 27, "綠色", '男');
Dog d5 = new Dog("網", 27, "綠色", '女');
hs.add(d1);
hs.add(d2);
hs.add(d3);
hs.add(d4);
hs.add(d5);
for (Dog d : hs) {
System.out.println(d.getName() + "---" + d.getAge() + "---" + d.getColor() + "---" + d.getSex());
}
}
}
Dog類
public class Dog {
private String name;
private int age;
private String color;
private char sex;
public Dog() {
super();
// TODO Auto-generated constructor stub
}
public Dog(String name, int age, String color, char sex) {
super();
this.name = name;
this.age = age;
this.color = color;
this.sex = sex;
}
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;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + sex;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (age != other.age)
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sex != other.sex)
return false;
return true;
}
}
6.TreeSet
TreeSet:能夠對元素按照某種規則進行排序。
排序有兩種方式
* A:自然排序
* B:比較器排序
*
* TreeSet集合的特點:排序和唯一
*
* 通過觀察TreeSet的add()方法,我們知道最終要看TreeMap的put()方法。
7.
TreeSet保證元素排序的源碼解析
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保證元素唯一性和自然排序的原理和圖解
7.TreeSet存儲自定義對象並遍歷練習1
下面貼代碼
TreeSetDemo2.java
===============分割線===================
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());
}
}
}
==============分割線==============
Student類
Student.java
==============分割線==============
/*
*
如果一個類的元素要想能夠進行自然排序,就必須實現自然排序接口
*/
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;
// 次要條件
//
年齡相同的時候,還得去看姓名是否也相同
// 如果年齡和姓名都相同,才是同一個元素
//String
默認已經實現了Comparable接口,所以可以大膽用compareTo方法
int num2 = num == 0 ? this.name.
compareTo(s.name) : num;
return num2;
}
}
下面是以上代碼的解析。
附:A:首先解析以下這行代碼
int num2 = num == 0 ?
this.name.
compareTo(
s.name) : num;
解:這行語句是三目運算符,意思是先比較主要條件---年齡,num為年齡比較產生的返回值,如果是零就不插入二叉樹(TreeSet)中(通過比較發現年齡重復就不添加),如果此時直接返回num的話會造成Student對象的意外丟失(例如年齡相同但實際上姓名不相同的學生對象),
因此為了解決這個問題,新添加了num2,考慮多了次要條件姓名,如果年齡相同的同時姓名也相同就返回num2的值0,代表不添加元素到二叉樹中。
B:String
默認已經實現了Comparable接口
C:為什么要在自定義類Student中實現Comparable接口呢?(implements Comparable<T>)
如果不實現這個接口,運行如下
查API
由上圖可知:實現這個借口
是為了進行自然排序。Student類默認並沒有實現Comparable接口
Comparable接口 只有一個compareTo方法,實現接口時需要重寫這個方法
8.TreeSet存儲自定義對象並遍歷練習2
先貼代碼
==============分割線=======================
import java.util.TreeSet;
/*
* 需求:請按照姓名的長度排序
*/
public class TreeSetDemo {
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);//s1與s3名字長度相同
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類
/*
*
如果一個類的元素要想能夠進行自然排序,就必須實現自然排序接口
*/
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) {
// 主要條件 姓名的長度
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;
}
}
留意看上面stuedent類中的compareTo方法,雖然需求中只說明了按照姓名的長度排序,但是
隱含的比較,隱含的條件(如姓名的內容,年齡是否相同)卻是不能忽略的!
9.TreeSet保證元素唯一性和
比較器排序的原理及代碼實現
TreeSet集合保證元素排序和唯一性的原理
*
唯一性:是根據比較的返回是否是0來決定。
* 排序:
* A:自然排序(元素具備比較性)
* 讓元素所屬的類實現自然排序接口 Comparable
* B:
比較器排序(集合具備比較性)
* 讓集合的構造方法接收一個
比較器接口的子類對象 Comparator
查API-----TreeSet 比較器排序 帶參構造方法

首先,慣例新建一個TreeSetDemo
=========分割線==========
import java.util.Comparator;
import java.util.TreeSet;
/*
* 需求:請按照姓名的長度排序
*/
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());
// 創建元素
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類
================分割線======================
public class 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;
}
}
================分割線================
最后,同一個包下定義一個MyComparator類

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;
}
}
以下為一些解析說明
A:上面專門定義了一個類MyComparator,其實也可以省略這一個類,直接在TreeSetDemo測試類中定義
一個匿名內部類
如下
TreeSetDemo.java
=================分割線========================
import java.util.Comparator;
import java.util.TreeSet;
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 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());
}
}
}
===============分割線=======================
B:在MyComparator類 中getName(),getAge()與this.name 和this.age 問題
外部類不能訪問private修飾的成員變量
C:注意兩個不同的接口以及它們的方法
接口 Comparable======方法compareTo
接口 Comparator ==== 方法compare
* TreeSet集合保證元素排序和唯一性的原理
* 唯一性:是根據比較的
返回是否是0來決定。
* 排序:
* A:
自然排序(
元素具備比較性)(Student類實現比較接口)
* 讓元素所屬的類實現自然排序接口 Comparable
* B:
比較器排序(
集合具備比較性)(也就是說,Student類不需要實現任何接口)
* 讓集合的構造方法接收一個比較器接口的子類對象 Comparator
10.一個案例----編寫一個程序,獲取
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>();//Integer默認已經實現了比較接口
Comparable
// 判斷集合的長度是不是小於10
while (ts.size() < 10) {
int num = r.nextInt(20) + 1;
ts.add(num);
}
// 遍歷Set集合
for (Integer i : ts) {
System.out.println(i);
}
}
}
11.一個案例----鍵盤錄入5個學生信息(姓名,語文成績,數學成績,英語成績),按照總分從高到低輸出到控制台
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 = s
2.getSum() -
s1.getSum();//s1與s2的位置已互換,因為成績從高到低而不是默認的從低到高
// 總分相同的不一定語文相同
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());
}
}
}
===================================================
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;
}
}
======================================
附上解析:
int num = s
2.getSum() -
s1.getSum();
但是之前是這樣的
int num = s
1.getSum() -
s2.getSum();
運行如下

成績並沒有從高到低,所以
int num = s
2.getSum() -
s1.getSum();
再次運行

12.最后附上一個致命bug 關於eclipse:
eclispe 控制台光標位置bug
Eclipse控制台輸入數據后光標直接回到行首不跳到下一行

留意光標位置,要手動移動至下一行
day17筆記補充
A:Collection集合總結(掌握)
Collection
|--List 有序,可重復
|--ArrayList
底層數據結構是數組,查詢快,增刪慢。
線程不安全,效率高
|--Vector
底層數據結構是數組,查詢快,增刪慢。
線程安全,效率低
|--LinkedList
底層數據結構是鏈表,查詢慢,增刪快。
線程不安全,效率高
|--Set 無序,唯一
|--HashSet
底層數據結構是哈希表。
如何保證元素唯一性的呢?
依賴兩個方法:hashCode()和equals()
開發中自動生成這兩個方法即可
|--LinkedHashSet
底層數據結構是鏈表和哈希表
由鏈表保證元素有序
由哈希表保證元素唯一
|--TreeSet
底層數據結構是紅黑樹。
如何保證元素排序的呢?
自然排序
比較器排序
如何保證元素唯一性的呢?
根據比較的返回值是否是0來決定
B:針對Collection集合我們到底使用誰呢?(掌握)
唯一嗎?
是:Set
排序嗎?
是:TreeSet
否:HashSet
如果你知道是Set,但是不知道是哪個Set,就用HashSet。
否:List
要安全嗎?
是:Vector
否:ArrayList或者LinkedList
查詢多:ArrayList
增刪多:LinkedList
如果你知道是List,但是不知道是哪個List,就用ArrayList。
如果你知道是Collection集合,但是不知道使用誰,就用ArrayList。
如果你知道用集合,就用ArrayList。
C:在集合中常見的數據結構(掌握)
ArrayXxx:底層數據結構是數組,查詢快,增刪慢
LinkedXxx:底層數據結構是鏈表,查詢慢,增刪快
HashXxx:底層數據結構是哈希表。依賴兩個方法:hashCode()和equals()
TreeXxx:底層數據結構是二叉樹。兩種方式排序:自然排序和比較器排序