今日目标
- 泛型
- 集合工具类
- 自带排序集合
一.泛型
Java泛型是jdk 1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
-
引入案例
需求:输出集合中所有的字符串
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add(666);
//需求:输出集合中所以的字符串
for (Object o:list){
//会抛出类型转换异常
System.out.println((String)o);
}
//异常分析:集合中数据类型不统一
-
案例改进
在源头上对数据进行约束,除了字符串,其它类型数据不能放入集合
//增加了泛型对类型进行约束
ArrayList <String>list = new ArrayList();
list.add("hello");
list.add("world");
list.add(666);//编译不通过
for (String s:list){//直接用String接收,无须强转
//会抛出类型转换异常
System.out.println(s);
}
1.泛型类
类的后面定义一个或多个任意类型 ,可以在类的成员属性或方法中使用,例如:
public class Hello<T,A,B,C> {// <> 里表示声明
private T t;
private A a;
private B b;
private C c;
//省略seter/getter和构造方法
//应用于方法的形参
public void fun1(A a){
System.out.println(a);
}
public void fun2(B b){
System.out.println(b);
}
public void fun3(C c){
System.out.println(b);
}
}
//测试类中,调用构造方法,传入不同的类型作为参数,创建对象。
- 常见应用:List,Set,Map接口
案例:
- 定义一个Set集合,装入5本书(编号,书名,价格),且只能装入书籍。
- 定义一个Map集合,用来存入人物名称和对应的城池(刘备-荆州,张飞-徐州,关羽-樊城),使用泛型约束类型。
public class City {
private String city;
@Override
public String toString() {
return "City{" +
"city='" + city + '\'' +
'}';
}
public City() {
}
public City(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
import javax.print.attribute.standard.Chromaticity;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Fx {
public static void main(String[] args) {
HashMap<String, City> map = new HashMap();
map.put("关羽",new City("樊城"));
map.put("张飞",new City("新野"));
map.put("赵子龙",new City("徐州"));
map.put("刘备",new City("荆州"));
Set<String> keys = map.keySet();
for (String s:keys){
System.out.println(s+"---"+map.get(s));
}
Collection<City> values = map.values();
for (City c:values){
System.out.println(c);
}
Set<Map.Entry<String, City>> entries = map.entrySet();
for (Map.Entry<String, City> entry:entries){
System.out.println(entry.getKey()+"----"+entry.getValue());
}
}
}
- 定义一个人类People,声明3个泛型,尝试着从不同的方面去描述不同的人物,创建不同的对象。
People<String , Double, Integer> people1 = new People<>("曹操",999.99,26);
People<String , Boolean, Character> people2 = new People<>("刘备",false,'男');
public class People <A,B,C>{
private A a;
private B b;
private C c;
public People(A a, B b, C c) {
this.a = a;
this.b = b;
this.c = c;
}
}
public class TestPeople {
public static void main(String[] args) {
People p1 = new People<String, Double, Integer>("曹操", 999.99, 26);
People p2 = new People<String, Boolean, Character>("刘备", false, '男');
People <Boolean,Double,Character>p3 = new People("刘备", false, '男');
//如果有类被指定,构造方法无需指定,若要指定要与类一致
//People <Boolean,Double,Character>p3 = new People<String, Boolean, Character>("刘备", false, '男');
People <String, Boolean, Character>p4 = new People<String, Boolean, Character>("刘备", false, '男');
}
}
2.泛型接口
public interface Haha <T> {
void ff(T t);
}
-
编写实现类,重写ff方法
-
常见应用:比较器Comparable
3.泛型方法
在方法结构上声明一个或多个泛型,可用于方法的返回值或形参。
public <T> void fun1(T t){
System.out.println(t);
}
public <T> T fun1(T t){
System.out.println(t);
return t;
}
4.泛型通配符
<? extends 类型> 表示某个类型或它的任意子类型
<? super 类型> 表示某个类型或它的任意父类型
案例:
动物类Animal有一个方法,返回动物的腿的个数。子类有狗狗和企鹅,分别重写该方法,返回各自腿的个数。
编写一个测试类,定义一个方法,该方法可以计算出一个动物集合List共有多少条腿,并输出。
再定义一个测试方法,分别计算一批动物(2只狗狗和3只企鹅)和一批狗狗(3只),一批企鹅(3只)的腿的数量。
public abstract class Animal {
abstract int legs();
}
class Dog extends Animal{
@Override
int legs() {
return 4;
}
}
class Penguin extends Animal{
@Override
int legs() {
return 2;
}
}
class TestAni{
static void calLegs(List<? extends Animal> animals){// List集合中可以是<? extends Animal> 这些类 也可用ArrayList<? extends Animal> animals
int sum=0;
for(Animal a:animals){
sum+=a.legs();
}
System.out.println("这批动物的腿的个数:"+sum);
}
public static void main(String[] args) {
//准备第一批:2只狗狗和3只企鹅
ArrayList<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Dog());
animals.add(new Penguin());
animals.add(new Penguin());
animals.add(new Penguin());
calLegs(animals);
//准备第二批:3只狗狗
ArrayList<Dog> animals2 = new ArrayList<>();
animals2.add(new Dog());
animals2.add(new Dog());
animals2.add(new Dog());
calLegs(animals2);
//准备第三批:3只企鹅
ArrayList<Penguin> animals3 = new ArrayList<>();
animals3.add(new Penguin());
animals3.add(new Penguin());
animals3.add(new Penguin());
calLegs(animals3);
}
}
二.集合工具类
Collections工具类:是一个主要对List集合进行操作的工具类,里面包含静态方法。
- 随机打乱shuffle
- 排序sort
- 交换swap
- 查找binarySearch:前提是集合中的元素必须按某种规则升序排序
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Collections.shuffle(list);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
System.out.println(Collections.binarySearch(list,4));
Collections.swap(list,1,2);
System.out.println(list);
}
public static void main(String[] args) {
Integer [] arr={1,2,3};
List<Integer> l = Arrays.asList(arr);
//将数组转换为集合
System.out.println(l);
System.out.println(l.size());
System.out.println("-------");
int [] arr1={1,2,3};
IntStream s = Arrays.stream(arr1);
//遍历流
s.forEach(System.out::println);
/* Stream<Integer> ss = s.boxed();
List<Integer> list = ss.collect(Collectors.toList());*/
/*IntStream s = Arrays.stream(arr);
s.forEach(System.out::println);
List<Integer> list = Arrays.stream(arr1).boxed().collect(Collectors.toList());
System.out.println(list);
System.out.println(list.size());*/
}
案例:
1.现有5只猴子(姓名,年龄),将他们存入List集合中,先随机打乱,然后使用工具类,对这一群猴子按照年龄进行排序。
2.交换集合中的第一个和第三个猴子
3.查找名称叫 肉肉 的猴子
public class Monkey implements Comparable<Monkey>{
@Override
public int compareTo(Monkey o) {
return this.age-o.age;
//return this.name.compareTo(o.name);
}
private String name;
private int age;
@Override
public String toString() {
return "Monkey{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Monkey(String name, int age) {
this.name = name;
this.age = age;
}
public Monkey() {
}
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;
}
}
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class TestM {
public static void main(String[] args) {
Monkey[] monkeys={new Monkey("孙悟空",6),
new Monkey("菲菲",1),
new Monkey("肥肥",6),
new Monkey("狒狒",2),
new Monkey("肉肉",9)};
List<Monkey> ms = Arrays.asList(monkeys);
//随机打乱
Collections.shuffle(ms);
System.out.println(ms);
//内部比较器,实体类实现Comparable接口
Collections.sort(ms);
System.out.println(ms);
//再次随机打乱
/* Collections.shuffle(ms);
System.out.println(ms);*/
//外部比较器 如下2种方式都行
//Collections.sort(ms,new AgeCompare());
/*Collections.sort(ms,( o1, o2)-> o1.getAge()-o2.getAge());
System.out.println(ms);*/
//查找 肉肉 查找什么属性,就要按照什么属性排序
//内部比较器 查找
int i = Collections.binarySearch(ms, new Monkey("肉肉", 2));
System.out.println(i);
//外部比较器查找
//int i1 = Collections.binarySearch(ms, new Monkey("肉肉", 1), new NameCompare());
/*int i2 = Collections.binarySearch(ms,new Monkey("肉肉", 1), (o1,o2)->o1.getName().compareTo(o2.getName()));
System.out.println(i2);*/
}
}
class NameCompare implements Comparator<Monkey> {
@Override
public int compare(Monkey o1, Monkey o2) {
return o1.getName().compareTo(o2.getName());
}
}
class AgeCompare implements Comparator<Monkey> {
@Override
public int compare(Monkey o1, Monkey o2) {
return o1.getAge()-o2.getAge();
}
}
三.TreeMap和TreeSet
-
Set和Map的关系:
set使用了map的key.
-
继承关系:
Set接口有一个实现类是HashSet,还有一个子接口是SortedSet,该接口有一个实现类是TreeSet。
TreeSet是一个有序集合,会根据自然排序排列或比较器进行排序,且没有重复元素,也没有下标。通过TreeMap实现。
TreeMap中的元素默认按照keys的自然排序排列或比较器进行排序。
- 构造方法
//1.无参构造
new TreeSet<>();
new TreeMap<>();
//2.有参构造
new TreeSet<>(外部比较器Comparator);
new TreeMap<>(外部比较器Comparator);
案例:
1.将5个大象(姓名,年龄,体重)存入TreeSet中,并输出
public class Elephant implements Comparable<Elephant>{
@Override
public int compareTo(Elephant o) {
return this.age-o.age;
}
private String name;
private int age;
private double weight;
@Override
public String toString() {
return "Elephant{" +
"name='" + name + '\'' +
", age=" + age +
", weight=" + weight +
'}';
}
public Elephant() {
}
public Elephant(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
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 double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
public class TestTreeSet {
/*1.将5个大象(姓名,年龄,体重)存入TreeSet中,并输出
* 2.给每一个大象安排一个主人,存入TreeMap中,并输出*/
public static void main(String[] args) {
fun1();
}
private static void fun2() {
TreeMap<String,Elephant> es = new TreeMap<String,Elephant>();
es.put("曹操",new Elephant("胖胖",2,3.6));
es.put("曹植",new Elephant("肥肥",1,4.6));
es.put("曹丕",new Elephant("菲菲",3,5.6));
es.put("曹洪",new Elephant("毛毛",8,2.6));
es.put("曹仁",new Elephant("壮壮",5,1.6));
System.out.println(es);
}
private static void fun1() {
//自然排序--基本数据类型
/* TreeSet<Integer> es = new TreeSet();
es.add(2);
es.add(6);
es.add(9);
es.add(0);*/
/* //内部比较器排序--对象
TreeSet<Elephant> es = new TreeSet();
es.add(new Elephant("胖胖",2,3.6));
es.add(new Elephant("肥肥",1,4.6));
es.add(new Elephant("菲菲",3,5.6));
es.add(new Elephant("毛毛",8,2.6));
es.add(new Elephant("壮壮",5,1.6));
System.out.println(es);*/
//外部比较器排序--对象
TreeSet<Elephant> es = new TreeSet<Elephant>((o1, o2)-> Double.compare(o1.getWeight(),o2.getWeight()) );
es.add(new Elephant("胖胖",2,3.6));
es.add(new Elephant("肥肥",1,4.6));
es.add(new Elephant("菲菲",3,5.6));
es.add(new Elephant("毛毛",8,2.6));
es.add(new Elephant("壮壮",5,1.6));
System.out.println(es);
}
}
2.给每一个大象安排一个主人,存入TreeMap中,并输出
public class Elephant {
private String name;
private int age;
private double weight;
@Override
public String toString() {
return "Elephant{" +
"name='" + name + '\'' +
", age=" + age +
", weight=" + weight +
'}'+"\n";
}
public Elephant() {
}
public Elephant(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
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 double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
public static void main(String[] args) {
TreeMap<String, Elephant> treeMap = new TreeMap<>();
treeMap.put("曹操3",new Elephant("大1",2,3.6));
treeMap.put("曹操2",new Elephant("大3",5,2.6));
treeMap.put("曹操5",new Elephant("大5",1,4.6));
treeMap.put("曹操6",new Elephant("大2",3,1.6));
treeMap.put("曹操1",new Elephant("大6",4,6.6));
System.out.println(treeMap);
}
作业:
1.判断以下哪种书写时正确的?
1.4.5正确
2.将一系列字符串“hello”,“helloworld”,“how”,“do”,“you”,"what"存入TreeSet集合,要求按照字符串长度进行排序。
import java.util.Comparator;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if (o1.length()!=o2.length()){
return o1.length()-o2.length();
}else {
return 1;
}
}
});
set.add("hello");
set.add("helloworld");
set.add("how");
set.add("do");
set.add("you");
set.add("what");
System.out.println(set);
}
}
3.有一个记事本,可以记录做了哪些事情和每件事对应得次数。请输入10件事,可以重复,例如:
学java,
打球,
溜冰,
打球,
溜冰,
打球,
打球,
学java,
溜冰,
吃烧烤。
输入结束后,输出每件事和对应得次数,例如:
学java–2次
打球–4次
溜冰–3次
吃烧烤–1次
要求:所选的集合都要用泛型进行约束。
HashMap<String, Integer> map = new HashMap<>();
Scanner sc = new Scanner(System.in);
for (int i = 1; i <=10 ; i++) {
System.out.println("请输入第"+i+"件事");
String s=sc.next();
map.put(s,map.containsKey(s)?map.get(s)+1:1);
}
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry:entries){
System.out.println(entry.getKey()+"的次数有"+entry.getValue());
}
集合嵌套应用–选做:
4.有一个记事本,能记录周一到周天,每天做的所有事情和事情的次数,周而复始。小明在这个记事本上记录了3周,内容如下:
第1周
- 周1:学java,逛街
- 周2:打台球,旅游
- 周3:溜冰,吃烧烤
- 周4:打篮球,逛街,吃烧烤
- 周5:学前端,溜冰
- 周6:逛街,吃烧烤
- 周7:旅游,打台球
第2周:
- 周1:学java,学前端
- 周2:打台球,溜冰,学java
- 周3:旅游,吃烧烤
- 周4:逛街,学java
- 周5:学前端,旅游
- 周6:逛街,打台球,吃烧烤
- 周7:旅游,逛街,打台球,吃烧烤
第3周:
- 周1:学java,学前端,学python
- 周2:打台球,溜冰,学java,学C++
- 周3:旅游,吃烧烤,吃冰淇淋
- 周4:逛街,学java,吃烧烤
- 周5:学前端,旅游,打高尔夫
- 周6:逛街,打台球,吃烧烤,溜冰,蹦迪
- 周7:旅游,逛街,打台球,吃烧烤,跑步
使用Scanner接收小明3周所做的所有事情,并存入相应的集合中。然后输出周一到周五(不区分第几周)小明所做的所有事情以及相应的次数。(要求:所选的集合都要用泛型进行约束。)
public static void main(String [] args){
Scanner sc=new Scanner(System.in);
//week 共有7个元素
TreeMap<String, Map<String,Integer>> week = new TreeMap<String, Map<String,Integer>>();
//数据录入
for (int i = 1; i <= 2; i++) {
System.out.println("第"+i+"周:");
Map<String, Integer> map;
for (int j = 1; j <=3 ; j++) {
map= new HashMap<String, Integer>();//每天都会清空昨天的事情和次数
System.out.println("周"+j+":");
String things = sc.next();//旅游,逛街,旅游,打台球,吃烧烤,跑步
String[] things_arr = things.split(",");
for (String s : things_arr) {
//map存入的是:事情和次数
map.put(s,map.containsKey(s)?map.get(s)+1:1);
}
//第二周,第三周
if(week.containsKey("周"+j)){
Map<String, Integer> map1 = week.get("周" + j);
mapAddMap(map1,map);
//week.put("周"+j,map);
}else {//第一周
week.put("周"+j,map);
}
}
}
//数据输出 week
Set<Map.Entry<String, Map<String, Integer>>> weeks = week.entrySet();
for (Map.Entry<String, Map<String, Integer>> week1 : weeks) {
System.out.println(week1.getKey()+":");
Map<String, Integer> map = week1.getValue();
Set<Map.Entry<String, Integer>> things = map.entrySet();
for (Map.Entry<String, Integer> thing : things) {
String key = thing.getKey();
Integer count = thing.getValue();
System.out.print(key+"--"+count+"次 \t");
}
System.out.println();//换行
}
}
public static void mapAddMap(Map<String ,Integer> map1,Map<String ,Integer> map2){
Set<String> map2key = map2.keySet();
for (String m2key : map2key) {
map1.put(m2key,map1.containsKey(m2key)?map1.get(m2key)+map2.get(m2key):map2.get(m2key));
}
}