14天-01-集合框架
集合类出现:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组与集合类同是容器,有何不同?
数组长度是固定的,集合长度是可变的;数组中只可以存储基本数据类型,集合可以存储对象。
迭代器其实就是集合的取出元素的方式,用于循环遍历。
集合迭代器Iterator:
在集合中,把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。那么取出方式就被定义成了内部类。而每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容,判断和取出,那么就将这些共性抽取,这个就是Iterator,对外提供iterator();方法,hasNext();判断是否还有元素,next();获取下一个元素,remove();移除此元素。
Collection 接口 add,remove,contains,clear,iterator
List: 元素是有序的,元素可以重复,因为该集合体系有索引。
ArrayList:底层使用的是数组数据结构。特点:查询、修改操作很快,增加、删除慢。线程非同步
LinkList:底层使用的是链表数据结构。特点:增加、删除、修改操作快,查询慢。
Vector:底层使用的是数组数据结构。特点:线程同步,被ArrayList代替了。
Set: 元素是无序的(存入和取出的顺序不一致),元素不可以重复。
HashSet:底层使用的是哈希表数据结构。线程非同步。保证元素唯一性的原理:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法。
TreeSet:底层使用的是二叉树数据结构。保证元素唯一性的原理:比较compareTo方法return -1,0,1。可以对Set集合中的元素排序。
List:特有方法,凡是可以操作角标的方法都是该体系特有的方法。
增 add(index,element); addAll(index,Collection);
删 remove(index);
改 set(index,element);
查 get(index); subList(from,to); //包括开始,不包括结束元素 listIterator();
Listiterator:该接口只能通过List集合的listIterator()方法获取。
List集合特有的迭代器,ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModifyException异常。所以,在迭代器时,只能用迭代器的删取操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。如果想要其他操作如添加,修改等,就需使用其子接口:ListIterator
Vector:
枚举就是Vector特有的取出方式,其实枚举和迭代器是一样的,因为枚举的名称以及方法名称都过长,所以被迭代器取代了。Enumeration<E> elements()获取Vector枚举元素类似Iterator,hasMoreElements();//判断是否有下一个元素 nextElement();//获取下一个元素
LinkedList:
LinkedList特有方法:
addFirst(); addLast(); //添加元素
getFirst(); getLast(); //获取元素,不删除元素
removeFirst(); removeLast(); //删除元素,并获取元素。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了替代方法:
offerFirst(); offerLast(); //添加元素
peekFirst(); peekLast(); //获取元素,不删除元素。如果集合中没有元素,会返回null
pollFirst(); pollLast(); //删除元素,并获取元素。如果集合中没有元素,会返回null
List集合判断元素是否相同,依据元素的equals方法。
1 /* 2 使用LinkedList模拟一个堆栈和队列数据结构 3 堆栈:先进后出。队列:先进先出。 4 */ 5 //队列:先进先出 6 class Queue 7 { 8 private LinkedList link; 9 10 Queue() 11 { 12 link = new LinkedList(); 13 } 14 15 public void add(Object object) 16 { 17 link.addFirst(object); 18 } 19 20 public Object get() 21 { 22 return link.removeLast(); 23 } 24 25 public boolean isEmpty() 26 { 27 return link.isEmpty(); 28 } 29 } 30 //堆栈:先进后出 31 class Stack 32 { 33 private LinkedList link; 34 35 Stack() 36 { 37 link = new LinkedList(); 38 } 39 40 public void add(Object object) 41 { 42 link.addFirst(object); 43 } 44 45 public Object get() 46 { 47 return link.removeFirst(); 48 } 49 50 public boolean isEmpty() 51 { 52 return link.isEmpty(); 53 } 54 }
HashSet:
HashSet是如何保证元素唯一性的?
是通过元素的两个方法,hashCode和equals来完成。如果元素的hashCode值相同,才会判断equals是否为true;如果元素的hashCode值不同,不会调用equals。
注意:对于HashSet判断元素是否存在,以及添加,删除等操作,依赖的方法是元素的hashCode和equals方法,如果添加操作判断元素已经存在,则丢弃要添加的元素。List判断元素是否相同是用equals方法。
注:排序时,当主要条件相同时,一定要判断一下次要条件。
TreeSet: 比较compareTo方法return -1,0,1,-1是比自身小,0是相同,1是比自身大。
TreeSet排序的第一种方式,是让元素自身具备比较性,元素需要实现Comparabel接口,覆盖compareTo方法。这种方式也成为元素的自然顺序或者叫做默认顺序。
TreeSet排序的第二种方式,当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。在集合初始化时,就传入特定比较方式的比较器。当两种排序方式都存在时,以比较器为主。
TreeSet存储自定义对象示例:
1 import java.util.*; 2 /* 3 需求:往TreeSet集合中存储自定义对象Person,并按照Person的age进行排序。 4 */ 5 class Demo 6 { 7 public static void main(String[] args) 8 { 9 TreeSet array = new TreeSet(); 10 array.add(new Person("test2", 12)); 11 array.add(new Person("test4", 14)); 12 array.add(new Person("test1", 11)); 13 array.add(new Person("test4", 16)); 14 array.add(new Person("test3", 13)); 15 Iterator it = array.iterator(); 16 while (it.hasNext()) 17 { 18 Object temp = it.next(); 19 Person p = (Person) temp; 20 sop("array element is " + p.name + " " + p.age); 21 } 22 sop("********Game over******"); 23 } 24 25 public static void sop(Object obj) 26 { 27 System.out.println(obj); 28 } 29 } 30 //Comparable该接口强制要求实现比较方式 31 class Person implements Comparable 32 { 33 public String name; 34 public int age; 35 36 Person(String name, int age) 37 { 38 this.name = name; 39 this.age = age; 40 } 41 42 public int compareTo(Object obj) 43 { 44 if (!(obj instanceof Person)) 45 { 46 throw new RuntimeException(obj + " is not a Person Object"); 47 } 48 Person p = (Person) obj; 49 if (this.age > p.age) 50 { 51 return 1; 52 } 53 if (this.age == p.age) 54 { 55 return this.name.compareTo(p.name); 56 } 57 return -1; 58 } 59 }
15天-06-集合框架-泛型
泛型:即“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。JDK1.5版本出现的新特性,用于解决安全问题,是一个类型安全机制。
好处:1.将运行时期出现的问题ClassCastException转移到了编译时期。方便于程序员解决问题,让运行时问题更少,更安全。
2.避免了强制转换。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候使用泛型?
通常在集合框架中很常见,只要见到<>就可以使用泛型。其实<>就是用来接收类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
泛型方法定义的泛型,在整个方法中有效。如果不同方法操作不同类型,可以将泛型定义在方法上。
注:静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
泛型的限定:?通配符,也可以理解为占位符。
<? extends T>: 可以接收T类型或者T的子类型,上限;
<? super E>: 可以接收E类型或者E的父类型,下限。
16天-01-集合Map
Map HashTable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0,效率低。
HashMap:底层是哈希表数据结构,允许使用null键null值,该集合是线程非同步的。JDK1.2,效率高。
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
注:Map和Set很像,其实Set底层使用的就是Map集合。
Map集合:该集合存储键值对,一对一对存储,而且要保证键的唯一性
Map集合的取出原理:将map集合转成Set集合,再通过迭代器取出。
1.添加 putAll(Map<? extends K,? extends V> m)
put(K key,V value);//添加元素,添加时如果出现相同的键,那么后添加的值会覆盖原有键对应值,并put方法会返回被覆盖的值。如果没有相同的键,put方法返回null。
2.删除 clear(); remove();
3.判断 containsValue(Object); containsKey(Object key); isEmpty();
4.获取 get(Object key); //获取值 size();//获取Map集合键数量 values();//获取Map集合值集合
keySet();将map中所有的键存入到Set集合中,因为Set集合具备迭代器。以迭代方式取出所有的键,再根据get方法获取每一个键对应的值。
Set<Map.Entry<k,v>> entrySet(); 将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry,再通过Map.Entry中getKey和getValue获取键和值。
Map.Entry:其实Entry也是一个接口,它是Map接口中的一个内部static接口。
TreeMap获取字符串中字母出现的次数:
1 import java.util.*; 2 /* 3 需求:"fghjdadadlfczcdadfaf"获取该字符串中的字母出现的次数。打印:a(4),c(2)... 4 */ 5 class Demo{ 6 public static void main(String[] args) 7 { 8 //原始字符串 9 String sourceString = "fghjdadadlfczcdadfaf"; 10 char[] chs = sourceString.toCharArray(); 11 TreeMap<Character, Integer> result = new TreeMap<Character, Integer>(); 12 int length = chs.length; 13 for (int i = 0; i < length; i++) 14 { 15 char ch = chs[i]; 16 int temp = 0; 17 boolean flag = (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); 18 if (!flag) 19 { 20 continue; 21 } 22 Integer value = result.get(ch); 23 if (value != null) 24 { 25 temp = value; 26 } 27 value = value == null ? 1 : 1 + value; 28 result.put(ch, value); 29 } 30 sop("source string is: " + sourceString); 31 StringBuilder showResult = new StringBuilder(); 32 for (Iterator<Map.Entry<Character, Integer>> it = result.entrySet().iterator(); it.hasNext(); ) 33 { 34 Map.Entry<Character, Integer> temp = it.next(); 35 showResult.append(temp.getKey() + "(" + temp.getValue() + ") "); 36 } 37 sop("char statistics result:" + showResult); 38 sop("********Game over******"); 39 } 40 41 private static void sop(Object obj) 42 { 43 System.out.println(obj); 44 } 45 }
集合框架的工具类:主要提供对集合常用操作,里面都是静态方法。
Collections:
static <T> List<T> synchronizedList(List<T> list); //创建一个同步List集合对象,底层加锁调用List方法。
static void shuffle(List<?> list); //随机排序集合
Arrays:用于操作数组的工具类。排序,查找,反转
asList:将数组变成List集合。优点:可以使用集合的思想和方法来操作数组中的元素。
注:将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。否则有UnsupportedOperationException
如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的一个元素存在。
ArrayList转成数组:<T> T[] toArray(T[] a);
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。
当指定类型的数组长度大于了集合的size,就不会新创建数组,而是使用传递进来的数组。所以创建一个大小是size的数组最优。
为什么要将集合变成数组? 为了限定对元素的操作,不需要进行增删了。
高级for循环:格式 for(数据类型 变量 ; 被遍历的集合(Collection)或者数组){ }
对集合进行遍历,只能获取集合元素,但是不能对集合进行操作。
迭代器除了遍历,还可以进行remove操作集合中的元素。
如果是用ListIterator,还可以在遍历过程中进行增删改查的操作。
传统for与高级for有什么区别?
高级for有一个局限性,必须有被遍历的目标。
建议在遍历数组的时候,还是用传统for,因为传统for可以定义脚标。
JDK1.5版本新特性
可变参数:(形参类型... param)其实就是一种数组参数的简写形式,不用每一次都手动的建立数组对象,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。
注:在使用可变参数时,可变参数一定要定义在参数列表最后面。
静态导入(StaticImport): import static java.lang.System.*; //导入System类中的所有静态成员。
当类名重名时,需要指定具体的包名。当方法重名时,需要指定具体所属的对象或者类。
18天-01-其他对象System类:描述系统的一些信息。System类中的方法和属性都是静态的。
PrintStream out:标准输出,默认是控制台
InputStream in:标准输入,默认是键盘
String getProperty(String key);//获取系统属性信息
String setProperty(String key, String value);//设置系统属性
18天-02-其他对象Runtime类:每个Java应用程序都有一个Runtime类的实例,是应用程序与运行应用程序的环境进行交互的接口。
该类并没有提供构造函数,说明不可以new对象,那么会直接想到该类中的方法都是静态的。发现该类中还有非静态方法,说明该类肯定会提供方法获取本类对象,而且该方法是静态的并且返回值类型是本类类型。由此特点可以看出该类使用了单例设计模式完成。
Runtime getRuntime();获取Runtime类。
Process exec(String command);执行命令,返回一个Process进程,可用于启动外部程序。
18天-03-其他对象Date类:表示特定的瞬间,精确到毫秒。
SimpleDateFormat类是Date的格式化类,调用format(Date date)方法格式化指定的Date对象。
18天-04-其他对象Calendar类:用于替换Date类,操作日期
static int DAY_OF_MONTH; 月中的天数
static int DAY_OF_WEEK; 周中的天数
calendar.set(year,2,1); //某一年的3月1日
calendar.add(Calendar.DAY_OF_MONTH,-1);//3月1日向前推一天就是2月最后一天。
18天-05-其他对象Math-Random类:
static double abs(double a);//求一个数字的绝对值
static double ceil(double a);//求大于一个数字的最小整数,向上取整。
static double floor(double a);//求小于一个数字的最大整数,向下取整。
static long round(double a);//求一个小数四舍五入的整数。
static double pow(double a, double b);//求a的b次幂,求幂。
static double random();//随机数,返回带正号的double值,[0,1)
Random r=new Random();r.nextInt(10)+1;//获取一个[1~10)之间的随机数。