泛型通配符
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
向下限定,E及其子类
? super E
向上限定,E及其父类
父类Animal
public class Animal {
}
子类Dog
public class Dog extends Animal {
}
子类Cat
public class Cat extends Animal {
}
import java.util.ArrayList;
public class GenericDemo1 {
public static void main(String[] args) {
ArrayList<Animal> list1 = new ArrayList<Animal>();
ArrayList<Dog> list2 = new ArrayList<Dog>();
ArrayList<Cat> list3 = new ArrayList<Cat>();
//泛型通配符<?>
//任意类型,如果没有明确,那么就是Object以及任意的Java类了
ArrayList<?> list = new ArrayList<Animal>();
ArrayList<?> list4 = new ArrayList<Dog>();
ArrayList<?> list5= new ArrayList<Cat>();
//? super E 向上限定,E及其父类
ArrayList<?super Animal> list6 = new ArrayList<Animal>();
ArrayList<? super Animal> list7 = new ArrayList<Object>();
// ArrayList<? super Animal> list11 = new ArrayList<Dog>();会报错
//? extends E 向下限定,E及其子类
ArrayList<? extends Animal> list8 = new ArrayList<Animal>();
ArrayList<? extends Animal> list9 = new ArrayList<Dog>();
ArrayList<? extends Animal> list10 = new ArrayList<Cat>();
// ArrayList<? extends Animal> list11 = new ArrayList<Object>();会报错
}
}
泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…> 注意:泛型类型必须是引用类型 这里的<>里面的内容仅仅表示的使一种参数数据类型,参数类型是一种变量 既然是一种变量,就要符合变量的命名规则,可以使任意符合标识符起名字规则的名字。 一般情况下,在定义的时候,习惯用一个大写字母表示。
public class GenericTool1 <T>{
private T obj;
public T getObj(){
return obj;
}
public void setObj(T obj){
this.obj=obj;
}
}
测试类:
public class GenericTest1 {
public static void main(String[] args) {
//如果不加泛型,默认使Object类型
// GenericTool1 gt1=new GenericTool1();
// gt1.setObj("hello");
// gt1.setObj("20");
// gt1.setObj("3.1415");
GenericTool1<String> gt2 = new GenericTool1<>();
gt2.setObj("hell0");
// gt2.setObj(20);会报错
String obj=gt2.getObj();
}
}
泛型方法
把泛型定义在方法上
格式:public 返回类型 方法名(泛型类型 .)
public class GenericTool2 {
// public void show(String s) {
// System.out.println(s);
// }
//
// public void show(int i) {
// System.out.println(i);
//
// }
//
// public void show(double j) {
// System.out.println(j);
// }
//用泛型方法改进,因为将来不确定要传入什么类型的数据
public <F>void show(F f){
System.out.println(f);
}
}
测试类:
public class GenericTest2 {
public static void main(String[] args){
GenericTool2 genericTool2 = new GenericTool2();
genericTool2.show("herllo");
genericTool2.show(10);
genericTool2.show(3.1415);
}
}
泛型接口
把泛型定义在接口上
格式:public interface 接口名
接口类
public interface GenericTool3<W> {
public abstract void show(W w);
}
public class Genericlmpl<W> implements GenericTool3<W> {
@Override
public void show(W w) {
System.out.println(w);
}
}
public class GenericTest3 {
public static void main(String[] args) {
Genericlmpl<String> stringGenericlmpl = new Genericlmpl<>();
stringGenericlmpl.show("hello");
// stringGenericlmpl.show(20);会报错
}
}
结果:
hello
JDK1.5之后出现的新特性:
到目前为止,学过哪些知识使JDK1.5之后出现的?
泛型,增强for,包装类,Scanner,枚举
增强for循环概述:简化数组和Collection集合的遍历
语句定义格式:
for(元素数据类型 变量名(自定义) : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
好处:简化遍历
import java.util.ArrayList;
import java.util.ListIterator;
public class ForDemo {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
for (int i=0;i< arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("使用增强for循环遍历数组");
for (int num:arr){
System.out.println(num);
}
System.out.println("================================");
ArrayList<String> strings = new ArrayList<>();
strings.add("hello");
strings.add("world");
strings.add("java");
strings.add("bigdata");
strings.add("hadoop");
for (String string :strings){
System.out.println(string);
}
//我们应该在遍历之前判断一下是不是null
if (strings!=null){
for (String string :strings){
System.out.println(string);
}
}else {
System.out.println("该集合为空");
}
//其实增强for循环就是用来替代迭代器的
//怎么去验证它就是用来替代迭代器的呢?
//使用并发修改异常去验证
// for (String s:strings){
// //ConcurrentModificationException
// if ("java".equals(s)){
// strings.add("spark");
// }
// }
ListIterator<String> stringListIterator = strings.listIterator();
while (stringListIterator.hasNext()){
String next = stringListIterator.next();
if ("java".equals(next)){
stringListIterator.add("spark");
}
}
System.out.println(strings);
}
}
静态导入:
语句定义格式:import static 包名...类名.方法名;
可以直接导入到方法级别
注意事项: 1、方法必须是静态的
public class StaticClass {
public static void fun() {
System.out.println(" 数家科技");
}
public static void show(String s){
System.out.println(s);
}
}
import static Days19.StaticClass.fun;
import static Days19.StaticClass.show;
import static java.lang.Math.abs;
import static java.lang.Math.pow;
public class StaticImportDemo {
public static void main(String[] args) {
// System.out.println(abs(-100));
// System.out.println(Math.pow(2,3));
// System.out.println(Math.max(1100,200));
//有没有什么方法,不同写类名,直接写方法名?
// System.out.println(abs(-200));
//这时候,就需要静态导入的技术
System.out.println(abs(-200));
System.out.println(pow(2, 4));
fun();
//当静态导入的方法名与本类中的方法名冲突的时候,调用的是本类中的方法
show("spark");
//如果此时我就是想使用静态导入的方法,怎么办?就是还想调用StaticClass种的方法
//将前缀路径写完整
Days19.StaticClass.show("flink");
}
public static void show(String s) {
System.out.println("这是本类中的show方法");
}
}
结果:
200
16.0
数家科技
这是本类中的show方法
flink
可变参数概述
定义方法的时候不知道该定义多少个参数
格式
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意:
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个
Arrays工具类中的一个方法 public static <T> List<T> asList(T... a)
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ArgsDemo {
public static void main(String[] args) {
//使用方法求两个数之和
int a = 10;
int b = 20;
sum(a, b);
//使用方法求三个数之和
int a1 = 10;
int b1 = 20;
int c2 = 30;
sum(a, b, c2);
sum("小明", 20, 56, 78, 90);
//数组--->List(ArrayList)集合
List<String> strings = Arrays.asList("hello", "world", "java", "bigdata");
{
for (String s : strings) {
System.out.println(s);
}
}
}
// public static void sum(int a,int b){
// System.out.println("两个数之和为:"+(a+b));
// }
// public static void sum(int a1,int b1,int c1){
// System.out.println("三个数之和为:"+(a1+b1+c1));
// }
//使用可变参数的形式定义加法的方法
//注意可变参数的变量最终是一个数组的变量名
//这里将来传入多个参数的时候,内部会自动将这多个参数形成一个数组,数组名就是我们定义的ints
public static void sum(int... ints) {
int sum = 0;
for (int i : ints) {
sum += i;
}
System.out.println(sum);
}
//当使用可变参数定义方法时候,有其他数据类型参与的时候,将可变参数的定义放在最后
public static void sum(String s, int... ints) {
int sum = 0;
for (int i : ints) {
sum += i;
}
System.out.println(sum);
}
//同一个方法定义中,可变参数只能出现一次
// public static void sum(int... ints1,int... ints2){
//
// }会提示错误
}
集合的嵌套遍历
需求:目前,数加学院有十五期,十六期。每一期有很多学生,每个学生都是一个学生对象
可以用一个集合表示一个班的学生
十五期的学生:ArrayList classList15;
十六期的学生:ArrayList classList16;
无论是十五也好还是十六期,都是属于数加学院的班级
数加学院本身也可以通过集合表示:ArrayList> shujia;
这样的现象叫做集合嵌套
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.ArrayList;
import java.util.Iterator;
public class ListQianTaoTest {
public static void main(String[] args) {
//定义一个十五期的班级集合
ArrayList<Student> ClassList15 = new ArrayList<>();
//定义一个十六期的班级集合
ArrayList<Student> ClassList16 = new ArrayList<>();
//定义一个学院集合
ArrayList<ArrayList<Student>> xueyuan = new ArrayList<>();
//将15,16,期加入到集合中
xueyuan.add(ClassList15);
xueyuan.add(ClassList16);
//创建15期对象
Student s1 = new Student("小名", 21);
Student s2 = new Student("小白", 22);
Student s3 = new Student("小黄", 26);
Student s4 = new Student("小黑", 20);
//创建16期对象
Student s5 = new Student("小蓝", 19);
Student s6 = new Student("小红", 21);
Student s7 = new Student("小紫", 22);
Student s8 = new Student("小光", 28);
//将15期的学生对象添加到十五集合中
ClassList15.add(s1);
ClassList15.add(s2);
ClassList15.add(s3);
ClassList15.add(s4);
//将16期的学生对象添加到十六集合中
ClassList16.add(s5);
ClassList16.add(s6);
ClassList16.add(s7);
ClassList16.add(s8);
//遍历
//增强for循环遍历
for (ArrayList<Student> a : xueyuan) {
System.out.println(xueyuan);
for (Student S : a) {
System.out.println(S);
}
}
for (int i = 0; i < xueyuan.size(); i++) {
if (i == 0) {
System.out.println("=============十五期:===================");
for (int j = 0; j < xueyuan.get(i).size(); j++) {
Student student = xueyuan.get(i).get(j);
System.out.println(student);
}
} else if (i == 1) {
System.out.println("=============十六期:===================");
for (int j = 0; j < xueyuan.get(i).size(); j++) {
Student student = xueyuan.get(i).get(j);
System.out.println(student);
}
}
}
System.out.println("========================================================");
//迭代器遍历
Iterator<ArrayList<Student>> iterator = xueyuan.iterator();
while (iterator.hasNext()){
ArrayList<Student> next = iterator.next();
Iterator<Student> iterator1 = next.iterator();
while (iterator1.hasNext()){
Student next1 = iterator1.next();
System.out.println(next1);
}
}
}
}
结果:
[[Student{name='小名', age=21}, Student{name='小白', age=22}, Student{name='小黄', age=26}, Student{name='小黑', age=20}], [Student{name='小蓝', age=19}, Student{name='小红', age=21}, Student{name='小紫', age=22}, Student{name='小光', age=28}]]
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
[[Student{name='小名', age=21}, Student{name='小白', age=22}, Student{name='小黄', age=26}, Student{name='小黑', age=20}], [Student{name='小蓝', age=19}, Student{name='小红', age=21}, Student{name='小紫', age=22}, Student{name='小光', age=28}]]
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}
=============十五期:===================
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
=============十六期:===================
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}
========================================================
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}
获取10个1-20之间的随机数,要求不能重复
1、由于我们不确定获取随机数的次数,长度不好确定,所以我们选择集合
2、随机数生成的方式:Random类:nextInt(int num): 左闭右开
import java.util.ArrayList;
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
//创建随机数对象
Random random = new Random();
//创建集合储存随机数
ArrayList<Integer> integers = new ArrayList<>();
//定义一个变量统计集合里是否有十个元素
int count=0;
while (count<10){
int i = random.nextInt(20)+1;
if (!integers.contains(i)){
integers.add(i);
count++;
}
}
System.out.println(integers);
}
}
结果(随机):
[16, 2, 6, 11, 1, 14, 7, 4, 15, 19]
键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
1、由于不知道输入多少次,所以用while循环进行输入
2、用集合存储数据
3、toArray()
4、Arrays.sort()
5、取最后一个元素就是最大值
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class ListTest {
public static void main(String[] args) {
//创建盘录入对像
Scanner scanner = new Scanner(System.in);
//创建集合对象
ArrayList<Integer> integers = new ArrayList<>();
boolean flag=true;
while (flag){
int i = scanner.nextInt();
if (i==0){
System.out.println("数据录入完毕");
flag=false;
}else {
integers.add(i);
}
}
Object[] objects = integers.toArray();
Arrays.sort(objects);
System.out.println("最大值为"+objects[objects.length-1]);
}
}
Set集合:元素是唯一的,并且元素的顺序是无序的集合
在Set集合中存储的元素为什么不会有重复的呢?
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
HashSet<String> set1 = new HashSet<>();
set1.add("hello");
set1.add("world");
set1.add("java");
set1.add("bigdata");
set1.add("hadoop");
set1.add("world");
set1.add("java");
set1.add("hello");
set1.add("spark");
set1.add("spark");
set1.add("hbase");
set1.add("flink");
set1.add("java");
set1.add("hello");
//遍历
for (String s:set1){
System.out.println(s);
}
}
}
结果:
flink
world
java
bigdata
spark
hello
hadoop
hbase
分析源码:
public interface Set extends Collection{
void add(E e);
}
class HashSet implements Set{
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
//E -- String
//e -- "hello"
return map.put(e, PRESENT)==null;
}
}
class HashMap{
//key -- "hello"
//value -- new Object()
public V put(K key, V value) {
//读到这里我们知道put方法一定是与元素类中的hashCode()方法有关
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) { //key -- hello
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// hash -- (h = key.hashCode()) ^ (h >>> 16)结合hashCode()计算出来的值
// key -- "hello"
// value -- new Object()
// onlyIfAbsent -- false
// evict -- true
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
//理解为哈希表存储的是一个一个的节点数组
Node<K,V>[] tab;
Node<K,V> p;
int n, i;
//判断哈希表是否初始化完毕,如果没有初始化,就在这一步初始化
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//根据元素的对象计算好的哈希值再进行一次计算,计算出的是该元素存储在哈希表中的位置
//如果该元素的位置是null,说明这个位置没有元素,可以进行存储,创建新的节点,存储元素
//分析到这一步,我们再次验证一个结论,元素存储的位置与元素类中hashCode()有关
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
//如果该元素的位置不是null,说明这个位置上已经有元素了,可以确定的是哈希值是一样的
//但是呢,我不能确定这两个元素就是同一个元素。
Node<K,V> e;
K k;
//先将存入元素的哈希值与该位置上的元素的哈希值进行比较
//如果哈希值都不一样,继续走判断instanceof
//如果哈希值都一样,会调用元素的equals(k)方法进行比较
//如果equals(k)方法比较的结果是false的话,继续向下执行最终会将元素添加到集合中或者不添加
//如果equals(k)方法比较的结果是true的话,表示哈希值和内容都一样,表示元素重复了
//就覆盖,从现象上来看,其实就是不赋值
//说到这里,我们就已经知道HashSet中add()方法实际上与hashCode()方法和equals()方法有关
//集合中会不会去重取决于元素类有没有重写hashCode()方法和equals()方法
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Student2类要重写equals方法
import java.util.Objects;
public class Student2 {
private String name;
private int age;
public Student2() {
}
public Student2(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student2 student2 = (Student2) o;
return age == student2.age && Objects.equals(name, student2.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
测试类
import java.util.HashSet;
public class SetDemo2 {
public static void main(String[] args) {
HashSet<Student2> student2s = new HashSet<>();
//创建学生对象
Student2 s1 = new Student2("小王", 18);
Student2 s2 = new Student2("小白", 17);
Student2 s3 = new Student2("小懒猫", 19);
Student2 s4 = new Student2("小王", 18);
//将学生对象添加到集合中
student2s.add(s1);
student2s.add(s2);
student2s.add(s3);
student2s.add(s4);
//遍历
for (Student2 s:student2s){
System.out.println(s);
}
}
}
结果:
Student{name='小王', age=18}
Student{name='小白', age=17}
Student{name='小懒猫', age=19}
public class HashSet implements Set
public class LinkedHashSet extends HashSet implements Set,
LinkedHashSet:
1、底层数据结构是哈希表和链表
2、哈希表保证元素的唯一
3、链表保证了元素的有序(存储和取出的顺序一致)
4、线程不安全,效率高
一般不会去用因为线程不安全
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> set1 = new LinkedHashSet<>();
//添加元素到集合
set1.add("hello");
set1.add("world");
set1.add("java");
set1.add("bigdata");
set1.add("hadoop");
set1.add("world");
set1.add("java");
set1.add("hello");
set1.add("spark");
set1.add("spark");
set1.add("hbase");
set1.add("flink");
set1.add("java");
set1.add("hello");
//遍历:
for (String s:set1){
System.out.println(s);
}
}
}
结果:
hello
world
java
bigdata
hadoop
spark
hbase
flink
TreeSet:元素唯一,元素可以按照某种规则进行排序
两种排序方式:
自然排序
比较器排序
A NavigableSet实现基于TreeMap 。
的元件使用其有序natural ordering ,或由Comparator集合创建时提供,这取决于所使用的构造方法。
为什么会进行去重以及排序呢?怎么排序呢?看源码。
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(20);
treeSet.add(18);
treeSet.add(24);
treeSet.add(23);
treeSet.add(88);
treeSet.add(16);
treeSet.add(12);
treeSet.add(18);
treeSet.add(20);
treeSet.add(23);
treeSet.add(1);
treeSet.add(2);
//遍历:
for (Integer i:treeSet){
System.out.println(i);
}
}
}
结果:
1
2
12
16
18
20
23
24
88
源码分析:
public abstract class AbstractCollection<E> implements Collection<E>{}
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E>{}
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>{
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
public TreeSet() {
this(new TreeMap<E,Object>());
}
public boolean add(E e) {
//E -- Integer
//e -- 20
return m.put(e, PRESENT)==null;
}
}
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>{
private transient Entry<K,V> root;
public TreeMap() {
comparator = null;
}
public V put(K key, V value) {
//key -- 20,18
//value -- new Object()
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; //0
Entry<K,V> parent; //null
// split comparator and comparable paths
//由于我们使用的是无参构造方法,comparator的值是null
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 {
//key -- 18
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
//向下转型
//要想这里可以顺利进行向下转型,元素的数据类型必须要实现Comparable接口
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;
}
}
图解:
存储学生对象并遍历
按照正常的写法,我们一运行就报错了
java.lang.ClassCastException:类转换异常
由于我们这里TreeSet创建的时候使用的是无参构造构造方法,走的是自然排序
而这里底层源码中有一步是向下转型的
Comparable k = (Comparable) key;
报错了
原因是我们Student3类没有实现Comparable接口,无法进行向下转型,所以报错了。
创建Student3类:
public class Student3 implements Comparable<Student3> {
private String name;
private int age;
public Student3() {
}
public Student3(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student3 o) {
// return 0;
// return 1;
// return -1;
//这里返回什么,应该是根据我们自己定义的规则来排序
//比如说我想在去重的前提下,按照年龄进行排序。
// return this.age - o.age;
//年龄一样,姓名不一定一样
//这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的)
int i = this.age - o.age;
//判断姓名是否一样(三目运算符)
int i2 = i == 0 ? this.name.compareTo(o.name) : i;
return i2;
}
}
创建TreeSet类:
public class TreeDemo2 {
public static void main(String[] args) {
TreeSet<Student3> set = new TreeSet<>();
Student3 s1 = new Student3("theshy", 20);
Student3 s2 = new Student3("xiaohu", 24);
Student3 s3 = new Student3("uzi", 25);
Student3 s4 = new Student3("卡萨", 22);
Student3 s5 = new Student3("rookie", 23);
Student3 s6 = new Student3("姿态", 21);
Student3 s7 = new Student3("faker", 25);
Student3 s8 = new Student3("xiaohu", 24);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
set.add(s7);
set.add(s8);
for (Student3 s:set){
System.out.println(s);
}
}
}
结果:
Student{name='theshy', age=20}
Student{name='姿态', age=21}
Student{name='卡萨', age=22}
Student{name='rookie', age=23}
Student{name='xiaohu', age=24}
Student{name='faker', age=25}
Student{name='uzi', age=25}
需求:TreeSet集合存储学生对象,并且以姓名的长度来排序
创建Student类
public class Student3 implements Comparable<Student3> {
private String name;
private int age;
public Student3() {
}
public Student3(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student3 o) {
// return 0;
// return 1;
// return -1;
//这里返回什么,应该是根据我们自己定义的规则来排序
//比如说我想在去重的前提下,按照年龄进行排序。
// return this.age - o.age;
//年龄一样,姓名不一定一样
//这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的)
int i = this.age - o.age;
//判断姓名是否一样(三目运算符)
int i2 = i == 0 ? this.name.compareTo(o.name) : i;
return i2;
}
}
创建Tree类
import java.util.TreeSet;
public class TreeSetDemo3 {
public static void main(String[] args) {
//创建TreeSet集合对象
TreeSet<Student4> set = new TreeSet<>();
//创建学生对象
Student4 s1 = new Student4("mingwang", 18);
Student4 s2 = new Student4("wangyu", 19);
Student4 s3 = new Student4("zhoujiaxiang", 17);
Student4 s4 = new Student4("zhangbaogui", 18);
Student4 s5 = new Student4("liuzhicheng", 18);
Student4 s6 = new Student4("wangyu", 20);
//添加到集合里
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
for (Student4 s:set){
System.out.println(s);
}
}
}
结果:
Student{name='wangyu', age=19}
Student{name='wangyu', age=20}
Student{name='mingwang', age=18}
Student{name='liuzhicheng', age=18}
Student{name='zhangbaogui', age=18}
Student{name='zhoujiaxiang', age=17}
比较器排序
利用TreeSet创建对象时的带参数的构造方法来进行比较器排序
TreeSet(Comparator comparator)
构造一个新的,空的树集,根据指定的比较器进行排序。
创建学生类
public class Student5 {
private String name;
private int age;
public Student5() {
}
public Student5(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
创建MyComparator类
import java.util.Comparator;
public class MyComparator implements Comparator<Student5> {
@Override
public int compare(Student5 o1, Student5 o2) {
// return 0;
//主要条件:姓名的长度排序
int i = o1.getName().length() - o2.getName().length();
// return i;
//长度一样,姓名内容不一定一样
int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
//姓名内容一样,年龄的大小不一定一样
int i3 = i2 == 0 ? o1.getAge() -o2.getAge() : i2;
return i3;
}
}
创建TreeDemo类
import java.util.Comparator;
import java.util.TreeSet;
public class TreeDemo4 {
public static void main(String[] args) {
// MyComparator mc = new MyComparator();
// TreeSet<Student5> set = new TreeSet<>(mc);
//匿名内部类实现Comparator接口
//创建学生对象
//匿名内部类实现Comparator接口
TreeSet<Student5> set = new TreeSet<>(new Comparator<Student5>() {
@Override
public int compare(Student5 o1, Student5 o2) {
// return 0;
//主要条件:姓名的长度排序
int i = o1.getName().length() - o2.getName().length();
// return i;
//长度一样,姓名内容不一定一样
int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
//姓名内容一样,年龄的大小不一定一样
int i3 = i2 == 0 ? o1.getAge() -o2.getAge() : i2;
return i3;
}
});
Student5 s1 = new Student5("mingwang", 18);
Student5 s2 = new Student5("wangyu", 19);
Student5 s3 = new Student5("zhoujiaxiang", 17);
Student5 s4 = new Student5("zhangbaogui", 18);
Student5 s5 = new Student5("liuzhicheng", 18);
Student5 s6 = new Student5("wangyu", 20);
//将学生对象添加到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
for (Student5 Student5 : set) {
System.out.println(Student5);
}
}
}
结果:
Student{name='wangyu', age=19}
Student{name='wangyu', age=20}
Student{name='mingwang', age=18}
Student{name='liuzhicheng', age=18}
Student{name='zhangbaogui', age=18}
Student{name='zhoujiaxiang', age=17}