Java学习记录 Day14(List集合、泛型、for-each、可变参数)

Day 14

2019年5月3日。
这是我学习Java的第十四天。
这一天,我学到了以下的知识。

集合

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类

集合和数组的区别有

  1. 长度区别:
    数组的长度是固定的而集合的长度是可变的
  2. 存储数据类型的区别:
    数组可以存储基本数据类型 , 也可以存储引用数据类型; 而集合只能存储引用数据类型
  3. 内容区别:
    数组只能存储同种数据类型的元素 ,集合可以存储不同类型的元素

在集合框架中,Collection是顶层父接口,List和Set为子接口,List的实现类又有ArrayList、LinkedList、Vector,而Set的实现类有HashSet、LinkedHashSet、TreeSet,集合框架图如下所示
在这里插入图片描述
首先,讲解Collection顶层父接口下的方法

  • Collection
    常用的成员方法

    • 添加功能

      • boolean add(Object obj)添加一个元素
      • boolean addAll(Collection c)添加一个集合的元素 (给一个集合添加进另一个集合中的所有元素)
    • 删除功能

      • void clear()移除所有元素
      • boolean remove(Object o)移除一个元素
      • boolean removeAll(Collection c)移除一个集合的元素(移除一个以上返回的就是true) 删除的元素是两个集合的交集元素,如果没有交集元素 则删除失败 返回false
    • 判断功能

      • boolean contains(Object o)判断集合中是否包含指定的元素
      • boolean containsAll(Collection c)判断集合中是否包含指定的集合元素(这个集合 包含 另一个集合中所有的元素才算包含 才返回true)
      • boolean isEmpty()判断集合是否为空
    • 获取功能

      • Iterator<E> iterator()获取一个迭代器(主要用于遍历集合)
        - iterator().next()让迭代器的指针下移
        - iterator().hasNext()判断迭代器的指针下面是否为空
    • 长度功能

      • int size()元素的个数
    • 交集功能

      • boolean retainAll(Collection c)获取两个集合的交集元素(交集:两个集合都有的元素)
    • 转换功能

      • Object[] toArray()将集合转换为数组(依次获取集合中的每一个元素)

其次,讲解List子接口下的方法

  • List
    List,特点为元素有序,并且每一个元素都存在一个索引,元素可以重复
    常用的特有方法
    • void add(int index,E element)在指定索引处添加元素
    • E remove(int index)移除指定索引处的元素 ,返回的是移除的元素
    • E get(int index)获取指定索引处的元素
    • E set(int index,E element)更改指定索引处的元素 返回的而是被替换的元素
    • ListIterator<E> listIterator()获取一个list迭代器
      - boolean hasPrevious()是否存在前一个元素
      - E previous():返回列表中的前一个元素
      - 注意: 通过以上两个方法,可以实现反向遍历 但是注意,要在成反向遍历之前,要先进行正向遍历 ,这样迭代器的指针才能移到最后。如果直接反向遍历是没有效果的 ,因为指针默认位置就在最前面,它前面没有元素

最后,讲解List接口下的实现类(Set接口和Set接口下的实现类暂时不讲解)

  • ArrayList
    底层数据结构是数组,查询快,增删慢。
    线程不安全,效率高。

  • LinkedList
    底层数据结构是链表,查询慢,增删快。
    线程不安全,效率高。

  • Vector
    底层数据结构是数组,查询快,增删慢。
    线程安全,效率低。

集合框架的并发异常

当我们用Iterator这个迭代器遍历采用hasNext方法和next方法,用集合去修改集合,就会出现并发修改异常(ConcurrentModificationException)
原因是我们的迭代依赖与集合,当我们往集合中添加好了元素之后,获取迭代器 ,那么迭代器已经知道了集合的元素个数,这个时候你在遍历的时候又突然想给集合里面加一个元素(用的是集合的add方法),那迭代器不同意,就报错了
解决方案如下

  • 用ListIterator迭代器遍历,并且用迭代器自带的add方法添加元素,那就不会报错了,步骤如下
    - 迭代器迭代元素,迭代器修改元素(ListIterator的特有功能add)
    - 集合遍历元素,集合修改元素
  • 使用for循环遍历集合,添加元素,不会报错

函数式接口

JDK1.8之后引入的一种机制,若接口中只有一个抽象方法,那么就可以使用Lanbda表达式来简写匿名内部类

代码如下

public class MyTest3 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(200);
        list.add(100);

        //Consumer con= new Consumer() {
        //     @Override
        //     public void accept(Object o) {
        //         System.out.println(o);
        //     }
        // };
        //函数式接口:接口中只有一个抽象方法,那么你就可以使用 Lambda 表达式来简写匿名内部类
        Consumer con = (obj) -> System.out.println(obj);

        Consumer con2 = System.out::println;
        //JDK1.8 对应函数式接口,可以使用Lambda 表达式来简写
        //list.forEach(con2);
        list.forEach(new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        });

    }
}

