chapter07Java实用包.ppt_第1页
chapter07Java实用包.ppt_第2页
chapter07Java实用包.ppt_第3页
chapter07Java实用包.ppt_第4页
chapter07Java实用包.ppt_第5页
已阅读5页,还剩97页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第7章 Java实用包 本章知识点 nMath类 n包java.lang.Math n常用数学常量和方法(四舍五入、随机数等) nString类 nJava管理String的方法(创建、equals相等策略) nString类常用方法(字符串的连接、查找、比较、截取子 串)。 nStringBuffer类 nStringBuffer与String的区别(能否变化、对象的连接、 equals比较) nStringBuffer与String的转换 nStringTokenizer类 n词语分析 n使用默认和指定的定界符进行分析 nVector类 n与数组的区别 nVector的增、删、查操作 n利用Enumeration对Vector进行遍历 常用的类和包对应关系 包名 类 包名 类 Java.lang String javax.swing JButton Wrapper classes JLabel Math JTextField . Java.util Calendar java.io InputStream Date OutputStream Vector Java.text DataFormat Java.awt Graphics Button Label TextField 7.1 Math类 njava.lang.Math n标准的数学函数类,封装了一些数学函数和常量 ,如:三角函数、指数函数、随机数函数等。 njava.lang.Math类是final的,Math类的所有方法 和常量是静态的。 【例7-1】测试Math类中的方法 public static void main(String args) System.out.println(Math.E); System.out.println(Math.PI); System.out.println(Math.round(Math.E); System.out.println(Math.ceil(Math.E); System.out.println(Math.floor(Math.E); System.out.println(Math.log(Math.E); System.out.println(Math.sin(Math.PI/4); System.out.println(Math.random(); System.out.println( (int)(100*Math.random()+1) ); 2.718281828459045 3 3.141592653589793 3.0 2.0 1.0 0.7071067811865475 ceil(): 返回大于或者等于参数x的最小整数,返回值为double类型。 floor(): 返回小于或者等于参数x的最大整数,返回值为double类型。round(): 四舍五入,计算与参数x值最接近的整数 random():产生0, 1)区间内的随机小数 7.2 字符串类String n字符串 n字符串常量:用双引号括起来的一串字符, 如”hello”。 n字符串常量是 String的对象。 nString对象一旦创建后,其内容不能被改变。 String s=“I am a teacher.“; s.replace(“teacher“, “student“); System.out.println(s); s = s.replace(“teacher“, “student“); System.out.println(s); I am a teacher. I am a student. 注意区分对象和引用的关系。 7.2 字符串类String nJava程序中如果多处出现同一个字符串常量,则 编译器只创建一个String对象,所有的字符串常量将 使用同一个String对象。 String s1=“Hello”; String s2=“Hello”; String s3 = new String(“Hello”); String s4 = new String(“Hello”); s1和s2是同一个对象 s1、s3、s4是不同的对象 7.2 字符串类String n字符串的连接运算 nString对象之间可以使用操作符“+”,”+=”进行连 接。只要“+”运算两侧有一个运算对象是字符串,则 可以与任意类型的数据拼接为新的字符串。 int a=10; String str; str=“This is :“ + a + 20; boolean flag = true; str=“This boolean value is :“ + flag; This is 1020str = “This is :“ + (a + 20);This is 30 7.2 字符串类String 7.2.1 String的构造方法 7.2.2 String的方法 7.2.1 String构造方法 构造方法用途 String() 默认构造方法,创建一个String实例,该实例中不 包含字符。 String(byte bytes)创建一个被byte数组初始化的字符串。 String(byte bytes, int offset, int length) 创建一个被byte数组的子区域所初始化的字符串。 参数offset指定子区域开始的下标(注意:第一个 字符的下标为0),参数length指定所使用byte的长 度。 String(char value)创建一个被字符数组初始化的字符串。 String(char value, int offset, int count) 创建一个被字符数组的子区域所初始化的字符串 。参数offset指定子区域开始的下标(注意:第一 个字符的下标为0),参数count指定所用字符的个 数。 String(String original) 构造一个String对象,该对象包括了与String对象 original相同的字符序列。 【例7-2】演示String类的构造方法 char charArray = b,i,r,t,h, ,d,a,y; byte byteArray = (byte)n, (byte)e,(byte)w; String s = new String( “hello“ ); String s1 = new String(); String s2 = new String( s ); String s3 = new String( charArray ); String s4 = new String( charArray, 6, 3 ); String s5 = new String( byteArray, 1, 2 ); String s6 = new String( byteArray ); hello 空串 hello birth day day ew new 7.2.2 String的方法 方法用途 char charAt(int index)获取字符串中某一指定位置(从0开始编号)的 字符。 int compareTo (String anotherString) 比较调用compareTo方法的字符串和参数 anotherString的字符串。若相等,则返回0; 如小于,则返回一个负数;若大于,则返回 一个正数。 int compareToIgnoreCase (String str) 比较调用方法的字符串和参数str的字符串。 注意比较时不区分字符的大小写。 String concat(String str) 连接两个String对象,并返回一个新的String 对象,该对象包含两个源字符串中的字符。 boolean endsWith(String suffix) 判断调用方法的字符串是否以参数suffix所对 应的字符串为结尾。 boolean equals(Object anObject) 判断调用方法的字符串是否与参数anObject所 对应的字符串相等。 7.2.2 String方法 boolean equalsIgnoreCase (String anotherString) 判断调用方法的字符串是否与参数 anotherString所对应的字符串相等,判 断时不区分字符的大小写。 void getChars(int srcBegin, int srcEnd, char dst, int dstBegin) 以参数srcBegin作为起始下标,以参数 srcEnd-1作为结束下标,从调用方法的 字符串中取子串复制到以参数dstBegin 为起始下标的字符数组中。 int indexOf(String str) 定位参数str在字符串中第一次出现的位 置。 int indexOf(String str, int fromIndex) 以参数fromIndex为起始索引,定位参 数str在字符串中第一次出现的位置。 int lastIndexOf(String str) 定位参数str在字符串中最后一次出现的 位置。 int lastIndexOf (String str, int fromIndex) 以参数fromIndex为起始索引,进行反 向查找第一次出现str的位置。 7.2.2 String方法 int length()确定字符串的长度。 replace(char oldChar, char newChar) 返回一个新的String对象,在该对象中 ,字符串中的参数oldChar所指定的字符 均被参数newChar所指定的字符替代。 String substring(int beginIndex) 从字符串中截取从参数beginIndex所指 定的下标开始,到字符串结束的一个子 字符串。 String substring(int beginIndex, int endIndex) 从字符串中截取从参数beginIndex所指 定的下标开始,到endIndex-1指定的下 标结束的一个子字符串。 String toLowerCase() 将字符串中的所有大写字母改为小写, 并返回该字符串。 String toUpperCase() 将字符串中的所有小写字母改为大写, 并返回该字符串。 String trim() 将出现在字符串开头和结尾的空格删 除,并返回该字符串。 n字符串与数组 n求字符串的长度 int length() n按位置提取字符串中的字符 char charAt(int index) n由数组构造字符串 String (char) String(char, int offset, int length) n字符串数组写到数组 public void getChars(int start, int end, char c, int offset) 7.2.2 String的方法 【例7-3】检测某用户名是否合法。 n检测的条件是用户名只能包含字母和数字。 public boolean isFeasibalOfUsername(String logname) boolean isFeasible=true; /检测是否只由字母和数字组成 for(int i=0; i=a aj=aj+1; aj+1=temp; 对数组排序更便捷的方式 Arrays.sort(数组) import java.util.Arrays; String a = “apple”,”banana”,”orage”,”watermelon”,”peach”; n字符串查找。 n查找字符串首次出现的位置 int indexOf(String s, int startpoint) n查找字符串最后一次出现的位置 int lastIndexOf(String s) 7.2.2 String方法 【例7-7】字符串查找 letters.indexOf( “def“ ); letters.indexOf( “def“, 7 ); letters.indexOf( “hello“ ); letters.lastIndexOf( “def“ ); letters.lastIndexOf( “def“, 25 ); letters.lastIndexOf( “hello“ ); String letters = “abcdefghabcdefgh“; letters.indexOf( c ); letters.indexOf( a, 1 ); letters.indexOf( $ ); letters.lastIndexOf( c ); letters.lastIndexOf( a, 10 ); letters.lastIndexOf( $ ); 2 8 -1 10 8 -1 3 11 -1 11 11 -1 【例7-8】检测某Email地址是否合法 。 n检测的条件是需要存在“.”和“”;“.”在“”之后 ,不相邻; “”不在最前; “.”不在最后 。 public boolean isFeasibalOfEmail(String email) boolean isFeasible = true; int flag_at = email.indexOf(“); int flag_dot = email.indexOf(“.“); if(!(flag_at!=-1 /返回一个迭代器对象 while(it.hasNext() System.out.println(it.next(); 第一节 List (2)java.lang.Iterable:可迭代的访问接口。 n实现了该接口的类可以用迭代器访问。 可以使用 “foreach” 语句进行迭代(如 ArrayList,)。 njava.lang.Iterable接口的定义-API public Iterator iterator() 第一节 List (3)java.util.Iterator接口:迭代器,对集合对 象中的元素进行循环访问的工具。 n3个方法 nnext()(取到下一个没有被访问的元素) nhasNext()(是否还有下一个元素未访问) nremove() n说明:Iterable接口和Iterator接口之间无继承关 系,只是Iterable接口中方法的返回值为Iterator类型 。 第一节 List nLinkedList-API n具有队列的特征,可以进行队列的操作 。 nArrayList和LinkedList结构的选择 n 链表 n优点:插入和删除方便 n缺点:查询效率低 n 数组 n优点:查询效率高 n缺点:插入和删除效率低 第一节 List nVector接口集合 nVector是线程安全的,ArrayList是线程不安全 的。 n目前的技术:将线程不安全的集合转换为线程 安全的集合。 第二节 Set 1、Set接口中的方法-API n特征:不允许添加重复的元素 2、HashSet实现类 -API 3、HashSet的存储结构 n初始容量为数组的大小16,填充因子0.75 。 第二节 Set 4、向HashSet中添加对象的原理和过程 set.add(obj) n1)计算hobj.hashCode(),返回哈希码 。 说明:public int hashCode()在Object 中定义。计算得到对象的哈希码是一个整数 ,代表对象的内存地址(public String toString() 返回对象的地址,该地址实际是哈 希地址的16进制形式) n2)对h作一系列运算,p=运算结果%16 (0-15),该值作为对象在数组中的存储位置 。 第二节 Set n 3)如果p位置发生冲突,则对当前对象 obj和该位置对象obj2进行比较(equals方法 ),如果相同,则说明元素已存在,舍弃。 n 4)如果obj和obj2不相等,则再哈希( 链处理法处理冲突),向链表中插入结点。 n 5)如果p位置不发生冲突,则将obj存储 。 过滤的条件:哈希地址相同 set.add(new Student(“zhangsan”,20); set.add(new Student(“zhangsan“,21); set.add(new Student(“zhangsan“,22); set.add(“hello“); set.add(“haha“); set.add(3.14); set.add(5); set.add(“haha”); set.add(new String(“hello“); /应被舍弃,目前未被舍弃 /被舍弃,只保留一个,对象池 /未输出hello,说明String覆盖了hashCode()方法 第二节 Set n分析:每个对象的哈希码都不相同,在堆内存中 分配了不同的内存地址。哈希运算后哈希地址除非 巧合,否则不发生冲突。因此,对象在Set中都进行 了存储。 set.add(new Student(“zhangsan“,20); set.add(new Student(“zhangsan”,20); 第二节 Set 5、解决集合中相同对象不允许添加的问题 n向String类学习,在Student类中覆盖 hashCode()方法。 n原则1:保证equals相等的对象,返回相 同的hashCode。 n原则2:保证equals不相等的对象,尽量 返回不同的hashcode(避免作equals的比较 ,提高效率) n原则3:尽量令对象的哈希码散列,避免 局部聚集。 第二节 Set n原则1的满足:如果某两个对象的取值相同(name和age 相同,则name.hashCode()相同,String覆盖了hashCode()方 法),则产生的hashCode相同。 n证据:String的hashcode的计算方法(源代码文档),如 果字符串相同,则hashcode相同。 n原则2的满足:计算公式满足尽量令它们不相等。如: nZhangsan 20 181120 0x5f2ab673 与比较大的值进行异 或,使哈希地址尽量散列。 nlisi 21 190121 0x5f2ab673 public int hashCode() return name.hashCode() age 0x5f2ab673; 第二节 Set n关于原则3:不满足原则3的设计方案 n注意:hashcode可以标识对象不相等,不能标识 对象相等。不同的对象可能有相同的hashCode。 public int hashCode() return name.length()+age; 第二节 Set n总结 n覆盖hashCode()方法和equals()方法通常 同时出现,同时覆盖。 n如果只覆盖equals()方法:取值相同的不 同对象的hashcode不同,存在重复。 n如果只覆盖hashCode()方法:取值相同 的不同对象的hashcode相同,但equals()方法 只比较它们的引用,而不比较内容,两个对 象的引用肯定是不同的,所以会再哈希,导 致存储重复数据。 第二节 Set n举例:定义Student类,使其能够存储在Hashset 集合中。 第二节 Set 1、SortedSet接口:排好序的集合,从小到大。 2、实现类:TreeSet-查看API文档。 3、如何实现排序排序的原理。 n 建立二叉排序树,中序遍历二叉树,得 到有序序列。 第二节 Set 4、TreeSet中对象的比较方法 (1)加入字符串 (2)加入Student对象 报错,系统不知道如何比较Student对 象的大小。 set.add(“hello“); set.add(“haha“); set.add(“haha”); set.add(new String(“hello“); set.add(new Student(“zhangsan“,20); set.add(new Student(“lisi”,20); set.add(new Student(“wangwu“,21); 第二节 Set public static void main(String args) SortedSet set = new TreeSet(); set.add(new Student(“zhangsan“,20); set.add(new Student(“lisi“,20); set.add(new Student(“zhangsan“,21); set.add(new Student(“zhangsan“,22); set.add(new Student(“zhangsan“,20); Iterator it = set.iterator(); while(it.hasNext() System.out.println(it.next(); /加不进去,无法比较大小 第二节 Set n 方法一:Student类实现java.lang. Comparable 接口,实现其中的compareTo()方法-查看API nStudent对象的比较规则 n年龄 n年龄+姓名 第二节 Set n方式二:创建TreeSet对象时,传入一个比较器 ,比较器实现了Comparator接口。 njava.util.Comparator接口:比较器 n比较:java.lang. Comparable接口: 可 比较的接口 第二节 Set n比较器的实现和使用 public int compare(Object obj1, Object obj2) Student s1=(Student)obj1; Student s2=(Student)obj2; if(s1.getAge()=s2.getAge() return s1.getName().compareTo(s2.getName(); else return s1.getAge()-s2.getAge(); SortedSet set2 = new TreeSet(new MyComparator(); set2.add(new Student(“zhangsan“, 20); set2.add(new Student(“zhangsan”, 20); /? set2.add(new Student(“lisi“,20); set2.add(new Student(“zhangsan“, 21); set2.add(new Student(“zhangsan“, 22); Iterator it = set2.iterator(); while(it.hasNext() System.out.println(it.next(); 第二节 Set n方式二的改进: (1)将比较器定义为静态内部类,放在 Student类中。 (2)在Student类中添加全局静态常量,指向 相应的比较器 (3)创建TreeSet对象时,将比较器传入 n好处:建立多个比较规则,为排序作准备。按姓 名、年龄分别排序。 第二节 Set public static final NameAgeComparator NAME_AGE_COMPAROR = new NameAgeComparator(); public static final NameComparator NAME_COMPAROR = new NameComparator(); public static final AgeComparator AGE_COMPAROR = new AgeComparator(); static class NameAgeComparator implements Comparator public int compare(Object obj1, Object obj2) Student s1=(Student)obj1; Student s2=(Student)obj2; if(s1.getAge()=s2.getAge() return s1.getName().compareTo(s2.getName(); else return s1.getAge()-s2.getAge(); SortedSet set2 = new TreeSet(Student.NAME_AGE_COMPAROR); /传入按姓名年龄共同排序的比较器 SortedSet set3 = new TreeSet(Student.NAME_COMPAROR); /传入按姓名排序的比较器 SortedSet set4 = new TreeSet(Student.AGE_COMPAROR); /传入按年龄排序的比较器 第三节 Map n (key-value) 键值对,key不可重复,value可以 重复。 n 实现类:HashMap, HashTable 第三节 Map nHashMap-查看文档API (1)构造方法 (2)常用方法 n put(K key, V value) : n 例如:put(“zhangsan”, 4567) 如果已存在 ”zhangsan”(key),则覆盖原数据。原value作为返 回值返回。 nremove(Object key) n删除,返回与key对应的value. nValues()返回所有value的集合,collection,可 重复。 nkeySet()返回所有key的集合,set,不可重复。 第三节 Map nHashSet没有实现Iterable接口,不能用迭代器访 问。 n曲线救国:先取出set集合,找到value n发现:相同元素会被覆盖。 Set set=map.keySet(); Iterator it = set.iterator(); while(it.hasNext() Object k =it.next(); System.out.println( k+“:“+map.get(k) ); 第三节 Map n思考:“相同”的原则-与HashSet相同。 n实际上,在底层只有HashMap,HashSet只是 对HashMap进行了包装。 n(1)HashMap包含了key表和value表,而 HashSet只使用key表。 n(2)HashSet添加元素的方法:在发生冲突的 情况下,如果equals相等,则元素被抛弃(实际上未 抛弃,只是HashSet不管value的值而已)。 n(3)HashMap添加元素的方法:在发生冲突的 情况下,如果equals相等,则元素value被覆盖。 n结论:按照key的hashCode和equals进行比较,是否相 等。与value部分无关。 第三节 Map nHashTable n线程安全 n现在使用:Collections. synchronized Map(*); 将线程不安全的HashMap转换为线程安全的。 n JDK5.0后提供了新的Class Collections(java.util)。 n Collections类:几乎所有的方法都是static,工具 类。 nCollections类中的方法: nsynchronizedCollection(Collection c) n所有以“synchronized”开头的方法:将线程不 安全的转换为线程安全的。 第三节 Map nHashTable的子类Properties 实现了Map接口 属性集键值对 1、方法 nvoid load(InputStream inStream) 从一个字节流读取属性列表。 nString getProperty (String key) n获取key所对应的value nkey和value都是String类型。不能是其他 对象。(map里是object) n String getProperty(String key, String defaultValue) n如果没有key,则返回缺省值 第三节 Map public static void main(String args) Properties pro = new Properties(); try pro.load(new FileInputStream(“config.txt“); /读入一个输入流,配 置文件 catch (FileNotFoundException e) e.printStackTrace(); catch (IOException e) e.printStackTrace(); /保证参数为文件中左侧的名字 System.out.println(“server ip:“+ pro.getProperty(“server“) ); System.out.println(“port:“+ pro.getProperty(“port“) ); 注意:config文件要存储到项目下,而不是包下。 【例】读取配置文件的内容。 第三节 Map nSortedMap接口 n实现类TreeMap n底层结构:二叉树 第三节 Map n数据结构的选择: n【例题1】学籍管理系统-存储学生的信息 n数据进入有次序无次序? 无次序 set n数据排列有序无序? 无须排序 HashSet n【例题2】铁路售票系统-存储列车的所有站点 n数据进入有次序无次序? 有次序 List(站名,出发时间,到达时间) n是否经常进行增删? 不是 ArrayList 补充:正则表达式 n文档 补充:正则表达式 public static void main(String args) Pattern email = Ppile(“w+(.w+)*w+(.w+)+“); / w+ (ab) ababab . Matcher m = email.matcher(““); boolean res = m.find(); System.out.println(res); Pattern phone = Ppile(“(0d2,3-)?(2-9d6,7)+(- d1,4)?$“); /d ? m= phone.matcher(“6895742-6656“); res = m.find(); System.out.println(res); Pattern mobil = Ppile(“(d3)|(d3-)*?130-9|150- 3,5-9|180,5-9d8“); m = mobil.matcher(“(123)1542367999“); res = m.find(); System.out.println(res); 补充:日期及其格式处理类 njava.util.Date njava.text.SimpleDateFormat Date类 nDate类在java.util包中。 nDate对象表示时间的默认顺序是星期、月、日、小时、 分钟、秒、年。 1、创建日期 n Date date1 = new Date(); /当前系统时间 n Date date1 = new Date( timeOne ); /利用 timeOne对其初始化,timeOne为毫秒数 SimpleDateFormat类 n设置日期格式 n类SimpleDateFormat在java.text npublic SimpleDateFormat(String pattern) n说明:pattern中应当含有一些特殊意义的字符 ,称为元字符。 ny或yy:表示用两位数字输出年份;yyyy 表示用四位数字输出年份。 nM或MM:表示两位数字或文本输出月份 (如果要用汉字输出月份,至少使用连续的3个M )。 nd或dd:用两位数字输出日。 nH或HH:用两位数字输出小时。 nm或mm:用两位数字输出分。 ns或ss:用两位数字输出秒。 nE:用汉字字符串输出星期。 Date类 n使用说明:SimpleDateFormat对象.format(日 期对象) import java.util.*; /为使用Date类 import java.text.*; /为使用SimpleDateFormat类 public static void main(String args) Date nowTime=new Date(); System.out.println(nowTime); SimpleDateFormat matter1= new SimpleDateFormat(“time:yyyy年 MM月dd日E“); System.out.println(matter1.format(nowTime); SimpleDateFormat matter2= new SimpleDateFormat(“yyyy年MM月 dd日HH小时mm分ss秒“); System.out.println(matter2.format(nowTime); 注意:pattern中的普通字符,如果是ASCII码表中的字符,必须用单引号括起。 本章小结 nMath类 n包含静态常量和静态方法。 n常用常量:Math.PI, Math.E。 n常用方法:四舍五入round()、随机数random()等 。 nString类 nString类对象创建后内容不能修改。 n一个常量字符串Java只创建一次。 nString类重写了Object类equals方法,用于比较字符 串的内容是否相同。 n常用方法:字符串的连接+、查找indexOf()、比较 compareTo()、截取子串substring()。 本章小结 nStringBuffer类 nStringBuffer类对象创建后内容可以变化。 nStringBuffer对象使用append()方法进行连接。 nStringBuffer 类没有重写Object类的equals比较 ,不能比较字符串内容,而是比较引用的地址。 nStringBuffer的好处是更方便地进行字符串的增 、删、改等操作,但不能比较大小,必要时与String 进行类型转换toString()方法。 nStringTokenizer类 n进行词法分析,按定界符分析得到串中的词。 n可以使用默认定界符(空格等)分析 n也可以使用指定的定界符进行分析 考核目标 【掌握】 nMath类中的round()和random()方法。 nString类的创建,indexOf()、substring()方法 。 nStringBuffer类的append()方法。 nStringTokenizer类进行词语分析的方法。 nVector类的add()、remove()、indexOf()等方法 。 n利用Enumeration遍历Vector的方法。 【理解】 nStringBuffer类与String类对象的区别。 nVector类与Java数组的区别。 7.5 Vector类 n在Java中,数组对象一旦创建后其大小是固定的,数组 不能随应用程序的存储需求的变化而变大或缩小。 nJava.util包中的Vector类提供类似于数组的能力,但能 够动态地调整自身存储空间的大小。 nVector类似于一个数组,但与数组相比在使用上有以下 两个优点: (1) 使用的时候无需声明上限,随着元素的增加,Vector 的长度会自动增加。 (2) Vector提供方法来增加、删除元素,比数组操作高效 。 nVector中只能存储引用类型的数据,不能存储基本数据 类

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论