- 集合
集合和数组很类似,都是容器可以存放多个数据。但是数组有一个致命的弱点,数组长度固定不能动态增加。所以jdk就有创建了另外一种可以动态的随意增加长度的容器,叫做集合 - 集合的分类(不同的集合之间,存放在它们里面的数据的类型特点不一致)
Collection集合:又分为了List集合和Set集合
Map集合:
- List集合
容器:存储数据 基本功能:增删改查 增加: boolean add(E e) 将指定的元素追加到此列表的末尾(可选操作)。 id add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。 boolean addAll(Collection<? extends E> c) 按指定集合的迭代器(可选操作)返回的顺序将指定集合中的所有元素附加到此列表的末尾。 boolean addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。 删除: void clear() 从此列表中删除所有元素(可选操作)。 void remove(int index) 删除该列表中指定位置的元素(可选操作)。 boolean remove(Object o) 从列表中删除指定元素的第一个出现(如果存在)(可选操作) boolean removeAll(Collection<?> c) 从此列表中删除包含在指定集合中的所有元素(可选操作)。 修改: E set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。 查询: E get(int index) 返回此列表中指定位置的元素。 Iterator<E> iterator() 以正确的顺序返回该列表中的元素的迭代器。 Iterator迭代器对象 hasNext():可以通过它判断 集合里面是否还有下一个元素 next():获取下一个元素 ListIterator<E> listIterator() 返回列表中的列表迭代器(按适当的顺序)。 正向迭代: ListIterator lit =list.listIterator(); while(lit.hasNext()){ System.out.println(lit.next()); } 反向迭代: while(lit.hasPrevious()){ System.out.println(lit.previous()); } 注意:使用反向迭代,先要正向迭代一次。 ListIterator<E> listIterator(int index) 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。 判断: boolean contains(Object o) 如果此列表包含指定的元素,则返回 true 。
常用子类:
ArrayList:底层是数组结构,默认长度是10,当我们存储的数据超过了10个之后,它会自动的增加原来的一半也是自动增加5个长度
LinkedList:底层是链表结构,无下标排序。
例子: 模拟堆栈和队列的特点
堆栈:先进后出 (如同水杯)
队列:先进先出 (如同水管)
Vector :底层是数组结构,默认长度是10,超过默认长度自增10个。它和list相比是线程安全。这个是jdk1.2就有的原始元素,以及被ArrayList淘汰代码实例
package com.ly.listapi; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * 使用ArrayList测试List的api */ public class ListApi { public static void main(String[] args) { //创建一个集合 List list =new ArrayList(); List list2 =new ArrayList(); String str="hi update"; list2.add(1); list2.add(2); //添加元素 list.add("张三"); list.add(true); list.add(10); list.add(0.001f); list.add("1234444"); //制定的下标添加 list.add(2,"hi"); //在制定的下标插入一个集合 list.addAll(3,list2); // System.out.println(list2.size()); //删除集合中所有的元素 /* list2.clear();*/ // System.out.println(list2.size()); System.out.println("----------------------"); list.remove(0); list.remove(true); list.removeAll(list2); //修改元素 list.set(0,"hi update"); //包含 // System.out.println(list.contains(str)); /** * 遍历集合 (4种) */ /*for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); }*/ /* for(Object obj:list){ System.out.println(obj); }*/ /*** * 集合特有的迭代方式 迭代器 */ /* Iterator it =list.iterator(); while(it.hasNext()){ System.out.println(it.next()); }*/ /*** * 正向迭代 */ ListIterator lit =list.listIterator(); while(lit.hasNext()){ System.out.println(lit.next()); }/**/ /*** * 反向迭代 */ /* ListIterator lit =list.listIterator();*/ while(lit.hasPrevious()){ System.out.println(lit.previous()); } // System.out.println(list.size()); } }
package com.ly.linkedListDemo; import java.util.LinkedList; import java.util.List; /*** * 使用linkedList 完成堆栈和队列的效果 * removeFirst() 从此列表中删除并返回第一个元素。 removeLast() 从此列表中删除并返回最后一个元素。 */ public class LinkedListDemo { public static void main(String[] args) { LinkedList list =new LinkedList(); list.add(111); list.add("222"); list.add(true); /* while(!list.isEmpty()){ System.out.println(list.removeLast()); }*/ while(!list.isEmpty()){ System.out.println(list.removeFirst()); } } }
- ArrayList去重(其类一致的时候会将值进行比较【个人理解,里面存储的数据类型不一样,例如Person类,遇上相同的数据类型会调用本类(例如同样是Person就调用Person)中的equals方法,但像Person这样不具备比较性的则要继承Comparable类来实现重写equal方法】
依据equal方法(正常情况是使用hash值),则此时我们需要重写equal方法
public class ArrayListDemo { public static void main(String[] args) { ArrayList list =new ArrayList(); Person p=new Person(); p.setAge(19); p.setUsername("aaaa"); p.setPassword("aaaa"); list.add(p); Person p1=new Person(); p1.setAge(19); p1.setUsername("aaa1"); p1.setPassword("aaaa"); list.add(p1); ArrayList newList= replaceList(list); for(int i=0;i<newList.size();i++){ Person pi= (Person)newList.get(i); System.out.println(pi.getUsername()); } }
private static ArrayList replaceList(ArrayList list) { ArrayList newlist =new ArrayList(); Iterator it =list.iterator(); while(it.hasNext()){ Object obj =it.next(); if(!newlist.contains(obj)){ newlist.add(obj); } } return newlist; } }
package com.ly.po; /*** * 用户对象 */ public class Person implements Comparable{ private String username; private String password; private int age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { return 0; } public Person() { } public Person(String username, String password, int age) { this.username = username; this.password = password; this.age = age; } @Override public boolean equals(Object obj) { if(obj instanceof Person){ return this.username.equals(((Person) obj).getUsername()) && this.age==((Person) obj).getAge() && this.password.equals(((Person) obj).getPassword()); }else{ return false; } } //p.compareTo(p1){} @Override public int compareTo(Object o) { if(o instanceof Person){ Person p =(Person) o; return (this.getUsername().hashCode()-p.getUsername().hashCode()) -(this.age-p.age) -(this.getPassword().hashCode()-p.getPassword().hashCode()); } return -1; } }
这个的思路是:新建一个集合,迭代list,建立一个Object对象,使其通过if(!newlist.contains(obj))方法来实现判断【这里contains()方法会引用equals方法(所以需要重写equals方法),此时会将集合里的数据调用equal方法去比较obj】如果不包含则add()加入,包含则不添加
- List有序,元素可重复,集合有索引 || Set无序,元素不可重复,集合无索引
- Set的共性方法与List差不多
1.HashSet底层是哈希表(由哈希值(有16位进制组成的数)组成的表),在Java中每个元素都有一个HashCode方法,方法返回所在的物理内存地址(一般情况下每个数的hash值不同)
(输出对象(例如Person p)输出p(如果没有toString方法,则输出物理内存地)) - HashSet无顺序,不允许重复
HashSet存自定义对象去重思路:比较重复是根据hashcode值来比较,如果一样就使用equal方法再进行比较,但一般情况下hashcode的值是不相同的,所以要在自定义对象中重写hashcode方法使hashcode的值相等【public int hashcode( return 50;)】
package com.ly.com.ly.setdemo; import com.ly.po.Person; import java.util.HashSet; import java.util.Iterator; /*** * 测试hashset */ public class HashSetDemo { public static void main(String[] args) { HashSet set =new HashSet(); set.add("java 01"); set.add("java 02"); set.add("java 03"); set.add("java 04"); set.add("java 01"); set.add("java 03"); Iterator it =set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } Person p=new Person(); p.setUsername("zhangsan"); p.setPassword("123456"); p.setAge(19); Person p2 =new Person(); p2.setUsername("zhangsan"); p2.setPassword("123456"); p2.setAge(19); HashSet pset =new HashSet(); pset.add(p); pset.add(p2); Iterator it1 =pset.iterator(); while(it1.hasNext()){ System.out.println(it1.next()); } } }
- TreeSet 有序无下标,以二叉树来比较,底层是二分叉树,有自己的排序规则,存放元素必须具备比较性(八大元素和String都实现了Comparable)
要是自定义对象具备比较性,实现Comparable接口,实现comparableTo方法来进行比较【public int comparableTo(Object o){。。。}】
package com.ly.com.ly.treesetdemo; import com.ly.com.ly.comable.MyComparator; import com.ly.po.Person; import java.util.Iterator; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { /* TreeSet tset =new TreeSet();*/ // tset.add(true); // tset.add(false); // tset.add("java 03"); // tset.add("java 04"); // tset.add("java 01"); // Iterator it =tset.iterator(); // while(it.hasNext()){ // System.out.println(it.next()); // } TreeSet tset =new TreeSet(new MyComparator()); Person p =new Person("211","1111",22); Person p1 =new Person("222","2222",30); Person p2 =new Person("123","2222",30); tset.add(p); tset.add(p1); //p和p1已经比较完了 p p1 p1 p tset.add(p2); Iterator it =tset.iterator(); while(it.hasNext()){ Person obj =(Person)it.next(); System.out.println(obj.getUsername()); } } }
package com.ly.com.ly.comable; import com.ly.po.Person; import java.util.Comparator; public class MyComparator implements Comparator{ @Override public int compare(Object o1, Object o2) { if(o1 instanceof Person && o2 instanceof Person){ return (((Person) o1).getUsername().hashCode()+((Person) o1).getPassword().hashCode()+((Person) o1).getAge()) - (((Person) o2).getUsername().hashCode()+((Person) o2).getPassword().hashCode()+((Person) o2).getAge()); } return 0; }
/**
* 实现Comparable 接口
* 然后实现compareTo方法
* @param o
* @return
*/
public int compareTo(Object o) {
if (o instanceof User) {
User user = (User) o;
//比较两个对象的age 返回的是它们的减法值,如果this.age>user.age返回正数,反之返回负数,相等返回0
return this.age-user.age;
// System.out.println("this:"+(this.name.hashCode()+this.age));
// System.out.println("user:"+(user.name.hashCode()+user.age));
// System.out.println("compare:"+((this.name.hashCode()+this.age)-(user.name.hashCode()+user.age)));
// return (this.name.hashCode()+this.age)-(user.name.hashCode()+user.age);
}else{
throw new RuntimeException("不是用户类");
}
} },思路:TreeSet在add()对象时会自动将对象排序,但需要有可比较性,如自定义类就需要实现comparable类,实现comparableTo方法才可以进行比较
- TreeSet可以自传比较器(其本身自带二叉树比较)
除了上面那种实现接口比较以外,还有一种比较方式: /** * 新建一个比较器对象 * @author Administrator * */ public class MyCompare implements Comparator{ /** * 编写具体的比较规则 */ public int compare(Object o1, Object o2) { if(o1 instanceof User && o2 instanceof User){ User user1 =(User)o1; User user2 =(User)o2; return user1.getAge()-user2.getAge(); }else{ throw new RuntimeException("要比较的类型不一致无法比较"); } } } public static void main(String[] args) { TreeSet set1 =new TreeSet(new MyCompare()); set1.add(new User("java01",11)); set1.add(new User("java02",12)); set1.add(new User("java01",11)); set1.add(new User("java03",13)); Iterator it1 =set1.iterator(); while(it1.hasNext()){ System.out.println(it1.next()); }
当自定义(就是自己重写的equals方法)和比较器(自己写的)都存在时,以比较器为主
- HashSet和TreeSet的区别
HashSet 底层是哈希表,没有顺序,不允许重复
TreeSet 底层是二叉树结构,有顺序 ,不允许重复
但它们都是存储数据的容器 - 泛型 由于集合数据类型不同,迭代大多需要强行转型(由大转小可能导致数据丢失),所以泛型应此而生了
泛型:因为集合可以存储任意对象的元素,所以在开发过程中无法保证集合内元素的一致性,在早期的遍历过程中,
需要我们不断的去把Object 转换成我们所需要的对象的类型,来过滤掉其他数据类型,遍历出来。时间长了程序员就觉得这样很麻烦,
于是就有了泛型。泛型提供了更好的解决方案:类型参数。例如,ArrayList类用一个类型参数来指出元素的类型。 泛型是Java 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java泛型被引入的好处是安全简单。 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,
而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。作用:
1.申明准确类型(申明定义准确类型,集合只能插入准确的类型)package com.ly.com.ly.genericity; import com.ly.po.Person; import java.util.ArrayList; /*** * 通过ArrayList 来说明泛型的作用 * 1.申明准确的类型 * 声明的时候就顶了准确的类型,以后集合里面只能插入定义的类型 */ public class ArrayListDemo { public static void main(String[] args) { ArrayList<Person> plist=new ArrayList<>(); plist.add(new Person("aaa","aaaa",18)); for(Person p:plist){ System.out.println(p.getUsername()+" "+p.getPassword()+" "+p.getAge()); } } }
2.定义了抽象类型(一般用来编写扩展性强的类或者是工具类)
package com.ly.com.ly.dao; import com.ly.po.stu; //T 或者E 你就可以看成是Object public class BaseDao<T>{ private T t; public void add(T t){ System.out.println(t+"添加"); } public void update(T t){ System.out.println(t+"修改"); } public void find(T t){ System.out.println(t+"查询"); } public void delete(T t){ System.out.println(t+"删除"); } }
然后接下来顺便将例子放出
package com.ly.com.ly.test; import com.ly.com.ly.dao.StuDao; import com.ly.com.ly.dao.teacherDao; import com.ly.po.stu; import com.ly.po.teacher; public class demo { public static void main(String[] args) { teacher t =new teacher("t1","男",1000); teacherDao tdao =new teacherDao(); tdao.add(t); tdao.update(t); /* tdao.addtea(t); tdao.updatetea(t); tdao.findtea(t); tdao.deletetea(t);*/ stu s =new stu("aaa","男","软件1班"); StuDao dao =new StuDao(); dao.add(s); /*dao.addStu(s); dao.updatestu(s); dao.findstu(s); dao.deletestu(s);*/ } }
package com.ly.com.ly.dao; import com.ly.po.stu; import org.junit.Test; /*** * 模拟完成stu的增删改查方法 * */ public class StuDao extends BaseDao{ /*public void addStu(stu stu){ System.out.println(stu+"添加"); } public void updatestu(stu stu){ System.out.println(stu+"修改"); } public void deletestu(stu stu){ System.out.println(stu+"删除"); } public void findstu(stu stu){ System.out.println(stu+"查询"); }*/ }
package com.ly.com.ly.dao; import com.ly.po.stu; import com.ly.po.teacher; public class teacherDao extends BaseDao{ /*public void addtea(teacher tea){ System.out.println(tea+"添加"); } public void updatetea(teacher tea){ System.out.println(tea+"修改"); } public void deletetea(teacher tea){ System.out.println(tea+"删除"); } public void findtea(teacher tea){ System.out.println(tea+"查询"); }*/ }
- Map集合
java中的map集合使用键(key)值(value)来保存数据,其中值(value)可以重复,但键(key)必须是唯一,也可以为空,但最多只能有一个key为空,
它的主要实现类有HashMap、LinkedHashMap、TreeMap。共性方法: 1.添加: put(); putAll(); 2.删除 clear();清空数据 remove();通过Key删除单个值,还可以放集合删除 3.判断 containsKey(Object key); containsValue(Object value); isEmpty(); 4.获取 get(); size(); values(); entrySet(); keySet(); map的遍历: Map<String, String> map=new HashMap<String,String>(); map.put("01", "java 01"); map.put("02", "java 02"); map.put("03", "java 03"); map.put("04", "java 04"); map.put("05", "java 05"); /** * 遍历方式1 */ //获取到map中key值的集合 Set<String> keys= map.keySet(); //遍历其中的key值的集合 Iterator<String> it=keys.iterator(); //根据key获取到value while(it.hasNext()){ String key =it.next(); String value =map.get(key); System.out.println("key:"+key+" value:"+value); } /** * 遍历方式2 */ //获取到map的关系映射放到set集合中 Set<Map.Entry<String, String>> sets =map.entrySet(); //迭代集合 Iterator<Map.Entry<String, String>> it2=sets.iterator(); while(it2.hasNext()){ //获取到集合中的每个映射关系 Map.Entry<String, String> map2 =it2.next(); //获取key和value System.out.println("key:"+map2.getKey()+" value:"+map2.getValue()); }
package com.ly.mapdemo; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /*** * 学习map的数据类型 * mapapi: * V put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作) */ public class HashMapDemo { public static void main(String[] args) { HashMap map =new HashMap(); HashMap map1 =new HashMap(); map1.put(null,"ssss"); map1.put("lll",1111); /*** * map添加 key,value * k,v */ map.put("aaa",1111); map.put("cccc",222); map.put("aaa",2222); map.putAll(map1); System.out.println(map.containsKey("sskl;sks;lsk")); System.out.println(map.containsValue("1111")); System.out.println(map.get(null)); // map1.clear(); map1.remove(null); System.out.println(map1.size()); /*** * map的数据结构比较特殊,它是存一组数据,那如果来区分存进去的每组数据和每组数据列,它是通过列名来区分 * 所以说key 的值不允许出现重复的,或者会覆盖原先的数据。 */ System.out.println(map.size()); /*** * map遍历方式1 */ /* Set keySet=map.keySet(); Iterator it =keySet.iterator(); while(it.hasNext()){ System.out.println(map.get(it.next())); }*/ /*** * 第二种遍历方式 */ Set<Map.Entry<String,Object>> set = map.entrySet(); Iterator<Map.Entry<String,Object>> it =set.iterator(); while(it.hasNext()){ Map.Entry<String,Object> obj=it.next(); System.out.println(obj.getKey()+":"+obj.getValue()); } } }
思路:上面entryset()看成是一个Set对象,Map集合名.Entry<数据类型,数据类型>是将集合看成由一个个Key和Value组成的对象
Hashtable:底层是哈希表的数据结构,不可以存入null键和null值,是线程同步的。jdk1.0效率低
HashMap:底层也是哈希表数据结构,允许存入null键null值,线程不同步。(这 HashMap类大致相当于 Hashtable,除了它是不同步的,允许空值。)jdk2.0效率高
TreeMap:底层是二叉树结构,线程不同步,可以给map集合中的key 进行排序。
总结:通过这三个具体类的描述,我们发现它和set集合是不是很像,其实set集合底层调用的都是map集合的方法。- 例子
我们用user对象来作为key,判断如果年龄和姓名一样的user对象在map中只能有一个key存一个值。 public class User implements Comparable{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String name, int age) { super(); this.name = name; this.age = age; } public String toString() { return "User [name=" + name + ", age=" + age + "]"; } /** * 重写hashCode方法 * */ public int hashCode() { // TODO Auto-generated method stub return (name.hashCode()+age)*100; } /** * 重写 equals方法 */ public boolean equals(Object obj) { if(obj instanceof User){ User u =(User)obj; return this.name.equals(u.name) && this.age==u.age; }else{ return false; } } /** * 重写比较性的方法 */ public int compareTo(Object o) { if(o instanceof User){ User u =(User)o; int num=this.age-u.age; if(num==0){ return this.name.compareTo(u.name); } return num; }else{ throw new RuntimeException("传错了"); } } } public class Test { public static void main(String[] args) { // Map<User,String> map =new HashMap<User,String>(); Map<User,String> map=new TreeMap<User, String>(); map.put(new User("张三",18), "北京"); map.put(new User("张三",18), "北京"); map.put(new User("王武",18), "北京"); map.put(new User("王武",18), "上海"); map.put(new User("赵六",19), "武汉"); /** * 迭代 */ Set<User> keys= map.keySet(); Iterator<User> it= keys.iterator(); while(it.hasNext()){ User user =it.next(); String value =map.get(user); System.out.println("key:"+user+" value:"+value); } } }