JavaSE进阶22 - List接口、ArrayList集合、LinkedList集合、Vector集合、泛型、foreach

List接口中的特有的常用方法

package com.bjpowernode.javase.collection;

import java.util.*;

/*
测试List接口中常用方法
	1、List集合存储元素特点:有序可重复
		有序:List集合中的元素有下标。
		从0开始,以1递增。
		可重复:存储一个1,还可以再存储1。
	2、List集合既然是Collection接口的子接口,那么肯定List接口有自己“特色”的方法;
		以下只列出List接口特有的常用的方法:
		注:将E类型换成Object类型
			void add(int index, Object element) 添加
			Object set(int index, E element) 修改
			Object get(int index)
			int	indexOf(Object o)
			int	lastIndexOf(Object o)
			Object remove(int index)
 */
public class ListTest01 {

	public static void main(String[] args) {
		
		// 创建List集合对象
		//List mylist = new LinkedList();
		//List mylist = new Vector();
		List mylist = new ArrayList();
		
		// 添加元素
		mylist.add("A"); //默认都是向集合末尾添加元素
		mylist.add("B");
		mylist.add("C");
		mylist.add("D");
		//在列表的指定位置插入指定元素(第一个参数是下标)
		//这个方法使用不多,因为对于ArrayList集合来说效率较低。
		mylist.add(1,"KING");
		
		// 迭代
		Iterator it = mylist.iterator();
		while(it.hasNext()) {
			Object obj = it.next();
			System.out.println(obj);
		}
		
		// 根据下标获取元素
		Object firstObj = mylist.get(0);
		System.out.println(firstObj);
		
		// 因为有下标,所以List集合有自己比较特殊的遍历方式
		// 通过下标遍历.List集合特有的方式,Set没有。
		for(int i = 0; i < mylist.size(); i ++) {
			Object obj = mylist.get(i);
			System.out.println(obj);
		}
		
		// 获取指定对象第一次处出现的索引
		System.out.println(mylist.indexOf("KING"));//1
		// 获取指定对象最后一次处出现的索引
		System.out.println(mylist.lastIndexOf("C"));//3
		
		// 删除指定下标位置的元素
		mylist.remove(0);
		System.out.println(mylist.size());//4
		
		// 修改指定下标位置的元素
		mylist.set(0, "a");
		// 遍历集合
		for(int i = 0; i < mylist.size(); i ++) {
			Object obj = mylist.get(i);
			System.out.println(obj);
		}
		
	}

}

ArrayList集合初始化容量及扩容

package com.bjpowernode.javase.collection;

import java.util.*;

/**
ArrayList集合:
	1、默认初始化容量是10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量为10。)
	2、底层是Object类型的数组Object[]
	3、构造方法():
		new ArrayList();
		new ArrayList(20);
	4、ArrayList集合的扩容:
		原容量的1.5倍
	    ArrayList集合底层是数组,怎么优化?
	    	尽可能少的扩容。因为数组的扩容效率比较低,建议在使用ArrayList集合
	    	的时候预估下元素的个数,给定一个初始化容量。
	 5、数组优点:
	 	检索效率比较高。
	 6、数组缺点
	 	随机增删元素效率较低,
	 	另外数组无法存储大数据量。(很难找到非常巨大的连续内存空间)
	 7、向数组末尾添加元素,效率很高,不受影响。
	 8、面试官经常问的一个问题?
	 	这么多的集合中,你用哪个集合最多?
	 		答:ArrayList集合。
	 		因为往数组末尾添加元素,效率不受影响。
	 		另外,我们检索/查找某个元素的操作比较多。
 */
public class ArrayListTest01 {

	public static void main(String[] args) {
		
		// 默认初始化容量是10
		// 数组的长度是10
		List list1 = new ArrayList();
		// 集合的size()方法是获取当前集合中元素的个数。不是获取集合的容量。
		System.out.println(list1.size());//0
		
		// 指定初始化容量
		// 数组的长度是20
		List list2 = new ArrayList(20);
		System.out.println(list2.size());//0
		
		list1.add(1);
		list1.add(2);
		list1.add(3);
		list1.add(4);
		list1.add(5);
		list1.add(6);
		list1.add(7);
		list1.add(8);
		list1.add(9);
		list1.add(10);
		
		System.out.println(list1.size());//10
		
		// 再加一个元素
		list1.add(11);
		System.out.println(list1.size());//11
		// 增长之后的容量是之前容量的1.5倍
		// int newCapacity = oldCapacity + (oldCapacity >> 1);
		
	}

}

