【JavaSE 第十七天】

【JavaSE 第十七天】

一、泛型 Generic

泛型技术是 JDK 版本的一大升级,源自于 JDK1.5
泛型就是集合类 <泛型> (尖括号)

// 无泛型写法
public static void main(String[] args) {
	/**
     *  JDK1.4 及以前没有泛型技术,是这样写:
     *  1.集合可以存储任何数据类型
     *  2.添加元素的数据类型是 Object
     */
    List list = new ArrayList();
    list.add("a");
    list.add(1);
    Iterator it = list.iterator();
    while (it.hasNext()){
        Object obj = it.next(); // 不能类型转换
        System.out.println(obj);
    }
}
// 这种写法可以存储任意数据类型,但是如果进行类型转换就会出现错误,不安全,所以不能进行类型转换,导致无法使用某些其他功能

1. 泛型的安全机制

软件升级:安全性提高,修复 Bug 错误,改善用户体验,增加功能,提升性能
JDK1.5 被称为:里程碑版本

泛型作用:强制集合存储固定的数据类型

泛型的书写格式:

集合类<存储的数据类型>  变量名 = new 集合类<存储的数据类型>();
(后面尖括号里的类型可以不写:JDK7 里面把不写的尖括号叫做:钻石操作符)

加入泛型后,程序的安全性提升了:

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add(1); // 编译错误,数据类型不匹配
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String obj =it.next(); // 类型转换不需要
            System.out.println(obj);
        }
    }
  • 使用泛型的好处:
    • 程序安全性提高
    • 程序的代码量减少
    • 避免了类型的强制转换
    • 把程序的问题,由运行时期,提前到编译时期(不用泛型只有到运行时期才会报错,而使用泛型在编译时期就会报错)

2. 泛型中的 E 问题

E 没有什么实际价值,只是一个变量而已
这个变量的特殊性:等待接收指定的数据类型

ArrayList<E>
// 创建对象
ArrayList<String> al = new ArrayList<String>();
// new 创建完对象之后 E 不在是 E 了,变成 String
public boolean add(String e) {

}

3. 自定义泛型类

自定义泛型类:

/**
 *  定义一个类,类名叫工厂
 *  自定义泛型类
 *  Factory<变量名>  
 *  只是变量名而已,符合标识符规则即可
 */
public class Factory<QQ> {
    private QQ q;

    public void setQ(QQ q){
        this.q = q;
    }

    public QQ getQ(){
        return q;
    }
}

测试:

public static void main(String[] args) {
    // 创建对象 Factory 类对象
    // Factory factory = new Factory(); // 如果这么写就是 没有泛型 的写法,QQ 就是 Object
    // 泛型的写法:
    Factory<String> factory01 = new Factory<String>(); // QQ 是什么类型,只有等到尖括号中指定之后才能确定
    factory01.setQ("abc");
    String s = factory01.getQ();
    System.out.println(s);
	// 改变尖括号中的类型:
    Factory<Double> factory02 = new Factory<Double>(); // QQ 是什么类型,只有等到尖括号中指定之后才能确定
    factory02.setQ(1.5);
    Double q = factory02.getQ();
    System.out.println(q);
}

4. 泛型方法

/**
 * 泛型的方法,作用于方法参数上(或返回值)
 */
public class Factory<Q> {

	// 普通方法:
    public void print(Q q){
        System.out.println(q);
    }
    
    /**
     * 静态方法:
     * Q 是非静态的, 因为 Q 的数据类型,是 new 创建的时候指定的
     *
     * 静态方法参数中的泛型,不能和类一样(静态不能调用非静态的问题)
     * 静态方法的泛型,需要在方法上单独定义
     * 写在返回值类型的前面
     */
    public static <T> void staticMethod(T q){
        System.out.println(q);
    }
}

调用:

    public static void main(String[] args) {
        // 泛型普通方法的调用
        Factory<Integer> factory=new Factory<>();
        factory.print(1213);
        // 泛型静态方法的调用,参数随意
        Factory.staticMethod("true");
    }

5. 泛型接口

两种做法:

  1. 实现类实现接口,不实现泛型
  2. 实现类实现接口,同时指定泛型

定义泛型接口

// 泛型接口
public interface Inter <T> {
    public abstract void inter(T t);
}

实现接口:

