一、对象流
对象流 序列化 公共流(节点流)
ObjectInputStream 反序列化输入流 新增方法 readObject()
ObjectOutputStream 序列化输出流 新增方法 writeObject()
注意:
先序列化后反序列化
输入写出的顺序必须一致
不是所有的类都能够序列化 实现接口java.io.Serializable
不是所有的属性都需要序列化 transient
如果父类实现了序列化接口,子类中所有的内容都与能力序列化
如果子类实现了序列化接口,但是父类没有实现,子类只能序列化自己的内容
静态的内容不能序列化
public static void write(String dest,ArrayList<Student> stu) throws FileNotFoundException, IOException {
ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
for(int i=0;i<stu.size();i++) {
System.out.println(stu.get(i));
oos.writeObject(stu.get(i));
}
oos.close();
}
public static boolean read(String src,int size) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(new BufferedInputStream(new FileInputStream(src)));
ArrayList<Student> stu=null;
for(int i=0;i<size;i++) {
if("李凯".equals(((Student)(ois.readObject())).getName()))
return true;
}
ois.close();
return false;
}
二、、容器: 可变长的,任意数据类型的数据的集合
1、数组:
定长的
数据类型相同
有序,有索引,根据索引查询效率高
缺点:数组长度一旦确定,不可改变,因此,不灵活:容量需要事先定义好,不能随 着需求的变化而扩容。
2、容器类
数组远远不能满足我们的需求。我们需要一种灵活的,容量可以随时扩充的容 器来装载我们的对象。这就是容器类,或者叫集合框架。
手写简单容器:
自定义容器类 : 只存储字符串,实现随着内容的增删长度可变
class MyContainer{
private String[] arr=null;
private int size;
public MyContainer() {
arr=new String[0];
}
public String getArr(int index) {
if(index<0||index>=size) {
throw new ArrayIndexOutOfBoundsException();
}
return arr[index];
}
public int getSize() {
return size;
}
/*
* 修改功能
*/
//添加
public void add(String str) {
String[] temp=arr;
arr=new String[size+1];
for(int i=0;i<size;i++) {
arr[i]=temp[i];
}
arr[size]=str;
size++;
}
//删除
public void remove(int index) {
if(index<0||index>=size) {
throw new ArrayIndexOutOfBoundsException();
}
String[] temp=arr;
arr=new String[size-1];
for (int i = 0; i < temp.length; i++) {
if(i<=index) {
if(i==index)
continue;
arr[i]=temp[i];
}else {
arr[i-1]=temp[i];
}
}
size--;
}
}
3、集合 Collection
成员方法:
注意:
容器可以存储任意类型的数据
泛型中的数据类型只能为引用类型,基本数据类型会发生非自动装箱
遍历:
增强for
迭代器
Collection col1 = new ArrayList();
Collection col2 = new ArrayList();
Collection<String> col3 = new ArrayList();
col1.add("123");
col1.add("567");
// boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
System.out.println(col2.isEmpty());
// boolean addAll(Collection<? extends E> c)
// 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
col2.addAll(col1);
System.out.println(col2);
// boolean contains(Object o)如果此 collection 包含指定的元素,则返回 true。
System.out.println(col1.contains("123"));
// void clear() 移除此 collection 中的所有元素(可选操作)。
col1.clear();
System.out.println(col1.isEmpty());
// removeAll(Collection)
//移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
System.out.println(col2.removeAll(col1));
System.out.println(col2);
// int size() 返回此 collection 中的元素数。
System.out.println(col1.size());
// Object[] toArray() 返回包含此 collection 中所有元素的数组。
Object[] a = col1.toArray();
System.out.println(Arrays.toString(a));
//迭代器
Iterator it = col2.iterator();
if(it.hasNext()){
System.out.println(it.next());
}
//增强for
for(Object o:col2)
System.out.println(o);
4、 List接口:有序的,可重复的
新增功能:新增了一些关于索引操作的方法
接口遍历:
for普通for
for .. each
迭代器
List<String> list=new ArrayList();
list.add("钢铁侠");
list.add("雷神");
list.add("鹰眼");
list.add("快银");
list.add("浩克");
list.add("美国队长");
list.add("洛基");
list.add("灭霸");
System.out.println(list);
//remove(ele|index) 如果数据和索引都是整数,默认把参数认为index
list.remove(3);
System.out.println(list);
//List<E> subList(int fromIndex, int toIndex) toIndex取不到
System.out.println(list.subList(1, 3));
boolean flag=false;
for(int i=0;i<list.size();i++) {
if(list.get(i).equals("灭霸")) {
list.add("惊奇队长");
}
}
System.out.println(list);
for(String str:list) {
if(str.equals("灭霸")) {
flag=true;
}
}
if(flag) {
list.add("惊奇队长");
flag=false;
}
System.out.println(list);
for(Iterator it=list.iterator();it.hasNext();) {
if(it.next().equals("灭霸"))
flag=true;
}
if(flag) {
list.add("惊奇队长");
}
System.out.println(list);
5、ArrayList :有序的可重复的
底层:数组实现,进行动态扩容,每次使用copyOf方法进行扩容,每次扩容后的容量是原容量的1.5倍
优点:随机获取或者遍历效率高
缺点:增删效率低
线程不安全的,效率高
Vector: 向量
底层:数组实现,使用copyOf方法进行动态扩容,每次扩容后的容量是原容量的2倍
线程安全的,效率低
ArrayList<Person> al=new ArrayList<>();
al.add(new Person(1,"大锤",108));
System.out.println(al);
System.out.println(al.indexOf(new Person(1,"大锤",108)));
6、LinkedList
底层:双向链表实现
优点:做增删效率高
缺点:查询和遍历效率低
新增功能: 新增了一些操作与头部和尾部的方法
LinkedList<String> ls=new LinkedList<String>();
ls.add("小明");
ls.add("小黄");
ls.add("小花");
System.out.println(ls);
//void addFirst(E e) 将指定元素插入此列表的开头。
// void addLast(E e) 将指定元素添加到此列表的结尾。
ls.addFirst("1");
ls.addLast("0");
System.out.println(ls);
// E element() 获取但不移除此列表的头(第一个元素)。
System.out.println(ls.element());
自定义LinkedList容器类(单向链表)
public class LinkedList05 {
public static void main(String[] args) {
//Test for MyLinkdeList
MylinkedList myll=new MylinkedList();
myll.add("assassin");
myll.add("sabor");
myll.add("berserker");
myll.add("lancer");
System.out.println(myll.getSize());
System.out.println(myll.get(3));
}
}
//自定义LinkedList容器类
class MylinkedList{
//链表头
private Node head;
//链表长度
private int size;
//constructor
public MylinkedList() {}
//获取长度
public int getSize() {
return size;
}
//获取第index个数据
public String get(int index) {
Node temp=head;
for (int i = 0; i < size; i++) {
if(i==index) {
return temp.getData();
}else {
temp=temp.getAddress();
}
}
return null;
}
//添加元素
public void add(String str) {
//先创建一个新节点
Node newNode=new Node(str,null);
if(head==null) {
head=newNode;
size++;
}else {
Node temp=head;
for (int i = 0; i < size; i++) {
if(temp.getAddress()==null) {
temp.setAddress(newNode);
}else {
temp=temp.getAddress();
}
}
size++;
}
}
}
//节点类,模拟单向链表,存储数据和地址
class Node{
private String data;
private Node address;
public Node() { }
public Node(String data, Node address) {
super();
this.data = data;
this.address = address;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node getAddress() {
return address;
}
public void setAddress(Node address) {
this.address = address;
}
}
7、 Set 接口
无序的 不可重复
放入数据的顺序和内部真实存储的顺序不一致,内部有自己的存储顺序,一旦确定了存储顺序不会发生改变
Set set=new HashSet();
set.add(1);
set.add(true);
set.add("qwer");
System.out.println(set);
//运行结果[1, qwer, true]
8、HashSet
底层:哈希表结构(数组+链表+红黑树)
优点:查询,添加,删除,修改效率高
缺点:无序
注意:
如果两个对象的hashcode值不相同,两个对象肯定不相同,如果值相同,可能不是相同对象,可以是相同对象
HashSet<Person> hs=new HashSet<Person>();
hs.add(new Person(1,"张三",10));
hs.add(new Person(3,"赵四",22));
hs.add(new Person(3,"赵四",22));
System.out.println(hs);
//结果:
//[Person [id=3, name=二锅头, age=18],
//Person [id=3, name=赵四, age=22],
// Person [id=3, name=赵四, age=22]]
对对象类型数据进行去重:要重写hashCode和equals方法
先比较hashCode,如果值不同,不会调用equals方法,如果值相同才会调用equals方法
//重写hashCode和equals方法后运行结果:
//[Person [id=3, name=二锅头, age=18],
// Person [id=3, name=赵四, age=22]]
9、TreeSet
底层:红黑树
优点:升序排序
存放具有可比性的引用类型数据
TreeSet<Integer> ts=new TreeSet<Integer>();
ts.add(1);
ts.add(2);
ts.add(3);
System.out.println(ts);
TreeSet要求加入的所有元素都可以相互比较大小;可以控制比较位置来决定排序方向;hashset只能比较可相等不能比较大小
可以通过元素本身的类实现Comparable来自我解决
@Override
public int compareTo(Object o) {
if(this.id==((Person)o).getId()) {
return 0;
}else if (this.id>((Person)o).getId()) {
return -1;
}else {
return 1;
}
}
重写之后可以使用自定义对象Person
TreeSet<Person> tsp=new TreeSet<Person>();
tsp.add(new Person(1,"张三",10));
tsp.add(new Person(3,"赵四",22));
tsp.add(new Person(3,"赵四",22));
System.out.println(tsp);
三、Map
1、Map
实现Map接口的类用来存储键(key)-值(value) 对。
Map类中存储的键-值对通过键来标识,所以键值不能重复。
键值对:
存储的数据都是key,value键值对形式的,二者之间为映射关系
key 可以任意数据类型 无序的,唯一的 -->set结合
value 可以任意数据类型 无序的 ,不唯一的 -->Collection结合
一个key只能对应一个value(value可以为集合,集合中存储多个数据)
使用:
Map<String, Integer> map=new HashMap();
//添加元素 map.put("胡歌", 30);
map.put("胡歌", 28);//重复元素会覆盖,因为是按键值判断
map.put("刘德华", 50);
System.out.println(map);
//V get(Object key)
System.out.println(map.get("胡歌"));
//boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。
//boolean containsValue(Object value)
System.out.println(map.containsKey("胡歌"));
//remove(key) System.out.println(map.remove("胡歌"));
运行结果
{刘德华=50, 胡歌=28} 28 true 28
2、HashMap
HashSet是由HashMap维护的,但是HashMap是键值对的形式,初始容量是16,加载因子是0.75
底层是hash表的结构
HashMap的key如果是引用数据类型的对象,做去重要重写hashCode和equals
如果想要实现value去重,需要手动判断
HashMap<Person, Integer> hashmap=new HashMap();
hashmap.put(new Person(1,"赵",20),01);
hashmap.put(new Person(2,"钱",22),3); System.out.println(hashmap);
3、TreeMap
TreeSet是由TreeMap的key维护的,使用方式相同,但是是键值对的形式
//创建TreeMap对象 TreeMap<Person,Integer> tm1=new TreeMap();
//或调用有参构造器,传入比较器 TreeMap<Person,Integer> tm2=new TreeMap((o1,o2)->(((Person)o1).getAge()-((Person)o2).getAge()); tm1.put(new Person(1,"赵",20),01); tm2.put(new Person(2,"钱",22),3);
4、Properties
HashTable的子类,key和value都是string
Properties pp=new Properties(); // void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。 pp.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties01")); System.out.println(pp.stringPropertyNames());
四、注意点:
1、继承关系:Collection,Set,List,Map都是接口,不能实例化,使用其实现类创建对象
2、ConcurrentModificationException 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
网友评论