ArrayList集合的另一种构造方法

package com.bjpowernode.javase.collection;

import java.util.*;

// ArrayList集合的另一个构造方法

public class ArrayListTest02 {

	public static void main(String[] args) {
		
		// 默认初始化容量是10
		List myList1 = new ArrayList();
		// 指定容量是100
		List myList2 = new ArrayList(100);
		
		// 创建一个HashSet集合
		Collection c = new HashSet();
		c.add(100);
		c.add(200);
		c.add(900);
		c.add(50);
		
		// 通过这个构造方法就可以将HashSet集合转换成List集合
		List myList3 = new ArrayList(c);
		for(int i = 0; i < myList3.size(); i ++) {
			System.out.println(myList3.get(i));
		}
	}
}

单向链表数据结构

在这里插入图片描述

  • 手撕单向链表
package com.bjpowernode.javase.danlink;

/*
单链表中的节点。
节点是单向链表中基本的单元。
每一个节点Node都有两个属性:
	一个属性:是存储的数据
	另一个属性:是下一个节点的内存地址。
 */
public class Node {
	
	// 存储的数据
	Object data;
	
	// 下一个节点的内存地址
	Node next;
	
	public Node(){
	
	}
	
	public Node(Object data, Node next) {
		this.data = data;
		this.next = next;
	}
}

package com.bjpowernode.javase.danlink;

/*
 * 链表类
 */
public class Link {
	
	// 头结点
	Node header;
	
	int size = 0;
	
	// 返回链表中元素个数
	public int size() {
		return size;
	}
	
	
	// 向链表中添加元素的方法(向末尾添加)
	public void add(Object data) {
		// 创建一个新的节点对象。
		// 让之前单链表的末尾节点next指向新节点对象。
		// 有可能这个元素是第一个,也可能是第二个,也可能是第三个。
		if(header == null) {
			// 说明还没有结点
			// new一个新的节点对象,作为头结点对象
			// 这个时候的头结点既是一个头结点,又是一个末尾节点。
			header = new Node(data,null);
		}else {
			// 说明头不是空
			// 头结点已经存在
			// 找出当前末尾节点,让当前末尾节点的next是新节点
			Node currentLastNode = findLast(header);
			currentLastNode.next = new Node(data, null);
		}
		
		size ++;
	}
	
	// 专门查找末尾节点的方法
	private Node findLast(Node node) {
		if(node.next == null) {
			// 如果一个节点的next是null
			// 说明这个节点就是末尾节点
			return node;
		}
		// 程序执行到这里说明:node不是末尾节点
		return findLast(node.next);//递归
	}

	// 修改链表中某个数据的方法
	public void modify(Object newObj) {
		
	}
	
	// 查找链表中某个元素的方法
	public int find(Object obj) {
		
		return 1;
	}
}
package com.bjpowernode.javase.danlink;

public class Test {

	public static void main(String[] args) {
		
		// 创建一个集合对象
		Link link = new Link();
		
		// 向集合中添加元素
		link.add("abc");
		link.add("def");
		link.add("xyz");
		System.out.println(link.size());
	}
}

双项链表数据结构图

在这里插入图片描述

链表的优点和缺点

package com.bjpowernode.javase.collection;

import java.util.*;


/*
链表的优点:
	由于链表上的元素在空间存储上内存地址不连续。
	所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。
	在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。

链表的缺点:
	不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头
	节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率
	较低。
	ArrayList:把检索发挥到极致。(末尾添加元素效率还是很高的。)
	LinkedList:把随机增删发挥到极致。
	加元素都是往末尾添加,所以ArrayList用的比LinkedList多。
 */
public class LinkedListTest01 {

	public static void main(String[] args) {
		// LinkedList集合底层也是有下标的
		// 注意:ArrayList集合之所以检索效率较高,不是单纯因为下标的原因,是因为底层数组发挥的作用。
		// LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头结点开始一个一个遍历
		List list = new LinkedList();
		list.add("a");
		list.add("b");
		list.add("c");
		
		for(int i = 0; i < list.size(); i ++) {
			Object obj = list.get(i);
			System.out.println(obj);
		}
	}

}

  • 通过对LinkedList源码分析,将LinkedListTest01文件画出内存图
    在这里插入图片描述

Vector集合

package com.bjpowernode.javase.collection;

import java.util.*;
import java.util.Collections;