/**
 * 实现接口,不理会泛型
 * 对象创建的时候,才指定类型
 */
public class InterImpl01<T> implements Inter<T>{
    public void inter(T t){
        System.out.println(t);
    }
}

实现接口:

/**
 * 实现接口,同时指定泛型
 */
public class InterImpl02 implements Inter<String> {
    public void inter(String s) {
        System.out.println("s==" + s);
    }
}

测试:

public class GenericTest {
    public static void main(String[] args) {
    	// 第一种:
        Inter<String> in01 = new InterImpl01<String>(); //对象创建的时候,指定类型
        in.inter("ok");
		// 第二种:
        Inter in02 = new InterImpl02(); // 不能再次指定类型,已经在实现接口过程中指定了类型
        in2.inter("hello");
    }
}

6. 泛型通配符

// 泛型的通配符 (类似于文件的通配符: *.jpg)
public class GenericTest {
    public static void main(String[] args) {
    	// 第一种类型的集合:
        List<String> stringList = new ArrayList<String>();
        stringList.add("abc");
        stringList.add("bbc");
		// 第二种类型的集合:
        List<Integer> integerList =  new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
		// 调用:
        each(stringList);
        each(integerList);
    }
    /**
     * 定义方法,可以同时迭代器,遍历这两个集合
     * 方法的参数,是要遍历的集合,由于先前不确定是哪个集合
     * 定义参数,写接口类型,不要写实现类
     */
    public static void each(List<?> list){ // 在这里写通配符
    // 方法的参数,由于遍历的集合先前并不知道,所以把集合当作参数传递参数,参数不要写实现类,要写接口
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            Object obj = it.next(); 
            // 不允许用默认类型去接收,由于没有明确的类型,所以迭代器的方法是 Object,无法指定具体的类型
            System.out.println(obj);
        }
    }
}

7. 泛型限定

泛型限定:限制的是数据类型

  • <? extends Company> 传递类型可以是 Company 或者是它的子类
  • <? extends E> 传递 E 类型或者是 E 的子类,泛型上限限定写法
  • <? super E > 传递 E 类型或者是 E 的父类,泛型下限限定写法
// 事先创建一个公司类,一个开发部类,一个财务部类,开发部类和财务部类继承自公司类,并分别定义 work() 方法
public static void main(String[] args) {
    // 创建集合,存储员工对象
    // 开发部 集合 
    List<Development> devList = new ArrayList<Development>();
    // 存储开发部员工对象
    // 第一个对象
    Development d1 = new Development();
    d1.setName("张三");
    d1.setId("开发部001");
	// 第二个对象
    Development d2 = new Development();
    d2.setName("李四");
    d2.setId("开发部002");
    // 放入集合
    devList.add(d1);
    devList.add(d2);

    // 财务部 集合
    List<Financial> finList = new ArrayList<Financial>();
    // 存储财务部员工对象
    // 第一个对象
    Financial f1 = new Financial();
    f1.setName("王五");
    f1.setId("财务部001");
	// 第二个对象
    Financial f2 = new Financial();
    f2.setName("赵六");
    f2.setId("财务部002");
    // 放入集合
    finList.add(f1);
    finList.add(f2);
    // 打印两个集合:
    System.out.println(devList);
    System.out.println(finList);
	// 调用遍历方法传递参数
    each(devList);
    each(finList);
}
	/**
     * 1.要求:定义方法,同时遍历2个集合
     * 遍历的同时取出集合元素,调用方法 work()
     * 2.解决方法:由于使用 ? 接收任何一个类型
     * 所以使它只能接收 Company 和子类对象
     * 所以明确父类,不能明确子类
     */
public static void each(List<? extends Company> list){
    Iterator<? extends Company> it = list.iterator(); // 迭代器的类型跟随集合
    while (it.hasNext()){
        // 取出元素
        Company obj =it.next(); // 明确父类类型,不需要强转类型
        obj.work();
    }
}

8.泛型擦除

编译之前有泛型约束,编译之后没有泛型约束。泛型约束就是在编译时执行检察,在编译之后就进行了泛型擦除

例如:

List<Integer> intList = new ArrayList<Integer>(); 
List<String> intList = new ArrayList<String>();
// 这两者在编译执行完之后就都变为了:ArrayList<Object>

