java基础学习-------容器(一)

1、泛型Generics

开发和学习中需要时刻和数据打交道,如何组织这些数据是我们编程中重要的内容。 我们一般通过“容器”来容纳和管理数据。那什么是“容器”呢?生活中的容器不难理解,是用来容纳物体的,如锅碗瓢盆、箱子和包等。程序中的“容器”也有类似的功能,就是用来容纳和管理数据。

事实上,我们第七章所学的数组就是一种容器,可以在其中放置对象或基本类型数据。

数组的优势:

是一种简单的线性序列,可以快速地访问数组元素,效率高。如果从效率和类型检查的角度讲,数组是最好的。

数组的劣势:

不灵活。容量需要事先定义好,不能随着需求的变化而扩容。比如:我们在一个用户管理系统中,要把今天注册的
所有用户取出来,那么这样的用户有多少个?我们在写程序时是无法确定的。因此,在这里就不能使用数组。

基于数组并不能满足我们对于“管理和组织数据的需求”,所以我们需要一种更强大、更灵活、容量随时可扩的容器来装载我们的对象。 这就是我们今天要学习的容器,也叫集合(Collection)。以下是容器的接口层次结构图:
在这里插入图片描述
为了能够更好的学习容器,我们首先要先来学习一个概念:泛型。

  泛型是JDK1.5以后增加的,它可以帮助我们建立类型安全的集合。在使用了泛型的集合中,遍历时不必进行强制
  类型转换。JDK提供了支持泛型的编译器,将运行时的类型检查提前到了编译时执行,提高了代码可读性和安全性。

泛型的本质就是“数据类型的参数化”。 我们可以把“泛型”理解为数据类型的一个占位符(形式参数),即告诉编译器,在调用泛型时必须传入实际类型。

泛型就相当于给容器贴上标签,可以帮助我们建立类型安全的容器(或集合)。

(要点)泛型的作用:

数组里存放的是同类型的变量;而容器是广义的数组,里面存放的是不同类型的变量,所以需要一个参数定义类型。
简单来说:《泛型就是用来规范数组里存放数据的数据类型的》。

1.1 自定义泛型

我们可以在类的声明处增加泛型列表,如:<T,E,V>。

此处,字符可以是任何标识符,一般采用这3个字母。

package com.gk.collection;
/**
 * 测试泛型
 * @author 康哥
 *
 */
public class TestGeneric {
	public static void main(String[] args) {
		MyCollection<String> mc = new MyCollection<String>();
		
		mc.set("高明", 0);
		
		String str = mc.get(0);
		System.out.println(str);
	}
}

class MyCollection<E>{
	Object[] objs = new Object[5];
	
	public void set(E e, int index) {
		objs[index]  = e;
	}
	
	public E get(int index) {
		return (E) objs[index];
	}
}

1.2容器中使用的泛型

容器相关类都定义了泛型,我们在开发和工作中,在使用容器类时都要使用泛型。这样,在容器的存储数据、读取数据时都避免了大量的类型判断,非常便捷。

public class Test {
    public static void main(String[] args) {
        // 以下代码中List、Set、Map、Iterator都是与容器相关的接口;
        List<String> list = new ArrayList<String>();
        Set<Man> mans = new HashSet<Man>();
        Map<Integer, Man> maps = new HashMap<Integer, Man>();
        Iterator<Man> iterator = mans.iterator();
    }
}

2、Collection接口

Collection与List的详解:
点击这

Collection 表示一组对象,它是集中、收集的意思。Collection接口的两个子接口是List、Set接口。
在这里插入图片描述
例子:

package com.gk.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 测试Collection接口中的方法
 * Collection、List、Set基本都是这些方法
 * @author 康哥
 *
 */
public class TestList {
	public static void main(String[] args) {
		//test01();
		test02();
		
	}
	
	public static void test01() {
		
		Collection<String> c = new ArrayList<>();

		System.out.println(c.size());
		
		c.add("高老大");
		c.add("高老二");
		System.out.println(c.size());
		System.out.println(c.isEmpty());
		System.out.println(c);
		
		c.remove("高老二");//这里移除的是"高老二"对象的索引,"高老二"对象并未删除。
		System.out.println(c);
		
		System.out.println(c.contains("高老三"));//c中是否包含"高老三"。
		
		c.clear();//移除所有元素
		System.out.println(c);
	}
	
	public static void test02() {
		//这里的List也可以用Collection替换(List和Set是Collection的子接口)
		List<String> list01 = new ArrayList<>();		
		list01.add("aa");
		list01.add("bb");
		list01.add("cc");
		
		List<String> list02 = new ArrayList<>();
		list02.add("aa");
		list02.add("dd");
		list02.add("ee");
		
		System.out.println("list01:" + list01);
		
		//list01.addAll(list02);//把list02中的所有元素添加到list01中
		//list01.removeAll(list02);//移除list01中和list02共有的元素
		list01.retainAll(list02);//list01和list02取交集
		
		System.out.println("list01:" + list01);
	}
}

