Java学习总结2---Java集合类
在学习集合类前,发现个问题,比较collection和collections的区别。如下:
1.java.util.Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法。Collection在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供最大化的统一操作方法。
Collection
----List
----LinkedList
----ArrayList
----Vector
----Stack
----Set
2.java.util.Collections是一个包装类,它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架
言归正传
本讲内容:集合 collection
讲集合collection之前,我们先分清三个概念:
- colection 集合,用来表示任何一种数据结构
- Collection 集合接口,指的是 java.util.Collection接口,是 Set、List 和 Queue 接口的超类接口
- Collections 集合工具类,指的是 java.util.Collections 类。
要求了解的接口有:Collection , Set , SortedSet , List , Map , SortedMap , Queue , NavigableSet , NavigableMap, 还有一个 Iterator 接口也是必须了解的。
要求了解的类有: HashMap , Hashtable ,TreeMap , LinkedHashMap , HashSet , LinkedHashSet ,TreeSet , ArrayList , Vector , LinkedList , PriorityQueuee , Collections , Arrays
下面给出一个集合之间的关系图:
上图中加粗线的ArrayList 和 HashMap 是我们重点讲解的对象。下面这张图看起来层级结构更清晰些。
我们这里说的集合指的是小写的collection,集合有4种基本形式,其中前三种的父接口是Collection。
- List 关注事物的索引列表
- Set 关注事物的唯一性
- Queue 关注事物被处理时的顺序
- Map 关注事物的映射和键值的唯一性
一、Collection 接口
Collection接口是 Set 、List 和 Queue 接口的父接口,提供了多数集合常用的方法声明,包括 add()、remove()、contains() 、size() 、iterator() 等。
add(E e) | 将指定对象添加到集合中 |
remove(Object o) | 将指定的对象从集合中移除,移除成功返回true,不成功返回false |
contains(Object o) | 查看该集合中是否包含指定的对象,包含返回true,不包含返回flase |
size() | 返回集合中存放的对象的个数。返回值为int |
clear() | 移除该集合中的所有对象,清空该集合。 |
iterator() | 返回一个包含所有对象的iterator对象,用来循环遍历 |
toArray() | 返回一个包含所有对象的数组,类型是Object |
toArray(T[] t) | 返回一个包含所有对象的指定类型的数组 |
我们在这里只举一个把集合转成数组的例子,因为Collection本身是个接口所以,我们用它的实现类ArrayList做这个例子:
01
|
import java.util.ArrayList;
|
02
|
import java.util.Collection;
|
03
|
04
|
public class CollectionTest {
|
05
|
06
|
public static void main(String[] args) {
|
07
|
08
|
String a = "a" ,b= "b" ,c= "c" ;
|
09
|
Collection list = new ArrayList();
|
10
|
list.add(a);
|
11
|
list.add(b);
|
12
|
list.add(c);
|
13
|
14
|
String[] array = list.toArray( new String[ 1 ]);
|
15
|
16
|
for (String s : array){
|
17
|
System.out.println(s);
|
18
|
}
|
19
|
}
|
20
|
}
|
编译并运行程序,检查结果:
二、几个比较重要的接口和类简介
1、List接口
List 关心的是索引,与其他集合相比,List特有的就是和索引相关的一些方法:get(int index) 、 add(int index,Object o) 、 indexOf(Object o) 。
ArrayList 可以将它理解成一个可增长的数组,它提供快速迭代和快速随机访问的能力。
LinkedList 中的元素之间是双链接的,当需要快速插入和删除时LinkedList成为List中的不二选择。
Vector 是ArrayList的线程安全版本,性能比ArrayList要低,现在已经很少使用
2、Set接口
Set关心唯一性,它不允许重复。
HashSet 当不希望集合中有重复值,并且不关心元素之间的顺序时可以使用此类。
LinkedHashset 当不希望集合中有重复值,并且希望按照元素的插入顺序进行迭代遍历时可采用此类。
TreeSet 当不希望集合中有重复值,并且希望按照元素的自然顺序进行排序时可以采用此类。(自然顺序意思是某种和插入顺序无关,而是和元素本身的内容和特质有关的排序方式,譬如“abc”排在“abd”前面。)
3、Queue接口
Queue用于保存将要执行的任务列表。
LinkedList 同样实现了Queue接口,可以实现先进先出的队列。
PriorityQueue 用来创建自然排序的优先级队列。番外篇中有个例子http://android.yaohuiji.com/archives/3454你可以看一下。
4、Map接口
Map关心的是唯一的标识符。他将唯一的键映射到某个元素。当然键和值都是对象。
HashMap 当需要键值对表示,又不关心顺序时可采用HashMap。
Hashtable 注意Hashtable中的t是小写的,它是HashMap的线程安全版本,现在已经很少使用。
LinkedHashMap 当需要键值对,并且关心插入顺序时可采用它。
TreeMap 当需要键值对,并关心元素的自然排序时可采用它。
三、ArrayList的使用
ArrayList是一个可变长的数组实现,读取效率很高,是最常用的集合类型。
1、ArrayList的创建
在Java5版本之前我们使用:
1
|
List list = new ArrayList();
|
在Java5版本之后,我们使用带泛型的写法:
1
|
List<String> list = new ArrayList<String>();
|
上面的代码定义了一个只允许保存字符串的列表,尖括号括住的类型就是参数类型,也成泛型。带泛型的写法给了我们一个类型安全的集合。关于泛型的知识可以参见这里。
2、ArrayList的使用:
01
|
List<String> list = new ArrayList<String>();
|
02
|
list.add( "nihao!" );
|
03
|
list.add( "hi!" );
|
04
|
list.add( "konikiwa!" );
|
05
|
list.add( "hola" );
|
06
|
list.add( "Bonjour" );
|
07
|
System.out.println(list.size());
|
08
|
System.out.println(list.contains( 21 ));
|
09
|
System.out.println(list.remove( "hi!" ));
|
10
|
System.out.println(list.size());
|
关于List接口中的方法和ArrayList中的方法,大家可以看看JDK中的帮助。
3、基本数据类型的的自动装箱:
我们知道集合中存放的是对象,而不能是基本数据类型,在Java5之后可以使用自动装箱功能,更方便的导入基本数据类型。
1
|
List<Integer> list = new ArrayList<Integer>();
|
2
|
list.add( new Integer( 42 ));
|
3
|
list.add( 43 );
|
4、ArrayList的排序:
ArrayList本身不具备排序能力,但是我们可以使用Collections类的sort方法使其排序。我们看一个例子:
01
|
import java.util.ArrayList;
|
02
|
import java.util.Collections;
|
03
|
import java.util.List;
|
04
|
05
|
public class Test {
|
06
|
07
|
public static void main(String[] args) {
|
08
|
List<String> list = new ArrayList<String>();
|
09
|
list.add( "nihao!" );
|
10
|
list.add( "hi!" );
|
11
|
list.add( "konikiwa!" );
|
12
|
list.add( "hola" );
|
13
|
list.add( "Bonjour" );
|
14
|
15
|
System.out.println( "排序前:" + list);
|
16
|
17
|
Collections.sort(list);
|
18
|
19
|
System.out.println( "排序后:" + list);
|
20
|
}
|
21
|
22
|
}
|
编译并运行程序查看结果:
排序前:[nihao!, hi!, konikiwa!, hola, Bonjour]
排序后:[Bonjour, hi!, hola, konikiwa!, nihao!]
5、数组和List之间的转换
从数组转换成list,可以使用Arrays类的asList()方法:
01
|
import java.util.ArrayList;
|
02
|
import java.util.Collections;
|
03
|
import java.util.List;
|
04
|
05
|
public class Test {
|
06
|
07
|
public static void main(String[] args) {
|
08
|
09
|
String[] sa = { "one" , "two" , "three" , "four" };
|
10
|
List list = Arrays.asList(sa);
|
11
|
System.out.println( "list:" +list);
|
12
|
System.out.println( "list.size()=" +list.size());
|
13
|
}
|
14
|
15
|
}
|
6、Iterator和for-each
在for-each出现之前,我们想遍历ArrayList中的每个元素我们会使用Iterator接口:
01
|
import java.util.Arrays;
|
02
|
import java.util.Iterator;
|
03
|
import java.util.List;
|
04
|
05
|
public class Test {
|
06
|
07
|
public static void main(String[] args) {
|
08
|
09
|
// Arrays类为我们提供了一种list的便捷创建方式
|
10
|
List<String> list = Arrays.asList( "one" , "two" , "three" , "four" );
|
11
|
12
|
// 转换成Iterator实例
|
13
|
Iterator<String> it = list.iterator();
|
14
|
15
|
//遍历
|
16
|
while (it.hasNext()) {
|
17
|
System.out.println(it.next());
|
18
|
}
|
19
|
20
|
}
|
21
|
22
|
}
|
在for-each出现之后,遍历变得简单一些:
01
|
import java.util.Arrays;
|
02
|
import java.util.Iterator;
|
03
|
import java.util.List;
|
04
|
05
|
public class Test {
|
06
|
07
|
public static void main(String[] args) {
|
08
|
09
|
// Arrays类为我们提供了一种list的便捷创建方式
|
10
|
List<String> list = Arrays.asList( "one" , "two" , "three" , "four" );
|
11
|
12
|
for (String s : list) {
|
13
|
System.out.println(s);
|
14
|
}
|
15
|
16
|
}
|
17
|
18
|
}
|
本讲内容:Map HashMap
前面课程中我们知道Map是个接口,它关心的是映射关系,它里面的元素是成对出现的,键和值都是对象且键必须保持唯一。这一点上看它和Collection是很不相同的。
一、Map接口
Map接口的常用方法如下表所示:
put(K key, V value) | 向集合中添加指定的键值对 |
putAll(Map <? extends K,? extends V> t) | 把一个Map中的所有键值对添加到该集合 |
containsKey(Object key) | 如果包含该键,则返回true |
containsValue(Object value) | 如果包含该值,则返回true |
get(Object key) | 根据键,返回相应的值对象 |
keySet() | 将该集合中的所有键以Set集合形式返回 |
values() | 将该集合中所有的值以Collection形式返回 |
remove(Object key) | 如果存在指定的键,则移除该键值对,返回键所对应的值,如果不存在则返回null |
clear() | 移除Map中的所有键值对,或者说就是清空集合 |
isEmpty() | 查看Map中是否存在键值对 |
size() | 查看集合中包含键值对的个数,返回int类型 |
因为Map中的键必须是唯一的,所以虽然键可以是null,只能由一个键是null,而Map中的值可没有这种限制,值为null的情况经常出现,因此get(Object key)方法返回null,有两种情况一种是确实不存在该键值对,二是该键对应的值对象为null。为了确保某Map中确实有某个键,应该使用的方法是 containsKey(Object key) 。
二、HashMap
HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里。
1、HashMap的基本使用:
01
|
import java.util.Collection;
|
02
|
import java.util.HashMap;
|
03
|
import java.util.Map;
|
04
|
import java.util.Set;
|
05
|
06
|
public class Test {
|
07
|
08
|
public static void main(String[] args) {
|
09
|
10
|
Map<Integer,String> map = new HashMap<Integer,String>();
|
11
|
12
|
map.put( 1 , "白菜" );
|
13
|
map.put( 2 , "萝卜" );
|
14
|
map.put( 3 , "茄子" );
|
15
|
map.put( 4 , null );
|
16
|
map.put( null , null );
|
17
|
map.put( null , null );
|
18
|
19
|
System.out.println( "map.size()=" +map.size());
|
20
|
System.out.println( "map.containsKey(1)=" +map.containsKey( 2 ));
|
21
|
System.out.println( "map.containsKey(null)=" +map.containsKey( null ));
|
22
|
System.out.println( "map.get(null)=" +map.get( null ));
|
23
|
24
|
System.out.println( "map.get(2)=" +map.get( 2 ));
|
25
|
map.put( null , "黄瓜" );
|
26
|
System.out.println( "map.get(null)=" +map.get( null ));
|
27
|
28
|
Set set = map.keySet();
|
29
|
System.out.println( "set=" +set);
|
30
|
31
|
Collection<String> c = map.values();
|
32
|
33
|
System.out.println( "Collection=" +c);
|
34
|
35
|
}
|
36
|
37
|
}
|
编译并运行程序,查看结果:
1
|
map.size()= 5
|
2
|
map.containsKey( 1 )= true
|
3
|
map.containsKey( null )= true
|
4
|
map.get( null )= null
|
5
|
map.get( 2 )=萝卜
|
6
|
map.get( null )=黄瓜
|
7
|
set=[ null , 1 , 2 , 3 , 4 ]
|
8
|
Collection=[黄瓜, 白菜, 萝卜, 茄子, null ]
|
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法
下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
01
|
import java.util.HashMap;
|
02
|
import java.util.Map;
|
03
|
04
|
public class Test {
|
05
|
06
|
public static void main(String[] args) {
|
07
|
08
|
// 龙和它的巢穴映射表
|
09
|
Map<dragon , Nest> map = new HashMap<dragon , Nest>();
|
10
|
11
|
// 在Map中放入四只克莱恩大陆上的龙
|
12
|
map.put( new Dragon( "锐刃" , 98 ), new Nest( 98 ));
|
13
|
map.put( new Dragon( "明镜" , 95 ), new Nest( 95 ));
|
14
|
map.put( new Dragon( "碧雷" , 176 ), new Nest( 176 ));
|
15
|
map.put( new Dragon( "玛烈" , 255 ), new Nest( 255 ));
|
16
|
17
|
// 查看宝藏
|
18
|
System.out.println( "碧雷巢穴中有多少宝藏:" + map.get( new Dragon( "碧雷" , 176 )).getTreasure());
|
19
|
}
|
20
|
21
|
}
|
22
|
23
|
// 龙
|
24
|
class Dragon {
|
25
|
26
|
Dragon(String name, int level) {
|
27
|
this .level = level;
|
28
|
this .name = name;
|
29
|
}
|
30
|
31
|
// 龙的名字
|
32
|
private String name;
|
33
|
34
|
// 龙的级别
|
35
|
private int level;
|
36
|
37
|
public int getLevel() {
|
38
|
return level;
|
39
|
}
|
40
|
41
|
public void setLevel( int level) {
|
42
|
this .level = level;
|
43
|
}
|
44
|
45
|
public String getName() {
|
46
|
return name;
|
47
|
}
|
48
|
49
|
public void setName(String name) {
|
50
|
this .name = name;
|
51
|
}
|
52
|
53
|
}
|
54
|
55
|
// 巢穴
|
56
|
class Nest {
|
57
|
58
|
//我研究的龙之常数
|
59
|
final int DRAGON_M = 4162 ;
|
60
|
61
|
// 宝藏
|
62
|
private int treasure;
|
63
|
64
|
// 居住的龙的级别
|
65
|
private int level;
|
66
|
67
|
Nest( int level) {
|
68
|
this .level = level;
|
69
|
this .treasure = level * level * DRAGON_M;
|
70
|
}
|
71
|
72
|
int getTreasure() {
|
73
|
return treasure;
|
74
|
}
|
75
|
76
|
public int getLevel() {
|
77
|
return level;
|
78
|
}
|
79
|
80
|
public void setLevel( int level) {
|
81
|
this .level = level;
|
82
|
this .treasure = level * level * DRAGON_M;
|
83
|
}
|
84
|
85
|
}
|
编译并运行查看结果:
1
|
Exception in thread "main" java.lang.NullPointerException
|
2
|
at Test.main(Test.java: 18 )
|
我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。
在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。
假设现在有个6张中奖彩票的存根,放在5个桶里(彩票首位只有1-5,首位是1的就放在一号桶,是2的就放在2号桶,依次类推),现在你拿了3张彩票来兑奖,一个号码是113,一个号码是213,一个号码是313。那么现在先兑第一张,取出一号桶里的存根发现存根号码和你的号码不符,所以你第一张没中奖。继续兑第二张,二号桶里就没存根所以就直接放弃了,把三号桶里的所有彩票存根都拿出来对应一番,最后发现有一个存根恰好是313,那么恭喜你中奖了。
HashMap在确定一个键对象和另一个键对象是否是相同时用了同样的方法,每个桶就是一个键对象的散列码值,桶里放的就是散列码相同的彩票存根,如果散列码不同,那么肯定没有相关元素存在,如果散列码相同,那么还要用键的equals()方法去比较是否相同,如果相同才认为是相同的键。简单的说就是 hashCode()相同 && equals()==true 时才算两者相同。
到了这里我们应该明白了,在没有重写一个对象的hashcode()和equals()方法之前,它们执行的是Object中对应的方法。而Object的hashcode()是用对象在内存中存放的位置计算出来的,每个对象实例都不相同。Object的equals()的实现更简单就是看两个对象是否==,也就是两个对象除非是同一个对象,否则根本不会相同。因此上面的例子虽然都是名字叫碧雷的龙,但是HashMap中却无法认可它们是相同的。
因此我们只有重写Key对象的hashCode()和equals()方法,才能避免这种情形出现,好在Eclipse可以帮我们自动生成一个类的hashCode()和equals(),我们把上面的例子加上这两个方法再试试看:
001
|
import java.util.HashMap;
|
002
|
import java.util.Map;
|
003
|
004
|
public class Test {
|
005
|
006
|
public static void main(String[] args) {
|
007
|
008
|
// 龙和它的巢穴映射表
|
009
|
Map<dragon , Nest> map = new HashMap<dragon , Nest>();
|
010
|
011
|
// 在Map中放入四只克莱恩大陆上的龙
|
012
|
map.put( new Dragon( "锐刃" , 98 ), new Nest( 98 ));
|
013
|
map.put( new Dragon( "明镜" , 95 ), new Nest( 95 ));
|
014
|
map.put( new Dragon( "碧雷" , 176 ), new Nest( 176 ));
|
015
|
map.put( new Dragon( "玛烈" , 255 ), new Nest( 255 ));
|
016
|
017
|
// 查看宝藏
|
018
|
System.out.println( "碧雷巢穴中有多少宝藏:" + map.get( new Dragon( "碧雷" , 176 )).getTreasure());
|
019
|
}
|
020
|
021
|
}
|
022
|
023
|
// 龙
|
024
|
class Dragon {
|
025
|
026
|
Dragon(String name, int level) {
|
027
|
this .level = level;
|
028
|
this .name = name;
|
029
|
}
|
030
|
031
|
// 龙的名字
|
032
|
private String name;
|
033
|
034
|
// 龙的级别
|
035
|
private int level;
|
036
|
037
|
public int getLevel() {
|
038
|
return level;
|
039
|
}
|
040
|
041
|
public void setLevel( int level) {
|
042
|
this .level = level;
|
043
|
}
|
044
|
045
|
public String getName() {
|
046
|
return name;
|
047
|
}
|
048
|
049
|
public void setName(String name) {
|
050
|
this .name = name;
|
051
|
}
|
052
|
053
|
@Override
|
054
|
public int hashCode() {
|
055
|
final int PRIME = 31 ;
|
056
|
int result = 1 ;
|
057
|
result = PRIME * result + level;
|
058
|
result = PRIME * result + ((name == null ) ? 0 : name.hashCode());
|
059
|
return result;
|
060
|
}
|
061
|
062
|
@Override
|
063
|
public boolean equals(Object obj) {
|
064
|
if ( this == obj)
|
065
|
return true ;
|
066
|
if (obj == null )
|
067
|
return false ;
|
068
|
if (getClass() != obj.getClass())
|
069
|
return false ;
|
070
|
final Dragon other = (Dragon) obj;
|
071
|
if (level != other.level)
|
072
|
return false ;
|
073
|
if (name == null ) {
|
074
|
if (other.name != null )
|
075
|
return false ;
|
076
|
} else if (!name.equals(other.name))
|
077
|
return false ;
|
078
|
return true ;
|
079
|
}
|
080
|
081
|
}
|
082
|
083
|
// 巢穴
|
084
|
class Nest {
|
085
|
086
|
//我研究的龙之常数
|
087
|
final int DRAGON_M = 4162 ;
|
088
|
089
|
// 宝藏
|
090
|
private int treasure;
|
091
|
092
|
// 居住的龙的级别
|
093
|
private int level;
|
094
|
095
|
Nest( int level) {
|
096
|
this .level = level;
|
097
|
this .treasure = level * level * DRAGON_M;
|
098
|
}
|
099
|
100
|
int getTreasure() {
|
101
|
return treasure;
|
102
|
}
|
103
|
104
|
public int getLevel() {
|
105
|
return level;
|
106
|
}
|
107
|
108
|
public void setLevel( int level) {
|
109
|
this .level = level;
|
110
|
this .treasure = level * level * DRAGON_M;
|
111
|
}
|
112
|
113
|
}
|
编译并运行查看结果:
1
|
碧雷巢穴中有多少宝藏: 128922112
|
这一次正常输出了,真不容易^_^
Java学习总结2---Java集合类相关推荐
- bytes数组转string指定编码_好程序员Java学习路线分享Java基础之string
好程序员Java学习路线分享Java基础之string 好程序员Java培训 先来讲一下字符串 字串符分类: 不可变字符串:----String.字符串本身不能发生改变,与指向字符串的引用无关. St ...
- Java学习系列(十)Java面向对象之I/O流(上)
IO流 我们知道应用程序运行时数据是保存在内存中的,但由于内存中的数据不可持久保存(如断电或程序退出时数据会丢失),因此需要一种手段将数据写入硬盘或读入内存.面向IO流编程就是一种很好的选择.IO:I ...
- Java学习笔记1:Java中有关print、println、printf的用法和区别
Java学习笔记1:Java中有关print.println.printf的用法和区别 最近在学习java,写一些笔记记录下. 1.print()函数是一般的标准输出,但是不换行. 2.println ...
- Java学习07:Java面向对象
Java学习07: Java面向对象: 链接:https://pan.baidu.com/s/1gzlBk5OOVI6oEv-WOkHuhQ 提取码:iqov
- JAVA学习脚印3: java语言控制流程
JAVA学习脚印3: java语言控制流程 本节首先介绍,java语言中的字符串处理以及输入输出控制,最后介绍控制流程. 在讲述控制流程之前,先介绍以下java中字符串和输入输出的内容,以便后续练习编 ...
- Java学习路线,Java SE,EE,ME的区别,SSM框架基本概念
1.尚硅谷 视频课程:https://www.bilibili.com/read/cv5216534 初学者可按照尚硅谷公开的JAVA视频最快学习路线: JavaSE --> MySQL–> ...
- Java学习—初入Java
一.初入Java 文章目录 一.初入Java 2.JDK的目录介绍 3.PATH环境变量 4.ClassPath环境变量 5.编写第一个Java程序 6.Java的运行机制 7.Java包的定义与使用 ...
- java学习之路---java学习的方法和java学习路线
转载于: http://blog.csdn.net/zhangerqing 前段时间逛论坛,总会有很多新手很迷茫,问到:到底该怎么学好Java,这个问题很重要,尤其对于像我们这样大多数都是靠自学的人来 ...
- Java学习教程,Java从入门到精通,全套Java视频教程+笔记+配套工具
目录 一.大纲 一.Java基础 二.计算机基础 三.工具的使用 四.数据库 五.web前端 六.JavaWeb 七.框架 八.互联网分布式技术 发现身边很多自学java却放弃的,真的挺可惜的. 白白 ...
- java学习day01-初识java
初识java 1.Java的发展史 2.Jdk和jre以及jvm 3.虚拟机跨平台原理 4.第一个java小程序 5.命令行编译运行 6.环境变量 7.常用命令 8.关键字,注释,标识符 1.Java ...
最新文章
- Linux 4.18 内核新补丁移除了Lustre 文件系统
- 计算机科学速成课】[40集全/精校] - Crash Course Computer Science
- 通用AI咋发展?向大脑学习是条路子
- 自己实现内存操作函数memset(),memcmp(),memcpy(),memmove()
- 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )
- bst latex 最大作者数_latex 参考文献作者是三个以上时如何处理?
- PWM调光方法在LED亮度调节中的应用
- android104 帧动画,补间动画,属性动画
- HTML5学习笔记简明版(11):新API
- 9招让你皮肤迅速白嫩 - 健康程序员,至尚生活!
- 【EF】Entity Framework Core 2.0 特性介绍和使用指南
- sklearn库的学习
- Openssl(版本1.1.1)源码中的RSA加解密算法实现分析
- termux python 打开摄像头_python+opencv 电脑调用手机的摄像头
- SpringBoot 整合 ElasticSearch 实现京东搜索(手把手带你完成一个 “前后端分离项目”)
- 《人性的弱点》(戴尔-卡耐基)读书小结
- 全国各地省市地区plist文件(数据跟微信的地区一致)
- 高德地图/腾讯地图地址转换经纬度
- 解读CUDA Compiler Driver NVCC - Ch.2 - Compilation Phases
- 不同版本的Fiddler功能说明