Java基础-泛型
泛型和集合
泛型
泛型即参数化类型,也就是说数据类型变成了一个可变的参数,在不使用泛型的情况下,参数的数据类型都是写死了的,使用泛型之后,可以根据程序的需要进行改变。
- 只能是引用类型,不能是简单数据类型。
- 泛型参数可以有多个。
- 可以用使用 extends 语句或者 super 语句 如 表示类型的上界,T 只能是 superClass 或其子类, 表示类型的下界,K 只能是 childClass 或其父类。 
- 可以是通配符类型,比如常见的 Class<?>。单独使用 ? 可以表示任意类型。也可以结合 extends 和 super 来进行限制
/*
使用T代表类型,无论何时都没有比这更具体的类型来区分它。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。
*/
class Test<T> {
    private T ob;
    /*
    定义泛型成员变量,定义完类型参数后,可以在定义位置之后的方法的任意地方使用类型参数,就像使用普通的类型一样。
    注意,父类定义的类型参数不能被子类继承。
    */
    //构造函数
    public Test(T ob) {
        this.ob = ob;
    }
    //getter 方法
    public T getOb() {
        return ob;
    }
    //setter 方法
    public void setOb(T ob) {
        this.ob = ob;
    }
    public void showType() {
        System.out.println("T的实际类型是: " + ob.getClass().getName());
    }
}
public class TestDemo {
    public static void main(String[] args) {
        // 定义泛型类 Test 的一个Integer版本
        Test<Integer> intOb = new Test<Integer>(88);
        intOb.showType();
        int i = intOb.getOb();
        System.out.println("value= " + i);
        System.out.println("----------------------------------");
        // 定义泛型类Test的一个String版本
        Test<String> strOb = new Test<String>("Hello Gen!");
        strOb.showType();
        String s = strOb.getOb();
        System.out.println("value= " + s);
    }
}
T的实际类型是: java.lang.Integer
value= 88
----------------------------------
T的实际类型是: java.lang.String
value= Hello Gen!
// Test.java
public class hello {
    /*
    注意:定义带类型参数的方法,其主要目的是为了表达多个参数以及返回值之间的关系。例如本例子中T和S的继承关系, 返回值的类型和第一个类型参数的值相同。
    */
    public<T, S extends T> T testDemo(T t, S s){
        System.out.println("我是 T 类型,我的类型是" + t.getClass().getName());
        System.out.println("我是 S 类型,我的类型是" + s.getClass().getName());
        return t;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        hello test = new hello();
        System.out.println("hello=ok");
        Dog d = new Dog();
        System.out.println("dog=ok");
        Animal a0 = new Animal();
        System.out.println("animal=ok");
        Animal a1  = test.testDemo(a0, d);
        System.out.println("test=ok");
        System.out.println("我是对象 a1,我的类型是" + a1.getClass().getName());
    }
}
hello=ok
我是动物
我是狗
dog=ok
我是动物
animal=ok
我是 T 类型,我的类型是Animal
我是 S 类型,我的类型是Dog
test=ok
我是对象 a1,我的类型是Animal
import java.util.List;
import java.util.ArrayList;
public class hello {
    // List<?> 表示接受一个元素为任意类型的列表 List。
    public void testDemo(List<?> s){
        for(Object obj:s){
            System.out.println("我的类型是" + obj.getClass().getName());
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        hello test = new hello();
        Dog a0 = new Dog();
        System.out.println("dog=ok");
        Animal a1 = new Animal();
        System.out.println("animal=ok");
        // 声明一个接收元素类型是 Animal 的列表 List s。
        // 然后创建一个元素类型是 Animal 的 ArrayList 赋值给 s。
        List<Animal> s = new ArrayList<Animal>();
        // Dog a0 是 Animal 的子类,可以向上转型为 Animal 类型
        s.add(a0);
        s.add(a1);
        System.out.println("add=ok");
        test.testDemo(s);
        System.out.println("test=ok");
    }
}
我是动物
我是狗
dog=ok
我是动物
animal=ok
add=ok
我的类型是Dog
我的类型是Animal
test=ok
Collection
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大内容:对外的接口、接口的实现和对集合运算的算法。

| 方法 | 返回值 | 说明 | 
|---|---|---|
| add(E e) | boolean | 向 collection 的尾部追加指定的元素(可选操作) | 
| addAll(Collection<? extend E> c) | boolean | 将指定 collection 中的所有元素都添加到此 collection 中(可选操作) | 
| clear() | void | 移除此 collection 中的所有元素(可选操作) | 
| contains(Object o) | boolean | 如果此 collection 包含指定的元素,则返回 true | 
| containsAll(Collection<?> c) | boolean | 如果此 collection 包含指定 collection 的所有元素,则返回 true | 
| equals(Object o) | boolean | 比较此 collection 与指定对象是否相等 | 
| hashCode() | int | 返回此 collection 的哈希码值 | 
| isEmpty() | boolean | 如果此 collection 不包含元素,则返回 true | 
| iterator() | Iterator | 返回在此 collection 的元素上进行迭代的迭代器 | 
| remove(Object o) | boolean | 移除此 collection 中出现的首个指定元素(可选操作) | 
| removeAll(Collection<?> c) | boolean | 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作) | 
| retainAll(Collection<?> c) | boolean | 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作) | 
| size() | int | 返回此 collection 中的元素数 | 
| toArray() | Object[] | 返回包含此 collection 中所有元素的数组 | 
| toArray(T[] a) | T[] | 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的 | 
List
List 是一个接口,不能实例化 ,需要一个具体类来实现实例化。
List 集合中的对象按照一定的顺序排放,里面的内容可以重复。 List 接口实现的类有:ArrayList(实现动态数组),Vector(实现动态数组),LinkedList(实现链表),Stack(实现堆栈)。
| 方法 | 返回值 | 说明 | 
|---|---|---|
| add(int index, E element) | void | 在列表的指定位置插入指定元素(可选操作) | 
| addAll(int index, Collection<? extends E> c) | boolean | 将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作) | 
| get(int index) | E | 返回列表中指定位置的元素 | 
| indexOf(Object o) | int | 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1 | 
| lastIndexOf(Object o) | int | 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1 | 
| listIterator() | ListIterator | 返回此列表元素的列表迭代器(按适当顺序) | 
| listIterator(int index) | ListIterator | 返回此列表元素的列表迭代器(按适当顺序),从列表的指定位置开始 | 
| remove(int index) | E | 移除列表中指定位置的元素(可选操作) | 
| set(int index, E element) | E | 用指定元素替换列表中指定位置的元素(可选操作) | 
| subList(int fromIndex, int toIndex) | List | 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图 | 
ArrayList
ArrayList 类实现一个可增长的动态数组,位于 java.util.ArrayList。实现了 List 接口,它可以存储不同类型的对象(包括 null 在内),而数组则只能存放特定数据类型的值

