Java中的容器
来源:互联网 发布:河北新闻联播网络直播 编辑:程序博客网 时间:2024/05/22 14:34
一、容器的分类
1、Collection:独立的对象序列。
包括:List-按照顺序保存对象,set-按照顺序保存不重复的对象,queue-队列
2、Map:“键-值”对象或者字典或者关联数组。
package com.ray.ch09; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; public class Test { private ArrayList<String> list = new ArrayList<String>(); private HashSet<String> set = new HashSet<String>(); private HashMap<String, String> map = new HashMap<String, String>(); public Test() { for (int i = 0; i < 10; i++) { list.add("a"); } for (int i = 0; i < 10; i++) { set.add("a"); } for (int i = 0; i < 10; i++) { map.put("name" + i, "a"); } } public ArrayList<String> getList() { return list; } public void setList(ArrayList<String> list) { this.list = list; } public HashSet<String> getSet() { return set; } public void setSet(HashSet<String> set) { this.set = set; } public HashMap<String, String> getMap() { return map; } public void setMap(HashMap<String, String> map) { this.map = map; } public static void main(String[] args) { Test test = new Test(); System.out.println("--------list--------"); ArrayList<String> list = test.getList(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("--------set--------"); HashSet<String> set = test.getSet(); for (String str : set) { System.out.println(str); } System.out.println("--------map--------"); HashMap<String, String> map = test.getMap(); for (int i = 0; i < 10; i++) { System.out.println(map.get("name" + i)); } } }
输出:
——–list——–
a
a
a
a
a
a
a
a
a
a
——–set——–
a
——–map——–
a
a
a
a
a
a
a
a
a
a
上面的代码展现了list、set、map这三种我们常用的容器的特性。
二、向容器添加一组数据与容器的打印
1.向容器添加一组数据
容器可以通过addAll()方法可以想容器添加一组数据:
(1)添加另一个Collection
(2)添加一个数组
(3)添加一个使用逗号分割的列表
package com.ray.ch09; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; public class Test { public static void main(String[] args) { Collection<Integer> collection = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { collection.add(i); } Collection<Integer> collection2 = new ArrayList<Integer>(); for (int i = 0; i < 4; i++) { collection.add(i); } collection.addAll(collection2);// 添加一个Collection Collections.addAll(collection, 1, 2, 3);// 添加一个使用逗号分割的列表 Integer[] array = { 1, 2, 3, 4 }; Collections.addAll(collection, array);// 添加一个数组 } }
从上面的代码可以看见,其实Collections.addAll后面的参数是一组可变参数,因此它可以接受一个列表或者一个数组。
下面我们来展示一下另外一个方法:Arrays.asList
package com.ray.ch09; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class Test { public static void main(String[] args) { Integer[] array = { 1, 2, 3, 3, 4 }; List<Integer> list = (ArrayList<Integer>) Arrays.asList(array); List<Integer> list2 = Arrays.<Integer> asList(array); Collections.addAll(list, 1, 2, 3); Collections.addAll(list2, 1, 2, 3); } }
它也是可以向容器添加一组数据,但是需要注意,它有个限制,因为他的底层实现是以数组来实现,因此在添加删除数据的时候,需要Collections.addAll方法。
2.容器的打印
package com.ray.ch09; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; public class Test { public static void main(String[] args) { Collection<Integer> collection = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { collection.add(i); } Arrays.toString(collection.toArray()); } }
从上面的代码可以看见,一般使用Arrays.toString方法,但是有一点需要注意,Collection必须转换成数组才能够打印。
三、List
List里面的两个常用的容器ArrayList和LinkedList。
1、相同之处
两个list都是具有顺序的序列
2、不同之处
ArrayList善于执行查询操作,但是插入操作性能不好
LinkedList善于在中间插入元素,但是查询的性能不好。
3、演示List的一些常用方法
package com.ray.ch09; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { list.add(i); } System.out.println(list.get(3)); System.out.println(list.indexOf(5)); list.remove(list.indexOf(3)); for (Integer param : list) { System.out.println(param); } ArrayList<Integer> list2 = new ArrayList<Integer>(); list2.add(5); list.retainAll(list2); for (Integer param : list) { System.out.println(param); } list2.clear(); list.clear(); } }
4、测试性能
(1)插入元素的性能测试
代码:
package com.ray.ch09; import java.util.ArrayList; import java.util.LinkedList; public class Test { public static void main(String[] args) { long amount = 10000;// 随时改变这个插入元素的个数 long startTime = System.currentTimeMillis(); ArrayList<Double> arrayList = new ArrayList<Double>(); for (long i = 0; i < amount; i++) { arrayList.add(Math.ceil(i / 2)); } long endTime = System.currentTimeMillis(); System.out.println("ArrayList:" + (endTime - startTime)); System.gc(); System.out.println("------------------------------"); startTime = System.currentTimeMillis(); LinkedList<Double> linkedList = new LinkedList<Double>(); for (long i = 0; i < amount; i++) { linkedList.add(Math.ceil(i / 2)); } endTime = System.currentTimeMillis(); System.out.println("LinkedList:" + (endTime - startTime)); } }
上面的代码是在list的中间插入一个元素。
我们通过几个级别来测试:
amount=10000的输出:
ArrayList:16
LinkedList:0
amount=100000的输出:(大部分的时候是下面的结果)
ArrayList:31
LinkedList:15
amount=500000的输出:(出现逆转)
ArrayList:125
LinkedList:219
amount=5000000的输出:(出现逆转)
ArrayList:1953
LinkedList:2078
amount=9000000的输出:(linkedlist耗尽内存)
ArrayList:3375
java.lang.OutOfMemoryError
综上所述:LinkedList在数据规模较小的,插入的性能的确比ArrayList要来的好,但是,中间出现了转折点,当数据达到一定程度,LinkedList插入的性能竟然比ArrayList要低,而且当数量更大时,LinkedList耗尽内存抛异常,LinkedList比ArrayList要来到耗内存,因为他使用链式存储,存储的数据比ArrayList要多。
(2)查看元素
代码:
package com.ray.ch09; import java.util.ArrayList; import java.util.LinkedList; import java.util.Random; public class Test { public static void main(String[] args) { long amount = 1000000;// list的大小 int times = 1000;// 查看次数 ArrayList<Double> arrayList = new ArrayList<Double>(); for (long i = 0; i < amount; i++) { arrayList.add(Math.ceil(i / 2)); } LinkedList<Double> linkedList = new LinkedList<Double>(); for (long i = 0; i < amount; i++) { linkedList.add(Math.ceil(i / 2)); } System.out.println("===========查看测试开始==========="); Random random = new Random(); long startTime = System.currentTimeMillis(); for (int i = 0; i < times; i++) { arrayList.get(random.nextInt(times)); } long endTime = System.currentTimeMillis(); System.out.println("ArrayList:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i = 0; i < times; i++) { linkedList.get(random.nextInt(times)); } endTime = System.currentTimeMillis(); System.out.println("LinkedList:" + (endTime - startTime)); } }
我们先在两个list里面存放1000000个元素,然后进行随机查询。
times=1000时的输出:
===========查看测试开始===========
ArrayList:0
LinkedList:16
times=10000时的输出:
===========查看测试开始===========
ArrayList:0
LinkedList:969
事实证明,linkedLIst的查询性能非常差,ArrayList的非常好。
5、LinkedList
在中间插入或者删除元素会比ArrayList的性能好,但是有不一定的情况
package com.ray.ch09; import java.util.Arrays; import java.util.LinkedList; public class Test { public static void main(String[] args) { LinkedList<Integer> linkedList = new LinkedList<Integer>(); for (int i = 0; i < 10; i++) { linkedList.add(i); } linkedList.addFirst(12); linkedList.addLast(15); System.out.println(Arrays.toString(linkedList.toArray())); System.out.println(linkedList.removeLast()); System.out.println(linkedList.remove()); System.out.println(Arrays.toString(linkedList.toArray())); System.out.println(linkedList.poll()); System.out.println(linkedList.peek()); System.out.println(Arrays.toString(linkedList.toArray())); } }
输出:
[12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15]
15
12
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0
1
[1, 2, 3, 4, 5, 6, 7, 8, 9]
四、迭代器Iterator
1、概念
迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器(container,例如链表或阵列)上遍访的接口,设计人员无需关心容器的内容。
package com.ray.ch09; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class Test { public static void Traversal(Collection<Integer> collection) { Iterator<Integer> it = collection.iterator(); while (it.hasNext()) { int rtn = it.next(); System.out.println(rtn); } } public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { list.add(i); } HashSet<Integer> set = new HashSet<Integer>(); for (int i = 0; i < 10; i++) { set.add(i); } System.out.println("---------list---------"); Traversal(list); System.out.println("---------set---------"); Traversal(set); } }
从上面的代码可以看见,使用迭代器,不管是list还是set,都可以重复使用Traversal这个方法,这样使得代码重用性得到提高。
2、注意点
(1)我们只需要接收容器,即可以在每个对象上面操作
package com.ray.ch09; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Test { public static void Traversal(Collection<Person> collection) { Iterator<Person> it = collection.iterator(); while (it.hasNext()) { Person person = it.next(); System.out.println(person.getId()); } } public static void main(String[] args) { ArrayList<Person> list = new ArrayList<Person>(); for (int i = 0; i < 10; i++) { Person person = new Person(); person.setId(i); list.add(person); } Traversal(list); } } class Person { private int id = 0; public int getId() { return id; } public void setId(int id) { this.id = id; } }
从上面的代码可以看见,我们可以通过迭代器类型的转换,转换成Person类型,然后持有了Person这个对象的引用,那么现在就可以对person对象进行操作。
(2)remove()方法的使用
package com.ray.ch09; import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { list.add(i); } Iterator<Integer> iterator = list.iterator(); iterator.next();// 如果我们注释了这一句,运行时就会抛异常 iterator.remove(); } }
当我们使用remove方法的时候,必须先使用next方法,使得迭代器里面已经指向一个新的对象。
3、ListIterator
ListIterator主要就是补充了Iterator只能向后的问题,在ListIterator里面可以向前移动。
package com.ray.ch09;import java.util.ArrayList;import java.util.ListIterator;public class Test { public static void main(String[] args) { ArrayList<Integer> arrayList = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { arrayList.add(i); } ListIterator<Integer> iterator = arrayList.listIterator(); while (iterator.hasNext()) { Integer rtn = iterator.next(); System.out.print(rtn); } System.out.println(); while (iterator.hasPrevious()) { Integer rtn = iterator.previous(); System.out.print(rtn); } }}
输出:
0123456789
9876543210
注意:在使用iterator.previous()前必须检测iterator.hasPrevious()的真假,不然在第一个元素还没有压入迭代器的时候,会抛异常。
五、Set
由于set里面的对象的不重复性,因此决定了set里面搜索查询的函数用的非常频繁,因此,我们一般使用hashset,因为它对于搜索进行了特殊的优化处理。
1、HashSet
由于HashSet对对象进行hash操作,因为它的搜索是根据hash码来操作的,因此, 它的输出是无序的。
package com.ray.ch09;import java.util.Arrays;import java.util.HashSet;import java.util.Random;public class Test { public static void main(String[] args) { HashSet<Integer> set = new HashSet<Integer>(); Random random = new Random(); for (int i = 0; i < 10000; i++) { set.add(random.nextInt(30)); } System.out.println(Arrays.toString(set.toArray())); }}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 16, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28]
2、TreeSet
如果你需要结果是排序的,那么就应该使用TreeSet,它把对象放置在红黑树上面。
package com.ray.ch09;import java.util.Arrays;import java.util.Random;import java.util.TreeSet;public class Test { public static void main(String[] args) { TreeSet<Integer> set = new TreeSet<Integer>(); Random random = new Random(); for (int i = 0; i < 10000; i++) { set.add(random.nextInt(30)); } System.out.println(Arrays.toString(set.toArray())); }}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
3、set 的不重复性演示
package com.ray.ch09;import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;public class Test { public static void main(String[] args) { HashSet<Integer> set = new HashSet<Integer>(); for (int i = 0; i < 10; i++) { set.add(i); } System.out.println(Arrays.toString(set.toArray())); set.add(12); System.out.println(Arrays.toString(set.toArray())); ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); set.addAll(list); System.out.println(Arrays.toString(set.toArray())); }}
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12]
4、contains方法
由于set的不可重复性决定了contains方法是set里面使用的最频繁的方法。
package com.ray.ch09;import java.util.HashSet;public class Test { public static void main(String[] args) { HashSet<Integer> set = new HashSet<Integer>(); for (int i = 0; i < 10; i++) { set.add(i); } System.out.println(set.contains(2)); System.out.println(set.contains(12)); }}
输出:
true
false
5、有些时候我们需要使用排序的不重复的人员名单时,可以优先考虑TreeSet,请注意代码里面的注释。
package com.ray.ch09;import java.util.Arrays;import java.util.TreeSet;public class Test { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER);// 主要是这里设置了排序的属性,只是对字符串有效 String text = "Aabbye,Caesar,abbe,Bairn,cais,Dagmar,baby"; String[] names = text.split(","); for (int i = 0; i < names.length; i++) { treeSet.add(names[i]); } System.out.println(Arrays.toString(treeSet.toArray())); }}
输出:
[Aabbye, abbe, baby, Bairn, Caesar, cais, Dagmar]
六、Map
1、Map就是“键值”关联数组
package com.ray.ch09; import java.util.HashMap; import java.util.Random; public class Test { public static void main(String[] args) { HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); Random random = new Random(); for (int i = 0; i < 10; i++) { int key = random.nextInt(50); if (map.get(key) == null) { map.put(key, 1); } else { int value = map.get(key); map.put(key, value + 1); } } System.out.println(map.toString()); } }
输出:
{19=1, 38=1, 36=1, 37=1, 42=1, 10=1, 40=1, 41=1, 11=1, 45=1}
注意:由于我们上面的代码使用hashmap,因此它记录的结果是无序的,当我们下一次运行代码的时候,它们的顺序将会不一样。
2、常用方法containKeys和containValue
package com.ray.ch09; import java.util.HashMap; import java.util.Random; public class Test { public static void main(String[] args) { HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); Random random = new Random(); for (int i = 0; i < 10; i++) { int key = random.nextInt(50); if (map.get(key) == null) { map.put(key, 1); } else { int value = map.get(key); map.put(key, value + 1); } } System.out.println(map.toString()); System.out.println(map.containsKey(3)); System.out.println(map.containsValue(5)); } }
输出:
{32=1, 18=1, 38=1, 5=1, 23=1, 6=1, 42=1, 43=1, 29=1, 15=1}
false
false
一般我们会使用上面的方法来测试map里面是否有我们想要的对象。
3、把数据发展到多维。
package com.ray.ch09; import java.util.ArrayList; import java.util.HashMap; public class Test { public static void main(String[] args) { HashMap<Person, ArrayList<Pet>> map = new HashMap<Person, ArrayList<Pet>>(); Person person = new Person(); ArrayList<Pet> pets = new ArrayList<Pet>(); for (int i = 0; i < 10; i++) { pets.add(new Pet()); } map.put(person, pets); } } class Person { } class Pet { }
六、Queue
1、特性:先进先出,它跟栈的顺序不一样。
2、演示方法
由于LinkedList实现了Queue接口,因此我们将以LinkedList作为例子。
package com.ray.ch09; import java.util.LinkedList; import java.util.Queue; public class Test { public static void main(String[] args) { Queue<Integer> queue = new LinkedList<Integer>(); for (int i = 0; i < 10; i++) { queue.add(i); } System.out.println(queue.toString()); for (int i = 0; i < queue.size(); i++) { System.out.print(queue.peek());// 拿出第一个元素 } System.out.println(); for (int i = 0; i < queue.size(); i++) { System.out.print(queue.poll());// 去掉并返回第一个元素 System.out.println(queue.toString()); } } }
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0000000000
0[1, 2, 3, 4, 5, 6, 7, 8, 9]
1[2, 3, 4, 5, 6, 7, 8, 9]
2[3, 4, 5, 6, 7, 8, 9]
3[4, 5, 6, 7, 8, 9]
4[5, 6, 7, 8, 9]
3、PriorityQueue
PriorityQueue是一个有默认优先级的队列
package com.ray.ch09; import java.util.PriorityQueue; import java.util.Random; public class Test { public static void main(String[] args) { PriorityQueue<Integer> integers = new PriorityQueue<Integer>(); Random random = new Random(); for (int i = 0; i < 10; i++) { integers.offer(random.nextInt(50)); } System.out.println(integers.toString()); PriorityQueue<String> strings = new PriorityQueue<String>(); String text = "d,e,T,g,qe,R,j,k,b,h,G,v,Kj,a,d,h,u,f,g,s,ad,jk,f,"; String[] textArray = text.split(","); for (int i = 0; i < textArray.length; i++) { strings.offer(textArray[i]); } System.out.println(strings.toString()); } }
输出:
[12, 14, 18, 18, 26, 41, 30, 44, 33, 43]
[G, R, Kj, e, ad, T, a, h, f, b, f, v, d, j, d, k, u, g, g, s, qe, jk, h]
优先级:
数字是从小到大
字符串是大写到小写
七、接口Collection与Iterator
1、在Collection与Map的实现类里面,其实都实现了Collection与Iterator接口
package com.ray.ch09; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class Test { public static void showItems(Collection<Integer> collection) { for (Integer item : collection) { System.out.print(item + " "); } } public static void showItems(Iterator<Integer> iterator) { while (iterator.hasNext()) { Integer item = iterator.next(); System.out.print(item + " "); } } public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); HashSet<Integer> set = new HashSet<Integer>(); for (int i = 0; i < 10; i++) { list.add(i); set.add(i); } showItems(list); System.out.println(); showItems(set); System.out.println(); showItems(list.iterator()); System.out.println(); showItems(set.iterator()); System.out.println(); } }
从上面的代码都可以看见,list和set都分别实现了Collection与Iterator,因此可以通过向上转型来调用里面的方法。
2、当我们有一个对象想复用类似showItem这种遍历方法的时候,他必须实现Collection或Iterator,而且实现Iterator比较容易。
Collection:
package com.ray.ch09; import java.util.Collection; import java.util.Iterator; public class Test { } class Person implements Collection<Person> { @Override public int size() { // TODO Auto-generated method stub return 0; } @Override public boolean isEmpty() { // TODO Auto-generated method stub return false; } @Override public boolean contains(Object o) { // TODO Auto-generated method stub return false; } @Override public Iterator<Person> iterator() { // TODO Auto-generated method stub return null; } @Override public Object[] toArray() { // TODO Auto-generated method stub return null; } @Override public <T> T[] toArray(T[] a) { // TODO Auto-generated method stub return null; } @Override public boolean add(Person e) { // TODO Auto-generated method stub return false; } @Override public boolean remove(Object o) { // TODO Auto-generated method stub return false; } @Override public boolean containsAll(Collection<?> c) { // TODO Auto-generated method stub return false; } @Override public boolean addAll(Collection<? extends Person> c) { // TODO Auto-generated method stub return false; } @Override public boolean removeAll(Collection<?> c) { // TODO Auto-generated method stub return false; } @Override public boolean retainAll(Collection<?> c) { // TODO Auto-generated method stub return false; } @Override public void clear() { // TODO Auto-generated method stub } }
上面的实例代码我们可以看见,实现起来是非常麻烦的一件事情,达不到代码重用所应有的提供开发效率的效果。
我们知道有一个AbstractCollection实现了上面的接口,我们来继承它看看。
package com.ray.ch09; import java.util.AbstractCollection; import java.util.Collection; import java.util.Iterator; public class Test { public static void showItems(Collection<Person> collection) { for (Person person : collection) { System.out.print(person.getId() + " "); } } public static void showItems(Iterator<Person> iterator) { while (iterator.hasNext()) { Person person = iterator.next(); System.out.print(person.getId() + " "); } } public static void main(String[] args) { PersonList personList = new PersonList(); showItems(personList); System.out.println(); showItems(personList.iterator()); } } class Person { private int id = 0; public int getId() { return id; } public void setId(int id) { this.id = id; } } class PersonList extends AbstractCollection<Person> { private Person[] persons = new Person[10]; public PersonList() { for (int i = 0; i < persons.length; i++) { Person person = new Person(); person.setId(i); persons[i] = person; } } @Override public Iterator<Person> iterator() { return new Iterator<Person>() { private int index = 0; @Override public boolean hasNext() { return index < persons.length; } @Override public Person next() { return persons[index++]; } @Override public void remove() {// 以后会展开实现 } }; } @Override public int size() { return persons.length; } }
相对来说我们展现的例子就简单了一些,但是需要注意,继承了这个抽象类其实里面有很多方法是需要自己实现,只不过他里面没有给出来而已,就像我们的例子,必须自己初始化person的数组,不能使用外部add,因为在抽象类里面的实现,add是抛异常的。
Iterator:
package com.ray.ch09; import java.util.Iterator; public class Test { public static void showItems(Iterator<Person> iterator) { while (iterator.hasNext()) { Person person = iterator.next(); System.out.print(person.getId() + " "); } } public static void main(String[] args) { PersonList personList = new PersonList(); showItems(personList.iterator()); } } class Person { private int id = 0; public int getId() { return id; } public void setId(int id) { this.id = id; } } class PersonList { private Person[] persons = new Person[10]; public PersonList() { for (int i = 0; i < persons.length; i++) { Person person = new Person(); person.setId(i); persons[i] = person; } } public Iterator<Person> iterator() { return new Iterator<Person>() { private int index = 0; @Override public boolean hasNext() { return index < persons.length; } @Override public Person next() { return persons[index++]; } @Override public void remove() {// 以后会展开实现 } }; } }
八、foreach与Iterator
- Java中的容器
- JAVA中的容器arraylist
- java中的容器
- Java中的容器讲解
- Java中的容器
- Java中的缓存容器
- Java中的容器
- java中的容器类
- Java中的容器类
- Java中的容器类
- Java中的容器类
- Java中的容器类
- JAVA中的容器
- java中的各种容器
- java中的容器类
- java中的容器讲解
- Java中的容器
- Java中的容器
- 动态链接库的创建
- android studio 不支持 .9图片?
- [iOS]iOS9 3DTouch、ShortcutItem、Peek And Pop技术一览
- css3样式前缀:-ms -moz -webkit -o
- 如何制作chm格式的帮助文件
- Java中的容器
- Swift中的Lazy与计算属性
- 异步AIO的研究
- Android中的ANR如何分析又如何避免
- 我的前端生涯实录,虽然才开始
- 1692: [Usaco2007 Dec]队列变换 后缀数组+贪心
- linux AIO (异步IO) 那点事儿
- UI组件之TextView及其子类(一)TextView和EditText
- 你得学会并且学得会的Socket编程基础知识