【第11章】泛型和集合


一、泛型

1、简介:泛型是带一个或多个类型参数的类或接口。利用泛型可以编写更安全的程序。
常用的类型参数名: E(元素)、K(键)、N(数字)、T(类型)、V(值)

//泛型声明
public class 泛型类名<泛型类型参数T>{
	private T value;
	public 泛型类名() {}		//默认构造方法
	public 泛型类名(T value) {	//带参数构造方法
	   this.value = value;
   }
   public T get(){			//成员方法
   	return value;
   }
   public void set(T value){
   	this.value = value;
   }
}
//实例化泛型类对象
泛型类名  <实际类型> 对象名 = new 泛型类名<>();	
Node <Integer> intNode = new Node<>();	
//调用成员方法
对象名.setData(new Integer(999));		
对象名.getData();					
//多个类型参数的泛型
//两个参数的泛型接口
public interface Entry<K,V>{
	public K getKey();		//抽象方法
	public V getValue();
}
//实现泛型接口
public calss Pair<K,V> implements Entry<K,V>{	//注意接口和类都带两个参数
	private K key;
    private V value;
    public Pair(K key, V value) {		//构造方法,注意类型 K、V
	  this.key = key;
	  this.value= value;
   }
   //实现接口的抽象方法...
}
//创建泛型类实例
Pair<String,String> p = new Pair<>("china","Beijing");

2、泛型方法
简介:带类型参数的方法,有静态方法和非静态方法

//eg:	交换两个元素的位置
public class{
	public static <T> void 方法名(T[] array,int i,int j)	{	//注意在返回值之前加上<类型>
		T temp = array[i];
	    array[i] = array[j];
	    array[j] = temp;
	}
	...
	//在Integer数组中交换两个元素的位置
	Integer[] numbers = {1, 3, 5, 7};
	类名.<Integer>方法名(numbers, 0, 3);		
	//参数类型<Integer>可省略,即类名.方法名(numbers, 0, 3);
}

3、类型参数
(1)通配符(?):接收任何类型

public static void printList(List<?> list){ //表示该方法可接受的元素是任何类型的List对象
     for(Object element : list){
           System.out.println(element);
     }
}

(2)有界类型参数:限制传递给泛型的参数的类型
概念:
上界用extends指定,例如, List<? extends Number>
下界用super指定,例如, List<? super Integer>

二、集合

概念:处理对象组,集合都是泛型类型
导包:import java.util.*
两个基本接口:
(1)Collection
(2)Map
对应的子接口和实现类:
在这里插入图片描述

1、Collection接口

对集合的操作方法

//1、基本操作
boolean add(E e)		
boolean remove(Object o)
boolean contains(Object o)
boolean isEmpty()
int size()
//2、批量操作
boolean addAll(Collection<? extends E> c)	//将集合c的所有元素添加到当前集合中
boolean removeAll(Collection<?> c)
default boolean removeIf(Predicate<? super E> filter)
boolean containsAll(Collection<?> c)
boolean retainAll(Collection<?> c) 	//在当前集合中只保留集合c中指定的元素
void clear()
//3、数组操作
Object[] toArray() 		//返回包含集合中所有元素的对象数组
<T> T[] toArray(T[] a)		//可设置返回数组的元素类型
//4、流(String)操作
public default Stream<E> stream()	//返回顺序流对象
public default Stream<E> paralellStream()	//返回并行流对象

(1)List接口及实现类

1、简介:List接口实现一种对象列表的结构,通过从0开始的下标访问List中的元素。List中可以包含重复元素。
2、List接口的实现类:
在这里插入图片描述
3、基本操作

E get(int index)
E set(int index, E element)
void add(int index, E element)
E remove(int index)
int indexOf(Object o)		//查找对象第一次出现的位置
int lastIndexOf(Object o)
List<E> subList(int from, int to)	//返回从from到to的一个子线性表

4、ArrayList类
(1)简介:ArrayList类实际上实现了一个变长的对象数组,其元素可以动态地增加和删除。它的定位访问时间是常量时间。
(2)构造方法

ArrayList()			//空的数组线性表对象,初始容量为10		
ArrayList(Collection c)		// 用集合c的元素创建数组线性表对象
ArrayList(int initialCapacity)		//空的数组线性表对象,指定初始容量

(3)eg:
注意声明对象的时候一定要在前面加上 <类型>
由于声明了类型之后编译器可以自动识别,所有后面有的地方的<类型>省略了,如果以后对比源码发现有的代码有<类型>,有的没有,不要太纠结这个问题。

List <类型> 对象名 = new ArrayList<>();
对象名.add(元素);
对象名.add(下标,元素); 
//遍历集合
//方法1:for循环
for(int i=0;i<对象名.size();i++){
	System.out.print(对象名.get(i)+" ");
}
//方法2:增强for循环	顺序遍历
for(类型 别名:对象名){
	System.out.print(别名);	
}
//方法3:迭代器Interator接口	顺序遍历
for(Iterator iterator = 对象名.iterator();iterator.hasNext();){
		    System.out.println(iterator.next());
	   }