使用反射验证擦除(因为反射操作的是 Class,编译之后得到的文件),泛型擦除的目的就是为了减少占用内存,否则本例中就会有两个类型的对象
泛型擦除

二、 增强型的 for 循环

JDK1.5 出现的特性:循环的特性

由来:

  1. Collection 是单列集合的顶级接口,但是到 JDK1.5 后, Collection 继承了一个父接口
  2. java.lang.Iterable 接口:实现这个接口,就可以成为 “foreach” 语句的目标
  3. Collection、List、Set 都实现了该接口,包括数组
    (Map 没有实现)

1. 增强型 for 循环的格式

for(数据类型 变量名 : 集合或者数组){}
  • 遍历数组:
    /**
     * for 循环遍历数组
     */
    public static void forArray(){
        int[] arr = {1,3,5,7,9};
        for(int i : arr){
        	System.out.println(i);   // 1 3 5 7 9
            System.out.println(i+1); // 2 4 6 8 10
        }
        System.out.println("arr=="+arr[0]); // 结果是 1
    }
// (但是 Java 实际上这种 for 循环的格式,并不存在,编译特效,因为反编译 .class 依旧是原来的 for 循环格式)
  • 遍历集合:
	/**
     * for 循环遍历集合
     */
    public static void forList(){
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        for(String s : list){
            System.out.println(s);
        }
    }
// (遍历集合的 for 循环反编译 .class 是迭代器)

2. 单列集合转成数组

import java.util.ArrayList;
import java.util.List;
public class CollectionTest {
    /**
     * 单列集合转成数组
     * Collection 接口中的方法 toArray()
     */
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        // 集合对象调用方法 toArray()
        String[] str = list.toArray(new String[list.size()]);
        // 转换成数组就变为定长,不可以再改变长度
        for(String s:str){
            System.out.println(s);
        }
    }
}

三、Map 集合

java.util.Map 接口,是双列集合的顶级接口(Map 集合和 Collection 集合没有任何关系)
Map 集合容器每次存储两个对象,一个对象称为键(Key),另一个对象称为值(Value)(键值集合)
在一个Map的集合容器中,键保证唯一性,不包含重复键,每个键只能对应一个值

Map<k,v>

KV
K 存储键的数据类型V 存储值的数据类型
  1. K 和 V 称为:映射键值对
  2. 这种一一对应的关系称为:映射
  3. 在 Map 集合中 value 可以随便写,但是 key 必须保证唯一性
  4. 键和值是一一对应的关系,(好比是夫妻关系,并以结婚证作为证明)对应关系(结婚证)也是对象
  5. 对象也会产生 接口 Entry(这个接口是一个内部接口)(这个接口的实现类才能体现一一对应的映射关系),有几个对应关系就有几个 Entry 接口(对象多了之后就会装入集合),所以 Map 集合可以利用映射关系进行遍历
  6. Map 存储的方法:V put(K,V)

1. Map 接口的方法

  • V put(K,V) 存储键值对,如果没有存储重复键,返回的就是 null,如果存储重复键,返回被覆盖之前的值
/**
 * put 方法,存储键值对
 * Map 接口的实现类 HashMap
 */
public static void mapPut(){
    // 创建对象,指定键的数据类型,值的数据
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("a",1);
    map.put("b",2);
    map.put("c",3);
    map.put("d",4);
    Integer value = map.put("c",5); // 如果没有存储重复键,返回的就是 null;存储重复键,返回被覆盖之前的值
    System.out.println("map = " + map);
    System.out.println("value = " + value);
}
  • V get(K) 通过键获取值,参数传递键,找这个键对应的值,如果没有这个键就返回 null
/**
 * V get(K)通过键获取值,参数传递键,找这个键对应的值,没有这个键返回 null
 */
public static void mapGet(){
    // 创建对象,指定键的数据类型,值的数据
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("a",1);
    map.put("b",2);
    map.put("c",3);
    map.put("d",4);
    // 通过键找值
    Integer value = map.get("f"); // null
    System.out.println(value);
}
  • boolean containsKey(K) 判断集合是否包含这个键,包含返回 true
  • boolean containsValue(V) 判断集合是否包含这个值,包含返回 true
  • int size() 返回集合长度,Map 集合中键值对的个数
  • V remove(K) 移除指定的键值对,返回被移除之前的值
  • Collection<V> values() Map 集合中的所有的值拿出,存储到 Collection 集合
