集合和数组的区别
-
长度区别,集合长度可变,而数组长度固定
-
单一性区别:数组只能存储同一类型,而集合可以同时储存不同的类型的数据
-
对于存储数据的类型不一样,数组既可以存储基本类型的数据,也可以存储引用类型的数据而集合的只能存储引用类型的数据。存储基本数据类型的数据一般是存储基本类型的对于的包装类型的数据。
Collection
方法:
boolean add(E e):添加一个元素
//LIst的子类的add多是return true,只要上面代码不报异常,就永远返回true;
//vector的add
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//ArrayList
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//LinkedList
public boolean add(E e) {
linkLast(e);
return true;
}
boolean remove(Object):移除集合中你指定的类容,但是只能移除一个,如果是有相同的一般会移除前面的
void clear():清空集合
boolean contains():判断集合是否包含你传递的内容
boolean isEmpty():判断集合是否为空
int size():集合中有多少元素
toString():其实是重写了Object里面的toString 方法,打印的数据就是你集合中的元素
toArray():把集合转换为一个数组
boolean addAll(Conllection c):添加一整个集合,那一个集合的属性全部添加调用的那个集合里面,如果时list的2个集合的话有2个相同的元素是不会覆盖的,而set的话相同的元素就不会被添加;
boolean removeAll(Conllection c):删除一整个集合,如果集合和你的集合里面的元素不同的话,就会返回false,如果相同只删除相同的元素。只有调用集合会有影响。
boolean containsAll(Conllection c):判断是否包含一整个集合的元素,如果只有一个不包涵也会返回false
boolean retainAll(Conllection c):2个集合的交集,然后调用方法的集合就只有2个集合只有交集
集合
迭代:即是Collection集合元素的通用获取的方式,在取出元素之前先要判断集合中有没有元素,如果有就把这个元素取出,在继续判断,如果还有就在取出,一直把集合中所有的元素取出来。这种去除方式叫迭代。
迭代器:(获取迭代器的实现类对象,并且会把指针(索引)指向集合的-1索引,然后在用迭代器的.hasNext()了2件事情,1.去取下一个元素 2把指针向后移动一位,返回的值是一个boolean)
//这个是一个迭代set
Set lt=new TreeSet();
lt.add("dd");
lt.add("dd");
lt.add("dd");
lt.add("dd");
lt.add("dd");
Iterator it=lt.iterator();
//boolean b = it.hasNext();
//System.out.println(b);
//while方式
while (it.hasNext()){
System.out.println(it.next());
}
//for方式
for(Iterator i= lt.iterator();i.hasNext();){
System.out.println(i.next());
}
增强for循环
是JDK1.5以后出现的一个高级for循环,专门来遍历出租和集合的。他的内部原理其实是Iterator迭代器。所以在遍历过程中不能对集合中的元素进行一个增删的操作。实现了Iterable的都可以用。
泛型
泛型是一种未知的数据类型,当我们不知道是什么数据类型的时候,可以使用泛型
泛型也可以看成一个变量。用来接受数据类型
E:代表位置的类型(在创建集合对象的时候你给出一个指定的类型,就会确定类型)
比如:Set set=new HashSet ();会把String作为参数传递,把String赋值给E。
如果集合不适用泛型,默认就是Object类型,可以储存任意类型的数据,但是不安全,可能会引发异常。使用的话,可以避免类型转换的麻烦,储存的是什么类型,就去除什么类型,把运行期异常(类型转换异常),提升到了编译期(写代码就会报错),但是泛型是什么类型他就只能存储什么类型。
如果是放到类,方法,接口里面的话
package oop.collection;
public class Never<E> {//这里加了了一个泛型,就是你出传入的对象的一般就是object.
//Never never=new Never<String>();这个时候全部多是String类型的属性
private E a;
public E getA() {
return a;
}
public void setA(E a) {
this.a = a;
}
}
package oop.collection;
public class Never {//这里是加泛型的
private String a;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
}
//含有泛型的方法
public class Demp{
public static void main(String arg[]){
Demp demp =new Demp();
demp.method(1);
demp.method("1231");
Demp.medthoed1(1);
Demp.medthoed1("123");
}
//含有泛型的普通方法
public <M> void methoed(M e){
System.out.println(e);
}
//含有泛型的静态方法
public static<E> void medthoed1(E e){
System.out.println(e);
}
}
//含有泛型的接口
interface fx<E>{
void add(E e);
void del(E e);
void select(E e);
}
class dbh implements fx<String>{
@Override
public void add(String s) {
}
@Override
public void del(String s) {
}
@Override
public void select(String s) {
}
}
//泛型的通配符?不知到你的集合是什么数据类型的时候,就可以使用通配符?来接受收数据。
//? extends Number:这个是Number本身以及它的一个子类
//? super Number:这个数Number本身以及它的一个子类
//这个是一个分配牌,模拟斗地主的发牌,一人摸一张
package oop.collection.fx;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo02 {
public static void main(String[] args) {
List list=new ArrayList();
//存放花色
list.add("黑");
list.add("红");
list.add("梅");
list.add("方");
List list1=new ArrayList();
//存放值
list1.add("A");
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");
list1.add("J");
list1.add("Q");
list1.add("K");
List list2 =new ArrayList();
list2.add("小王");
list2.add("大王");
for (Object o : list) {
for (Object o1 : list1) {
list2.add(o+""+o1);
}
}
Collections.shuffle(list2);
System.out.println(list2.toString());
List penson=new ArrayList();
List penson2=new ArrayList();
List penson3=new ArrayList();
//54 51
for(int i=0;i<list2.size();i++){
if(i%3==0&&i<51){
penson.add(list2.get(i));
}
if(i%3==1&&i<51){
penson2.add(list2.get(i));
}
if(i%3==2&&i<51){
penson3.add(list2.get(i));
}
}
System.out.println(penson);
System.out.println(penson2);
System.out.println(penson3);
}
}
集合的数据储存结构
栈:
入口和出口在同一侧,(入口,栈顶,栈底,出口)从存储元素到集合(入,压栈)取出集合中元素(出,弹栈)先进后出(子弹弹夹)。
关于这个的先进后出:编码过程中,程序自上而下,嵌套越深的变量被出栈之后对程序的影响越小,嵌套越浅的变量(全局变量)是不能轻易将数据从对堆栈中取出来的。
队列:
入口和出口在集合的2侧,所以先进先出(和排队安检相似)
(入口,出口)
数组:
查询快(数组的下表是连续的,我们通过数组的首地址可以找到数组,通过数组的索引快速查找某一元素),但是增删慢
删除:
比如你要删除一个元素的话,必须船舰一个新的数组,长度是原来数组的长度-1.把原来数组的其他元素赋值到新的数组中,在把新数组的地址赋值给原来数组的变量,原来的数组就会在内存中被销毁(垃圾回收),在堆内存中频繁创建数组,赋值数组的元素,销毁数组,速率低下
增加:
因为数组的长度是固定不变的,想要增加/删除一个元素,你的数组容量满了的话,就必须创建一个新的数组,把源数组的数据复制过来。
链表:
是由一系列节点node组成,节点可以在运行时动态生成,每个节点包括3个部分:1个时存储元素的数据域,2个指针域(存储地址(存储自己地址和下一个节点的地址)。我们常说的链表结构有单向与双向,
查询慢:链表的地址不是连续的,每次都必须要从头开始查询
增删快:因为每增加/删除一个元素,对链表的整体结构没有影响,所以快、
链表中每一个元素就别称之为一个节点,一个节点包含了数据源(存储数据),2个指针域(存储地址(存储自己地址和下一个节点的地址))
单向链表:链表只有一条链子,不能保证元素的的顺序(存储元素和取出元素的顺序可能不一样
双向链表:链表中有2个链子,一个是记录元素顺序的,所以是有序的
红黑树
二叉树:分支不能超过俩个(左边的分支叫左子树,右边的叫右子树),二叉树的所有叶子节点都在最后一层, 并且结点总数=2^n-1, n为层数, 则我们称之为满二叉数。
如果该二叉树的所有叶子节点(没有子节点的节点)都在最后一层或者倒数第二层, 而且最后一层的叶子节点在左边连续, 倒数第二层的叶子节点在右边连续, 我们称之为完全二叉树。若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k 层所有的结点都连续集中在最左边,这就是完全二叉树。
排序树/查找树:在二叉树的基础上,元素的大小时有顺序的,左子树小,右子树大。
平衡树:左子树和右子树相等
不平衡树:左子树不等与右子树
红黑树:趋近于平衡树,查询速度非常快,查询叶子节点最大次数和最小次数不能超过2倍
约束,节点可以输红色也可以是黑色的,根节点必须是黑色的,叶子节点黑色的,每个红色的节点的子节点都是黑色的。任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
List
1.list集合遍历有3种方式(在操做此类集合是要注意防止索引越界异IndexOutOfBoundsException)
- 可以使用普通的for循环
- 可以使用for循环的加强版(foreach)
- 可以使用迭代器
2.3个实现类
- Arraylist(底层是一个可变数据,不是同步的)
- LinkedList(底层是一个双向链表,不同步)里面有大量操作首尾特有的方法,调用首尾这种方法,如果是集合种没有数据会报:NoSuchElementException
- Vector(底层也是一个数组,但是他是同步的,继承了Arraylist)
##### Set
hashSet:存储元素和取出元素的顺序有可能不一致,底层是一个哈希表结构(查询的速度非常快)
- 1.它不允许出现重复元素-----------无重复(必须重写元素的equals和hashCode方法,保证元素的不可重复性)
- 2.不保证集合中元素的顺序---------无序
- 3.允许包含值为null的元素,但最多只能有一个null元素。
在调用add方法的时候也,add方法会调用hashCode方法和equals方法如果hashcode的值一样的话就会返回一个true,在后在调用equals的方法判断,如果是false就会把它添加到集合,是true就不会添加到集合
,判断2个元素是否重复
哈希值:是一个十进制的整数,是由系统随机给出的(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际储存的物理地址)在object类中有一个方法hashcode(),可以返回对象的哈希码值.
哈希表:1.8以前是一个数组+链表,之后是数组+链表+红黑树,查询速度快
2个元素不同,但是他们的哈希值相同,就会导致hash冲突.如果链表的长度超过8位,就会把链表转换为红黑树(提高查询速度)
LinkedHashSet:
底层是一个哈希表+链表(记录元素的存储顺序,保证元素是有序的)
Collections
集合的工具类,是对集合进行一个操作.
方法:
List list=new ArrayList();
Collections.addAll(list,1,2,3,4,5);//往list集合种添加多个元素
Collections.shuffle(list);//打乱集合中元素的顺序
Collections.sort(list);//将集合中的元素按照默认规则排序,升序.
注意:使用它来排序自定义的元素,那那个元素必须实现Comparable接口,重写接口的compareTo方法定义排序的规则
//这个是我自己创建的一个
@Override
public int compareTo(ff o) {升序排序
return this.getA()-o.getA();//成员变量是a,默认是返回一个0,相当于都是相等的.升序排序(自己减去参数就是升序,相反则是降序)
}
//第二种,第一种就是自己(this)和别人(参数)比较,第二种就相当是找了一个第三方的裁判,来比较2个
Collections.sort(list, new Comparator<ff>() {
@Override
public int compare(ff o1, ff o2) {
// return o1.getA()-o2.getA();//升序
return o2.getA()-o1.getA();//降序
}
});
Map
Map集合是一个双列集合,一个元素包含2个值(键,值)
将键映射到值的对象,一个映射不能包含重复的值;每个键最多只能映射一个值.
key是不可以重复的,value是可以重复的。
方法:
//put():把指定的键与指定的值添加到Map集合种
//返回值v:如果keY不重复,返回null,重复的时候,会使用新的value来替换原本在map中的value,返回被替换的value值
Map<String,String> map=new HashMap();
Object put = map.put("1", "1");
Object put1 = map.put("2", "2");
Object put2 = map.put("3", "3");
Object put3= map.put("4", "4");
Object remove = map.remove("3");//把指定键位所对应的键值对元素在map集合中删除,返回被删除元素的值v:如果存在,v返回被删除的值,不存在就返回null.
Object o = map.get("1");//根据指定健位找到对应的值,如果存在就返回对应的value,不存在返回null.
boolean b = map.containsKey("1");//判断集合中是否包含指定key,包含返回true,不包含返回false
boolean b1 = map.containsValue("11");//判断集合中是否包含指定vale,包含返回true,不包含返回false
//遍历:
//第一种(通过键找值)
Set<String> keySet = map.keySet();//把map集合中的key取出来,存储到Set集合中
for (String s : keySet) {//遍历set里面的键在通过get方法来遍历map集合中的value
map.get(s);
}
//第二种
for(Object o :map.keySet()){
System.out.println(map.get(o));
}
//第三种
Set<Map.Entry<String, String>> entries = map.entrySet();//通过entrySet()方法,把Map集合内部的多个Entry对象取出来存放到Set集合中,通过遍历set集合获取Set集合中的每一个Entry对象
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getValue());
}
Entry:
在Map中有一个内部接口Entry
作用:当Map集合一创建,就会在Map集合中创建一个Entry对象,用来记录键和值(键值对对象,键与值的映射关系)
HashMap:
实现了Map接口,底层是哈希表,查询的速度特别快
存储元素和取出元素的顺序可能不同
HashTable
也是实现了Map接口,底层是哈希表,查询速度特别快,但是它的的所有方法都加了同步了锁,所以可能效率不是很高,但是安全。不能 存储空值
LinkedHashMap:
继承了Hashmap接口,底层是哈希表+链表(保证迭代的顺序),存储元素和取出元素的顺序是一直的。
Hashtable
底层也是一个哈希表,不能存储空,他是同步的。速度快,但是安全。实现了HashMap
扩展题(给你一个字符串,计算出字符串中的每个字符有多少个)
System.out.println("请输入一个字符串");
Scanner sc=new Scanner(System.in);
String next = sc.next();
char[] chars = next.toCharArray();
Map<Character,Integer> map= new HashMap();
int count;
for (char c : chars) {
if(map.containsKey(c)){
Integer value = map.get(c);
value++;
map.put(c,value);
}else {
map.put(c,1);
}
}
System.out.println(map);