在整个累计里面一共有以下几个核心接口:
Collection\List\Set
Map
Iterator\Enumeration
类集就是Java数据结构的实现,类集就是动态对象数组
Collection接口以及常用操作定义
Collection是整个类集之中,单值保存的最大父接口。即:每一次可以向集合里面保存一个对象
public interface Collection<E>
extends Iterable<E>
常用操作:
boolean add(E e);//向集合中保存数据
boolean addAll(Collection<? extends E> c)
//追加一个集合
void clear();//清空集合,根元素为null
boolean isEmpty();//判断是否是空集合,不是null
boolean remove(Object o);//删除对象
boolean contains(Object o)//判断是否有指定内容,需要equals支持
int size();
Object[] toArray();
<T> T[] toArray(T[] a);
Iterator<E> iterator();//为Iterator接口实现准备的
在所有的开发之中add和iterator的使用几率是最高的,但是其他的方法也要清楚
(向购物车中添加和取出物品)contains和remove必须有equals支持
现在已经知道Collection接口的方法,现在就应该使用子类为这个接口实例化并且使用。但是由于现在的开发由于要求的严格性不会再直接使用Collection接口。而都会去使用它的两个子接口Set和List。
小Tip:
最早java刚推出类集框架的时候,使用的就是Collection接口,最大的使用环境就是用在EJB上。但是现在已经不使用,EJB是Java很好的理论支持,只是实现不是很好呢。于是在Java的一个开源项目上——PetShop。由于此项目是Java爱好者开发的 ,没有考虑过多的性能问题和数据库的设计,那么就导致整个程序的技术是很牛的但是性能是很差的,此时正赶上微软推出.net平台。微软使用.net重新设计并开发了PetShop,对外宣称比Java好(实际上和Java没啥区别)此时Java重写了PetShop,但是由于此时微软的宣传已经进行了,所以基本上就成了性能上的差别,但是实际上不存在。
因为代码的规范性已经产生,所以从PetShop开始就不再使用模糊不清的Collection接口了,而都使用List、Set子接口进行开发。
- List(允许重复)/Set(不允许重复)
- Collection接口几乎不会再使用了,所有方法都要记住
LIst子接口的使用
- 使用List子接口验证Collection接口中所提供的操作方法
- 掌握List子接口的操作特点以及常用子类(ArrayList/Vector)
- List 子接口是最为常用的一个子接口,但是这个接口对Collection接口进行扩充。在List子接口中重点方法:
public interface List<E>
extends Collection<E>
LIst本身是一个接口,所以如果想要使用此接口进行操作,就必须存在有子类。可以使用ArrayLIst子类实现操作,还有Vector类,90%的情况下使用ArrayList
新的子类ArrayList
是LIst接口最常使用的子类
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("hello");
list.add("world");
//可以使用get方法和size方法配合进行集合遍历
//但是注意这里是List接口才有get方法
//如果换成Collection接口则无法实现
for(int i =0;i<list.size();i++)
System.out.println(list.get(i));
Collection<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("hello");
list1.add("world");
//也可以实现输出,但是不可以用get方法
Object[] obj = list1.toArray();
for(int i=0;i<obj.length;i++)
System.out.println(obj[i]);
}
Collection接口与List接口相比,功能会显得有所不足,而且以上所讲解的输出方式并不是常用的输出结构,只是一个基础的展示。
ArrayList和Vector
ArrayList是非线程安全的 ,Vector是线程安全的
ArrayList遍历:Iterator、listIterator、foreach
Vector遍历:Iterator、listIterator、foreach、Enumberation
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
Set接口
Set接口没有对Collection接口实现大量的扩充,而是简单继承了Collection接口,所以也不能使用get方法
Set接口下有两个常用子类:HashSet和TreeSet
- TreeSet类
TreeSet类主要是依靠Comparable的返回值来进行比较的,集合就是一个动态的对象数组,如果想为一组对象进行排序,在Java里必须要用比较器Comparable完成比较。
如果compareTo()方法返回的是0就认为是同样的数据,如果不会被保存,所以这个方法里面需要将这个类的所有属性都一起参与到比较之中。 - 关于重复元素的说明
Comparable接口只能负责TreeSet子类进行重复元素的判断,它并不是真正的重复元素判断操作,因为只有在实现排序的时候才会在某种意义上实现重复元素的判断操作。如果想要判断重复元素只能够依靠Object类中实现的方法:
- 取得hashcode
public int hashCode();
- 先判断对象的hashcode是否相同
- 对象比较
public boolean equals(Object obj);
- 在将对象的属性进行依次比较
hashcode和equals可以自动生成,不用自己写
⚠️以后在非排序的情况下,重复元素都是依靠hashcode和equals
Tips:
- 在开发之中Set接口绝对不是首选,如果真要使用也建议使用Hashset子类
- Comparable这种比较器绝大部分情况下只会存在于Java理论范畴内,例如要进行TreeSet排序,大部分企业开发很少考虑到这个类
- Set不管如何操作必须保证数据不能 重复
集合输出操作
Collection、LIst、Set三个接口里面只有List接口是最方便的输出
- 集合在JDK1.8之前支持四种输出:Iterator(95%)、LIstIterator(0.05%)、Enumberation(4.9%)、foreach(0.05%)
- 迭代输出:Iterator(核心)
如果遇见集合操作,那么一般都会使用Iterator接口进行集合的输出操作
public interface Iterator<E>
一般default方法都可以忽略先不看!!!
Iterator本身是一个接口,如果想要取得本接口的实例化只能够依靠Collection接口的一个操作方法:public Iterator<E> iterator();
范例:使用Iterator接口输出集合
public static void main(String[] args) {
var all = new HashSet<String>();
all.add("hello");
all.add("world");
all.add("you");
var it = all.iterator();
while (it.hasNext())
{
String str = it.next();
System.out.println(str);
}
}
可是有个问题iterator只能由前向后输出
双向迭代:ListIterator
Iterator只能实现从前向后的输出,但是希望可以反向
Collection接口没有为其提供实现方法
ListIterator在List中提供接口实现
public static void main(String[] args) {
var all = new ArrayList<String>();
all.add("hello");
all.add("world");
all.add("you");
var it = all.listIterator();
System.out.println("end to begin:");
while(it.hasPrevious())
{
String str = it.previous();
System.out.println(str);
}
System.out.println("begin to end");
while (it.hasNext())
{
String str = it.next();
System.out.println(str);
}
如果想要实现从后向前的输出,一定要发生从前向后的输出
很容易理解因为一开始第一个元素之前并没有元素所以没办法输出,所以这个其实也不是有太大的用处
foreach输出
理论上foreach输出是很方便使用的,但是现在过多的使用foreach不利于理解程序。foreach本身可以方便的输出数组,但是这种方法不怎么适用于现在的情况。
Enumberation接口
是一起于vector一起出现在jdk1.0中推出的输出接口,最早的vector要想输出就需要使用这个接口。
public interface Enumeration<E>
但是如果要想取得Enumberation接口的实例化对象只能使用Vector子类
在Vector子类中定义有如果下方法:
取得Enumberation接口对象:
虽然集合的输出有四种形式,但是以Iterator和Enumberation接口为准
Map接口
如果要保存一对关联数据(key=value)的时候如果使用Collection就不能够直接满足于我们的要求可以使用Map接口实现此类数据的保存,并且根据Map接口还提供有根据Key查找value的功能。
V put(K key,V value);
V get(Object key);
Set<Map.Entry<K,V>> entrySet();
//将map集合转化为set集合
Set<K> keySet();
//取出全部的key为一个Set集合,key不能重复
在Map接口下有两个常用子类:HashMap、Hashtable(但是实际上关注Map接口的方法,因为最后也得转型)
Map和Collection的区别
Map存储数据的目的实际上就是为了信息查找,但是Collection存放数据的目的是为了输出
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
System.out.println(map);
//使用hashmap定义的Map集合是无序的(顺序无用)
//如果发现了重复的key会进行覆盖,使用新内容替换旧内容
//在Map接口中有get方法主要是根据key去找value
var set = map.keySet();
var iter = set.iterator();
while(iter.hasNext())
System.out.println(iter.next());
}
在Map接口下还有一个Hashtable的子类,此类是在JDK1.0的时候提供的,属于JDK1.2的时候让其多实现了一个Map接口,从而保存下来继续使用。
HashMap采用异步处理,非线程安全,设置null:允许key或value为null
HashTable采用同步处理,线程安全,设置null:不允许
而在实际使用之中,遇见Map接口一般都用HashMap
关于Iterator输出的问题
- 只要是集合的输出那么一定要使用Iterator完成,但是在整个Map接口中没有返回Iterator接口对象的方法,所以要想使用Iterator输出Map集合,首先需要针对Map集合和Collection集合输出数据的特点进行分析后才能实现。
- 当向Map集合里面保存数据的时候实际上所有的数据都会被自动封装为Map.Entry接口对象(内部接口)
public static interface Map.Entry<K,V>
在这个接口里面定义了两个操作:
在Map接口里面有一个将Map集合转化为Set集合的方法:
Set<Map.Entry<K,V>> entrySet();
这样有了这个集合,就可以调用Iterator了
Map接口实现iterator输出
1. 利用Map接口中的entrySet()方法将Map集合变为Set集合,里面的泛型是Map.Entry
2. 利用Set集合中的iterator()方法将Set集合进行iterator输出
3.Iterator循环取出的都是Map.Entry接口对象,利用此对象进行key与value的取出
使用Iterator进行Map输出的标准结构
public static void main(String[] args) {
Map<String,Integer> map = new Hashtable<>();
map.put("one",1);
map.put("two",2);
map.put("three",3);
//将Map集合变为Set集合,目的是为了使用iterator方法
Set<Map.Entry<String, Integer>> set = map.entrySet();
Iterator<Map.Entry<String, Integer>> iter = set.iterator();
while(iter.hasNext()){
Map.Entry<String, Integer> me = iter.next();
System.out.println(me.getKey()+"="+me.getValue());
}
}
⚠️一定要掌握步骤,并且熟练掌握
关于Map集合中Key的说明
- 在使用map接口的时候发现几乎可以使用任何 的类型来作为key或value的实例,也可以使用自定义的类型,那么这个作为key的自定义的类必须要覆写Object类中的hashCode()与equals()方法,因为只有依靠这两个方法才能判断类是否重复。否则会出现错误。
- 在以后使用Map的时候key的首选类型是String,尽量不要去使用自定义的类型作为key(因为String已经准备好了hashCode和equals)
summary:
- Map集合保存数据的目的是为了查询使用,而Collection保存数据的目的是为了输出
- Map使用Iterator接口输出的步骤以及具体实现代码
- HashMap可以保存null,key重复会出现覆盖
Stack类
Stack是Vector类的子类
public class Stack<E>
extends Vector<E>
但是需要注意的是,虽然Stack是Vector子类,但是不使用Vector类的方法:
栈的这种操作现在唯一还算是有点能够编程的应用,就在Android上。
Properties子类
国际化程序:同一个程序根据不同的语言选择资源文件,所有的资源文件后缀必须是“*.properties"
Properties类的操作特点:是Hashtable的子类,主要是进行属性的操作,属性的最大特点是利用字符串设置key和value。首先观察Properties类的定义结构:
public class Properties
extends Hashtable<Object,Object>
在使用Properties类的时候不需要设置泛型类型,因为从它一开始出现就是只能够保存String。在Properties类中主要使用如下方法:
//设置属性
public Object setProperty(String key,String value);
//取得属性,第一种如果不存在返回null,第二种如果不存在返回默认值
public String getProperty(String key);
public String getProperty(String key,String defaultValue);
Collections工具类
Properties pro = new Properties();
pro.setProperty("beijing","capital");
pro.setProperty("tianjin","next");
System.out.println(pro.get("beijing"));
System.out.println(pro.getProperty("guangzhou","dream"));
//没有返回null
在properties类里面提供有数据输出操作:
public void store(OutputStream out, String comments)throws IOException
try {
pro.store(new FileOutputStream("/users/hong/hongs/test.properties"),"this is an international file");
} catch (IOException e) {
e.printStackTrace();
}
//一般后缀可以随意设置,但是标准来讲,既然是属性文件,后缀就必须是.properties,为了国际化
//后面的注释可以随便写,但是必须是英文
public void load(InputStream inStream)throws IOException
//读数据
对于属性文件(资源文件),除了可以使用Properties类读取之外,也可以使用SourceBundle类来读取,这也是将属性的属性文件统一设置为.properties的原因
tips:
- 资源文件的特点:
key=value;
key=value; - 资源文件中的数据一定都是字符串
Collections工具类
了解Collections类的基本功能
在Java提供类库的时候考虑到用户的使用方便,专门设置了一个集合的工具类,可以实现list,set,map的结合操作
public class Collections
extends Object
- 为集合追加数据
public static void main(String[] args) {
var list = new ArrayList<String>();
Collections.addAll(list,"alice","in","wonderland");
System.out.println(list);
//可以把平常多行add追加变成一行addAll
Collections.reverse(list);
System.out.println(list);
}
⚠️解释Collection与Collections的区别
Collection是集合操作的接口,Collections是集合操作的工具类,可以进行List、Set、Map集合的操作。
这个类不会使用到,但是作为知识点清楚有这么一个类就够了