/*
Vector:
	1、底层也是一个数组
	
	2、初始化容量10
	
	3、怎么扩容的?
		扩容之后是原容量的2倍。
		
	4、ArrayList集合扩容特点:
		扩容之后是原容量的1.5倍。
		
	5、Vector中所有方法都是线程同步的,都带有synchronized关键字。
	是线程安全的,效率比较低,使用较少。
	
	6、怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
		使用集合工具类:
			java.util.Collections;
			
			java.util.Collection 是集合接口
			java.util.Collections 是集合工具类
	
 */
public class VectorTest01 {

	
	public static void main(String[] args) {
		// 创建Vector对象
		List vector = new Vector();
		//Vector vector = new Vector();
		
		// 默认容量是10
		vector.add(1);
		vector.add(2);
		vector.add(3);
		vector.add(4);
		vector.add(5);
		vector.add(6);
		vector.add(7);
		vector.add(8);
		vector.add(9);
		vector.add(10);
		
		// 满了之后扩容(扩容后容量是20)
		vector.add(11);
		
		Iterator it = vector.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		
		// 这个可能以后要使用!!!
		List myList = new ArrayList();//非线程安全的。
		// 变成线程安全的
		Collections.synchronizedList(myList);// 这里没有办法看效果,因为多线程没学,你记住先!

		// myList集合是线程安全的
		myList.add("111");
		myList.add("222");
		myList.add("333");
		myList.add("444");
		myList.add("555");
		
	}

}

泛型机制

package com.bjpowernode.javase.collection;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
1、JDK5.0之后推出的新特性:泛型
2、泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的。(运行阶段泛型没用!)
3、使用泛型的好处:
     	集合中存储的元素类型统一了。
		从集合中取出的元素类型是泛型指定的类型,不需要进行大量的“向下转型”。
     使用泛型的缺点:
     	导致集合中存储的元素缺乏多样性。
     	大多数业务中,集合中元素的类型还是统一的,所以这种泛型特性被大家所认可。
 */
public class GenericTest01 {

	public static void main(String[] args) {
		
		/*
		// 不适用泛型,分析程序存在哪些缺点
		// 创建对象
		List myList = new ArrayList();
		
		// 准备对象
		Cat c = new Cat();
		Bird b = new Bird();
		
		// 将对象添加到集合当中
		myList.add(c);
		myList.add(b);
		
		
		// 遍历集合,取出每个Animal,让它move。
		Iterator it = myList.iterator();
		while(it.hasNext()) {
			// 没有这个语法,通过迭代器取出的就是Object
			// Animal a = it.next();
			Object obj = it.next();
			
			// obj中没有move方法,无法调用,需要向下转型。
			if(obj instanceof Animal) {
				Animal a = (Animal)obj;
				a.move();
			}
		
		}
		*/
		
		// 使用JDK5之后的泛型机制
		// 使用泛型List<Animal>之后,表示List集合中只允许存储Animal类型的数据。
		// 用泛型来指定集合中存储的数据类型。
		List<Animal> myList = new ArrayList<Animal>();
		
		// 指定List集合中只能存储Animal,那么存储String就编译报错了。
		// 这样用了泛型之后,集合中元素的数据类型就更加统一了。
		//myList.add("abc");
		
		Cat c = new Cat();
		Bird b = new Bird();	
		myList.add(c);
		myList.add(b);
		
		
		// 获取迭代器
		// 这个表示迭代器迭代的是Animal类型。
		Iterator<Animal> it = myList.iterator();
		while(it.hasNext()) {
			// 使用泛型之后,每一次迭代返回的数据都是Animal类型。
			Animal a = it.next();
			// 这里不需要强制类型转换了,直接调用
			a.move();
			// 调用子类型特有的方法,还是需要进行“向下强转”
			if(a instanceof Cat) {
				Cat cat = (Cat)a;
				cat.catchMouse();
			}else if(a instanceof Bird) {
				Bird bird = (Bird)a;
				bird.fly();
			}
		}
	}

}

class Animal{
	public void move() {
		System.out.println("动物在移动!");
	}
}
class Cat extends Animal{
	public void catchMouse() {
		System.out.println("猫抓老鼠!");
	}
}
class Bird extends Animal{
	public void fly() {
		System.out.println("鸟儿在飞翔!");
	}
}

泛型-类型自动推断

package com.bjpowernode.javase.collection;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/*
JDK8之后引入了:自动类型推断机制。(又称为钻石表达式)
 */
public class GenericTest02 {