import java.util.*;
public class ListTest {
    //集合后面的<>代表泛型的意思
    //泛型是规定了集合元素的类型
    /**
     * 用于存放学生的List
     */
    public List<Student> students;
    public ListTest() {
        this.students = new ArrayList<Student>();
    }
    /**
     * 用于往students中添加学生
     */
    public void testAdd() {
        // 创建一个学生对象,并通过调用add方法,添加到学生管理List中
        Student st1 = new Student("1", "张三");
        //add(int index, E element)	void	在列表的指定位置插入指定元素(可选操作)
        students.add(st1);
        //get(int index)	E	返回列表中指定位置的元素
        // 取出 List中的Student对象 索引为0 也就是第一个
        Student temp = students.get(0);
        System.out.println("添加了学生:" + temp.id + ":" + temp.name);
        Student st2 = new Student("2", "李四");
        //添加到list中,插入到索引为0的位置,也就是第一个
        students.add(0, st2);
        Student temp2 = students.get(0);
        System.out.println("添加了学生:" + temp2.id + ":" + temp2.name);
        // 对象数组的形式添加
        Student[] student = {new Student("3", "王五"), new Student("4", "马六")};
        // Arrays类包含用来操作数组(比如排序和搜索)的各种方法,asList() 方法用来返回一个受指定数组支持的固定大小的列表
        // 该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新
        students.addAll(Arrays.asList(student));
        Student temp3 = students.get(2);
        Student temp4 = students.get(3);
        System.out.println("添加了学生:" + temp3.id + ":" + temp3.name);
        System.out.println("添加了学生:" + temp4.id + ":" + temp4.name);
        Student[] student2 = {new Student("5", "周七"), new Student("6", "赵八")};
        students.addAll(2, Arrays.asList(student2));
        Student temp5 = students.get(2);
        Student temp6 = students.get(3);
        System.out.println("添加了学生:" + temp5.id + ":" + temp5.name);
        System.out.println("添加了学生:" + temp6.id + ":" + temp6.name);
    }
    /**
     * 取得List中的元素的方法
     */
    public void testGet() {
        int size = students.size();
        for (int i = 0; i < size; i++) {
            Student st = students.get(i);
            System.out.println("学生:" + st.id + ":" + st.name);
        }
    }
    /**
     * 通过迭代器来遍历
     * 迭代器的工作是遍历并选择序列中的对象,Java 中 Iterator 只能单向移动
     */
    public void testIterator() {
        // 通过集合的iterator方法,取得迭代器实例
        Iterator<Student> it = students.iterator();
        System.out.println("有如下学生(通过迭代器访问):");
        while (it.hasNext()) {
            Student st = it.next();
            System.out.println("学生" + st.id + ":" + st.name);
        }
    }
    /**
     * 通过for each 方法访问集合元素
     *
     */
    public void testForEach() {
        System.out.println("有如下学生(通过for each):");
        for (Student obj : students) {
            Student st = obj;
            System.out.println("学生:" + st.id + ":" + st.name);
        }
        //使用java8 Steam将学生排序后输出
        students.stream()//创建Stream
                //通过学生id排序
                .sorted(Comparator.comparing(x -> x.id))
                //输出
                .forEach(System.out::println);
    }
    /**
     * 修改List中的元素
     *
     */
    public void testModify() {
        students.set(4, new Student("3", "吴酒"));
    }
    /**
     * 删除List中的元素
     *
     */
    public void testRemove() {
        Student st = students.get(4);
        System.out.println("我是学生:" + st.id + ":" + st.name + ",我即将被删除");
        students.remove(st);
        System.out.println("成功删除学生!");
        testForEach();
    }
    public static void main(String[] args) {
        ListTest lt = new ListTest();
        lt.testAdd();
        lt.testGet();
        lt.testIterator();
        lt.testModify();
        lt.testForEach();
        lt.testRemove();
    }
}
  // IntelliJ API Decompiler stub source generated from a class file
  // Implementation of methods is not available