//双向迭代器ListInterator 可反向遍历,也可进行add()、set()、remove()
ListIterator iterator = 对象名.listIterator();	
while(iterator.hasNext())	// 将迭代器指针移到线性表末尾
	iterator.next();
while (iterator.hasPrevious())	  // 从后向前访问线性表每个元素
	System.out.println(iterator.previous());

(4)数组转为List对象
使用java.util.Arrays类的静态方法:==asList()==方法

List<类型> list集合名 = Arrays.asList(元素1,元素2...); 

(2)Set接口及其实现类

简介:类似于数学上的集合,不允许元素重复,用树结构来存储元素
Set接口的实现类:HashSet类、TreeSet类
1、HashSet类
(1)简介:HashSet类用散列方法存储元素,具有最好的存取性能,但元素没有顺序。
(2)构造方法:

HashSet() 		//初始容量是16,默认装填因子是0.75。
HashSet(Collection c)	//使用集合c元素
HashSet(int initialCapacity)		//指定初始容量
Set <类型> 对象名 = new HashSet<>();
对象名.add(元素);
//用Set对象实现集合操作
s1.addAll(s2):实现集合s1与s2的并运算。
s1.retainAll(s2):实现集合s1与s2的交运算。
s1.removeAll(s2):实现集合s1与s2的差运算。
s1.containsAll(s2):如果s2是s1的子集,该方法返回true

2、TreeSet类
(1)简介:它使用红-黑树算法为元素排序。添加到TreeSet中的元素必须是可比较的,即元素的类必须实现Comparable接口。
(2)构造方法

TreeSet()
TreeSet(Collection c)	//按照自然顺序为集合元素排序
TreeSet(Comparator c)	//按给定的比较器c的规则排序
//eg:自然排序(从小到大)
Set<Integer> ts = new TreeSet<>();  
Integer[] s = new Integer[]{88,-12,56,90};
for (int i = 0; i < s.length; i++){
    ts.add(s[i]);			//向TreeSet类的对象ts添加元素,TreeSet中的元素将自动排序
}
System.out.println(ts);		// {four,one,three,two}
//eg:自定义的比较器排序
Set<Integer> ts = new TreeSet<>(new Comparator<Integer>(){
	public int compare(Integer o1, Integer o2){
		return o2.compareTo(o1);	//从大到小
	}
});
//或者用nb的Lambda表达式
Set<Integer> ts = new TreeSet<>((o1,o2) -> o2.compareTo(o1));

(3)Queue接口及其实现类

简介:Queue接口以先进先出的方式排列其元素,称为队列(queue)。
实现类:
在这里插入图片描述

//Queue接口常用方法
//操作失败抛出异常
boolean add(E e)	//向队列中插入指定元素e
E remove()			//返回队列头元素,同时将其删除
E element()			//返回队列头元素,不将其删除
//操作含义和上面一样,但操作失败返回值
boolean offer(E e)
E poll()
E peek()

Deque接口常用方法
在这里插入图片描述
LinkedList类更灵活,允许插入null元素,适合经常在线性表头部增加元素或删除元素

//eg: ArrayDeque
int [] elements = {1,2,3,0,7,8,9};
ArrayDeque<Integer> queue = new ArrayDeque<>();
queue.addFirst(5);     // 5
for(int i = 0; i < 3; i++) {
	queue.addFirst(elements[i]);   //  3  2  1  5 
}
for(int i = 4; i<7;i++) {
	queue.offerLast(elements[i]);  // 3  2 1  5 7 8 9 
}
for(Integer v : queue) {
	System.out.print(v + "   ");
}
// 队列大小:queue.size());

2、Map接口

1、简介:存储“键/值”对的对象。在Map中存储的关键字和值都必须是对象,并要求关键字是唯一的,而值可以重复。
2、Map接口实现类
在这里插入图片描述
HashMap类:以散列方法存放“键/值”对
TreeMap类:默认按键 对“键/值”对 进行排序
3、基本操作

public V put(K key, V value)	//添加 键值对
public V get(Object key)
public V remove(Object key)
public void clear()
public Set<K> keySet()		//返回由键组成的集合对象
public Collection<V> values()	//返回由值组成的集合对象
//HashMap类 eg:
String[] country={"中国","印度","澳大利亚"};
String[] capital={"Beijing","New Delhi","Canberra"};
Map<String, String> m = new TreeMap<>();
for(int i = 0;i<country.length;i++)
     m.put(country[i], capital[i]);

3、Collections类

简介:java.util .Collections类是工具类,提供了若干static方法实现集合对象的操作。大多是对List操作。
主要操作:

Integer []num = {30,-20,99, 50, 0, 8};
List<Integer> list = Arrays.asList(num);	
1、排序
Collections.sort(list);
2、查找
Collection.binarySearch(list,元素);
3、重排(打乱次序)         
Collections.shuffle(list);
4、求极值
Collections.max(list);		//最大值
5、反转
Collections.reverse(list);	

