Fork me on GitHub

Java-18 泛型、Comparable、TreeSet、TreeMap

1.泛型

  • 泛型是jdk5引入新的特性,为什么要产生泛型呢,主要以下原因:

    1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成Object类型,但其运行时类型仍然为其本身类型。

    2.因此,取出集合元素时需要认为加入强制类型转换到具体的目标类型,且很容易出现"Java.lang.ClassCaseExcepiton"异常。

  • 那么到底什么是泛型呢,就是所说的类型参数化,即可以像参数一样控制某种数据类型,有了泛型我们可以指定集合中所能存储的数据类型。

  • 注意:泛型只是在编译时期有效,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说,成功编译过后的class文件中是不包含任何泛型信息的,泛型信息不回进入到运行阶段。

    它可以有效控制集合参数的类型

  • 自定义泛型

    格式: class 类名 <泛型符号>{}    符号为任意字母,常用的有T,E,K,V
    
    示例:List<String> list = new ArrayList<>();
    
  • 自定义泛型示例:

    import java.util.List;
    import java.util.ArrayList;
    public class GenericDemo {
    	public static void main(String[] args) {
    		List<String> list = new ArrayList<>();
    		
    		Box<String> box = new Box("haha");
    		String b = box.getData();
    		System.out.println(b);
    	}
    }
    
    class Box<T>{
    	T data;
    	public Box(T t) {
    		this.data = t;
    	}
    	public T getData() {
    		return data;
    	}
    }
    
  • 泛型定义接口

    interface InterA<B>{
    	public void show(B b);
    }
    // 未传入泛型实参
    class Test<B> implements InterA<B>{
    	@Override
    	public void show(B b) {
    		
    	}
    }
    // 传入泛型实参
    class Test2 implements InterA<String>{
    	@Override
    	public void show(String b) {
    		
    	}
    }
    
    

    未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中,如果不声明泛型,编译会报错 Unknown class。

    当实现泛型接口的类,传入泛型实参时,则所有使用泛型的地方都要替换成传入的实参类型,即:interA public void show(T t) 中的T都要替换成传入的String类型。

  • 泛型定义在方法上

    • 用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回值之前,也就是紧邻返回值之前。

      1.public 与返回值中间非常重要,可以理解为声明此方法为泛型方法。

      2.只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

      3.表名该方法将使用了泛型类型T,此时才可以在方法中使用反省类型T.

      4.与泛型类的定义一样,此处T可以随便写为任意标识,常见如:T,E,K,V等形式的参数常用语表示型。

    public class GenericDemo {
    	public static void main(String[] args) {
    		test(123);// java.lang.Integer
    	}
    	
    	public static <T> void test(T t){
    		System.out.println(t.getClass().getName());
    	}
    	
    }
    
  • 泛型的通配符

    <?>   任意类型,如果没有明确,那么就是Object以及任意Java类
    ? extends E		向下限定,E及其子类
    ? super E		向上限定, E及其父类
    
  • 泛型示例

    import java.util.ArrayList;
    import java.util.Collection;
    
    public class GenericDemo2 {
    	public static void main(String[] args) {
    		Collection <?> c1 = new ArrayList<Animal>();
    		Collection <?> c2= new ArrayList<Dog>();
    		Collection <?> c3= new ArrayList<Cat>();
    		Collection <?> c4= new ArrayList<Object>();
    		
    		//  extends Animal 则后面可以传 Animal 和Animal 子类
    		Collection <? extends Animal> c5= new ArrayList<Animal>();
    		Collection <? extends Animal> c6= new ArrayList<Dog>();
    		Collection <? extends Animal> c7= new ArrayList<Cat>();
    		// super Animal   则后面可以传 Animal 和Animal 父类
    		Collection <? super Animal> c9= new ArrayList<Animal>();
    		Collection <? super Animal> c12= new ArrayList<Object>();
    		
    	}
    }
    
    class Animal{};
    class Dog extends Animal{};
    class Cat extends Animal{};
    