public class Student {
    public java.lang.String id;
    public java.lang.String name;
    public Student(java.lang.String id, java.lang.String name) { /* compiled code */ }
    public java.lang.String toString() { /* compiled code */ }
}
添加了学生:1:张三
添加了学生:2:李四
添加了学生:3:王五
添加了学生:4:马六
添加了学生:5:周七
添加了学生:6:赵八
学生:2:李四
学生:1:张三
学生:5:周七
学生:6:赵八
学生:3:王五
学生:4:马六
有如下学生(通过迭代器访问):
学生2:李四
学生1:张三
学生5:周七
学生6:赵八
学生3:王五
学生4:马六
有如下学生(通过for each):
学生:2:李四
学生:1:张三
学生:5:周七
学生:6:赵八
学生:3:吴酒
学生:4:马六
Student{id='1', name='张三'}
Student{id='2', name='李四'}
Student{id='3', name='吴酒'}
Student{id='4', name='马六'}
Student{id='5', name='周七'}
Student{id='6', name='赵八'}
我是学生:3:吴酒,我即将被删除
成功删除学生!
有如下学生(通过for each):
学生:2:李四
学生:1:张三
学生:5:周七
学生:6:赵八
学生:4:马六
Student{id='1', name='张三'}
Student{id='2', name='李四'}
Student{id='4', name='马六'}
Student{id='5', name='周七'}
Student
Map
Map 接口也是一个非常重要的集合接口,用于存储键 / 值对。Map 中的元素都是成对出现的,键值对就像数组的索引与数组的内容的关系一样,将一个键映射到一个值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。我们可以通过键去找到相应的值。