test01();的运行结果:
在这里插入图片描述
test02();的运行结果自己测试。

3.1List特点和常用方法

List是有序、可重复的容器。

有序:List中每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素。

可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。

除了Collection接口中的方法,List多了一些跟顺序(索引)有关的方法,参见下表:
在这里插入图片描述
在这里插入图片描述
List接口常用的实现类:ArrayList(查询效率高)、LinkedList(增删效率高)、Vector(线程安全)。
在这里插入图片描述
例子:

//测试跟索引相关的方法
	public static void test03() {
		List<String> list = new ArrayList<>();
		
		list.add("A");
		list.add("B");
		list.add("C");
		list.add("D");
		System.out.println(list);
		
		list.add(2, "高明");//相当于插入
		System.out.println(list);
		
		list.set(3, "高明");//相当于修改
		System.out.println(list);
		
		System.out.println(list.get(2));//返回索引处的元素
		
		list.add("C");
		list.add("B");
		list.add("A");
		System.out.println(list.indexOf("B"));//返回第一个"B"的索引
		System.out.println(list.lastIndexOf("B"));//返回最后一个"B"的索引
	}

运行结果:
在这里插入图片描述

3.2ArrayList特点和底层实现

ArrayList底层是用数组实现的存储。 特点:查询效率高,增删效率低,线程不安全。我们一般使用它。查看源码:
在这里插入图片描述
我们可以看出ArrayList底层使用Object数组来存储元素数据。所有的方法,都围绕这个核心的Object数组来开展。
我们知道,数组长度是有限的,而ArrayList是可以存放任意数量的对象,长度不受限制,那么它是怎么实现的呢?本质上就是通过定义新的更大的数组,将旧数组中的内容拷贝到新数组,来实现扩容。 ArrayList的Object数组初始化长度为10,如果我们存储满了这个数组,需要存储第11个对象,就会定义新的长度更大的数组,并将原数组内容和新的元素一起加入到新数组中,源码如下:
在这里插入图片描述

package com.gk.mycollection;

import java.util.Arrays;

/**
 * 自定义实现一个ArrayList,体会底层原理
 * @author 康哥
 *
 */
public class SxtArrayList01 {
	private Object[] elementDate;
	private int size;
	private static final int DEFAULT_CAPACITY = 10;
	
	public SxtArrayList01() {
		elementDate = new Object[DEFAULT_CAPACITY];
	}
	
	public SxtArrayList01(int capacity) {//capacity:容量
		elementDate = new Object[capacity];
	}
	