/** 
 *	boolean containsKey(K)  判断集合是否包含这个键,包含返回 true
 *  boolean containsValue(V)  判断集合是否包含这个值,包含返回 true
 *  int size()  返回集合长度,Map 集合中键值对的个数
 *  V remove(K)  移除指定的键值对,返回被移除之前的值
 *  Collection<V> values()  Map 集合中的所有的值拿出,存储到 Collection 集合
 */
public static void mapMethod(){
    // 创建集合,键是整数,值是String
    Map<Integer,String> map = new HashMap<Integer, String>();
    map.put(1,"a");
    map.put(2,"b");
    map.put(3,"c");
    map.put(4,"d");
    map.put(5,"e");
    // 1.boolean containsKey(K)  判断集合是否包含这个键,包含返回 true
    boolean b = map.containsKey(1);
    System.out.println("集合中包含键:"+b);
    // 2.boolean containsValue(V)  判断集合是否包含这个值,包含返回 true
    b = map.containsValue("c");
    System.out.println("集合中包含值:"+b);
    // 3.int size()  返回集合的长度
    int size = map.size();
    System.out.println("集合长度:"+size);
    // 4.V remove(K)  移除指定的键值对,返回被移除之前的值
    String value =  map.remove(1);
    System.out.println("被删除之前的值:"+value);
    System.out.println(map);
    // 5.Collection<V> values()  Map 集合中的所有的值拿出,存储到 Collection 集合
    Collection<String> coll =  map.values();
    for(String s : coll){
    	System.out.println(s);
    }
}

2. Map 集合的遍历:键找值

  • 实现思想:
    1. Map接口中定义了方法 keySet() 使所有的键,存储到 Set 集合
    2. 遍历 Set 集合(迭代器)
    3. 取出 Set 集合元素 Set 集合的元素是 Map 集合的键
    4. Map 集合的方法 get() 传递键,获取值
public static void mapKeySet(){
    Map<String,String> map = new HashMap<String, String>();
    map.put("a","java");
    map.put("b","c++");
    map.put("c","php");
    map.put("d","python");
    map.put("e","erlang");
    // Map 接口定义了方法  keySet() 所有的键,存储到 Set 集合
    Set<String> set = map.keySet();
    // 遍历 Set 集合
    Iterator<String> it = set.iterator();
    // 取出 Set 集合元素
    while (it.hasNext()){
        String key = it.next();
        // Map 集合的方法 get() 传递键获取值
        String value =  map.get(key);
        System.out.println(key+"="+value);
    }
}

3. 实现类的外部接口和实现类内部接口问题

①定义接口和抽象方法以及内部接口和抽象方法:

public interface Outer {
    // 内部接口
    interface Inner{ // 内部接口有固定的修饰符:public static
        void inner(); // 内部接口的抽象方法
    }
    void outer(); //外部接口的抽象方法
}

②实现接口:

/**
 * InnerImplement 实现接口
 * 1. 实现外部接口,不需要完成内部接口的方法重写
 */
public class InnerImplement implements Outer {
    public void outer(){}
}

③实现内部接口:

/**
 * InnerImplement 实现接口
 * 2. 实现内部接口,也不需要完成外部接口的方法重写
 *      因为内部接口有固定的修饰符:public static
 */
public class InnerImplement implements Outer.Inner {
    public void inner(){}
}

了解实现类的外部接口和实现类内部接口问题之后,可以进行 Map 集合的另一种遍历,使用内部接口

4. Map 集合的遍历:键值对映射关系

  • 实现思想:
    • Map 接口的方法 Set< Map.Entry<Key,Value> > entrySet()
      1. 方法返回 Set 集合,集合中存储的元素,比较特殊
      2. 存储的是 Map 集合中,键值对映射关系的对象,用内部接口 Map.Entry 表示
    • 遍历 Set 集合
    • 取出 Set 集合的元素
      1. 取出的是 Map.Entry 接口对象(实现类)
      2. 使用接口的对象方法:getKey()getValue()
 public static void mapEntrySet(){
     Map<String,String> map = new HashMap<String, String>();
     map.put("a","java");
     map.put("b","c++");
     map.put("c","php");
     map.put("d","python");
     map.put("e","erlang");
     // Map 接口的方法 Set< Map.Entry<Key,Value> > entrySet()
     Set<Map.Entry<String,String>>  set = map.entrySet();
     // 遍历 Set 集合
     Iterator<Map.Entry<String,String>> it = set.iterator(); // 迭代器泛型要和集合一致
     while (it.hasNext()){
         // 取出 Set 集合的元素
         Map.Entry<String,String> entry =  it.next(); // 取出的是接口的实现类
         // 接口的对象方法:getKey()  getValue()
         String key = entry.getKey();
         String value = entry.getValue();
         System.out.println(key +"="+ value);
     }
 }