	public static void main(String[] args) {
		// ArrayList<这里的类型会自动推断>(),前提是JDK8之后才允许。
		// 自动类型转换,钻石表达式! 
		List<Animal> myList = new ArrayList<>();
		
		myList.add(new Animal());
		myList.add(new Cat());
		myList.add(new Bird());
		
		// 遍历
		Iterator<Animal> it = myList.iterator();
		while(it.hasNext()) {
			Animal a = it.next();
			a.move();
		}
		
		List<String> strList = new ArrayList<>();
		
		//类型不匹配
		//myList2.add(new Animal())
		strList.add("123");
		strList.add("http://www.163.com");
		strList.add("http://www.bjpowernode.com");
		
		
		Iterator<String> it2 = strList.iterator(); 
		while(it2.hasNext()) {
			
			// 如果没有使用泛型
			/*
			Object obj = it2.next();
			if(obj instanceof String) {
				String ss = (String)obj;
				System.out.println(ss.substring(1));
			}
			*/
			
			// 直接通过迭代器获取了String类型的数据
			String s = it2.next();
			// 直接调用String类型的subStrign方法截取字符串
			String newString = s.substring(1);
			System.out.println(newString);
		}
		
	}

}

自定义泛型

package com.bjpowernode.javase.collection;

/*
自定义泛型可以吗?可以
	自定义泛型的时候,< >大括号中的是一个标识符,随便写。
	java源代码经常出现的是:
		<E>和<T>
	E是Element单词的首字母
	T是Type单词的首字母
 */
public class GenericTest03<标志符随便写> {
	
	public void doSome(标志符随便写 o) {
		System.out.println(o);
	}
	
	public static void main(String[] args) {
		
		// new对象的时候指定了泛型是:String类型
		GenericTest03<String> gt = new GenericTest03<>();
		
		// 类型不匹配
		// gt.doSome(100);
		
		gt.doSome("abc");
		
		// ---------------------------------------------
		GenericTest03<Integer> gt2 = new GenericTest03<>();
		
		// 类型不匹配
		//gt2.doSome("a");
		gt2.doSome(100);
		
		// ----------------------------------------------
		MyInteger<String> mi = new MyInteger<>();
		String s1 = mi.get();
		
		MyInteger<Animal> mi2 = new MyInteger<>();
		Animal a1 = mi2.get();
		
		// 不用泛型就是Object类型。
		/*
		GenericTest03 gt3 = new GenericTest03();
		gt3.doSome(new Object());
		*/
		
		
		
	}
}

class MyInteger<T>{
	
	public T get() {
		return null;
	}
	
}

foreach

package com.bjpowernode.javase.collection;


/**
JDK5.0之后推出了一种新特性:叫做增强for循环,或者叫做foreach
 */
public class ForEachTest01 {

	public static void main(String[] args) {
		
		int[] arr = {23,45,67,89};
		
		// 普通for循环
		for(int i = 0;i < arr.length; i ++) {
			System.out.println(arr[i]);
		}
		
		// 增强for(foreach)
		/*
		for(元素类型 变量名 : 数组或集合) {
			System.out.println(变量名);
		}
		*/
		
		System.out.println("-------------------------");
		// foreach有一个缺点:没有下标。在需要使用下标的循环中,不建议使用增强型循环(foreach)
		for(int data : arr) {
			// data就是数组中的每一个元素
			System.out.println(data);
		}
	}

}

package com.bjpowernode.javase.collection;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/*
集合使用foreach
 */
public class ForEachTest02 {

	public static void main(String[] args) {
		
		List<String> strList = new ArrayList<>();
		
		// 添加元素
		strList.add("hello");
		strList.add("world!");
		strList.add("kitty!");
		
		//遍历,需要使用迭代器的方式
		Iterator<String> it = strList.iterator();
		while(it.hasNext()) {
			String s = it.next();
			System.out.println(s);
		}
		
		System.out.println(" ----------------1-----------------");
		//遍历,使用for循环的方式;
		//使用下标方式:只针对有下标的集合;
		for(int i = 0; i < strList.size(); i ++) {
			System.out.println(strList.get(i));
		}
		
		System.out.println(" -----------------2----------------");
		//使用foreach
		for(String s : strList) {//因为泛型使用的String类型,所以是String s
			System.out.println(s);
		}
		
		List<Integer> myList2 = new ArrayList<>();
		
		myList2.add(100);
		myList2.add(200);
		myList2.add(300);
		
		for(Integer i : myList2) {
			System.out.println(i);
		}
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值