2.Comparable用法

  • sort 排序

    public static <T> void sort(List<T> list)
    
    List<Integer> list = Arrays.asList(12,34,56,73,17,44);
    Collections.sort(list);
    System.out.println(list);//默认升序排列   [12, 17, 34, 44, 56, 73]
    
  • binarySearch 二分查找,不存在返回负数,只能针对升序集合

    public static <T> int binarySearch(List<?> list, T key)
    
    System.out.println(Collections.binarySearch(list, 17));// 1
    
  • max 最大值

    public static <T> T max(Collection<?> coll)
    
    System.out.println(Collections.max(list));
    
  • reverse 反转

    public static void reverse(List<?> list)
    
    Collections.reverse(list);
    System.out.println(list);
    
  • shuffle 随机打乱

    public static void shuffle(List<?> list)
    
    Collections.shuffle(list);
    System.out.println(list);
    
  • 排序和比较器配合使用

    public static <T> void sort(List<T> listm Comparator<? super T> c) 
    
  • 按照年龄进行对象的排序

    // Person.java
    public class Person implements Comparable<Person> {
    	String name;
    	int age;
    	public Person(String name,int age) {
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    	// 重写compareTo 实现排序
    	@Override
    	public int compareTo(Person o) {
    //		return this.age - o.age;// 升序
    		return o.age - this.age;// 降序
    	}
    }
    // ComparableDemo.java
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class ComparableDemo {
    	public static void main(String[] args) {
    		List<Person> list = new ArrayList<>();
    		list.add(new Person("张三", 53));
    		list.add(new Person("李四", 23));
    		list.add(new Person("王二", 41));
    		list.add(new Person("刘大", 55));
    		
    		Collections.sort(list);
    		System.out.println(list);
    	}
    }
    // 上面对象年龄是整型,对整型进行的排序。那么如何进行字符串排序,只需重写compareTo 方法
    @Override
    	public int compareTo(Person o) {
    		return this.name.compareTo(o.name);
    	}
    }
    
  • Comparable练习

    // 创建一个学生类,姓名,年龄,成绩(double),默认按照年龄升序,如果年龄相同按照分数降序。
    public class Student implements Comparable<Student>{
    	String name;
    	int age;
    	double score;
    	public Student(String name, int age, double score) {
    		this.name = name;
    		this.age = age;
    		this.score = score;
    		// TODO Auto-generated constructor stub
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + ",score=" +score+ "]";
    	}
    	// 默认按照年龄升序,如果年龄相同按照分数降序。
    	@Override
    	public int compareTo(Student o) {
    		if (this.age != o.age) {
    			return this.age - o.age;
    		} else {
    			return o.score - this.score >0 ? 1:-1;
    		}
    //		return this.name.compareTo(o.name);
    	}
    }
    
  • 如何用Comparator实现上面练习呢, 先举个List降序实现:

    // 1.接口子类实现降序
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    public class ComparableDemo3 {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(12,5,6,11,7);
    		Collections.sort(list, new IntegerComparator());
    		System.out.println(list);
    		// 实现List<Integer> 的降序。
    	}
    }
    
    // 重写compare方法
    class IntegerComparator implements Comparator<Integer>{
    	@Override
    	public int compare(Integer o1, Integer o2) {
    		return o2-o1;
    	}
    }
    // 2.匿名内部类实现降序
    
    public class ComparableDemo3 {
    	public static void main(String[] args) {
    		List<Integer> list = Arrays.asList(12,5,6,11,7);
    		Collections.sort(list, new Comparator<Integer>() {
    			@Override
    			public int compare(Integer o1, Integer o2) {
                      // o2-o1 降序
                      // o1-o2 升序
    				return o2-o1;
    			}
    		});
    		System.out.println(list);
    		// 实现List<Integer> 的降序。
    	}
    }
    
    
  • 那么通过Comparator实现排序,其实是重写compare方法,通过匿名内部类实现降序。

    Collections.sort(list);
    System.out.println(list);
    // 默认按照成绩升序,成绩相同,按照年龄降序
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
        if (o1.score == o2.score) {
        	return o2.age - o1.age;
        }
        	return o1.score - o2.score > 0?1:-1;
        }
    });
    
  • 上述写法还有2中简单写法:

    // 1.通过list方式实现排序,匿名接口
    list.sort(new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
        	return o2.age -o1.age;
        }
    });
    // 2.通过lambda方式实现排序
    // lambda表达式写法
    Collections.sort(list,(o1,o2)->o2.age - o1.age);
    
  • Comparable 和 Comparator比较

    Comparable :内部比较器,在java.lang下,如果一个List想要使用Collections.sort()做排序,需要集合中的元素所在的类实现Comparable<T>接口重写compareTo
    	this在前表示升序,参数在前表示降序
    Comparator:外部比较器,在java.util下,如果一个类中不能实现Comparable或者对应COmparable中的排序方式不满意。可以通过Comparator重新定义排序的规则,而不需要修改原有类的结构,Collections.sort(list,Comparator)//匿名内部类。
    

