1、TreeSet
1 package learn; 2 /* 3 * |--TreeSet 4 * 可以对Set集合排序 5 * 底层数据结构是二叉树 6 * 保证数据唯一性的依据:compareTo方法return 0;原序return 1; 7 * 8 * TreeSet排序的第一种方式:让元素子集具备比较性。元素需要实现compareTo接口,覆盖compareTo方法 9 * 也称为元素的自然顺序,默认顺序 10 * 11 * TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的 12 * 这是就需要让集合自身具备比较性 13 * 在集合初始化时就有了比较方式 14 * 15 * 16 * 需求:往TreeSet集合中存储自定义对象学生 17 * 想按照学生的年龄进行排序 18 * 19 * 排序时,主要条件一致,一定要判断次要条件! 20 * */ 21 import java.util.Iterator; 22 import java.util.TreeSet; 23 24 import learn.Student; 25 26 public class TreeSetDemo { 27 public static void main(String[] args) { 28 TreeSet ts=new TreeSet(); 29 ts.add(new Student("lisi02",22)); 30 ts.add(new Student("lisi007",20)); 31 ts.add(new Student("lisi09",19)); 32 ts.add(new Student("lisi08",19)); 33 // ts.add(new Student("lisi01",40)); 34 35 36 Iterator it=ts.iterator(); 37 while(it.hasNext()) 38 { 39 Student stu=(Student)it.next(); 40 System.out.println(stu.getName()+"..."+stu.getAge()); 41 } 42 } 43 } 44 45 class Student implements Comparable//该接口强制让学生具备比较性 46 { 47 private String name; 48 private int age; 49 Student(String name,int age) 50 { 51 this.name=name; 52 this.age=age; 53 } 54 public int compareTo(Object obj) 55 { 56 if(!(obj instanceof Student)) 57 throw new RuntimeException("不是学生对象"); 58 Student s =(Student)obj; 59 if(this.age>s.age) 60 return 1; 61 if(this.age==s.age) 62 return this.name.compareTo(s.name); 63 return -1; 64 } 65 public String getName() 66 { 67 return name; 68 } 69 public int getAge() 70 { 71 return age; 72 } 73 }
1.2、TreeSet的比较器
1 package learn2; 2 /* 3 * 当元素自身不具备比较性,或者具备的比较性不是所需要的 4 * 这时需要让容器自身具备比较性 5 * 定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数 6 * 当两种排序都存在时,以比较器为主 7 B"> 8 * 定义了一个类,实现Comparator接口,覆盖compare方法 9 * */ 10 import java.util.Comparator; 11 import java.util.Iterator; 12 import java.util.TreeSet; 13 14 class Student implements Comparable//该接口强制让学生具备比较性 15 { 16 private String name; 17 private int age; 18 Student(String name,int age) 19 { 20 this.name=name; 21 this.age=age; 22 } 23 public int compareTo(Object obj) 24 { 25 if(!(obj instanceof Student)) 26 throw new RuntimeException("不是学生对象"); 27 Student s =(Student)obj; 28 if(this.age>s.age) 29 return 1; 30 if(this.age==s.age) 31 return this.name.compareTo(s.name); 32 return -1; 33 } 34 public String getName() 35 { 36 return name; 37 } 38 public int getAge() 39 { 40 return age; 41 } 42 } 43 public class TreeSetDemo2 { 44 public static void main(String[] args) { 45 TreeSet ts=new TreeSet(new MyCompare()); 46 ts.add(new Student("lisi02",22)); 47 ts.add(new Student("lisi007",20)); 48 ts.add(new Student("lisi09",19)); 49 ts.add(new Student("lisi06",19)); 50 // ts.add(new Student("lisi01",40)); 51 52 53 Iterator it=ts.iterator(); 54 while(it.hasNext()) 55 { 56 Student stu=(Student)it.next(); 57 System.out.println(stu.getName()+"..."+stu.getAge()); 58 } 59 } 60 } 61 62 class MyCompare implements Comparator 63 { 64 public int compare(Object o1,Object o2) 65 { 66 Student s1=(Student)o1; 67 Student s2=(Student)o2; 68 69 int num=s1.getName().compareTo(s2.getName()); 70 if(num==0) 71 { 72 return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); 73 /* 74 if(s1.getAge()>s2.getAge()) 75 return 1; 76 if(s1.getAge()==s2.getAge()) 77 return 0; 78 */ 79 } 80 return num; 81 82 } 83 }
1.3、TreeSet练习
1 package Test; 2 3 import java.util.Comparator; 4 import java.util.Iterator; 5 import java.util.TreeSet; 6 7 /* 8 * 练习,按照字符串长度排序 9 * 字符串本身具备比较性,但是比较方式不是所需要的 10 * */ 11 public class TreeSetTest { 12 public static void main(String[] args) { 13 TreeSet ts=new TreeSet(new StrLengthComparator()); 14 ts.add("abcd"); 15 ts.add("cc"); 16 ts.add("cba"); 17 ts.add("aaa"); 18 ts.add("z"); 19 ts.add("hahaha"); 20 21 Iterator it=ts.iterator(); 22 while(it.hasNext()) 23 { 24 System.out.println(it.next()); 25 } 26 } 27 } 28 29 class StrLengthComparator implements Comparator 30 { 31 public int compare(Object o1,Object o2) 32 { 33 String s1=(String)o1; 34 String s2=(String)o2; 35 // if(s1.length()>s2.length()) 36 // return 1; 37 // if(s1.length()==s2.length()) 38 // return 0; 39 int num=new Integer(s1.length()).compareTo(new Integer(s2.length())); 40 if(num==0) 41 return s1.compareTo(s2); 42 return num; 43 } 44 }
1.4、泛型限定
(1)JDK1.5版本之后出现的新特性,用于解决安全问题,是一个类型安全机制。
作用是希望在定义集合时,标识你要传入的对象的类型,不是这个类型的不让传入。
泛型是给编译器看的,即在编译时不加入泛型指定的类型的元素会发生异常。
但ArrayList<Integer>和ArrayList<String>的对象的字节码形式一样,说明泛型被转换成字节码之后就消失了,
所以可以用反射取得add方法,在ArrayList<Integer>对象中添加String类型的元素,不会发生异常。
(2)没有使用泛型时,不管是什么类型的对象都可以存储进同一个集合中。使用泛型后,可以将一个集合中的元素规定为一个类型,
这个集合中只能存储一种类型的对象,更加安全,并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,
不需要对对象进行强制类型转换,更加方便。泛型就是把原来的类名进行了延长。
而如果将各种不同类型的数据装到一个集合中,编译器会报告unchecked警告。
(3) 格式:
通过<>来定义要操作的引用数据类型
如:ArrayList<String>//这个集合中只能存入String类型的元素
好处
(1) 将运行时期出现的问题ClassCastException转移到了编译时期,方便于程序员解决诶问题,让运行时期问题减少,安全
(2) 避免强制转换的麻烦
1 package learn4; 2 /* 3 * 泛型限定 4 * ? 通配符,也可以理解为占位符 5 * ? extends E:可以接受E类型或者E的子类型,上限 6 * ? super E:可以接收E类型或者E的父类型,下限 7 * */ 8 import java.util.ArrayList; 9 import java.util.Comparator; 10 import java.util.Iterator; 11 import java.util.TreeSet; 12 13 public class GenericDemo6 { 14 public static void main(String[] args) { 15 /* 16 ArrayList<String> al = new ArrayList<String>(); 17 18 al.add("abc1"); 19 al.add("abc2"); 20 al.add("abc3"); 21 22 ArrayList<Integer> al1 = new ArrayList<Integer>(); 23 al1.add(4); 24 al1.add(7); 25 al1.add(1); 26 printColl(al); 27 printColl(al1); 28 */ 29 ArrayList<Person> al = new ArrayList<Person>(); 30 al.add(new Person("abc1")); 31 al.add(new Person("abc2")); 32 al.add(new Person("abc3")); 33 34 ArrayList<Student> al1 = new ArrayList<Student>(); 35 al1.add(new Student("abc---1")); 36 al1.add(new Student("abc---2")); 37 al1.add(new Student("abc---3")); 38 printColl(al1);//ArrayList<Person> al = new ArrayList<Student>(); 39 40 41 42 43 } 44 //泛型限定 45 public static void printColl(ArrayList<? extends Person> al) 46 { 47 Iterator<? extends Person> it = al.iterator(); 48 while(it.hasNext()) 49 { 50 System.out.println(it.next().getName()); 51 } 52 } 53 /* 54 public static void printColl(ArrayList<?> al) 55 { 56 Iterator<?> it = al.iterator(); 57 while(it.hasNext()) 58 { 59 System.out.println(it.next()); 60 } 61 } 62 */ 63 64 } 65 66 class Person 67 { 68 private String name; 69 Person(String name) 70 { 71 this.name=name; 72 } 73 public String getName() 74 { 75 return name; 76 } 77 } 78 79 class Student extends Person 80 { 81 Student(String name) 82 { 83 super(name); 84 } 85 } 86 87 //class Student implements Comparable<Person> 88 //{ 89 // public int compareTo(Person s) 90 // { 91 // this.getName(); 92 // } 93 //} 94 95 //class Comp implements Comparator<Student> 96 //{ 97 // public int compare(Student s1,Student s2) 98 // { 99 // Person s1 = new Student("abc1"); 100 // return s1.getName().compareTo(s2.getName()); 101 // } 102 //} 103 // 104 //TreeSet<Student> ts = new TreeSet<Student>(); 105 //ts.add(new Student("abc1")); 106 //ts.add(new Student("abc2")); 107 //ts.add(new Student("abc3"));
1.4.2、泛型限定2
用于泛型扩展
1 package learn5; 2 3 import java.util.Comparator; 4 import java.util.Iterator; 5 import java.util.TreeSet; 6 7 8 9 class Person 10 { 11 private String name; 12 Person(String name) 13 { 14 this.name=name; 15 } 16 public String getName() 17 { 18 return name; 19 } 20 } 21 22 class Student extends Person 23 { 24 Student(String name) 25 { 26 super(name); 27 } 28 } 29 30 class Worker extends Person 31 { 32 Worker(String name) 33 { 34 super(name); 35 } 36 } 37 38 public class GenericDemo7 { 39 public static void main(String[] args) { 40 TreeSet<Student> ts = new TreeSet<Student>(new Comp()); 41 ts.add(new Student("abc03")); 42 ts.add(new Student("abc02")); 43 ts.add(new Student("abc06")); 44 ts.add(new Student("abc01")); 45 46 Iterator<Student> it = ts.iterator(); 47 while(it.hasNext()) 48 { 49 System.out.println(it.next().getName()); 50 } 51 TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp()); 52 ts1.add(new Worker("wabc03")); 53 ts1.add(new Worker("wabc02")); 54 ts1.add(new Worker("wabc06")); 55 ts1.add(new Worker("wabc01")); 56 Iterator<Worker> it1 = ts1.iterator(); 57 while(it1.hasNext()) 58 { 59 System.out.println(it1.next().getName()); 60 } 61 62 63 64 } 65 } 66 /* 67 class StuComp implements Comparator<Student> 68 { 69 public int compare(Student s1,Student s2) 70 { 71 return s1.getName().compareTo(s2.getName()); 72 } 73 } 74 75 class WorkerComp implements Comparator<Worker> 76 { 77 public int compare(Worker s1,Worker s2) 78 { 79 return s1.getName().compareTo(s2.getName()); 80 } 81 } 82 */ 83 84 class Comp implements Comparator<Person> 85 { 86 public int compare(Person p1,Person p2) 87 { 88 return p2.getName().compareTo(p1.getName()); 89 } 90 }
2、Map
1 package learn5; 2 3 import java.util.Collection; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 /* 8 * Map集合,双列集合,该集合存储键值对,一对一对往里存,而且要保证键的唯一性 9 *1、添加 10 * put(Key k,Value v); 11 * putAll(Map<? extends K, ?extends V>m) 12 * 13 *2、删除 14 * clear() 15 * 16 *3、判断 17 * containsValue(Object value); 18 * containsKey(Object key); 19 * isEmpty(); 20 * 21 *4、获取 22 * get(Object key); 23 * size() 24 * value() 25 * entrySet(); 26 * keySet(); 27 * 28 *Map 29 * |--Hashtable: 底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步 JDK1.0 30 * |--HashMap:底层是哈希表数据结构,允许使用null值和null键,该集合是不同步的 JDK1.2 效率高 31 * |--TreeMap:底层是二叉树结构,线程不同步,可以用于给Map集合中的键排序。 32 * Set底层调用的就是map 33 * */ 34 public class MapDemo { 35 public static void main(String[] args) { 36 Map<String,String> map = new HashMap<String,String>(); 37 //添加元素,如果出现添加是相同的键,后添加的值会覆盖原有的键对应的值,并返回被覆盖的值 38 System.out.println("put: "+map.put("01","zhangsan1")); 39 System.out.println("put: "+map.put("01", "lsii2")); 40 41 map.put("02", "zhangsan2"); 42 map.put("03", "zhangsan3"); 43 System.out.println("contansKey: "+map.containsKey("022")); 44 // System.out.println("remove: "+map.remove("02")); 45 System.out.println("get: "+map.get("02")); 46 System.out.println(map); 47 //null可以作为键存在 48 map.put("04", null); 49 System.out.println("get: "+map.get("04")); 50 //可以通过get方法返回值来判断一个键是否存在,通过返回null来判断 51 //获取map集合中所有的值 52 Collection<String> coll = map.values(); 53 System.out.println(coll); 54 System.out.println(map); 55 56 } 57 58 }
2.1、Map集合的两种取出方式
1 package learn5; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import java.util.Map; 6 import java.util.Set; 7 8 /* 9 * Map集合的两种取出方式 10 * 1.Set<key> keySet:将map中所有的键存入到Set集合,因为Set具备迭代器 11 * 所有可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值 12 * map集合取出原理:将map集合转成Set集合,再通过迭代器输出 13 * 2、Set<Map.Entry<k,v>>entrySet: 将map集合中的映射关系存到了set集合中,这个关系的类型:Map.Entry 14 * 15 * Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口 16 * interface Map 17 * { 18 * public static interface Map.Entry 19 * { 20 * public abstract Object getKey(); 21 * public abstract Object getValue(); 22 * } 23 * } 24 * class HashMap implements Map 25 * .Entry 26 * { 27 * class haha implements Map.Entry 28 * { 29 * public Object getKey(){} 30 * public Object getValue(){} 31 * } 32 * } 33 * */ 34 public class MapDemo2 { 35 public static void main(String[] args) { 36 Map<String,String> map = new HashMap<String,String>(); 37 map.put("02","zhangsan2"); 38 map.put("03","zhangsan3"); 39 map.put("01","zhangsan1"); 40 map.put("04","zhangsan4"); 41 //将Map集合中的映射关系取出,存入到Set集合中 42 Set<Map.Entry<String, String>> entrySet = map.entrySet(); 43 Iterator<Map.Entry<String, String>> it = entrySet.iterator(); 44 while(it.hasNext()) 45 { 46 Map.Entry<String, String> me=it.next(); 47 String key = me.getKey(); 48 String value = me.getValue(); 49 System.out.println(key+""); 50 } 51 52 53 54 // //先获取map集合中所有键的Set集合,keySet(); 55 // Set<String> keySet = map.keySet(); 56 // //有了Set集合就可以获取迭代器 57 // Iterator<String> it = keySet.iterator(); 58 // while(it.hasNext()) 59 // { 60 // String key=it.next(); 61 // //有了键可以通过map集合的get方法获取其对应的值 62 // String value = map.get(key); 63 // System.out.println("key: "+key); 64 // } 65 } 66 }
2.2、TreeMap
1 package Test2; 2 3 import java.util.Comparator; 4 import java.util.Iterator; 5 import java.util.Map; 6 import java.util.Set; 7 import java.util.TreeMap; 8 9 10 11 /* 12 * 需求:对学生对象的年龄进行升序排序 13 * 因为数据是以键值对形式存在的 14 * 所以要使用可以排序的Map集合,TreeMap。 15 * */ 16 class StuNameComparator implements Comparator<Student> 17 { 18 public int compare(Student s1,Student s2) 19 { 20 int num = s1.getName().compareTo(s2.getName()); 21 if(num==0) 22 return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); 23 return num; 24 } 25 } 26 class Student implements Comparable<Student> 27 { 28 private String name; 29 private int age; 30 Student(String name,int age) 31 { 32 this.name=name; 33 this.age=age; 34 } 35 public int compareTo(Student s) 36 { 37 int num = new Integer(this.age).compareTo(new Integer(s.age)); 38 if(num==0) 39 return this.name.compareTo(s.name); 40 return num; 41 } 42 public int hashCode() 43 { 44 return name.hashCode()+age*34; 45 } 46 public boolean equals(Object obj) 47 { 48 if(!(obj instanceof Student)) 49 throw new ClassCastException("类型不匹配"); 50 Student s=(Student)obj; 51 return this.name.equals(s.name)&&this.age==s.age; 52 } 53 public String getName() 54 { 55 return name; 56 } 57 public int getAge() 58 { 59 return age; 60 } 61 public String toString() 62 { 63 return name+":"+age; 64 } 65 } 66 public class MapTest2 { 67 public static void main(String[] args) { 68 TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator()); 69 tm.put(new Student("blisi3",23),"Nanjing"); 70 tm.put(new Student("lisi1",21),"Beijing"); 71 tm.put(new Student("alisi4",24),"Wuhan"); 72 tm.put(new Student("lisi1",21),"tianjin"); 73 tm.put(new Student("lisi2",22),"Shanghai"); 74 75 Set<Map.Entry<Student,String>> entrySet = tm.entrySet(); 76 Iterator<Map.Entry<Student,String>> it = entrySet.iterator(); 77 while(it.hasNext()) 78 { 79 Map.Entry<Student,String> me = it.next(); 80 Student stu = me.getKey(); 81 String addr = me.getValue(); 82 System.out.println(stu+"..."+addr); 83 } 84 } 85 }
2.3、字符排序
1 package Test2; 2 3 import java.util.Iterator; 4 import java.util.Map; 5 import java.util.Set; 6 import java.util.TreeMap; 7 8 /*练习 9 * "sdfgzxcvasdfxvdf"获取该字符串中字母出现的次数 10 * 希望打印结果a(1)c(2); 11 * 12 * 通过结果发现,每一个字母都有对应的次数 13 * 说明字母和次数之间都有映射关系 14 * 注意,当发现有映射关系时,可以选择map集合 15 * 因为map集合中存放的就是映射关系 16 * 17 * 何时使用mao集合? 18 * 当数据之间存在着映射关系时,就可以使用map集合 19 * 20 * 思路: 21 * 1、字符串转换成字符数组,因为要对每一个字符进行操作 22 * 2、定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合 23 * 3、遍历字符数组 24 * 将每一个字母作为键去查map集合 25 * 如果返回null,将该字母和1存入到map集合中 26 * 如果返回不是null,说明该字母在mao集合中已经存在,并有对应的次数, 27 * 那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到map集合中,覆盖调用原有键所对应的值, 28 * 4、将map集合中的数据变成指定的字符串形式返回。 29 * */ 30 public class MapTest3 { 31 public static void main(String[] args) 32 { 33 String s = charCount("aabcdabcdefa"); 34 System.out.println(s); 35 } 36 public static String charCount(String str) 37 { 38 char[] chs=str.toCharArray(); 39 //字母作为键,次数作为值,泛型里接收的都是引用数据类型,转换成基本包装类 40 //排序依赖Character 实现了Comparable,所以默认了字符排序 41 TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>(); 42 int count=0; 43 for(int x=0; x<chs.length;x++) 44 { 45 46 if(!(chs[x]>='a'&&chs[x]<='z'||chs[x]>='A'&&chs[x]<='Z')) 47 continue; 48 //字母作为键找集合 49 Integer value = tm.get(chs[x]); 50 if(value!=null) 51 count=value; 52 count++; 53 tm.put(chs[x], count); 54 count=0; 55 // if(value==null) 56 // { 57 // tm.put(chs[x], 1); 58 // } 59 // else 60 // { 61 // value = value + 1; 62 // tm.put(chs[x], value); 63 // } 64 } 65 // System.out.println(tm); 66 //缓冲区存 67 StringBuilder sb = new StringBuilder(); 68 Set<Map.Entry<Character,Integer>>entrySet = tm.entrySet(); 69 Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator(); 70 while(it.hasNext()) 71 { 72 Map.Entry<Character,Integer> me = it.next(); 73 Character ch = me.getKey(); 74 Integer value=me.getValue(); 75 sb.append(ch+"("+value+")"); 76 77 78 } 79 //返回值为String类型,sb是builder 80 return sb.toString(); 81 } 82 }
2.4、集合中套集合
一对多
1 package learn6; 2 3 import java.util.List; 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.Iterator; 7 8 9 10 /*map扩展知识 11 * map被使用是因为具备映射关系 12 * "yureban" "01" "zhangsan"; 13 * "yureban" "02" "lisi"; 14 * "jiuyeban" "01" "wangwu"; 15 * "jiuyeban" "02" "zhaoliu"; 16 * 17 * 一个学校有多个教室,每个教室有多个学生 18 * */ 19 class Student 20 { 21 private String id; 22 private String name; 23 Student(String name,String id) 24 { 25 this.id=id; 26 this.name=name; 27 } 28 public String toString() 29 { 30 return id+":::"+name; 31 } 32 } 33 public class MapDemo3 { 34 public static void demo(){ 35 HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>(); 36 List<Student> yure = new ArrayList<Student>(); 37 List<Student> jiuye = new ArrayList<Student>(); 38 czbk.put("yureban",yure); 39 czbk.put("jiuyeban",jiuye); 40 yure.add(new Student("01","zhangsan")); 41 yure.add(new Student("04","wangwu")); 42 jiuye.add(new Student("01","zhaoqi")); 43 jiuye.add(new Student("01","zhaoqi")); 44 45 Iterator<String> it = czbk.keySet().iterator(); 46 while(it.hasNext()) 47 { 48 String roomName = it.next(); 49 List<Student> room = czbk.get(roomName); 50 System.out.println(roomName); 51 getInfos(room); 52 } 53 54 55 } 56 public static void getInfos(List<Student> list) 57 { 58 Iterator<Student> it = list.iterator(); 59 while(it.hasNext()) 60 { 61 Student s=it.next(); 62 System.out.println(s); 63 } 64 } 65 66 67 68 public static void main(String[] args) { 69 demo(); 70 // HashMap<String,HashMap<String,String>> czbk = new HashMap<String, HashMap<String,String>>(); 71 // HashMap<String,String> yure = new HashMap<String,String>(); 72 // HashMap<String,String> jiuye = new HashMap<String,String>(); 73 // 74 // czbk.put("yureban", yure); 75 // czbk.put("jiuye", jiuye); 76 // 77 // yure.put("01", "zhangsan"); 78 // yure.put("02", "lisi"); 79 // 80 // jiuye.put("01", "wangwu"); 81 // jiuye.put("02", "zhaoliu"); 82 // 83 // //遍历传智播客 84 // Iterator<String> it = czbk.keySet().iterator(); 85 // while(it.hasNext()) 86 // { 87 // String roomName = it.next(); 88 // HashMap<String,String> room = czbk.get(roomName); 89 // System.out.println(roomName); 90 // getStudentInfo(room); 91 // } 92 93 // getStudentInfo(yure); 94 } 95 public static void getStudentInfo(HashMap<String,String> roomMap) 96 { 97 Iterator<String> it = roomMap.keySet().iterator(); 98 while(it.hasNext()) 99 { 100 String id= it.next(); 101 String name = roomMap.get(id); 102 System.out.println(id+":"+name); 103 } 104 } 105 }