四、Map 接口的实现类 HashMap

HashMap 是一个 Map 接口的实现类

  • HashMap 集合特点:
    • 是哈希表结构
    • 保证键唯一性,用于键的对象,必须重写 hashCode()equals() 方法
    • 线程不安全集合,运行速度快
    • 集合允许使用 null,作为键或者值

定义一个 Person 类:

public class Person {
    private String name;
    private int age;
    public Person(){}
    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    // 重写 hashCode(),equals() 方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
    /**
     * HashMap 集合
     * 键是字符串,值是 Person
     */
    public static void hashMap1(){
        Map<String, Person> map =  new HashMap<String, Person>();
        map.put("a",new Person("张三",20));
        map.put("b",new Person("张三",20));
        map.put("c",new Person("张三",20));
        map.put(null,null);
        // 由于 Map 集合无法使用增强 for 循环遍历所以要把它转换成 Set 集合
        // 一、第一种遍历方法:
        // 1.完整写法:
        Set<String> set = map.keySet();
        for(String key : set()){
            Person person =  map.get(key);
            System.out.println(key+"="+ person);
        }
        // 2.压缩写法:
        // Set<String> set = map.keySet();
        for(String key : map.keySet()){
            // Person person =  map.get(key);
            System.out.println(key+"="+ map.get(key));
        }
        // 二、第二种遍历方法:
        for(Map.Entry<String,Person> entry : map.entrySet()){
            System.out.println(entry.getKey()+"==="+entry.getValue());
        }
        
    /**
     * HashMap 集合
     * 键是 Person,值是 String
     */
    public static void hashMap2(){
        Map<Person,String> map = new HashMap<Person, String>();
        map.put(new Person("a",20),"广东");
        map.put(new Person("b",22),"香港");
        map.put(new Person("b",22),"广西"); // 不重写 hashCode(),equals()方法会出现两个 b,如果hashCode(),equals()方法在 Person 类中被重写则就会有一个,前一个会被覆盖
        map.put(new Person("c",24),"澳门");
        map.put(new Person("d",26),"深圳");
        System.out.println("map = " + map);
    }

1. HashMap 的子类 LinkedHashMap

LinkedHashMap 继承 HashMap 实现 Map 接口,LinkedHashMap 底层实现原理是哈希表
特性:①双向链,②存取有序, ③线程不安全,运行速度快,④其它的特性和父类 HashMap 一样
(LinkedHashSet 依赖的是 LinkedHashMap,LinkedHashSet 本身没有什么功能)

public static void main(String[] args) {
    Map<String,String> map = new LinkedHashMap<String, String>();
    map.put("a","qq");
    map.put("b","qq");
    map.put("c","qq");
    System.out.println(map); // 怎么存怎么取
}

五、 Map 接口的实现类 Hashtable 集合类

Map 接口的实现类 Hashtable,Hashtable 类诞生于 JDK1.0 版本,Map 接口诞生于 JDK1.2 版本,Hashtable 类从 JDK1.2 开始,改进为实现 Map 接口

  • Hashtable 类的特点:
    • 底层数据结构是哈希表
    • 线程安全,运行速度慢,所以被更加先进的 HashMap 取代(Hashtable 的使用和 HashMap 一样)
    • 不允许 null 值,null 键,,存储 null 会直接抛出空指针异常

1. Hashtable 的子类 Properties

  • Properties 集合特点:
    • 继承 Hashtable,实现 Map 接口
    • 底层是哈希表结构
    • 线程是安全的,运行速度慢
    • 集合没有泛型的写法,键和值的数据类型锁定为 String 类型
    • 集合有自己的特有方法
    • 此集合可以和 IO 流对象结合使用,实现数据的持久存储
    • 它其中有一个方法和 IO 相关:load (输入流)
    /**
     *  集合存储键值对
     *  Properties 集合存储方法:setProperty(String key,String value) (其实这其中还是调用的 put() 方法)
     */
    public static void prop1(){
        Properties prop = new Properties();
        prop.setProperty("a","1");
        prop.setProperty("b","2");
        prop.setProperty("c","3");
        System.out.println(prop);
    }
    
    /**
     * 集合取出元素
     *  Properties 集合取出方法:getProperty(String key)
     */
    public static void prop2(){
        Properties prop = new Properties();
        prop.setProperty("a","1");
        prop.setProperty("b","2");
        prop.setProperty("c","3");
        System.out.println(prop);
        String value = prop.getProperty("a");
        System.out.println(value);
    }
    
 	/**
     * 集合遍历
     *   Properties 类的方法:stringPropertyNames() [等效于 map.keySet()] 返回 Set 集合
     *   Set 集合存储的是 Properties 集合的所有键
     */
    public static void prop3(){
        Properties prop = new Properties();
        prop.setProperty("a","1");
        prop.setProperty("b","2");
        prop.setProperty("c","3");
        Set<String> set = prop.stringPropertyNames();
        for(String key : set){
            System.out.println(key +"="+ prop.getProperty(key));
        }
    }

六、Collection 接口下的 List 接口的实现类 Vector 集合类

List 接口的实现类 Vector,命运和 Hashtable 一样
Vector 类诞生于 JDK1.0 版本,List 接口诞生于 JDK1.2 版本

  • Vector类的特点:
    • 底层实现结构是数组
    • 数组的默认容量是10,每次扩容是:原来的长度 * 2
    • 线程安全,运行速度慢,所以被 ArrayList 取代(Vector 的使用和 ArrayList 一样)

七、 Collection 接口下的 Map 接口的实现类 TreeMap 集合

  • TreeMap 集合的特点:
    • 底层实现是红黑树结构 (添加查询速度都比较快)
      • 线程不安全,但是运行速度快
    • 存储到 TreeMap 中的元素,要求对键进行排序(与值无关)
      • 排序依据:
        1. 对象的自然顺序:作为键的对象,实现了接口 Comparable(只要实现了这个接口就叫做具备了自然顺序)
        2. 可以自己提供比较器,需要实现接口 Comparator,(比较器的优先级高)

应用之前定义的 Person 类,并进行实现接口 Comparable ,重写抽象方法:

public class Person implements Comparable<Person>{
    /**
     *  为使 TreeMap 集合存储对象后可以取出对象,所以要实现接口 Comparable
     *  重写抽象方法,这样 Person 就具备了自然顺序
     */
    private String name;
    private int age;

    /**
     *  进行比较
     *  compareTo 此方法由 集合 TreeMap 调用
     *  传递相关的参数:集合中后来的参数是 this ,先来的对象是参数 p
     */
    public int compareTo(Person p){
        return this.age - p.age; // 这样 Person
    }

    public Person(){}
    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

方法:

    /**
     * TreeMap 集合存储对象
     * Person 作为键,字符串作为值
     */
    public static void treeMap01(){
        Map<Person,String> map = new TreeMap<Person, String>();
        map.put(new Person("a",20),"广东");
        map.put(new Person("b",19),"广西");
        System.out.println("map = " + map);
        // 为了具备自然顺序,调用的比较的方法返回值是 0 时,后者就会覆盖前者
    }

定义一个 Student 类:

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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

自定义的比较器:

/**
 * 自定义的比较器,实现接口 Comparator
 */
class MyCom implements Comparator<Student>{
    /**
     *  方法compare 是TreeMap调用
     *  传递参数,后来的对象传递到s1, 已经有的对象传递到s2
     */
   public int compare(Student s1, Student s2){
       return s1.getAge() - s2.getAge();
   }
}

方法:

	/**
     * TreeMap 集合存储对象
     * Student 作为键,字符串作为值
     * 自定义的比较器排序
     */
    public static void treeMap02(){
        Map<Student,String> map = new TreeMap<Student, String>( new MyCom() );
        map.put(new Student("a",20),"广东");
        map.put(new Student("b",19),"广西");
        System.out.println("map = " + map);
    }

八、案例:客户的关系管理系统

需求:

  1. 必须提供用户的菜单(展示本系统的所有功能,用户选择)
  2. 定义类描述客户的数据,属性:姓名,年龄,邮件
  3. 客户数据,存储在集合,定义集合,存储客户对象
  4. 初始化数据,程序启动,集合中存储一些数据
  5. 添加客户数据 (录入信息),重名的不能添加
  6. 修改客户数据,判断是否存在用户,检测姓名
  7. 删除客户数据,判断是否存在用户,检测姓名
  8. 查询数据:集合遍历

定义用户类:

/**
 * 客户类 对象
 */
public class Customer {
    private String name; // 姓名
    private int age; // 年龄
    private String email; // 电子邮件
    public Customer(){}
    public Customer(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

客户关系管理系统:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 客户关系管理系统
 */
public class CustomerManager {
    // 定义集合(增删改查)
    private List<Customer>customerList=new ArrayList<>();
    // 共性方法,成为成员私有变量
    private Scanner scanner=new Scanner(System.in);
    // 集合数据的初始化(让系统中先存在一部分数据)
    private void init(){
        customerList.add(new Customer("张三",20,"zs@qq.com"));
        customerList.add(new Customer("李四",22,"ls@sina.com"));
    }
    // 构造器(外界一 new 创建对象,就会有数据)
    public CustomerManager(){
        init();
    }
    // 提供用户的功能菜单
    public void menu(){
        while (true){ // 只有在读入退出系统时才退出
            System.out.println("欢迎进入客户的关系管理系统");
            System.out.println("1.添加用户的数据");
            System.out.println("2.修改用户的数据");
            System.out.println("3.删除用户的数据");
            System.out.println("4.查找用户的数据");
            System.out.println("5.退出系统");
            System.out.println("请输入编号,选择功能");
            String number=scanner.nextLine();
            switch (number){
                case "1":
                    // 调用增加客户信息的方法
                    addCustomer();
                    break;
                case "2":
                    // 调用修改客户信息的方法
                    break;
                case "3":
                    // 调用删除客户信息的方法
                    deleteCustomer();
                    break;
                case "4":
                    // 调用查找客户信息的方法
                    selectCustomer();
                    break;
                case "5":
                    System.exit(0); //虚拟机停止运行
                default:
                    System.out.println("输入错误!");
                    break;
            }
        }
    }


    // 添加客户的方法
    private void addCustomer(){
        // 提示
        System.out.println("选择的是添加客户数据");
        System.out.println("请输入姓名:");
        String name=scanner.nextLine();
        // 遍历集合,取出每个客户的对象,检查是否重名,禁止输入重名
        for(Customer customer:customerList){
            if(customer.getName().equals(name)){
                // 重名禁止添加
                System.out.println("姓名已存在,请重新选择功能:");
                return; // 循环结束,方法结束
            }
        }
        System.out.println("请输入年龄:");
        int age=Integer.parseInt(scanner.nextLine()); // 转换数据类型吗,nextInt() 会有异常
        System.out.println("输入邮箱地址:");
        String email=scanner.nextLine();
        // 把用户的数据,存储到 customer 对象,存储集合
        customerList.add(new Customer(name,age,email));
        // 提示:
        System.out.println("数据添加成功!");
    }
    // 查询客户数据 遍历集合
    private void selectCustomer(){
        if(customerList.isEmpty()){ // 判断集合是否为空,没有元素直接结束方法
            System.out.println("对不起,没有该数据");
            return; // 方法结束
        }
        for(Customer customer:customerList){
            System.out.println(customer);
        }
    }
    // 删除用户数据
    private void deleteCustomer(){
        System.out.println("选择的是删除用户功能");
        System.out.println("请输入要删除的姓名:");
        String name=scanner.nextLine();
        // 定义变量,保存可以删除的索引
        int index=-1;
        // 遍历集合,查找集合中是否有这个名字
        for(int x=0;x<customerList.size();x++){
            Customer customer=customerList.get(x);
            if(customer.getName().equals(name)){
                // 如果集合中有这个名字,循环结束
                index=x; // 记录名字出现的索引
                break;
            }
        }
        if(index==-1){
            System.out.println("对不起,没有该用户");
            return;
        }
        customerList.remove(index);
        System.out.println("删除成功!");
    }
}

测试:

    public static void main(String[] args) {
        // 启动程序,调用菜单方法
        new CustomerManager().menu();
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值