集合(上)
一、Collection
1.1、集合的概述
根據面向對象的思想,數據多了就用對象來存儲;對象多了,就用數組或者集合來存儲。數組雖然可以存儲對象,但長度不可變,類型固定,有很大的侷限性;集合長度可變,類型不固定。正因爲集合克服了數組的侷限性,所以對象的存儲大多數存在集合中。
因爲底層的數據結構不同,所以集合可以分爲很多種,但根據共性抽取的原則,可以把多種不同的集合不斷地向上抽取。Collection接口就是不斷抽取而成的,它可以分爲List和Set兩大接口。
List:元素有序,元素可以重複,有索引;
Set:元素無序(存入取出無序),元素不可重複。
Collection中有抽取了一些共性的方法,例如:add(Object obj):添加元素到集合中。
注意:集合中存儲的都是對象的引用,也就是地址,並非對象本身。Java中的集合框架如下圖所示:
迭代器:迭代器就是取出集合元素的方式。由於每個集合內部的數據結構不同,取出方式也就有所不同,但該怎麼取出元素,只有集合本身最清楚,所以迭代器應該定義在集合的內部,成爲內部類或者內部接口。但每種集合元素的取出方式都有一些共性,比如:內容判斷、取出等,那麼就將這些共性抽取形成一個接口:Iterator。
在java中,形成了Iterator接口後,取出不同集合的元素就在不同集合的內部實現;
那麼該如何獲取取出對象呢?通過對外提供的方法iterator()即可,這就是迭代器的基本原理。
二、List
List是Collection接口中的一個重要子接口,實現List接口的子類有很多,但比較重要的有Vector、ArrayList和LinkedList三個,下面主要介紹的也就是這三個。
ArrayList:底層的數據結構是數組,查詢速度快,但增刪操作稍慢,線程不同步。
LinkedList:底層的數據結構是鏈表,查詢速度稍慢,但增刪操作很快,線程不同步。
Vector:底層的數據結構是數組,線程同步,已經被ArrayList替代。
List接口中,有自己特有的方法,注意:凡是可以操作角標的方法都是該體系特有的方法。
增:add(index,element); addAll(index,Collection);
刪:remove(index);
改:set(index,element);
查:get(index);SubList(from,to);ListIterator()。
List集合特有的迭代器:ListIterator。ListIterator是Iterator的子接口。
在迭代時,不可以通過集合對象的方法操作集合中的元素,因爲會發生異常。所以在迭代時,只能用迭代的方式操作元素,可是Iterator中的方法是有限的,只能對元素進行判斷、取出、刪除等操作。
如果想進行其他的操作如添加、修改等,必須使用ListIterator,該接口只能通過List集合中的ListIterator()方法獲取。
LinkList特有方法:
addFirst();addlast();添加元素;
getFirst();getLast(); 獲取但不刪除;
removeFirst();removeLast():獲取但刪除。
JDK1.6出現了替代方法:
offerFirst();offerLast();添加元素;
peekFirst();peekLast()獲取但不刪除;
pollFirst();pollLast()獲取但刪除。
在List集合中,判斷元素是否相同,調用的是元素的equals()方法;remove(),contains()等方法的底層也是調用了equals()方法。
注意:List集合中開發多用ArrayList,因爲集合中一般都是查詢的多。
下面代碼體現:
1、將自定義的對象作爲元素存到ArrayList集合中,並去除重複的元素
package itheima.day14;
import java.util.ArrayList;
import java.util.Iterator;
//需求:
// 將自定義對象作爲元素存到ArrayList集合中,並去除重複元素
// 比如:人對象,同姓名同年齡,視爲同一個人
public class ArrayListTest2 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
// 添加元素
al.add(new Person("zhangsan",15));
al.add(new Person("zhangsan1",16));
al.add(new Person("zhangsan2",17));
al.add(new Person("zhangsan1",16));
al = singleElement(al);
// 通過迭代器的方式取出集合中的元素
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
Person p = (Person)obj;
sop(p.getName()+"::::"+p.getAge());
}
}
private static ArrayList singleElement(ArrayList al) {
// 定義一個臨時容器
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!newAl.contains(obj))//是否包含
newAl.add(obj);
}
return newAl;
}
public static void sop(Object obj){
System.out.println(obj);
}
}
//人
class Person{
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
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;
}
// List集合判斷元素是否相同,依據的是元素的equals方法。
// remove(),contains()方法的底層也是調用了equals方法.
// 必須覆蓋Object中的equals方法,根據自定義的方式判斷兩個元素是否相同
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.name .equals(p.name) && this.age == p.age;
}
}
2、使用LinkedList模擬一個堆棧或者隊列數據結構
package itheima.day14;
import java.util.LinkedList;
//使用LinkedList模擬一個堆棧或者隊列數據結構*/
//堆棧:先進後出,如同杯子
// 隊列:先進先出:如同水管
public class LinkedListTest {
public static void main(String[] args) {
DuiLie dl = new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull()){
sop(dl.myGet());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
//封裝一個隊列的類
class DuiLie{
// 底層封裝一個鏈表,改造
private LinkedList link;
DuiLie(){
link = new LinkedList();
}
public void myAdd(Object obj){
link.addFirst(obj);
}
public Object myGet(){
return link.removeLast();//隊列:先進先出
// return link.removeFirst();//如果是堆棧的話,就後進先出
}
public boolean isNull(){
return link.isEmpty();
}
}
三、Set
Set中的元素無序(存入和取出無序),元素不可以重複;Set是Collection接口中一個重要的子接口;實現Set接口的子類有很多,但比較重要的有HashSet、TreeSet兩個。
HashSet:底層數據結構是哈希表。HashSet通過調用元素自身的hashCode()、equals()方法來保證元素的唯一性。
如果元素的hashCode()返回的值不同,則直接認爲兩個元素不是同一個元素;否則,繼續判斷元素的equals()方法,如果返回值是false,則認爲兩個元素不是同一個元素;返回值爲true,則認爲兩個元素是同一個元素,注意:若哈希值不一樣,不會繼續判斷equals()方法。
所以:如果自定義的對象要存儲到HashSet集合中,必須覆蓋對象自身的hashCode()方法和equals()方法。
TreeSet:HashSet集合可以保證元素的唯一性,但不能保證元素的有序性;而TreeSet集合既可以保證元素的唯一性,也可以保證元素在集合中存儲的有序性。
TreeSet保證元素有序性有兩種方式:讓元素自身基本具備比較性、讓TreeSet集合本身具備比較性。
1、讓元素自身具備比較性:Copareable接口可以讓元素具備比較性,實現該接口的類必須實現CompareTo()方法;所以,要想讓元素自身具備比較性,需要實現Comparable接口,複寫compareTo方法,即可。
2、讓TreeSet集合自身具備比較性:當元素自身不具備比較性時,或者具備的比較性不是所需要的,這時就需要讓TreeSet具備比較性。可以定義一個類,實現Comparator接口,並且覆蓋compare()方法,稱之爲比較器;然後將比較器對象作爲參數傳遞給TreeSet集合的構造函數,即可。
TreeSet集合底層數據結構是二叉樹,當元素進入二叉樹時,可以減少比較次數,提高效率。
下面代碼體現:
1、往HashSet集合中存入自定義對象
package itheima.day14;
import java.util.HashSet;
import java.util.Iterator;
//往HashSet集合中存入自定義對象
// 人:姓名和年齡相同,那麼視爲同一個對象
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
// 添加元素
hs.add(new Person1("a1",12));
hs.add(new Person1("a2",13));
hs.add(new Person1("a3",14));
hs.add(new Person1("a1",12));
hs.add(new Person1("a4",15));
boolean yes =hs.contains(new Person1("a1",12));
System.out.println(yes);
// 迭代器的=方式取出元素
Iterator it = hs.iterator();
while(it.hasNext()){
Person1 p = (Person1)it.next();
System.out.println(p.getName()+"::::"+p.getAge());
}
}
}
//人
class Person1{
private String name;
private int age;
Person1(String name,int age){
this.name = name;
this.age = age;
}
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;
}
// 爲了讓能夠存入HashSet集合中,元素自身必須覆蓋hashCode()函數
public int hashCode(){
return name.hashCode()+age*23;//哈希值按照本類的屬性進行計算,更合理
}
// 爲了讓能夠存入HashSet集合中,元素自身必須覆蓋equals()函數
public boolean equals(Object obj){
if(!(obj instanceof Person1))
throw new RuntimeException("哥們,類型錯誤啦");
Person1 p = (Person1)obj;
// 如果姓名、年齡相同,視爲同一個人
return this.name .equals(p.name) && this.age == p.age;
}
}
2、往TreeSet集合中存儲自定義對象學生,按照學生的年齡進行排序
package itheima.day15;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
//需求:
// 往TreeSet集合中存儲自定義對象學生,按照學生的年齡進行排序
public class TreeSetDemo {
public static void main(String[] args) {
// new一個比較器對象作爲參數傳給構造函數,讓集合自身具備比較性
// TreeSet ts = new TreeSet(new MyCompare());
// 根據元素自身的排序方式進行排序
TreeSet ts = new TreeSet();
// 添加元素
ts.add(new Student("zhangsan1",23));
ts.add(new Student("zhangsan611",23));
ts.add(new Student("zhangsan2",24));
ts.add(new Student("zhangsan4",25));
ts.add(new Student("zhangsan0",23));
// 通過迭代器方式取出元素
Iterator it = ts.iterator();
while(it.hasNext()){
Student stu = (Student)(it.next());
System.out.println(stu.getName()+":::::"+stu.getAge());
}
}
}
//學生的類
class Student implements Comparable//該接口強制學生對象具有比較性
{
private String name;
private int age;
Student(String name,int age){
this.name = name;
this.age = age;
}
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;
}
// 爲了存入TreeSet集合中,可以讓元素自身具備比較性
public int compareTo(Object obj){
if(!(obj instanceof Student))
throw new RuntimeException("不是學生對象!!!");
Student s = (Student)obj;
// 按照年齡排序,年齡相同時,按照姓名的自然順序比較
if(this.age>s.age)
return 1;
if(this.age <s.age)
return -1;
return this.name.compareTo(s.name);
}
}
//讓TreeSet集合具備比較性,定義一個比較器
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2){
if(!(o1 instanceof Student)|| !(o2 instanceof Student))
throw new RuntimeException("不是學生類!!!");
Student s1 =(Student)o1;
Student s2 = (Student)o2;
// 按姓名的自然順序排序,當姓名相同時,按年齡排序
int num = s1.getName().compareTo(s2.getName());
if(num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
3、按照字符串長度進行排序
package itheima.day15;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
//練習:按照字符串長度進行排序
//字符串自身具備的比較性時按照自然順序比較的,不是我們想要的,
// 所以,必須要讓TreeSet集合自身具備比較性
public class TreeSetTest {
public static void main(String[] args) {
// 讓TreeSet集合自身具備比較性,傳比較器給構造函數
TreeSet ts = new TreeSet(new StrLenComparator());
// 添加元素
ts.add("abcdef");
ts.add("abcde");
ts.add("abcd");
ts.add("a");
ts.add("abc");
ts.add("abd");
// 取出元素
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
//定義一個比較器
class StrLenComparator implements Comparator
{
// 覆蓋該方法,具有比較性
public int compare(Object o1,Object o2){
String s1 = (String)o1;
String s2 = (String)o2;
// 按照自然順序進行排序,若長度相同,則按照字符串的自然比較順序排序
if(s1.length()>s2.length())
return 1;
if(s1.length()<s2.length())
return -1;
return s1.compareTo(s2);
}
}
四、泛型
泛型:泛型是JDK1.5版本以後出現的新特性,是一種類型安全機制,專門用於解決安全問題;泛型常常出現在集合框架中。
好處1:集合中可以存儲任意類型的元素,也就是說一個集合中可以存儲兩個或者以上不同類型的元素,但操作類型的方法底層在調用不同類型元素的方法時,往往會出現問題;所以:程序員必須主觀控制存入集合中的類型,往往編譯能通過,但運行時會出現ClassCastException異常。泛型的出現,可以將運行時期出現的ClassCastException轉移到了編譯時期,方便於程序員解決問題,讓運行時問題減少,安全。
好處2:避免了強制類型轉換帶來的麻煩。
泛型格式:通過<>來定義要操作的引用類型,當使用集合時,將集合中要存儲的類型寫到<>中即可。
泛型的定義:當集合中要操作的引用數據類型不確定時,早期定義Object來完成擴展,現在定義泛型來完成擴展。
定義在類上的泛型,在整個類中有效,稱之爲:帶泛型的類。
定義在方法上的泛型,在整個方法體中有效,稱之爲:帶泛型的方法。
注意:靜態方法不可以訪問類上定義的泛型,如果靜態方法操作的應用數據類型不確定,可以將泛型定義在方法上。
泛型的限定:
?:通配符,也可以理解爲佔位符;
?extends E:可以接收E類型或者E的子類型,上限;
?super E:可以接收E類型或者E的父類型,下限。
下面代碼體現:
1、演示泛型類、泛型方法、靜態泛型方法
package itheima.day15;
//泛型類,泛型方法,靜態泛型方法的演示
public class GenericDemo4 {
public static void main(String[] args) {
Demo<String> d = new Demo<String>();
d.show("haha");
d.print_1(new Integer(4));
d.method(new Double(153.652));
}
}
//類型不確定,定義帶泛型的類
class Demo<T>{
// 類的泛型在類中的成員方法上有效
public void show(T t){
System.out.println("Class Generic show::"+t);
}
// 方法上要操作的類型不確定,定義帶泛型的方法
public <Q> void print_1(Q q){
System.out.println("Method Generic show:::"+q);
}
// 靜態方法不可以使用類上的泛型,帶泛型的靜態方法
public static <W> void method(W w){
System.out.println("Generic static method show:::"+w);
}
}
2、上限的使用,舉例說明
package itheima.day15;
import java.util.ArrayList;
import java.util.Iterator;
//泛型的上限,舉例說明
public class GenericDemo6 {
public static void main(String[] args) {
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
al.add(new Person("abc4"));
// printColl(al);
ArrayList<Student2> al1 = new ArrayList<Student2>();
al1.add(new Student2("abc---1"));
al1.add(new Student2("abc---2"));
al1.add(new Student2("abc---3"));
al1.add(new Student2("abc---4"));
// printColl(ArrayList<? extends Person> al),Student2繼承Person,上限
printColl(al1);
}
// ? extends E:可以接收E類型或者E的子類型,上限
public static void printColl(ArrayList<? extends Person> al){
Iterator<? extends Person> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Person{
private String name;
Person(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name:::" + name ;
}
}
//學生
class Student2 extends Person implements Comparable<Person>//<? extends E>
{
public Student2(String name) {
super(name);
}
public int compareTo(Person s){
return this.getName().compareTo(s.getName());
}
}
3、下限的使用,舉例說明
package itheima.day15;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
//泛型的下限,舉例說明
public class GenericDemo8 {
public static void main(String[] args) {
// TreeSet(Comparator<? super E> comparator)
// E:泛型;Student3:參數化的泛型;Comparator<? super E>:意思是說:可以使用Student3父類的比較器
TreeSet<Student3> ts = new TreeSet<Student3>(new Comp());
// 添加元素
ts.add(new Student3("abc01"));
ts.add(new Student3("abc05"));
ts.add(new Student3("abc03"));
ts.add(new Student3("abc04"));
Iterator<Student3> it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
TreeSet<Worker1> ts1 = new TreeSet<Worker1>(new Comp());
// 添加元素
ts1.add(new Worker1("abc----01"));
ts1.add(new Worker1("abc----05"));
ts1.add(new Worker1("abc----03"));
ts1.add(new Worker1("abc----04"));
Iterator<Worker1> it1 = ts1.iterator();
while(it1.hasNext()){
System.out.println(it1.next().getName());
}
}
}
//比較器
class Comp implements Comparator<Person2>{
public int compare(Person2 s1,Person2 s2){
return s1.getName().compareTo(s2.getName());
}
}
//人
class Person2{
private String name;
Person2(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//學生類,並繼承於人
class Student3 extends Person2{
Student3(String name){
super(name);
}
}
//工人類,並繼承於人
class Worker1 extends Person2{
Worker1(String name){
super(name);
}
}
五、Map
Map集合:Map不同於Collection,Collection中存儲的是單個元素,而Map中存儲的是鍵值對,一對一對往裏存儲,並要保證唯一性。
Map集合中的共性方法:
1、添加:put(K key, V value);putAll(Map<? extendsK, <? extends K> m);
2、刪除:clear();remove(Object key);
3、判斷:containsValue(Object value);containsKey(Objectkey);isEmpty();
4、獲取:get(Object key);size();value();entrySet();keySet()。
實現Map接口的子類有很多,但重要的有Hashtable、HashMap、TreeMap三個。下面主要介紹這三個。
Hashtable:底層是哈希表數據結構,不可以存入null鍵null值,線程同步,效率低;
HashMap:底層是哈希表數據結構,允許使用null值和null鍵,線程不同步,效率高;
TreeMap:底層是二叉樹數據結構,線程不同步,可以用於給map集合中的鍵進行排序。
Map集合的兩種取出方式:
1、keySet:將map中所有的鍵存入到Set集合,因爲Set具備迭代器,所以可以迭代方式取出所有的鍵,再通過get()方法獲取每一個鍵對應的值。
2、Set<Map.Entry<K,V>>:將map集合中的映射關係存入到set集合 中,而這個關係就是Map.Entey。Map.Entry:其實Entry也是 一個接口,它是Map接口中的一個內部接口。
總之:Set底層就是使用了Map集合;Map集合的取出原理:將map集合轉成set集合,再通過迭代器取出。
下面代碼體現:
1、存儲:學生Student對應一個地址String,姓名和年齡相同視爲同一個學生
package itheima.day16;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
//每個學生都有對應的歸屬地,學生Student,地址String,
// 學生屬性:姓名,年齡。注意:姓名和年齡相同視爲同一個學生。
// 要保證學生的唯一性
//思路:1描述學生
// 2、定義map容器,學生作爲鍵,地址作爲值,存入
// 3、獲取map集合中的元素
public class MapTest {
public static void main(String[] args) {
HashMap<Student,String> hm = new HashMap<Student,String>();
hm.put(new Student("zhangsan01",21), "北京");
hm.put(new Student("zhangsan05",25), "上海");
hm.put(new Student("zhangsan03",23), "廣州");
hm.put(new Student("zhangsan02",22), "南京");
hm.put(new Student("zhangsan06",26), "西安");
hm.put(new Student("zhangsan04",24), "桂林");
Set<Student> keySet = hm.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext()){
Student stu = it.next();
String addr = hm.get(stu);
System.out.println(stu+"::::"+addr);
}
}
}
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age){
this.name = name;
this.age = age;
}
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;
}
public String toString(){
return name+"::::"+age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public int compareTo(Student o) {
int num = new Integer(this.age).compareTo(new Integer(o.age));
if(num ==0)
return this.getName().compareTo(o.getName());
return num;
}
}
2、對學生對象的姓名進行升序排序
package itheima.day16;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import itheima.day16.Student;
//需求:對學生對象的姓名進行升序排序,。
// 因爲數據是以鍵值對形式存在,所以要使用可以排序的Map集合,TreeMap
public class MapTest2 {
public static void main(String[] args) {
TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator());
tm.put(new Student("zhangsan01",21), "北京");
tm.put(new Student("zhangsan005",25), "上海");
tm.put(new Student("zhangsan03",23), "廣州");
tm.put(new Student("zhangsan002",22), "南京");
tm.put(new Student("zhangsan06",26), "西安");
tm.put(new Student("zhangsan004",24), "桂林");
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 stu = me.getKey();
String addr = me.getValue();
System.out.println(stu+":::"+addr);
}
}
}
class StuNameComparator implements Comparator<Student>{
@Override
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;
}
}
3、獲取一個字符串中字母出現的次數,希望打印結果爲:a(1)b(2)...
package itheima.day16;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
//練習:獲取一個字符串中字母出現的次數,希望打印結果爲:a(1)b(2)...
//思路:1、將字符串轉換成字符數組,因爲要對每一個字母進行操作;
// 2、定義一個map集合,因爲打印結果的字母有順序,TreeMap;
// 3、遍歷字符數組,將每一個字母作爲鍵去查map集合,如果返回null,
// 存入;如果不是null,則對應的值加1。
// 4、將map集合中的數據變成指定的字符串形式返回。
public class MapTest3 {
public static void main(String[] args) {
String str ="54653gfghfhvfagfgafsdg";
System.out.println(charCount(str));
}
public static String charCount(String str){
char[] chs = str.toCharArray();
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
int count =0;
for(int x=0;x<chs.length;x++){
if(!(chs[x]>='a'&& chs[x]<='z' || chs[x]>='A'&&chs[x]<='Z'))//非字母,不存
continue;
Integer value = tm.get(chs[x]);
if(value!=null)
count = value;
count++;
tm.put(chs[x], count);
count=0;
}
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 ch = me.getKey();
Integer value = me.getValue();
sb.append(ch+"("+value+")");
}
return sb.toString();
}
}