1.泛型
为什么引入泛型?
1)泛型是为了模拟数组的元素类型检查
2)泛型通常与集合一起使用,用来约束集合中元素的类型
3)泛型的格式:,这个Type必须是引用类型(包括包装类型),不能是基本类型
4)泛型可以帮助我们写出更加通用的代码,减少代码的冗余,提高程序通用性
5)写泛型一定要注意格式的要求(定义集合/定义泛型方法)
泛型集合:
泛型方法:
6)泛型是一个“语法糖”,可以提前报错,在编译前就可以检查数据的类型,如果不是要求的类型,就报错;但是通过编译以后,泛型的作用就消失了,也就是说,编译后生成的字节码文件中没有泛型
7)高效for循环
格式:
for(每轮遍历得到的元素的类型 遍历得到的元素名字 : 要遍历的元素){循环体}
与普通for循环使用哪一个都可以
优点:比普通for循环写法简单,效率高
缺点:没有办法按照下标来操作值,只能从头到尾依次遍历
8)泛型的声明:泛型可以在接口/类/方法上使用
9)泛型<?>常用方法
泛型常用名称 | |
E | Element(在集合中使用,因为集合中存放的是元素) |
T | Type(Java中的类) |
K | Key(键) |
V | Value(值) |
N | Number(数值类型) |
? | 表示不确定的java类型 |
练习1:泛型集合的使用
package cn.tedu.generic;
import java.util.ArrayList;
import java.util.List;
/*本类测试泛型的优点1*/
public class TestGeneric1 {
public static void main(String[] args) {
/*1.泛型是怎么产生的?--想要模拟数组的类型检查*/
//1.创建一个String类型的长度为5的数组
String[] a =new String[5];
//数组的好处:在编译时检查数据的类型,如果不是指定的类型就报错
// a[0] = 1;
// a[1] = 3.4;
// a[2] = 'a';
a[3] = "泡泡";
a[4] = "超超";
/*2.泛型通常结合着集合一起使用*/
//多态对象:父类引用 指向子类对象
List list = new ArrayList();//注意导包:java.util...
//没有类型约束,数据类型太自由!!!无法进行运算或者其他行为
list.add("平平");
list.add(1);
list.add(6.6);
list.add('a');
System.out.println(list);//[平平, 1, 6.6, a],查看集合中的元素结果
/*3.引入泛型--主要目的是想通过泛型<?> 来约束集合中的数据类型
4.泛型的好处:可以把报错的时机提前,在编译期就报错,而不是运行后才抛出异常
向集合中添加元素时,会先检查元素的数据类型,不是要求的数据类型就编译失败*/
List<String> list2 = new ArrayList<String>();//注意导包:java.util...
// list2.add(1);
// list2.add(6.6);
// list2.add('a');
list2.add("平平");
System.out.println(list2);//[平平]
/*5.<type> --type该如何写?
* 可以根据自己的需求设定类型,但注意必须是引用类型(包装类型),不能是基本类型*/
//List<int> list3 = new ArrayList<int>();//Type argument cannot be of primitive type
List<Integer> list3 = new ArrayList<Integer>();
for(int i =100;i<=500;i+=100){
list3.add(i);
}
System.out.println(list3);//[100, 200, 300, 400, 500]
}
}
练习2:泛型方法的使用
package cn.tedu.generic;
import java.util.Arrays;
/*本类测试泛型的优点2*/
public class TestGeneric2 {
public static void main(String[] args) {
//需求:打印指定数组中的所有元素
Integer[] a = {123456789};
String[] b ={"大哥","二哥","三哥","四哥","五哥","六哥","小弟"};
Double[] c ={6.0,6.6,6.66,6.666,6.6666};
print(a);
print(b);
print(c);
}
/*1.泛型可以实现通用代码的编写,使用E表示元素的类型是Element类型
* 2.泛型的语法要求:如果在方法上使用泛型,必须两处同时出现
* 一个是传入参数的类型是泛型,另一个是返回值前的泛型类型
* 表示这是一个泛型方法*/
private static<E> void print(E[] e) {
for (E f: e){//E是泛型类型,f是随便起的名字,e是所有数组名的统称
System.out.println(f);
}
}
// private static void print(Double[] c) {
// for (Double d : c){
// System.out.println(d);
// }
//
// }
//
// private static void print(String[] b) {
// for (String s: b){
// System.out.println(s);
// }
//
// }
//
// private static void print(Integer[] a) {
// //普通for循环遍历数组
// /*普通for循环
// * 优点:可以设置循环的步长(怎么变化)*/
for(int i = 0;i<a.length;i++){
System.out.println(a[i]);
}
// /*高效for循环(增强for循环)
// * 格式:for(1 2 : 3){循环体}
// * 1是每次遍历得到的元素类型,
// * 2是遍历得到的元素的名字,
// * 3是要遍历的元素
// * 优点:比普通for循环写法简单,效率高
// * 缺点:没有办法按照下标来操作值,只能从头到尾依次遍历*/
// for (Integer i: a){
// System.out.println(i);
// }
// }
}
2.集合Collection接口
2.1集合和数组区别:
都是容器:
1)数组array:长度是固定的,通过数组下标访问内容,访问方式比较单一,插入/删除等操作较繁琐
2)集合collection:长度可变,访问方式比较灵活
3)java常用集合关系
2.2集合Collection
1)存放对象的数据结构,而且长度可变,可以存放不同类型的对象,并且还提供了一组操作成批对象的方法.
2)Collection接口层次结构中的根接口,接口不能直接使用,但是该接口提供了添加元素/删除元素/管理元素的父接口公共方法.
3)由于List接口与Set接口都继承了Collection接口,因此这些方法对于List集合和Set集合是通用的.
2.3Collection方法速查表
2.3.1针对单个集合的常用方法
针对单个集合的常用方法 | |
c.add(100) | 向集合c添加元素100 |
clear() | 清空集合中所有的元素 |
contains() | 判断集合是否包含指定元素 |
hashCode() | 获取集合的哈希码值 |
isEmpty() | 判断集合是否为空 |
remove() | 移除指定元素(首次出现),成功返回true |
size() | 获取集合个数 |
equals() | 比较两对象是否相等 |
Object[] array = c.toArray(); | 集合转成数组,数组用Arrays.toString()查看 |
2.3.2针对两集合之间的常用方法
集合与集合之间的常用方法 | |
c.addAll(c2) | 把c2集合添加到c集合中(泛型上/下限) |
c.containsAll(c2) | 判断c集合是否包含c2集合中的所有元素 |
c.retainAll(c2) | 取两集合之间的公共部分(交集) |
c.removeAll(c2) | 删除c集合中属于c2集合的所有元素 |
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Callable;
/*本类测试Collection相关API方法*/
public class TestCollection {
public static void main(String[] args) {
//1.创建Collection接口对象,因为Collection是接口,也是接口List,不能自身创建对象
//Collection c =new Collection();
//Collection<Integer> c = new List<Integer>();
/*1.<Integer>是泛型,用来约束集合c中可存入的元素类型
* 泛型中的<type>只能是引用类型,不能是基本类型*/
//只能用List接口的子类创建对象
Collection<Integer> c = new ArrayList<Integer>();
//2.1测试常用方法--针对单个集合的方法
c.add(100);//向集合中添加元素
c.add(200);//add()添加
c.add(300);
c.add(400);
c.add(500);
System.out.println(c);//[100, 200, 300, 400, 500],打印查看集合中的元素
//c.clear();//清空集合中的所有元素
System.out.println(c);//[]
System.out.println(c.contains(300));//true,判断集合是否包含指定元素300
System.out.println(c.hashCode());//127240651,获取哈希码值
System.out.println(c.isEmpty());//false,判断集合是否为空
System.out.println(c.remove(300));//true,移除指定元素,成功返回true
System.out.println(c);//[100, 200, 400, 500]
System.out.println(c.size());//4,获取集合的个数
System.out.println(c.equals(200));//false,比较两个对象是否相等
//Alt+Enter,自动补全正确的类型
Object[] array = c.toArray();//集合对象转成数组,数组用Arrays.toString()查看
System.out.println(Arrays.toString(array));//[100, 200, 400, 500]
//2.2集合与集合之间的操作
Collection<Integer> c2 = new ArrayList<>();//创建第二个集合对象c2
c2.add(2);//
c2.add(4);//
c2.add(6);//向集合中添加指定元素
System.out.println(c2);//[2, 4, 6],打印查看c2集合中的元素
c.addAll(c2);//把c2集合添加到c集合中
System.out.println(c);//[100, 200, 400, 500, 2, 4, 6]
System.out.println(c.contains(c2));//false,c集合是否包含指定元素c2
System.out.println(c.containsAll(c2));//true,判断c集合是否包含c2集合中的所有元素
System.out.println(c.retainAll(c2));//取两集合之间的公共部分
System.out.println(c);//[2, 4, 6]
// System.out.println(c.removeAll(c2));//删除c集合中属于c2集合的所有元素
// System.out.println(c);//[]
//3.遍历/迭代集合中的元素
/*1.获取集合对应的迭代器Iterator<E> it = c.iterator()
* 2.判断集合中是否有下个元素it.hasNext()
* 3.获取当前迭代到的元素it.next()*/
//3.1获取集合的迭代器
Iterator<Integer> it = c.iterator();
//3.2通过循环变量集合
while(it.hasNext()){//判断是否有下个元素,若有,继续循环,直到没有
//3.3next()获取本类循环迭代到的元素
Integer next = it.next();
System.out.println(next);
}
}
}
2.3.3遍历/迭代集合中的元素
1).获取集合对应的迭代器Iterator it = c.iterator()
2).判断集合中是否有下个元素it.hasNext()
3).获取当前迭代到的元素it.next()
3.List接口
3.1有序集合接口:
1)对列表中的每个元素的插入位置进行精确的控制
2)根据元素的整数索引(在列表中的位置)来访问元素,并搜索列表中的元素
3)List接口集合可以使用Collection接口集合的常用方法,也可以使用部分数组的常用方法
3.2List接口的特点:
- 数据是有序的
- 元素都有下标
- 允许存放重复的元素
3.3List接口常用方法:
注意:List接口集合可以使用Collection接口集合的常用方法,也可以使用部分数组的常用方法
List单个集合接口 | |
add(1,"蝎子精") | 在有序集合中指定下标处添加元素 |
get(3) | 获取指定下标上的元素 |
indexOf("小蝴蝶") | 获取指定元素首次出现的索引(下标),不包含返回-1 |
lastIndexOf("小蝴蝶") | 获取指定元素最后一次出现的索引,不包含返回-1 |
remove(5) | 移除指定下标中的元素 |
set(3,"蛇精") | 修改指定下标处元素的值 |
list.subList(3, 7) | 截取子串[3,7)左闭右开 |
List集合与集合之间的常用方法 | |
addAll(list2) | 添加到末尾 |
addAll(0,list2) | 指定下标添加集合 |
contains(list2) | 判断集合中是否有一个元素叫list2 |
containsAll(list2) | 判断集合中是否包含集合list2 |
removeAll(list2) | 移除集合在属于集合2中的所有元素 |
练习1:List常用方法的测试
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*本类测试List接口方法*/
public class TestList {
public static void main(String[] args) {
//1.创建List接口多态对象,注意List是接口无法实例化
List<String> list =new ArrayList<String>();
//2.测试继承自Collection的方法
list.add("大力娃");//向集合中添加元素
list.add("千瞬娃");
list.add("铁头娃");
list.add("火娃");
list.add("水娃");
list.add("隐身娃");
list.add("七娃");
System.out.println(list);//打印查看集合
// list.clear();//清空集合所有元素
// System.out.println(list);
System.out.println(list.contains("千瞬娃"));//是否包含指定元素
System.out.println(list.equals("千瞬娃"));//判断指定的值与集合是否相等
System.out.println(list.hashCode());//哈希码值
System.out.println(list.isEmpty());//判断集合是否为空
System.out.println(list.remove("大力娃"));//移除集合中首次出现指定的元素
System.out.println(list.size());//获取集合的元素个数
System.out.println(Arrays.toString(list.toArray()));//将集合转成数组并查看
//3.List集合特有的方法--可以根据索引来操作的方式
list.add("小蝴蝶");
System.out.println(list);//[千瞬娃, 铁头娃, 火娃, 水娃, 隐身娃, 七娃, 小蝴蝶]
list.add(1,"蝎子精");//在有序集合中指定下标处添加元素
System.out.println(list);//[千瞬娃, 蝎子精, 铁头娃, 火娃, 水娃, 隐身娃, 七娃, 小蝴蝶]
System.out.println(list.get(3));//水娃,获取指定下标上的元素
list.add(3,"小蝴蝶");//指定下标添加元素
System.out.println(list);
System.out.println(list.indexOf("小蝴蝶"));//获取指定元素首次出现的索引(下标)
System.out.println(list.lastIndexOf("小蝴蝶"));//获取指定元素最后一次出现的索引
System.out.println(list.remove(5));//移除指定下标中的元素
System.out.println(list.set(3,"蛇精"));//修改指定下标处元素的值
System.out.println(list);//[千瞬娃, 蝎子精, 铁头娃, 蛇精, 火娃, 隐身娃, 七娃, 小蝴蝶]
List<String> subList = list.subList(3, 7);//截取子串[3,7)左闭右开
System.out.println(subList);//[蛇精, 火娃, 隐身娃, 七娃]
//4.集合间的操作
List<String> list2 = new ArrayList<>();//创建有序集合2对象
list2.add("1");//向集合2添加元素
list2.add("2");
list2.add("3");
System.out.println(list.addAll(list2));//添加到末尾
System.out.println(list);//[千瞬娃, 蝎子精, 铁头娃, 蛇精, 火娃, 隐身娃, 七娃, 小蝴蝶, 1, 2, 3]
System.out.println(list.addAll(0,list2));//指定下标添加集合
System.out.println(list);//[1, 2, 3, 千瞬娃, 蝎子精, 铁头娃, 蛇精, 火娃, 隐身娃, 七娃, 小蝴蝶, 1, 2, 3]
System.out.println(list.contains(list2));//false,判断集合中是否有一个元素叫list2
System.out.println(list.containsAll(list2));//true,判断集合中是否包含集合list2
System.out.println(list.removeAll(list2));//移除集合在属于集合2中的所有元素
System.out.println(list);//[千瞬娃, 蝎子精, 铁头娃, 蛇精, 火娃, 隐身娃, 七娃, 小蝴蝶]
}
}
练习2:List集合接口的4种遍历/迭代方式
list集合的迭代方式:
* 1.for循环
* 2.高效for循环
* 3.iterator()
* 4.listIterator():ListIterator()是Iterator的子接口,拥有逆向遍历的特有功能,但不常用
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*测试List接口的4种遍历方式*/
public class TestList2 {
public static void main(String[] args) {
//1.创建List接口的多态对象
List<String> list = new ArrayList<>();
//2.向集合中添加元素
list.add("喜羊羊");
list.add("美羊羊");
list.add("懒羊羊");
list.add("沸羊羊");
list.add("慢羊羊");
list.add("红太狼");
System.out.println(list);
//3.测试集合的迭代
/*集合迭代的方式:
* 1.for循环
* 2.高效for循环
* 3.iterator()
* 4.listIterator()*/
//方式1:由于list是有序的,可根据下标进行迭代
//从下标为0处开始,最大下标是集合的元素个数减1
for (int i =0;i<list.size();i++){
System.out.print(list.get(i));//根据下标获取本轮循环得到的元素
}
System.out.println();
System.out.println("=================================");
//方式2:提高效率,高效for循环(每轮遍历到的元素类型 元素的名字 : 要遍历的内容){}
for (String s : list){
System.out.println(s);
}
System.out.println("**********************************");
//方式3:iterator(),继承自父类Collection的迭代器
Iterator<String> iterator = list.iterator();//迭代器
//由于集合有很多元素,需要重复操作,所有使用循环结构
while(iterator.hasNext()){//判断是否有下一个元素
System.out.println(iterator.next());//打印本轮循环中获取的元素
}
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
//方式4:ListItreator是List的迭代器
/*ListIterator()是Iterator的子接口,拥有逆向遍历的特有功能*/
ListIterator<String> it2 = list.listIterator();
while(it2.hasNext()){
System.out.println(it2.next());
}
}
}
4.ArrayList
4.1概念:
- 存在java.util包中
- 内部是用数组结构存放数据,封装数组的操作,每个对象都有下标
- 内部数组默认的初始容量是10,如果不够会以1.5倍的容量增长
- 查询快,增删数据效率会低
练习:ArrayList的常用方法以及4中迭代方式
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;
/*测试List接口的子类ArrayList*/
public class TestArrayList {
public static void main(String[] args) {
//1.创建对象,使用无参构造
//底层会自动创建数组帮我们存放集合对象,数组的初始容量为10
ArrayList<Integer> list = new ArrayList<>();
//2.存入一些数据
list.add(100);
list.add(200);
list.add(300);
list.add(400);
list.add(200);
//3.测试ArrayList接口的方法
// list.clear();
// System.out.println(list);
System.out.println(list.contains(100));//true,包含指定元素
System.out.println(list.get(1));//200,获取下标1的元素
System.out.println(list.indexOf(200));//1,获取第一次出现指定元素的下标
System.out.println(list.lastIndexOf(200));//4,获取指定元素最后一次出现时的下标
System.out.println(list.remove(1));//移除指定下标下的元素
System.out.println(list);//[100, 300, 400, 200]
/*注意:写法报错:
* 300默认是int,会匹配根据索引删除元素的方法,所以需要int转成Integer
* 才会匹配根据指定元素来删除的方法*/
//System.out.println(list.remove(300));
//int类型转成包装类Integer,手动装箱
System.out.println(list.remove(Integer.valueOf(300)));
System.out.println(list.size());//获取集合元素个数
System.out.println(Arrays.toString(list.toArray()));//list数组集合转为普通数组
//4.4种迭代/遍历方式
//方式1:
System.out.println("方式1:for循环");
for (int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println("方式2:高效for循环");
for (Integer i :list){
System.out.println(i);
}
System.out.println("方式3:iterator()");
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
Integer next = it.next();
System.out.println(next);
}
System.out.println("方式4:listIterator()");
ListIterator<Integer> it2 = list.listIterator();
while(it2.hasNext()){
Integer next = it2.next();
System.out.println(next);
}
}
}
5.链表LinkedList
5.1面试题:LinkedList链表与ArrayList数组的区别?
答:1)ArrayList是一个集合,底层维护的是一个数组结构
数组结构:查询快,增删慢
2)LinkedList是一个集合,底层维护的是一个链表结构
链表结构:查询慢,增删快
TIPS:两者指的都是数据量比较大的情况,而且链表首尾操作还是比较快的,中间反而慢
练习:链表的常用方法以及特有方法
注意:链表常用方法继承自Collection中的方法
除了集合的方法外,LinkedList还有自己特有的方法
查询方法: | |
element()/peek() | 获取指定集合所有元素 |
peekFirst()/peekLast() | 获取集合第一个/最后一个元素 |
增加方法: | |
offer() | 指定元素添加到集合中 |
offerFirst()/offerLast() | 指定元素添加到集合的首位/末位 |
移除方法: | |
pool() | 移除元素(默认移除首位) |
poolFirst()/poolLast() | 移除集合中的首位/末位元素 |
package cn.tedu.collection;
import java.util.LinkedList;
/*测试链表的常用方法,特有方法测试*/
public class TestLinkedList {
public static void main(String[] args) {
//1.创建集合对象
LinkedList<String> list = new LinkedList<>();
//2.添加数据
list.add("唐三藏");
list.add("孙悟空");
list.add("猪八戒");
list.add("沙悟净");
list.add("白龙马");
System.out.println(list);
//3.1自行测试继承自Collection中的方法
//3.2LinkedList特有方法测试
list.addFirst("蜘蛛精");//添加首元素
list.addLast("玉兔精");//添加尾元素
System.out.println(list);//[蜘蛛精, 唐三藏, 孙悟空, 猪八戒, 沙悟净, 白龙马, 玉兔精]
System.out.println(list.getFirst());//获取首元素
System.out.println(list.getLast());//获取尾元素
System.out.println(list.removeFirst());//蜘蛛精,删除首元素
System.out.println(list.removeLast());//玉兔精,删除尾元素
System.out.println(list);
//4.其他测试
//4.1创建对象
LinkedList<String> list1 = new LinkedList<>();
//4.2添加数据
list1.add("西游记");
list1.add("红楼梦");
list1.add("三国演义");
list1.add("水浒传");
System.out.println(list1);
/*别名:查询系列*/
System.out.println(list1.element());//获取但不移除集合的首元素
System.out.println(list1.peek());//西游记,获取集合中的首元素但不移除
System.out.println(list1.peekFirst());//西游记,获取但不移除集合中的首元素
System.out.println(list1.peekLast());//水浒传,获取但不移除集合中的尾元素
System.out.println(list1);
/*别名:新增系列*/
System.out.println(list1.offer("雪中悍刀行"));//指定元素添加在集合的末尾
System.out.println(list1.offerFirst("吞噬星空"));//添加在首元素
System.out.println(list1.offerLast("完美世界"));//添加在尾元素
System.out.println(list1);
/*别名:移除系列*/
System.out.println(list1.poll());//吞噬星空,获取并移除集合中的首元素
System.out.println(list1.pollFirst());//西游记,获取并移除集合首元素
System.out.println(list1.pollLast());//完美世界,获取并移除集合尾元素
System.out.println(list1);
}
}