	public void add(Object obj) {
		elementDate[size++] = obj;
	}
	
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(int i = 0; i < size; i++) {
			sb.append(elementDate[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		SxtArrayList01 s1 = new SxtArrayList01(12);
		s1.add("aa");
		s1.add("bb");
		System.out.println(s1);
	}
}

package com.gk.mycollection;

import java.util.Arrays;

/**
 * 自定义实现一个ArrayList,体会底层原理
 * 增加泛型
 * @author 康哥
 *
 */
public class SxtArrayList02<E> {
	private Object[] elementDate;
	private int size;
	private static final int DEFAULT_CAPACITY = 10;
	
	public SxtArrayList02() {
		elementDate = new Object[DEFAULT_CAPACITY];
	}
	
	public SxtArrayList02(int capacity) {//capacity:容量
		elementDate = new Object[capacity];
	}
	
	public void add(E element) {
		elementDate[size++] = element;
	}
	
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(int i = 0; i < size; i++) {
			sb.append(elementDate[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		SxtArrayList02 s1 = new SxtArrayList02(12);
		s1.add("aa");
		s1.add("bb");
		System.out.println(s1);
	}
}

package com.gk.mycollection;

import java.util.Arrays;

/**
 * 增加数组扩容
 * @author 康哥
 *
 */
public class SxtArrayList03<E> {
	private Object[] elementDate;
	private int size;
	private static final int DEFAULT_CAPACITY = 10;
	
	public SxtArrayList03() {
		elementDate = new Object[DEFAULT_CAPACITY];
	}
	
	public SxtArrayList03(int capacity) {//capacity:容量
		elementDate = new Object[capacity];
	}
	
	public void add(E element) {
		//什么时候需要扩容?
		if(size == elementDate.length) {
			//怎么扩容
			Object[] newArray = new Object[elementDate.length + (elementDate.length >> 1)];//扩容一半; "+"的运算优先级大于">>"的优先级,所以加括号;10-->10+10/2
			System.arraycopy(elementDate, 0, newArray, 0, elementDate.length);//把数组elementDate拷贝到newArray中
			elementDate = newArray;
		}			
		
		elementDate[size++] = element;
	}
	
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(int i = 0; i < size; i++) {
			sb.append(elementDate[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		SxtArrayList03 s1 = new SxtArrayList03();

		for(int i = 0; i < 30; i++) {
			s1.add("gao" + i);
		}
		System.out.println(s1);
	}
}

package com.gk.mycollection;

import java.util.Arrays;

/**
 * 增加get、set方法,数组索引越界检查
 * @author 康哥
 *
 */
public class SxtArrayList04<E> {
	private Object[] elementDate;
	private int size;
	private static final int DEFAULT_CAPACITY = 10;//容器的默认容量
	
	public SxtArrayList04() {
		elementDate = new Object[DEFAULT_CAPACITY];
	}
	
	public SxtArrayList04(int capacity) {//capacity:容量	
		if(capacity < 0) {
			throw new RuntimeException("容器的容量不可能为负!");			
		}else if(capacity == 0){
			elementDate = new Object[DEFAULT_CAPACITY];
		}else {
			elementDate = new Object[capacity];
		}	
	}
	
	public void add(E element) {
		//什么时候需要扩容?
		if(size == elementDate.length) {
			//怎么扩容
			Object[] newArray = new Object[elementDate.length + (elementDate.length >> 1)];//扩容一半; "+"的运算优先级大于">>"的优先级,所以加括号;10-->10+10/2
			System.arraycopy(elementDate, 0, newArray, 0, elementDate.length);//把数组elementDate拷贝到newArray中
			elementDate = newArray;
		}					
		elementDate[size++] = element;
	}
	
	public E get(int index) {
		checkRange(index);
		return (E) elementDate[index];
	}
	
	public void set(E element, int index) {
		checkRange(index);
		elementDate[index] = element;
	}
	
	//索引合法判断
	public void checkRange(int index) {
		//索引合法判断[0,size)
		if(index < 0 || index > size - 1) {
			throw new RuntimeException("索引越界:" + index);
		}
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(int i = 0; i < size; i++) {
			sb.append(elementDate[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		SxtArrayList04 s1 = new SxtArrayList04(10);

		for(int i = 0; i < 30; i++) {
			s1.add("gao" + i);
		}		
		
		s1.set("Gao", 20);
		System.out.println(s1);
		System.out.println(s1.get(20));
	}
}

package com.gk.mycollection;

import java.util.Arrays;

/**
 * 增加remove方法,size(),isEmpty()方法
 * @author 康哥
 *
 */
public class SxtArrayList05<E> {
	private Object[] elementDate;
	private int size;//数组里元素的个数
	private static final int DEFAULT_CAPACITY = 10;//容器的默认容量
	
	public SxtArrayList05() {
		elementDate = new Object[DEFAULT_CAPACITY];
	}
	
	public SxtArrayList05(int capacity) {//capacity:容量	
		if(capacity < 0) {
			throw new RuntimeException("容器的容量不可能为负!");			
		}else if(capacity == 0){
			elementDate = new Object[DEFAULT_CAPACITY];
		}else {
			elementDate = new Object[capacity];
		}	
	}
	
	public int size() {
		return size;
	}
	
	public boolean isEmpty() {
		return size == 0 ? true : false;
	}
	
	public void add(E element) {
		//什么时候需要扩容?
		if(size == elementDate.length) {
			//怎么扩容
			Object[] newArray = new Object[elementDate.length + (elementDate.length >> 1)];//扩容一半; "+"的运算优先级大于">>"的优先级,所以加括号;10-->10+10/2
			System.arraycopy(elementDate, 0, newArray, 0, elementDate.length);//把数组elementDate拷贝到newArray中
			elementDate = newArray;
		}					
		elementDate[size++] = element;
	}
	
	public E get(int index) {
		checkRange(index);
		return (E) elementDate[index];
	}
	
	public void set(E element, int index) {
		checkRange(index);
		elementDate[index] = element;
	}
	
	//索引合法判断
	public void checkRange(int index) {
		//索引合法判断[0,size)
		if(index < 0 || index > size - 1) {
			throw new RuntimeException("索引越界:" + index);
		}
	}
	
	//通过元素移除
	public void remove(E element) {
		//element,将它和所有的元素挨个比较,获得第一个比较为true的返回
		for(int i = 0; i < size; i++) {
			if(element.equals(get(i))){
				remove(i);//调用索引移除的方法
			}
		}	
	}	
	//通过索引移除
	public void remove(int index) {
		int numMoved = size - 1 - index;
		if(numMoved > 0) {
			//通过索引移除实际上还是数组的拷贝
			System.arraycopy(elementDate, index + 1, elementDate, index, numMoved);
		}
		elementDate[--size] = null;//移除某个元素后 size-1(数组元素个数减1),且最后一个索引位置设置为空
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(int i = 0; i < size; i++) {
			sb.append(elementDate[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		SxtArrayList05 s1 = new SxtArrayList05(10);

		for(int i = 0; i < 30; i++) {
			s1.add("gao" + i);
		}		
		
		s1.set("Gao", 20);
		System.out.println(s1);
		System.out.println(s1.get(20));
		
		s1.remove(3);
		System.out.println(s1);
		s1.remove("gao0");
		System.out.println(s1);
		
		System.out.println(s1.size());
		System.out.println(s1.isEmpty());
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值