JavaSE(八)集合
前言
集合任何时候存储的都是引用,在java.util.*下,Iterable有一个返回迭代器的方法 Iterator Iterator() ;子类可使用
提示:以下是本篇文章正文内容,下面案例可供参考
一、Collection(interface)(单例集合)
父接口为Iterable,放入Collection中的元素建议重写equals()方法
继承图:
Collection常用方法:
Collection c = new ArrayList();
c.add(3); // 实际上是添加了 new Integer(1200)
c.add(true);
System.out.println(c.size()); //获取元素个数
c.clear(); //清空元素
c.add("hello");
c.add("tian");
c.contains("tian") //底层调用"tian"的equals()方法
c.remove("hello"); //删除单个元素,底层调用“hello” 的equals()方法
c.isEmpty() //判断是否为空,size()是否为零
System.out.println(Arrays.asList(c.toArray())); //转数组
1. Iterator
迭代器方法:
boolean hasNext() 如果仍有元素可以迭代,则返回true
Object next() 指针向后移一位,然后返回该元素
void remove() 从collection中移除迭代器中返回的最后一个元素
迭代器方法理解图示:
迭代器使用:
Collection c = new ArrayList();
c.add("abc");
c.add("def");
c.add(100);
c.add(true);
Iterator it = c.iterator(); //获取迭代器对象
while(it.hasNext()){
System.out.println(it.next()); //abc def 100 true
}
在使用迭代器迭代元素的过程中,不使用迭代器的方法删除元素,或其他方式使Collection结构发生改变时,需要重新获取迭代器
2.List(interface)
有序(存取顺序不变,因为有下标)可重复
特有常用方法:
c.add(1,"ds"); //特定位置插入元素
System.out.println(c.get(1)); //获取特定位置元素
c.set(1,"hao"); //修改特定位置元素
c.remove(1); //删除特定位置元素
System.out.println(c.indexOf("def")); //放回"def" 在集合中第一次出现处的索引
Iterator it = c.iterator(); //获取迭代器对象
(1)ArrayList
底层采用数组结构,初始化容量是0(在添加第一个元素时,才为10),每次扩容是原容量的1.5倍,非线程安全
创建:
ArrayList arrayList1 = new ArrayList();
ArrayList arrayList2 = new ArrayList(30);
Collection c = new HashSet();
c.add(100);
c.add(230);
ArrayList arrayList3 = new ArrayList(c); //可将HashSet转换成ArrayList
System.out.println(Arrays.asList(arrayList3.toArray())); // [100, 230]
(2)LinkedList
双向链表结构,查询效率较低,增删效率较高
(3)Vector(使用较少)
底层采用数组结构,初始化容量10,扩容为2倍,线程安全
3.Set(interface)
无序(因为没有下标)不可重复
(1)HashSet
底层为一个HashMap集合,HashMap集合是一个哈希表结构,放入的值存在与HashMap的key部分,value部分为PRESENT
示例:
HashSet<String> hashSet = new HashSet<>();
hashSet.add("String1");
hashSet.add("String2");
hashSet.add("String3");
hashSet.add("String4");
hashSet.add("String3");
hashSet.add("String3");
for (String str: hashSet) {
System.out.println(str);
}
(2)SotedSet(interface)
①TreeSet
底层为treeMap,treeMap集合是一个二叉树结构,放入的值存在与HashMap的key部分,value部分为PRESENT
实现自定义的比较功能需要在创建TreeSet时传入一个comparator(实现Comparator接口)比较器,存入的对象类实现Comparable接口重写comparaTo()方法
继承Comparable:
public class Test{
public static void main(String[] args) throws Exception{
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student(10));
treeSet.add(new Student(80));
treeSet.add(new Student(30));
treeSet.add(new Student(40));
for(Student s: treeSet){
System.out.println(s);
//结果:
//Student{age=10}
//Student{age=30}
//Student{age=40}
//Student{age=80}
}
}
}
class Student implements Comparable{
int age;
public Student(int age) {
this.age = age;
}
@Override
public int compareTo(Object o) {
return this.age - ((Student)o).age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
传比较器:
public class Test{
public static void main(String[] args) throws Exception{
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
});
treeSet.add(new Student(10));
treeSet.add(new Student(80));
treeSet.add(new Student(30));
treeSet.add(new Student(40));
for(Student s: treeSet){
System.out.println(s);
//结果:
//Student{age=10}
//Student{age=30}
//Student{age=40}
//Student{age=80}
}
}
}
class Student{
int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
建议:比较规则不会发生改变时,实现Comparable接口,比较规则切换频繁时,使用Comparator接口
3.Collections(集合工具类)
二、Map(双列集合)
key与value都是存储Java对象的内存地址
继承图:
Map接口常用方法:
Map map = new HashMap();
map.put("key1","value1"); //添加元素
System.out.println(map.get("key1")); //获取元素 value1
map.clear(); //清空元素
System.out.println(map.isEmpty()); //判断受否为空 true
System.out.println(map.containsKey("key1")); //判断受否包括特定key值 false
map.put("key2","value2");
System.out.println(map.containsValue("value2")); //判断受否包括特定value值 true
map.put("key3","value3");
System.out.println(map.keySet()); //返回所有key值组成的Set [key2, key3]
map.remove("key2"); //删除元素
System.out.println(map.size()); //获取元素个数 1
System.out.println(map.values()); //返回所有value值组成的Set [value3]
map.put("key4","value4");
System.out.println(map.entrySet()); //获取key=value组成的Set [key3=value3, key4=value4]
遍历:
Map<String,String> map = new HashMap();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
map.put("key4","value4");
for(String str: map.keySet()){
System.out.println(map.get(str));
}
System.out.println("****************************");
Iterator it = map.keySet().iterator();
while(it.hasNext()){
System.out.println(map.get(it.next()));
}
System.out.println("****************************");
Set<Map.Entry<String,String>> set = map.entrySet();
Iterator<Map.Entry<String,String>> iterator = set.iterator();
while(iterator.hasNext()){
Map.Entry<String,String> node = iterator.next();
System.out.println(node.getKey() + "=>" + node.getValue());
}
System.out.println("****************************");
for(Map.Entry<String,String> node: map.entrySet()){
System.out.println(node.getKey() + "=>" + node.getValue());
}
Node 是一个Map接口的内部接口Map.Entry的实现类,可以通过getKey(),getValue()获取键,值
源码:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; //key的hashcode()方法的值,可以转换存储成数组的下标
final K key;
V value;
Node<K,V> next; //下一个Node的地址
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
1.HashMap
底层哈希表(每一个元素都是一个单向链表的一维数组),非线程安全
初始化容量为16,最好是2的倍数(有利提高效率),默认加载因子0.75,jdk8之后,单项链表中元素超过8个,会变换成红黑树数据结构,红黑数上的个数少于6个时,会变回单向链表
key值可以为null
2.HashTable(用得较少)
底层哈希表,初始化容量11,默认加载因子0.75,扩容后=原容量*2+1,线程安全
key与value都不可为null
(1)Properties(重要)
线程安全,且key与value必须是String类型,称为属性类
使用:
Properties properties = new Properties();
properties.setProperty("url","jdbc:mysql://localhost:3306/bjpowernode");
properties.setProperty("driver","com.mysql.jdbc.Driver");
properties.setProperty("username","root");
properties.setProperty("password","123456");
System.out.println(properties.getProperty("username"));
(2)资源绑定器
//资源绑定器,自能绑定xxx.properties文件,且这个文件必须在类路径下,写路径时省略后缀
ResourceBundle bundle = ResourceBundle.getBundle("classinfo");
String className = bundle.getString("className");
System.out.println(className);
System.out.println(Class.forName(className).newInstance());
(3)使用绝对路径加载Properties
Thread.currentThread() 当前线程对象
getContextClassLoader() 是线程对象的方法,获取当前线程的类加载器对象
getResource() 类加载器的方法,当前线程的类加载器默认从类的根路径下加载资源
String path = Thread.currentThread().getContextClassLoader()
.getResource("./classinfo.properties").toURI().getPath();
//加一个toURI可解决路径中文乱码
FileReader reader = new FileReader(path);
/*InputStream reader = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("./classinfo.properties"); */ //直接返回流对象
//当前类.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(reader);
reader.close();
String className = properties.getProperty("className");
3.SortedMap(interface)
集合key部分的元素会自动排序
(1)TreeMap
4.put()与get()的实现原理
(1)put()
(2)get()
强烈建议:放入的对象需要重写hashCode(),equals()方法,直接IDEA生成
三、泛型
就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时确定,也称参数化类型,若使用时没有指明类的泛型,则认为此泛型类型为Object类型
规定集合中的存放的数据类型,迭代器返回的值不在是Object类型,而是泛型
通配符 ?使用 有限制条件的通配符 ?extends Person ?super Person
@Test
public void test(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
}
自定义泛型:
ArrayList<String> arrayList = new ArrayList<>();
//自定义泛型
//泛型类
class MyIterato<T>{
public T get(){
return null;
}
}
//泛型方法
public <E> List cf(E[] arr){
ArrayList<E> list = new ArrayList<>();
return list;
}
四、forEach
缺点,无法取到下标
示例:
int[] arr = {1,43,3,453,45};
for(int a: arr){
System.out.println(a);
}
注意:回到页首