3.TreeSet

  • 可以对集合中的元素实现自然排序,要想使用TreeSet对集合中元素做排序,要求Set中元素所在的类必须实现Comparable接口,否则会出现转型异常。

  • Java.lang.Comparable.TreeSet中元素不可重复,依赖compareTo/compare也就是说如果compare/compareTo方法返回的结果是0,TreeSet就会认为是相同的元素,只保存一个,所以我们在使用时候尽量不要只比较一个属性,还有TreeSet中的元素不能为null需要使用元素调用compare/compareTo作比较,如果为空,会出现空指针异常。

    // 若想对TreeSet进行自定义排序,需要继承Comparable接口,并实现compareTo方法
    import java.util.Set;
    import java.util.TreeSet;
    
    public class TreeSetDemo {
    	public static void main(String[] args) {
    		Set<Integer> set = new TreeSet<>();
    		set.add(12);
    		set.add(55);
    		set.add(566);
    		// 对集合中元素进行排序
    		System.out.println(set);
    		
    		Set<Person> p = new TreeSet<>();
    		p.add(new Person("xiaoming", 22));
    		p.add(new Person("hong", 25));
    		p.add(new Person("cc", 31));
    	}
    }
    
    
    class Person implements Comparable <Person>{
    	String name;
    	int age;
    	public Person(String name,int age) {
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    	public int compareTo(Person o) {
    		return o.age - this.age;
    	}
    }
    
  • 使用TreeSet 对Integer做降序

    Set<Integer> set3= new TreeSet<>(new Comparator<Integer>) {
    	@Override
    	public int compare(Integer o1, Integer o2) {
    		return o2 - o1;
    	}
    };
    set3.add(102);
    set3.add(1);
    set3.add(333);
    

4.TreeMap

  • TreeMap 对map中key进行降序, 它的key不能为null,因为需要调用compare/compareTo,如果为空,会出现空指针异常。
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

public class TreeMapDemo {
	public static void main(String[] args) {
		Map<Integer, String> map = new TreeMap();// {1=a, 2=b, 3=c, 4=d, 5=e}
		map.put(1, "a");
		map.put(2, "b");
		map.put(3, "c");
		map.put(4, "d");
		map.put(5, "e");
		System.out.println(map);
		// TreeMap 对map中key进行降序
		Map<Integer, String> map2 = new TreeMap<>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o2 - o1;
			}
		});
		map2.put(1, "a");
		map2.put(2, "b");
		map2.put(3, "c");
	}
}
  • 对象排序
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

public class TreeMapDemo {
	public static void main(String[] args) {
		Map<Teacher, String> map3 = new TreeMap<>();
		map3.put(new Teacher("zz",15,99), "a");
		map3.put(new Teacher("bb",15,85), "b");
		map3.put(new Teacher("vv",15,70), "c");
		map3.put(new Teacher("dd",15,70), "d");
		System.out.println(map3);
	}
	
}



class Teacher implements Comparable<Teacher>{
	String name;
	int age;
	double score;
	public Teacher(String name, int age, double score) {
		this.name = name;
		this.age = age;
		this.score = score;
	}
	public int compareTo(Teacher o) {
		return this.score - o.score>0?1:(this.score==o.score)?0:-1;
	}
	@Override
	public String toString() {
		return "Teacher [name=" + name + ", age=" + age + ", score=" + score + "]";
	}
	
}

posted @ 2020-10-19 08:42  是阿凯啊  阅读(234)  评论(0编辑  收藏  举报