三、Stream API

(1)流(Sream)简介:
①流(stream)指的是数据流,它像一个管道,可以将数据从源传输到目的地。流仅用来移动数据,不能像集合一样向流中添加元素。
②流可分为顺序流和并行流。使用流的主要原因是它支持顺序的和并行的聚集操作。例如,可以很容易地排序、过滤或转换流中的元素。
③Stream API 中的Stream接口最常用。Stream对象可用来传输任何类型的对象。
导入包:import java.util.stream.*;
(2)Stream接口中常用方法
中间操作:将一个流转换成另一个流
终止操作:产生一个最终结果
在这里插入图片描述

1、各种流操作

(1)创建流

方法一:Stream.of()方法
Stream<类型> 流对象名stream = Stream.of(数组名或元素);
方法二:Arrays.stream()方法
Stream<类型> stream = Arrays.stream(数组名);
方法三:集合接口的stream()
List<类型> 集合对象名list = new ArrayList<>();
Stream<类型> stream = list.stream();	//顺序流
Stream<类型> stream = list.parallelStream();	//并行流

(2)连接流、排序流、限制流、过滤流

concat(1,2):连接两个流
sorted():进行排序,依然是两种:自然排序和自定义比较器排序
limit(元素个数):返回一个包含原始流前n个原素的新流
filter(规则):返回一个包含按某种规则选择的元素的新流。规则可用Lambda表达式表示
map(转换函数):对原始流进行某种形式的转换,返回一个新流
	map(转换函数)举例:
	map(String::toLowerCase)	//转成小写
	map(String::toUpperCase).map(x->x.substring(0,1));	//转成大写、取出元素的第一个字符
//eg:两个流连接、自然排序、输出
Stream<String> stream1 = Stream.of("","");
Stream<String> stream2 = Stream.of("","");
Stream<String> stream = Stream.concat(stream1,stream2).sorted().forEach(System.out::println);
//eg:比较器排序(长度长的排在前面)、返回前3个元素
String[] words = {"","","",""};
Stream<String> stream4 = Stream.of(words).sorted(
	Comparator.comparing(String::length).reversed().limit(3));
//eg:过滤流,过滤长度>=4的元素
Stream<String> stream5 = Stream.of(words).filter(x->x.length()>=4);

(3)流规约
简介:从流中获得一个结果的方法为规约方法。规约是终止操作。
归约方法:

count():流中元素个数
max()min():返回流中最大值和最小值。返回一个Optional<T>类型的值,它可能会封装返回值,当流为空时没有返回。
String[] words = {"","","",""};
long n = Stream.of(words).count();
Optional <String> largest = Stream.of(words).max(String::compareTo);	//返回元素首字母Unicode码的大
System.out.println(largest.get());

(4)收集结果
1、stream.toArray() :将流中所有元素转换成一个Object[]类型数组
如果要返回指定类型的数组,则给toArray()传递一个构造方法引用,

//返回一个字符串数组
String[] result = stream.toArray(String[]::new);

2、Stream.collect(Collectors.实例方法):将流中元素收集到另一个集合

List<String> result =  stream.collect(Collectors.toList());	//列表
Set<String> result =  stream.collect(Collectors.toSet());	//集合
TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet::new)); //Set中的TreeSet

2、基本类型流

1、简介:上面说的流是对象流,基本类型流有IntStream类型(short、char、byte、boolean),DoubleStream类型(float)
2、创建基本类型流

//创建IntStream
1IntStream.of()方法
IntStream stream = IntStream.of(1, 1, 2, 3, 5, 8, 11);
2Arrays.stream()方法
stream = Arrays.stream(整型数组, 开始下标, 结束下标); 

3、一些方法
(1)sum()、average()、max()、min()

int[] integers = new int[] (1, 1, 2, 3, 5, 8, 11);
int min = Arrays.stream(integers).min().getAsInt(); 
int sum = Arrays.stream(integers).sum(); 
double avg =  Arrays.stream(integers).average().getAsDouble(); 

(2)IntStream拥有range()和rangeClosed()静态方法,可以产生步长为1的一个整数范围。

int sum = IntStream.range(1, 10).sum(); // returns 45
int sum = IntStream.rangeClosed(1, 10).sum(); // returns 55

3、并行流

简介:并行流可以提高效率,但不是所有情况下并行流都比顺序流要快
创建并行流
paralellStream():可以从任何集合获得一个并行流。

Stream<String> 并行流名 = 集合名.parallelStream();

paralell():将顺序流转换成并行流。

Stream<String> 并行流名 = Stream.of(顺序流名).paralell();
// 计算第n个斐波那契数方法
public static long fibonacci(long n) {
  if (n == 1 || n == 2) {
    return 1;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}
...
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 41, 42);
numbers.parallelStream().map((input) -> fibonacci(input)).forEach(System.out::println);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值