》Collection接口:单列集合,用来存储一个一个的对象
》 List接口:存储有序的,可重复的数据---》动态数组,实现类:ArrayList,LinkedList,Vector
》Set接口,存储无序的,不可重复的数据--》高中讲的集合
实现类:Hash Set,LinkedHashSet,TreeSet
对应图示:
add(Object obj),addAll(Collection coll),size(),isEmpty(),clear()
contains(Object obj),containsAll(Collection coll),remove(Object obj),removeAll(Collection coll)
retainsAll(Collection coll),retainsAll(Collection coll),equals(Collection coll),hashCOde(),toArray(),iterator()
集合---》数组:toArray()
数组---》集合 Arrays.asList(T...t)
向Collection接口的实现类的对象中添加数据obj时,要求obj所在的类要重写equals()
1.iterator迭代器 2 foreach循环(增强for循环)
2.遍历的代码实现:
Iterator iterator = coll.iterator();
//hasNext():判断是否还有下一个元素
while(iterator.hasNext()){
//next()①指针下移,②将下移以后集合位置上的元素返回
System.out.println(iterator.next());}
3.迭代器图示:
List 接口:存储有序,可重复的数据--》“动态数组”替换原来的数组
增:add(Object obj)
删:remove(int index), remove(Object obj)
改:set(int index,Object ele)
查:get(int index)
插:add(int index,Object ele)
长度:size()
遍历:①Iterator迭代器方式
②增强for循环
③普通的循环
》ArrayList:作为List接口的主要实现类,线程不安全的,效率高;底层使用Object[] elementData存储
》LinkedList:对于频繁的插入,删除操作,使用此类效率比ArrayList高,底层使用双向链表存储
》vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
ArrayList的源码分析:
1jdk7情况下:
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组 elementData
List.add(123);//elementData[0]=new Integer(123);
...
List.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原来的数组中的数据复制到新数组中
结论:建议开发中使用带参的构造器:ArrayList list= new ArrayList(int capacity)
2jdk8中的ArrayList的变化:
ArrayList list = new ArrayList();//底层 Object[] elementData初始化为{},并没有创建长度为10的数组
List.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据添加到elementData[0]
后续的添加和扩容操作与jdk7无异
3 小结:jdk7中ArrayList的对象的创建类似于单列的饿汉模式,而jkd8中的ArrayList对象创建类似于单列的懒汉式,延迟数组的创建,节省内存
1.存储的数据特点:
无序的,不可重复的数据
具体的以HashSet为例说明:
》无序性:不等于随机性。存储的数据在底层数组中并非按照数组的索引顺序添加,而且根据数据的哈希值决定的
》不可重复性:保证添加的元素按照equals()判断不能返回true,即相同的元素只能添加一个
2.元素的添加过程:(以HashSet为例)
我们在向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值
,此哈希值接着通过某种计算方法计算出在HashSet底层数组中存放位置(即为:索引位置,判断数组此位置上是否已经有元素:
如果此时位置上没有其他元素,则元素a添加成功---》情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素,则比较元素a与元素b的hash值:
如果hash值不同,则元素a添加成功----》情况2
如果hash值相同,进而调用元素a所在类的equals()方法:
equals()返回true,元素a添加失败
equals()返回false,元素a添加成功----》情况3
对于添加成功的情况2和情况3而言:元素a与已经存在的指定索引位置上的数据以链表的方式存储。
jdk7:元素a放在数组中,指向原来的元素
jdk8:原来的元素在数组中,指向元素a
总结:七上八下
HashSet底层:数组+链表的结构
3.常用方法:
Set接口中没有额外定义新的方法,使用的都是Collection中声明的方法
4.常用实现类
》HashSet:作为Set 接口的主要实现类;线程不安全的可以存储null值
》LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,LinkedhashSet效率高于HashSet
》TreeSet:可以按照添加对象的指定属性,进行排序
5.存储对象所在类的要求:
HashSet/LinkedHashSet:
要求:向Set(主要指:HashSet,LinkedHashSet)中添加数据,其所在的类一定要重写
HashCode()和equals
要求:重写的hashcode()和equals()尽可能保持一致性:相同的对象必须有相同的散列码
重写两个方法的小技巧:对象中用作equals()方法比较的Filed,都应该用来计算hashcode值
TreeSet:
1.自然排序中,比较两个对象是否相同的标准为:compareTo() 返回0,不在是equals()
2.在定制排序中,比较两个对象是否相同的标准为:compare() 返回0,不在是equals()
6.TreeSet的使用:
1.使用说明:
》向TreeSet添加数据,必须是相同类的对象
》两种排序方式:自然排序实现Compareable接口和定制Comparator
--Map:双列数据,存储key-value对的数据 ------ 类似高中的函数:y=f(x)
》HashMap:作为Map的主要实现类,线程不安全的,效率高;存储null的key和value
--LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
原因:在原来的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素
对于频繁的遍历操作,此类执行效率高于HashMap
》TreeMap: 保证添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序底层使用红黑树
》Hashtable:作为古老的实现类;线程安全的,效率低,不能存储null的key和value
---Properties:常用来处置配置文件。key和vaule都是String类型
HashMap的底层:数组+链接(jdk7及以前)
数组+链表+红黑树(jdk8)
》Map中的key:无序的,不可重复的,使用Set存储所有的Key--key所在的类要重写equals()和hashcode()以hashMap为例
》Map中的value:无序的,可重复的,使用Collection存储所有的value---》value所在的类要重写equals()
》Map中的entry:无序的,不可重复的,使用Set存储所有的entry
*添加: put(Object key,Object value)
*删除:remove(Object key)
*修改: put(Object key,Object value)
*查询:get(Object key)
*长度:size()
*遍历:KeySet()/values()/entrySet()
4.1 HashMap 在jdk7中实现原理:
HashMap map =new HashMap()
* 在实例化后,底层创建了长度时16的一维数组Entry[]table
map.put(key1,value1):
*首先,调用key1所在类的hashcod()计算key1哈希值,此哈希值经过某种算法计算后
得到在Entry数组中的存放位置
* 如果此位置上的数据为空,此时的key1-value1 添加成功----情况1
* 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在))
比较key1和已经存在的一个或多个数据的哈希值:
*如果key1的哈希值与已经存在的哈希值都不相同,此时的key1-value1 添加成功---情况2
*如果key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,继续比较调用 key2所在类的equals(Key2)方法:
如果equals()返回false:此时的key1-value1 添加成功----情况3
如果equals()返回true:使用value1替换value2
补充:关于情况2和情况3:此时 key1-value1和原来的数据以链表的方式存储
在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时。扩容的默认方式:扩容为原来容量的2倍,并将原来的数据复制过来
4.2 HashMap 在jdk8中相较于jdk7 底层实现不同:
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk8 底层的数组时Node[] ,而非Entry[]
3.首次调用put()方法时,底层创建一个长度为16的数组
4.jdk7 底层结构只要 数组+链表,jdk8中底层结构:数组+链表+红黑树
*当数组的某一个索引位置上的元素以链接形式存在的数据个数>8,且当数组长度>64,
此时的索引位置上的所有数据改为使用红黑树存储。
*向TreeMap中添加key-value,要求key必须由同一个类创建的对象
*因为要按照key进行排序:自然排序,定制排序
public static void main(String[] args) { Properties pro = new Properties(); FileInputStream fileinput=null; try { fileinput =new FileInputStream("jdbc.properties"); pro.load(fileinput); String name = pro.getProperty("name"); String password =pro.getProperty("password"); System.out.println(name); System.out.println(password); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fileinput.close(); } catch (IOException e) { e.printStackTrace(); } }
操作Collection和Map工具类
*reverse(List):反转List中元素的顺序
*shuffle(List): 对List 集合随机排序
*sort(List):根据元素的自然顺序对指定List 集合元素升序排序
*sort(List,Compartor)::根据指定的Comparator产生的顺序对List 集合元素升序排序
*int frequency(Collection Object):返回指定集合中指定元素的出现次数
*voidcopy(List dest,List src):将src的中的内容复制到dest中
* boolean replaceAll(List list,Object oleVal,Object newVal):使用新值替换list 对象所有的旧值
Collection:集合接口
Collections 操作Collection 和Map接口的工具类
泛型:就是在定义类,接口时通过一个标识表示类中的某个属性的类型或者某个方法的返回值及参数类型。
jdk1.5引入。 例如 :List
解决问题:
//问题1:类型不安全问题
list.add(Object obj)
//问题2:强转出现ClassCastException
l
总结:
>集合接口或集合类在jdk5.0时都修改为带泛型的结构
>在实例化集合类时,可以指明具体的泛型类型
>指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法,构造器,属性等)便显示为具体的类型:比如 add(E e) --->实例化以后:add (Integer e)
>泛型的类型必须时类,不能时基本类型,需要用到基本类型,拿包装类替换
>如果实例化时,没有指明泛型类型,默认类型为java.lang.Object类型
public void test(){ Listlist = new ArrayList (); list.add(10); list.add(20); list.add(30); list.add(40); list.add(50); Iterator iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } }
Mapmap = new HashMap (); map.put("one",10); map.put("two",20); map.put("three",30); map.put("four",40); map.put("five",50); Set > entry=map.entrySet(); Iterator > it=entry.iterator(); while(it.hasNext()){ Map.Entry vaule =it.next(); System.out.println(vaule.getKey()+":"+vaule.getValue()); }
1.泛型在继承方面的体现:
》虽然类A时类B的父类,但是G和G两者不具备子父类关系,两者是并列关系
》类A是类B的父类,A
@Test public void test1() { Object obj = null; String str = null; //可以赋值,编译通过 obj = str; List
通配符:?
>类A是类B的父类,G和G是没有关系的,两者的共同父类是:G>
>G> 不能添加数据,但是可以获取数据
@Test public void test3() { List
@Test public void test4() { Listlist1 =new ArrayList<>(); list1.add("AA"); list1.add("BB"); list1.add("CC"); List>list =null; list=list1; //list> 不能添加数据,只能添加null list.add("DD"); list.add(null); //list>可以读取数据 Object o = list.get(0); System.out.println(o); }
public class DAO{ private Mapmap =new HashMap<>(); //保存 public void save(String key, T t) { map.put(key, t); } //获取 public T get(String key) { return map.get(key); } //修改 public void update(String key, T value) { if (map.containsKey(key)) { map.put(key, value); } } //获取全部 public List List() { Collection values = (Collection ) map.values(); List list = new ArrayList(); for (T t : values) { list.add(t); } return list; } //删除 public void delete(String key) { if (map.containsKey(key)) { map.remove(key); } } }
public class User { public User() { } public User(String name, int age) { this.name = name; this.age = age; } private String name; private int age; public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class DAOTest { public static void main(String[] args) { DAOdao = new DAO<>(); User user1 =new User("周杰伦",34); User user2 =new User("方文山",30); User user3 =new User("陈冠希",25); dao.save("1001",user1); dao.save("1002",user2); dao.save("1003",user3); System.out.println(dao.List()); dao.update("1003",new User("蔡依林",22)); System.out.println(dao.List()); dao.delete("1003"); System.out.println(dao.List()); System.out.println(dao.get("1001")); } }