| 方法 | 返回值 | 说明 | 
|---|---|---|
| clear() | void | 从此映射中移除所用映射关系(可选操作) | 
| containsKey(Object key) | boolean | 如果此映射包含指定键的映射关系,则返回 true | 
| containsValue(Object value) | boolean | 如果此映射将一个或多个键映射到指定值,则返回 true | 
| entrySet() | Set<Map.Entry<K,V>> | 返回此映射中包含的映射关系的 Set 视图 | 
| equals(Object o) | boolean | 比较指定的对象与此映射是否相等 | 
| get(Object key) | V | 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null | 
| hashCode() | int | 返回此映射的哈希码值 | 
| isEmpty() | boolean | 如果此映射未包含键 - 值映射关系,则返回 true | 
| keySet() | Set | 返回此映射中包含的键的 Set 视图 | 
| put(K key, V value) | V | 将指定的值与此映射中的指定键关联(可选操作) | 
| putAll(Map<? extends K, ? extends V> m) | void | 从指定映射中将所有映射关系复制到此映射中(可选操作) | 
| remove(Object key) | V | 如果存在一个键的映射关系,则将其从此映射中移除(可选操作) | 
| size | int | 返回此映射中的键 - 值映射关系数 | 
| values() | Collection | 返回此映射中包含的值的 Collection 视图 | 
HashMap
HashMap 是基于哈希表的 Map 接口的一个重要实现类。HashMap 中的 Entry 对象是 无序 排列的,Key 值和 value 值都可以为 null,但是一个 HashMap 只能有一个 key 值为 null 的映射(key 值不可重复)。
// MapTest.java
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
public class MapTest {
    /**
     * 用来承装课程类型对象
     */
    public Map<String, Course> courses;
    /**
     * 在构造器中初始化 courses 属性
     * @param args
     */
    public MapTest() {
        this.courses = new HashMap<String, Course>();
    }
    /**
     * 测试添加:输入课程 ID,判断是否被占用
     * 若未被占用,输入课程名称,创建新课程对象
     * 并且添加到 courses 中
     * @param args
     */
    public void testPut() {
        //创建一个 Scanner 对象,用来获取输入的课程 ID 和名称
        Scanner console = new Scanner(System.in);
        for(int i = 0; i < 3; i++) {
            System.out.println("请输入课程 ID:");
            String ID = console.next();
            //判断该 ID 是否被占用
            Course cr = courses.get(ID);
            if(cr == null){
                //提示输入课程名称
                System.out.println("请输入课程名称:");
                String name = console.next();
                //创建新的课程对象
                Course newCourse = new Course(ID,name);
                //通过调用 courses 的 put 方法,添加 ID-课程映射
                courses.put(ID, newCourse);
                System.out.println("成功添加课程:" + courses.get(ID).name);
            }
            else {
                System.out.println("该课程 ID 已被占用");
                continue;
            }
        }
    }
    /**
     * 测试 Map 的 keySet 方法
     * @param args
     */
    public void testKeySet() {
        //通过 keySet 方法,返回 Map 中的所有键的 Set 集合
        Set<String> keySet = courses.keySet();
        //遍历 keySet,取得每一个键,在调用 get 方法取得每个键对应的 value
        for(String crID: keySet) {
            Course cr = courses.get(crID);
            if(cr != null){
                System.out.println("课程:" + cr.name);
            }
        }
    }
    /**
     * 测试删除 Map 中的映射
     * @param args
     */
    public void testRemove() {
        //获取从键盘输入的待删除课程 ID 字符串
        Scanner console = new Scanner(System.in);
        while(true){
            //提示输出待删除的课程 ID
            System.out.println("请输入要删除的课程 ID!");
            String ID = console.next();
            //判断该 ID 是否对应的课程对象
            Course cr = courses.get(ID);
            if(cr == null) {
                //提示输入的 ID 并不存在
                System.out.println("该 ID 不存在!");
                continue;
            }
            courses.remove(ID);
            System.out.println("成功删除课程" + cr.name);
            break;
        }
    }
    /**
     * 通过 entrySet 方法来遍历 Map
     * @param args
     */
    public void testEntrySet() {
        //通过 entrySet 方法,返回 Map 中的所有键值对
        //entrySet()	Set<Map.Entry<K,V>>	返回此映射中包含的映射关系的 Set 视图
        Set<Entry<String,Course>> entrySet = courses.entrySet();
        for(Entry<String,Course> entry: entrySet) {
            System.out.println("取得键:" + entry.getKey());
            System.out.println("对应的值为:" + entry.getValue().name);
        }
    }
    /**
     * 利用 put 方法修改Map 中的已有映射
     * @param args
     */
    public void testModify(){
        //提示输入要修改的课程 ID
        System.out.println("请输入要修改的课程 ID:");
        //创建一个 Scanner 对象,去获取从键盘上输入的课程 ID 字符串
        Scanner console = new Scanner(System.in);
        while(true) {
            //取得从键盘输入的课程 ID
            String crID = console.next();
            //从 courses 中查找该课程 ID 对应的对象
            Course course = courses.get(crID);
            if(course == null) {
                System.out.println("该 ID 不存在!请重新输入!");
                continue;
            }
            //提示当前对应的课程对象的名称
            System.out.println("当前该课程 ID,所对应的课程为:" + course.name);
            //提示输入新的课程名称,来修改已有的映射
            System.out.println("请输入新的课程名称:");
            String name = console.next();
            Course newCourse = new Course(crID,name);
            courses.put(crID, newCourse);
            System.out.println("修改成功!");
            break;
        }
    }
    public static void main(String[] args) {
        MapTest mt = new MapTest();
        mt.testPut();
        mt.testKeySet();
        mt.testRemove();
        mt.testModify();
        mt.testEntrySet();
    }
}
// Course.java
public class Course {
    public String id;
    public String name;
    public Course(String id, String name){
        this.id = id;
        this.name = name;
    }
}
Set 和 HashSet
Set 接口也是 Collection 接口的子接口,它有一个很重要也是很常用的实现类——HashSet,Set 是元素无序并且不包含重复元素的 collection(List 可以重复),被称为集。
HashSet 由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
Collections
java.util.Collections 是一个工具类,他包含了大量对集合进行操作的静态方法。
| 方法名 | 描述 | 
|---|---|
| void sort(List list) | 按自然升序排序 | 
| void sort(List list, Comparator c) | 自定义排序规则排序 | 
| void shuffle(List list) | 随机排序,用于打乱顺序 | 
| void reverse(List list) | 反转,将列表元素顺序反转 | 
| void swap(List list, int i , int j) | 交换处于索引 i 和 j 位置的元素 | 
| int binarySearch(List list, Object key) | 二分查找,列表必须有序,返回找到的元素索引位置 | 
| int max(Collection coll) | 查找最大值 | 
| int min(Collection coll) | 查找最小值 | 
| void fill(List list, Object obj) | 使用 obj 填充 list 所有元素 | 
| boolean replaceAll(List list, Object oldVal, Object newVal) | 使用用 newVal 替换所有的 oldVal。 | 
| <K,V> Map<K,V> synchronizedMap(Map<K,V> m) | 将 m 包装为线程安全的 Map | 
| List synchronizedList(List list) | 将 list 包装为线程安全的 List | 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsDemo {
    public static void main(String[] args) {
//        创建一个空List
        List<Integer> list = new ArrayList<Integer>();
        //赋值
        list.add(3);
        list.add(5);
        list.add(7);
        list.add(9);
        list.add(12);
        System.out.print("初始顺序:");
        list.forEach(v -> System.out.print(v + "\t"));
        //打乱顺序
        Collections.shuffle(list);
        System.out.print("\n打乱顺序:");
        list.forEach(v -> System.out.print(v + "\t"));
        //反转
        Collections.reverse(list);
        System.out.print("\n反转集合:");
        list.forEach(v -> System.out.print(v + "\t"));
        //第一个位和最后一位交换
        Collections.swap(list,0,list.size()-1);
        System.out.print("\n交换第一位和最后一位:");
        list.forEach(v -> System.out.print(v + "\t"));
        //按自然升序排序
        Collections.sort(list);
        System.out.print("\nSort排序后:");
        list.forEach(v -> System.out.print(v + "\t"));
        //二分查找 必须排序后
        System.out.print("\n二分查找数值7的位置:"+Collections.binarySearch(list, 7));
        //返回线程安全的list
        List<Integer> synchronizedList = Collections.synchronizedList(list);
    }
}
初始顺序:3 5 7 9 12
打乱顺序:12 3 9 5 7
反转集合:7 5 9 3 12
交换第一位和最后一位:12 5 9 3 7
Sort排序后:3 5 7 9 12
二分查找数值7的位置:2
| 🐳  作者:hiszm 📢 版权:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,万分感谢。 💬 留言:同时 , 如果文中有什么错误,欢迎指出。以免更多的人被误导。 |  | 

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号