Map集合
该集合存储键值对,一对一对往里存,而且要保证键的唯一性。
1.添加
put(K key,V value)
putAll( Map<? extends K,? extends V> m )
2.删除
clear()
remove( Object key )
3.判断
containsValue( Object value )
containsKey( Object key )
4.获取
get( Object key )
size( )
value( )
entrySet( )
keySet( )
Map
|——HashTable:底层是哈希表数据结构,不可以存入null键和null值,该集合是线程同步的,效率低
|——HashMap:底层是哈希表数据结构,允许使用null键和null值,该集合是线程不同步的,将HashTable替代,效率高
|——TreeMap:底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序
和Set很像,其实,Set底层就是使用了Map集合。
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
class MapDemo
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
//添加元素,如果出现添加时,相同的键,那么后添加的值会覆盖原有键的对应值。
//put方法会返回被覆盖的值。
sop("put:"+map.put("01","zhangsan1"));
sop("put:"+map.put("01","lisi1"));
map.put("02","zhangsan2");
map.put("03","zhangsan3");
sop("containsKey:"+map.containsKey("022"));
sop("remove:"+map.remove("022"));
//可以通过get方法的返回值来判断一个键是否存在,通过返回null来判断。
sop("get:"+map.get("02"));
map.put("04",null);
sop("get:"+map.get("04"));
sop(map);
//获取Map集合中所有的值
Collection<String> coll = map.values();
sop(coll);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
Map集合的两种取出方式:
1.Set<k> keySet ,将Map中的所有键存入到Set集合,因为Set具备迭代器。
所以可以用迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
Map集合取出原理,将Map集合转成Set集合,再通过迭代器取出。
2.Set<Map.Entry<k,v>> entrySet:将Map集合中的映射关系存入到Set集合中,
而这个关系的数据类型就是:Map.Entry。
Entry其实就是Map中的一个static内部接口,为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值对的映射关系。
关系属于Map集合中的一个内部事务,而且该事物在直接访问Map集合中的元素。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapDemo2 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("02", "zhangsan");
map.put("01", "zhaoliu");
map.put("04", "lisi");
map.put("03", "wangwu");
//Map集合的第一种取出方式,keySet
Set<String> keySet = map.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext()){
String key = it.next();
String value = map.get(key);
System.out.println(key+"::"+value);
}
//Map集合的第二种取出方式,Map.Entry
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
while(iter.hasNext()){
Map.Entry<String, String> me = iter.next();
String key = me.getKey();
String value = me.getValue();
System.out.println(key+"::"+value);
}
}
}
Map集合练习1:
每一个学生都有对应的归属地。
学生Student,地址String
学生属性:姓名,年龄
注意:姓名和年龄相同视为同一个学生。
保证学生的唯一性。
学生Student,地址String
学生属性:姓名,年龄
注意:姓名和年龄相同视为同一个学生。
保证学生的唯一性。
思路:
1.描述学生
2.定义map容器,将学生作为键,地址作为值,存入。
3.获取map集合中的元素。
1.描述学生
2.定义map容器,将学生作为键,地址作为值,存入。
3.获取map集合中的元素。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapDemo3 {
public static void main(String[] args) {
HashMap<Student,String> hm = new HashMap<Student,String>();
hm.put(new Student("lisi1",21),"beijing");
//hm.put(new Student("lisi1",21),"tianjin");
hm.put(new Student("lisi2",22),"shanghai");
hm.put(new Student("lisi3",23),"nanjing");
hm.put(new Student("lisi4",24),"wuhan");
//第一种方式 keySet
Set<Student> keySet = hm.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext()){
Student key = (Student)it.next();
String value = hm.get(key);
System.out.println(key.getName()+":::"+key.getAge()+":::"+value);
}
System.out.println("------------------------------------------");
//第二种方式entrySet
Set<Map.Entry<Student, String>> entrySet = hm.entrySet();
Iterator<Map.Entry<Student, String>> iter = entrySet.iterator();
while(iter.hasNext()){
Map.Entry<Student, String> me = iter.next();
Student key = me.getKey();
String value = me.getValue();
System.out.println(key.getName()+":::"+key.getAge()+":::"+value);
}
}
}
//描述学生类,复写hashCode、equals、compareTo
class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public int hashCode(){
return this.name.hashCode()+this.age*37;
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){
throw new RuntimeException("传入的对象有误!");
}
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public int compareTo(Student stu){
int num = new Integer(this.age).compareTo(new Integer(stu.age));
if(num==0){
return this.name.compareTo(stu.name);
}
return num;
}
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;
}
}
TreeMap练习2:
需求:
对学生对象的年龄进行升序排序。
对学生对象进行姓名排序。
思路:
因为数据是以键值对形式存在的,
所以要使用可以排序的Map集合。TreeMap
对学生对象进行姓名排序。
思路:
因为数据是以键值对形式存在的,
所以要使用可以排序的Map集合。TreeMap
class MapTest2
{
public static void main(String[] args)
{
TreeMap<Student,String> tm = new TreeMap<Student,String>(new stuNameComparator());
tm.put(new Student("blisi3",23),"nanjing");
tm.put(new Student("lisi1",21),"beijing");
tm.put(new Student("alisi4",24),"wuhan");
tm.put(new Student("lisi1",21),"tianjin");
tm.put(new Student("lisi2",22),"shanghai");
Set<Map.Entry<Student,String>> entrySet = tm.entrySet();
Iterator<Map.Entry<Student,String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Student,String> me = it.next();
Student s = me.getKey();
String addr = me.getValue();
System.out.println(s+".."+addr);
}
}
}
class stuNameComparator implements Comparator<Student>
{
public int compare(Student s1,Student s2){
int num = s1.getName().compareTo(s2.getName());
if(num==0){
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
TreeMap练习3:
"dhsafkjdhasfjk"获取该字符串中的字幕出现的次数
希望打印结果:a(1)b(2)c(4)...
通过结果发现:每一个字母都有对应的次数,
说明字母和次数之间都有映射关系。
注意了,当发现有映射关系时,可以考虑Map集合。
因为Map集合中存放的就是映射关系。
什么时候使用Map集合呢?
当数据之间存在者映射关系时,就要先想Map集合。
思路:
1.将字符串转成字符数组,因为要对每一个字母进行操作
2.定义一个Map集合,因为打印结果的字母有顺序,所以使用TreeMap集合。
3.遍历字符数组。
将每一个字母作为键去查Map集合,
如果返回null,将该字母和1存入到Map集合中。
如果返回不是null,说明该字母在Map集合中已经存在并有对应次数。
那么就获取该次数并进行自增,然后将该字母和自增后的次数存进Map集合中,覆盖掉原有值。
4.将Map集合中的数据变成指定的字符串形式返回。
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MapDemo4 {
public static void main(String[] args) {
String s = printChar("dacssdabac");
System.out.println(s);
}
public static String printChar(String str){
//转成字符数组
char[] ch = str.toCharArray();
//定义一个TreeMap集合,方便排序
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
//到Map集合中查找,如果ch[x]存在,那么存入ch[x]、1;如果不存在,那么存入ch[x]、value
for(int x=0;x<ch.length;x++){
Integer value = tm.get(ch[x]);
if(value==null){
tm.put(ch[x], 1);
}else{
value = value + 1;
tm.put(ch[x], value);
}
}
//取出Map中的元素,并按指定的格式存入到StringBuilder中
StringBuilder sb = new StringBuilder();
Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Character, Integer> me = it.next();
Character key = me.getKey();
Integer value = me.getValue();
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
集合框架工具类
Collections:集合框架的工具类,里面定义的都是静态方法。
Collections和Collection有什么区别?
Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
它有两个常用的子接口:
List:存放在List集合中的元素都有定义索引,有序,可以重复。
Set:元素不可以重复,无序。
Collections是集合框架的一个工具类,该类中的方法都是静态的,
提供的方法中有可以对List集合进行排序的,二分查找等方法。
通常常用的集合都是线程不安全的,因为要提高效率,
如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
import java.util.*;
class CollectionsDemo
{
public static void main(String[] args)
{
binarySearchDemo();
//maxDemo();
//sortDemo();
}
//二分查找法
public static void binarySearchDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
/*自然排序,并获取角标值
Collections.sort(list);
sop(list);
int index = Collections.binarySearch(list,"aaa");
sop(index);
*/
/*自然排序,演示二分查找原理
Collections.sort(list);
sop(list);
int index = halfSearch(list,"aaaa");
sop(index);
*/
//自定义比较器,演示二分查找原理
Collections.sort(list,new StrLenComparator());
sop(list);
int index = halfSearch2(list,"kkkkk",new StrLenComparator());
sop(index);
}
//二分查找原理方法
public static int halfSearch(List<String> list,String key){
int max,min,mid;
min = 0;
max = list.size()-1;
while(min<=max){
mid = (min+max)/2;
String str = list.get(mid);
int num = str.compareTo(key);
if(num>0){
max = mid - 1;
}else if(num<0){
min = mid + 1;
}else{
return mid;
}
}
return -min-1;
}
//二分查找原理方法(加入比较器)
public static int halfSearch2(List<String> list,String key,Comparator<String> comp){
int max,min,mid;
min = 0;
max = list.size();
while(min<=max){
mid = (min+max)/2;
String str = list.get(mid);
int num = comp.compare(str,key);
if(num>0){
max = mid - 1;
}else if(num<0){
min = mid + 1;
}else{
return mid;
}
}
return -min-1;
}
//获取集合的最大元素
public static void maxDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
sop(list);
//按照元素的自然顺序获取最大值。--zz
//Collections.sort(list);
//sop(list);
//String max = Collections.max(list);
//按照自定义比较器的比较顺序进行排序。--kkkkk
Collections.sort(list,new StrLenComparator());
sop(list);
String max = Collections.max(list,new StrLenComparator());
sop(max);
}
//排序方法
public static void sortDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
sop(list);
//按照元素的自然顺序排序。
//Collections.sort(list);
//sop(list);
//按照自定义比较器进行排序。
Collections.sort(list,new StrLenComparator());
//Collections.swap(list,1,2);
sop(list);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2){
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0){
return s1.compareTo(s2);
}
return num;
}
}
Collections练习2:
import java.util.*;
class CollectionsDemo2
{
public static void main(String[] args)
{
//shuffleDemo();
//orderDemo();
//replaceAllDemo();
fillDemo();
}
//随机排列
public static void shuffleDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
sop(list);
//对list随机排序
Collections.shuffle(list);
sop(list);
}
//对集合进行自定义比较顺序的逆反转。
public static void orderDemo(){
TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator()));
ts.add("abcde");
ts.add("aaa");
ts.add("k");
ts.add("cc");
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
//使用另一个值替换列表中出现的所有某一指定值
//反转List集合
public static void replaceAllDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
sop(list);
Collections.replaceAll(list,"aaa","pp");
sop(list);
Collections.reverse(list);
sop(list);
}
/*
练习:fill方法可以将list集合中所有元素替换成指定元素。
将list集合中部分元素替换成指定元素。
*/
public static void fillDemo(){
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
sop(list);
Collections.fill(list,"pp");
sop(list);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2){
if(s1.length()>s2.length()){
return 1;
}else if(s1.length()<s2.length()){
return -1;
}else{
return s1.compareTo(s2);
}
}
}
Arrays工具类练习:
Arrays:用于操作数组的工具类。
里面都是静态方法。
asList:将数组变成list集合。
*/
import java.util.*;
class ArraysDemo
{
public static void main(String[] args)
{
/*数组变字符串
int[] arr = {2,3,5};
System.out.println(Arrays.toString(arr));
*/
String[] arr = {"abc","ee","ggg"};
/*
把数组变成list集合有什么好处?
可以使用集合的思想和方法来操作数组中的元素。
注意:将数组变成集合,不可以使用集合的增删方法。
因为数组的长度是固定的。
eg:
contains()
get()
indexOf()
subList();
如果你增删,那么会发生UnsupportedOperationException。
*/
List<String> list = Arrays.asList(arr);
//sop("contains:"+list.contains("ee"));
//list.add("qq");不能增加,报UnsupportedOperationException。
/*看现象---li打印出来的是哈希值,为什么?
sop(list);
int[] arr1 = {2,4,5};
List li = Arrays.asList(arr1);
sop(li);
*/
//这里打印的则是[2,4,5]
/*
原因:如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成了集合中的元素。
如果数组中的元素是基本数据类型,那么会将该数组作为集合中的元素存在。
*/
sop(list);
Integer[] arr1 = {2,4,5};
List<Integer> li = Arrays.asList(arr1);
sop(li);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
集合变成数组
1.指定类型的数组到底要定义多长呢?
当指定类型的数组长度大于了集合的长度,那么该方法内部会创建一个新的数组,长度为集合的size。
当指定类型的数组长度小于了集合的size,就不会新创建数组,而是使用传递进来的数组。
2.为什么要将集合变数组?
为了限定对元素的操作,不需要进行增删。
当指定类型的数组长度大于了集合的长度,那么该方法内部会创建一个新的数组,长度为集合的size。
当指定类型的数组长度小于了集合的size,就不会新创建数组,而是使用传递进来的数组。
2.为什么要将集合变数组?
为了限定对元素的操作,不需要进行增删。
/*
集合变数组。
Collection接口中的toArray方法
*/
import java.util.*;
class CollectionToArray
{
public static void main(String[] args)
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
String[] arr = al.toArray(new String[al.size()]);
System.out.println(Arrays.toString(arr));
}
}
高级for循环
格式:
for( 数据类型 变量名:被遍历的集合(Collection)或者数组){ }
局限性:对集合进行遍历,只能获取集合元素,但是不能对集合进行操作
迭代器除了遍历,还可以进行remove集合中的元素的动作,
如果使用了ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
高级for与传统for有什么区别呢?
高级for有一个局限性,必须有被遍历的目标,
建议在遍历数组时,还是希望使用传统for,因为传统for可以定义角标。
import java.util.*;
class ForEachDemo
{
public static void main(String[] args)
{
/*遍历集合
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
for(String s:al){
System.out.println(s);
}*/
//System.out.println(al);
/*遍历数组
int[] arr = {3,5,1};
for(int x=0;x<arr.length;x++){
System.out.print(arr[x]+",");
}
System.out.println();
for(int i:arr){
System.out.print(i+",");
}*/
//遍历Map集合
HashMap<Integer,String> hm = new HashMap<Integer,String>();
hm.put(1,"a");
hm.put(2,"b");
hm.put(3,"c");
Set<Integer> keySet = hm.keySet();
for(Integer i:keySet){
System.out.println(i+":"+hm.get(i));
}
for(Map.Entry<Integer,String> me:hm.entrySet()){
System.out.println(me.getKey()+"----"+me.getValue());
}
}
}
JDK1.5新特性:可变参数
在使用时注意:
可变参数一定要定义在参数列表的最后面。
可变参数一定要定义在参数列表的最后面。
class ParamMethodDemo
{
public static void main(String[] args)
{
/*方法一:
show(3,4);
show(3,4,5);
*/
/*方法二:
虽然少定义了多个方法,但是每次都要定义数组,作为实际参数。
int[] arr = {3,4};
show(arr);
int[] arr1 = {3,4,5};
show(arr1);
*/
/*
方法三:可变参数
其实就是上一种数组参数的简写形式,不用每一次都手动的建立数组对象。
只要将要操作的元素作为参数传递即可,隐式的将这些参数封装成了数组。
*/
show("haha",2,3,4);
//show(2,3,4,"hehe"); 错误,可变参数必须放在最后面。
}
//方法三:
public static void show(String str,int... arr){
System.out.println(arr.length);
}
/*
想调用含不同参数的方法,但是又想简化代码,尝试二:
//虽然不用重复写方法,但是每次调用都要定义数组,也很繁琐。
public static void show(int[] arr){
}
*/
/*
想调用含不同参数的方法,但是又想简化代码,尝试一:
//代码太繁琐,每次都要重复写方法。
public static void show(int a,int b){
System.out.println(a+","+b);
}
public static void show(int a,int b,int c){
System.out.println(a+","+b+","+c);
}
*/
}
JDK1.5新特性:静态导入
StaticImport 静态导入。
当类名重名时,需要指定具体的包名。
当方法重名时,需要指定具备所属的对象或者类。
eg:
import java.util.*;
import static java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员。
import static java.util.Collections.*;
packa/Demo.class
packb/Demo.class
import packa.*;
import packb.*;
当类名重名时,需要指定具体的包名。
当方法重名时,需要指定具备所属的对象或者类。
eg:
import java.util.*;
import static java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员。
import static java.util.Collections.*;
packa/Demo.class
packb/Demo.class
import packa.*;
import packb.*;
import static java.lang.System.*;//导入了System类中所有静态成员。
class StaticImport
{
public static void main(String[] args)
{
out.println("haha");
int[] arr = {3,1,5};
sort(arr);
int index = binarySearch(arr,1);
out.println(Arrays.toString(arr));
System.out.println("Index="+index);
ArrayList al = new ArrayList();
al.add(1);
al.add(3);
al.add(2);
out.println(al);
sort(al);
out.println(al);
}
}
System类
System:类中的方法和属性都是静态的。
out:标准输出,默认是控制台
in:标准输入,默认是键盘
描述系统一些信息。
获取系统属性信息:Properties getProperties( );
import java.util.*;
class SystemDemo
{
public static void main(String[] args)
{
Properties prop = System.getProperties();
/*
因为Properties是Hashtable的子类,也就是Map集合的一个子类对象。
那么可以通过Map的方法取出该集合中的元素。
该集合中存储的都是字符串,没有泛型定义。
*/
//如何在系统中自定义一些特有信息呢?
System.setProperty("myKey","myValue");
//获取指定属性信息。
String value = System.getProperty("os.name");
System.out.println(value);
//可不可以在jvm启动时,动态加载一些属性信息呢?
//java -Dhaha=qqqqqq SystemDemo.java
String v = System.getProperty("haha");
System.out.println("v="+v);
/*获取所有属性信息
for(Object obj:prop.keySet()){
String value = (String)prop.get(obj);
System.out.println(obj+"::"+value);
}*/
}
}
Runtime对象
该类中并没有提供构造函数。
说明不可以new对象,那么会直接想到该类中的方法都是静态的,
但是发现该类中还有非静态方法,说明该类肯定提供了方法获取本类对象,
而且该方法是静态的,并且返回值类型是本类对象。
由这个特点可以看出,该类使用了单例设计模式完成。
Date对象
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
//将模式封装到SimpleDateFormat对象中
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
//调用format方法让模式格式化指定Date对象
String time = sdf.format(d);
System.out.println(time);
long l = System.currentTimeMillis();
Date d1 = new Date(l);
System.out.print(d1);
}
}
Calendar对象
import java.util.*;
import java.text.*;
class CalendarDemo
{
public static void main(String[] args)
{
Calendar c = Calendar.getInstance();
String[] mons = {"一月","二月","三月","四月"
,"五月","六月","七月","八月"
,"九月","十月","十一月","十二月"};
String[] weeks = {"","星期日","星期一","星期二","星期三",
"星期四","星期五","星期六"};
int index = c.get(Calendar.MONTH);
int index1 = c.get(Calendar.DAY_OF_WEEK);
sop(c.get(Calendar.YEAR)+"年");
//sop(c.get(Calendar.MONTH)+"月");
sop(mons[index]);
sop(c.get(Calendar.DAY_OF_MONTH)+"日");
//sop("星期"+c.get(Calendar.DAY_OF_WEEK));
sop(weeks[index1]);
/*
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年");
String time = sdf.format(d);
System.out.println(time);*/
}
public static void sop(Object obj){
System.out.println(obj);
}
}