泛型

JDK1.5之后引入的一种机制,是把类型明确工作推迟到创建对象或调用方法时,再去明确的一种机制,泛型可以提高代码的灵活性,扩展性,把问题提前到编译器
格式<数据类型> 这里的数据类型只能是引用数据类型
优点

  1. 把运行时期的问题提前到了编译期间(泛型只在编译期有效 ,但在运行期就擦除了)
  2. 避免了强制类型转换
  3. 优化了程序设计,解决了黄色警告线

使用


  • - 概述:把泛型定义在方法上
    - 格式:public <泛型类型> 返回类型 方法名(泛型类型 变量名
    - 定义

    public class Phone {
    
    /**
     * 泛型方法
     */
    public <E> void show(E e){
    	System.out.println(e);
    }
    
  • 接口
    - 概述:把泛型定义在接口上
    - 格式:public interface 接口名<泛型类型>
    - 定义

    //一般定义
    public interface Inter<T> {
    
    public abstract void show(T t) ;
    }
    ——————————————————————————————————————
    //特殊定义一: 在定义子类的时候,已经可以明确数据类型了
    //public class InterImpl implements Inter<String> {
    //
    //	@Override
    //	public void show(String t) {
    //		System.out.println(t);
    //	}
    //
    //}
    ——————————————————————————————————————
    //特殊定义二: 在定义子类的时候,还不知道到底使用什么数据类型,这个时候就需要将这个子类也定义成泛型
    public class InterImpl<T> implements Inter<T>  {
    @Override
      public void show(T t) {
    	System.out.println(t);
     }
    }
    

通配符

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

for-each循环

JDK1.5之后引入的一种机制,是简化数组和Collection集合的遍历
格式

for(元素数据类型 变量 : 数组或者Collection集合) {
		使用变量即可,该变量就是元素
	}

使用步骤

  1. 先确定容器中的元素的数据类型
  2. 确定容器的名字
  3. 注意:使用新式for循环在遍历时,若想在集合中添加或删除元素,同样会报出并发修改异常的错误(解决方案如上)

可变参数

若在定义方法的时候不知道该定义多少个参数,就可以使用可变参数
格式修饰符 返回值类型 方法名(数据类型… 变量名){}

注意事项

  1. 这里的变量其实是一个数组
  2. 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

范例

public static int add(int... a){
	
	// 定义一个累加变量
	int sum = 0 ;
	
	for(int s : a ){
		sum += s ;
	}
	
	return sum;
}

特殊
在集合中,存在一个与可变参数产生联动的方法:public static <T> List<T> asList(T... a)
该方法可以把多个数组转换成集合,但需要注意的是:

  • 若传入一个或多个int[]数组,则集合里面存放的是数组的引用
  • 若传入一个或多个Integer[]数组,则会把数组的元素取出来并放到集合中
  • 若通过这个方法获取到了一个转换过来的集合,则这个集合的长度是固定的,即只能从集合中取出元素,而不能增删元素

ArrayList嵌套

类似于数组的遍历,集合也有相似的遍历方式(即用两层for循环进行遍历)

代码如下

public class MyTest {
    public static void main(String[] args) {
        //A:
        //需求:
        //我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>
        //但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList<Student>。
        //而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢 ?
        //集合嵌套之ArrayList嵌套ArrayList

        ArrayList<Student> javaList = new ArrayList<>();
        javaList.add(new Student("张三1", 23));
        javaList.add(new Student("张三2", 23));
        javaList.add(new Student("张三3", 23));

        ArrayList<Student> webList = new ArrayList<>();
        webList.add(new Student("张三4", 23));
        webList.add(new Student("张三5", 23));
        webList.add(new Student("张三6", 23));

        ArrayList<Student> linuxList = new ArrayList<>();
        linuxList.add(new Student("张三7", 23));
        linuxList.add(new Student("张三8", 23));
        linuxList.add(new Student("张三9", 23));

        //创建一个大的集合,大的集合放小的集合
        ArrayList<ArrayList<Student>> maxList = new ArrayList<>();
        maxList.add(javaList);
        maxList.add(webList);
        maxList.add(linuxList);

        //
        //遍历:普通for循环
        for (int i = 0; i < maxList.size(); i++) {
            ArrayList<Student> minList = maxList.get(i);
            for (int j = 0; j < minList.size(); j++) {
                Student student = minList.get(j);
                System.out.println(student.getName() + "===" + student.getAge());
            }

        }
        System.out.println("----------------------------------------------------------");
        //新式for循环遍历
        for (ArrayList<Student> students : maxList) {
            for (Student student : students) {
                System.out.println(student.getName() + "===" + student.getAge());
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41151659/article/details/89928965