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);
}
}
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 = s2.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 = s2.getSum() - s1.getSum();
但是之前是这样的
int num = s1.getSum() - s2.getSum();
运行如下
成绩并没有从高到低,所以
int num = s2.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:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序