免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: rollingpig
打印 上一主题 下一主题

老虎来了,你准备好了吗?(增加for-each) [复制链接]

论坛徽章:
0
11 [报告]
发表于 2004-03-06 13:22 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

你的动漫是不错但有点太生硬了.

论坛徽章:
0
12 [报告]
发表于 2004-03-07 23:17 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

HoHo,Java也开始支持Generic了,原来的那个小不点也开始向巨无霸发展了

论坛徽章:
0
13 [报告]
发表于 2004-03-08 18:27 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

AutoBoxing-Unboxing

在Tiger之前,往Colletion里存取Object是很烦人的事,Tiger中用Genric解决了这个难题.还有一件挺烦而无谓的事情,那就是往Colletion里存取原始类型(primitive type).
比如有一个Hashtable,你需要在里面记录某种操作的次数.在没用Genric前是这样的


  1. //AccessRecord.java
  2. import java.util.*;
  3. public class AccessRecord{
  4. private  Hashtable accessRecord = new Hashtable();
  5. public  void addAccessRecord(String accessType){
  6.         int i = getAccessRecord(accessType);
  7.         accessRecord.put(accessType,new Integer(i+1));
  8. }
  9. public int getAccessRecord(String accessType){
  10.     Integer i = (Integer)(accessRecord.get(accessType));
  11.     if(i==null)
  12.     return 0;
  13.     else
  14.     return i.intValue();
  15. }
  16. }
复制代码

可以看出来,为了能够让Hashtable接受,我们必须用Integer来做一个wrapper,取出来之后还需要还原它.
就算现在有了Genric,也无济于事

  1. //AccessRecordGenric.java
  2. import java.util.*;
  3. public class AccessRecordGenric{
  4. private  Hashtable<String,Integer>; accessRecord = new Hashtable<String,Integer>;();
  5. public  void addAccessRecord(String accessType){
  6.         int i = getAccessRecord(accessType);
  7.         accessRecord.put(accessType,new Integer(i+1));
  8. }
  9. public int getAccessRecord(String accessType){
  10.     Integer i = accessRecord.get(accessType);
  11.     if(i==null)
  12.     return 0;
  13.     else
  14.     return i.intValue();
  15. }
  16. }
复制代码

通过加入Genric特性,也仅仅是省了Cast的一步.
于是,Tiger引入了另一个特性,AutoBoxing-Unboxing(呵呵,第一次看到时,误认为是自动拳击手套,很想买一个来玩玩).
AutoBoxing指的是:在需要使用Object的场合中,我们可以只提供原始类型,编译器会自动为我们转换成相应的Wrapper类
AutoUnboxing指的是:在需要使用原始类型的场合中,我们可以只提供Wrapper类,编译器会自动为我们转换成相应的primitive type

现在我们就用AutoBoxing-unBoxing来改写刚才的class


  1. //AccessRecordBoxing.java
  2. import java.util.*;
  3. public class AccessRecordBoxing{
  4. private  Hashtable<String,Integer>; accessRecord = new Hashtable<String,Integer>;();
  5. public  void addAccessRecord(String accessType){
  6.         accessRecord.put(accessType,getAccessRecord(accessType)+1);
  7. }
  8. public int getAccessRecord(String accessType){
  9.         Integer i = accessRecord.get(accessType);
  10.     return i==null?0:i;//hehe,想起oracle的nvl()函数 :)
  11. }
  12. public static void main(String args[]){
  13.     AccessRecordBoxing t = new AccessRecordBoxing();
  14.         t.addAccessRecord("asd");
  15.         System.out.println(t.accessRecord);
  16.         t.addAccessRecord("asd");
  17.         System.out.println(t.accessRecord);
  18.         t.addAccessRecord("sadfsd");
  19.         System.out.println(t.accessRecord);
  20.         t.addAccessRecord("df");
  21.         System.out.println(t.accessRecord);
  22.         t.addAccessRecord("sdf");
  23.         System.out.println(t.accessRecord);

  24.     }
  25. }
复制代码

代码简洁了好多了吧!
你甚至可以这样使用

  1. ...
  2. Integer i = 10;
  3. j = i+10;
  4. ...
复制代码

使用AutoBoxing-unBoxing时点需要注意null object
必须检查被unboxing的object是否为null
不然会有NullPointerException

  1. Interge i = null
  2. ;
  3. int j = i+1;//NullPointerException

复制代码

论坛徽章:
0
14 [报告]
发表于 2004-03-09 17:02 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

Type Safe Enum

Tiger的改进其实真的称得上是顺应民意,里面的好多特性都可以在两本Java巨著<<Think In Java>;>;和<<Effective Java>;>;发现一些端倪.
(不得不承认,<<Think In Java>;>;和<<Effective Java>;>;是Java历史上最经典的两本书,多读多受益)
比如,之前提到过的Genric,在<<Think In Java>;>; 第九章介绍Colletion时就对Genric作出了预期,同时也实现某种形式的Genric(TIJ 2ND,P449-P455).
另外,Think In Java里也提及了利用interface来定义一组常量的方法(P358-P360),不少标准的Java库类也使用了这种方法(如java.util.zip.ZipConsts.不过,你将会发现,在Tiger里它已经不复存在了)
这种做法叫做Const Interface,大家也许或多或少都使用过.但是,Const Interface的方式在<<Effective Java>;>;受到了极大的否定(Item 17).书里提出了使用Type Safe Enum的方法(Item 21)来取代Const Interface.让我们对比一下以下两段代码

Const Interface

  1. //SeasonConst.java
  2. // Constant interface pattern - do not use!
  3. public interface SeasonConst {
  4. public static final int SPRING = 1;
  5. public static final int SUMMER = 2;
  6. public static final int AUTUMN = 3;
  7. public static final int WINTER = 4;
  8. }

  9. //TestConst.java
  10. //using of Constant interface
  11. public class TestConst implements SeasonConst{
  12. public void seasonLiving(int season){
  13. if(season==SPRING){
  14. System.out.println("we BBQ at SPRING");
  15. }
  16. else if(season==SUMMER){
  17. System.out.println("we swim at SUMMER");
  18. }
  19. else if(season==AUTUMN){
  20. System.out.println("we kite at AUTUMN");
  21. }
  22. else if(season==WINTER){
  23. System.out.println("we skate at WINTER");
  24. }
  25. else{
  26. System.out.println("What ?");

  27. }
  28. }
  29. public static void main(String args[]){
  30. TestConst t = new TestConst();
  31. t.seasonLiving(SPRING);
  32. t.seasonLiving(WINTER);
  33. t.seasonLiving(WINTER+1);
  34. //t.sersonLiving(WEEK_DAY.MONDAY);//程序无法和其他常数完整的区分
  35. }
  36. }
复制代码


Type Safe Enum

  1. //SeasonEnum.java
  2. // The typesafe enum (j2sdk1.4)pattern
  3. public class SeasonEnum {
  4. private final String name;
  5. private SeasonEnum(String name) {
  6. this.name = name;
  7. }
  8. public String toString() { return name; }
  9. public static final SeasonEnum SPRING = new SeasonEnum("SPRING");
  10. public static final SeasonEnum SUMMER = new SeasonEnum("SUMMER");
  11. public static final SeasonEnum AUTUMN = new SeasonEnum("AUTUMN");
  12. public static final SeasonEnum WINTER = new SeasonEnum("WINTER");
  13. }

  14. //TestEnum.java
  15. //using of typesafe enum (j2sdk1.4)
  16. public class TestEnum{
  17. public void seasonLiving(SeasonEnum season){
  18. if(season==SeasonEnum.SPRING){
  19. System.out.println("we BBQ at "+season);
  20. }
  21. else if(season==SeasonEnum.SUMMER){
  22. System.out.println("we swim at "+season);
  23. }
  24. else if(season==SeasonEnum.AUTUMN){
  25. System.out.println("we kite at "+season);
  26. }
  27. else if(season==SeasonEnum.WINTER){
  28. System.out.println("we skate at "+season);
  29. }
  30. else{
  31. System.out.println("What ?");
  32. }
  33. }
  34. public static void main(String args[]){
  35. TestEnum t = new TestEnum();
  36. t.seasonLiving(SeasonEnum.SPRING);
  37. t.seasonLiving(SeasonEnum.WINTER);
  38. //t.seasonLiving(WINTER+1);no way to put a season not in the SeasonEnum

  39. }
  40. }
复制代码


可以看出,Type Safe Enum在以下几个方面优于Const Interface
1.不会违背OO继承的意义.
2.类型安全,不会有无意义的常数混进正常常数中
3.保持自己的独立性,不像Const interface再编译后就失去了意义
4.可直接用于print
5.作为一个Object,可以拥有自己的方法,变量,可以继承,implement interface

但是,相对的,Type Safe Enum在使用中也有几点不利的地方

1.不能直接用于switch
2.必须跟上类名,增加复杂性
3.繁琐

于是,Tiger中引入了 typesafe Enum和static import ,同时启用了一个新的关键字enum(这也是Tiger中引入的唯一一个关键字).再配合上Genric,使得整个结构变得严谨而易用.

让我们还是使用方才的例子来说明吧,先来一个最简单的例子.

  1. public class TestEnumTiger1{
  2. public enum SeasonSimpliest {        SPRING,        SUMMER,        AUTUMN,        WINTER}


  3. public void seasonLiving(SeasonSimpliest season){

  4. if(season==SeasonSimpliest.SPRING){
  5. System.out.println("we BBQ at "+season);
  6. }
  7. else if(season==SeasonSimpliest.SUMMER){
  8. System.out.println("we swim at "+season);
  9. }
  10. else if(season==SeasonSimpliest.AUTUMN){
  11. System.out.println("we kite at "+season);
  12. }
  13. else if(season==SeasonSimpliest.WINTER){
  14. System.out.println("we skate at "+season);
  15. }
  16. else{
  17. System.out.println("What ?");
  18. }
  19. }
  20. public static void main(String args[]){
  21. TestEnumTiger1 t = new TestEnumTiger1();
  22. t.seasonLiving(SeasonSimpliest.SPRING);
  23. t.seasonLiving(SeasonSimpliest.WINTER);
  24. System.out.println("the seasong is :"+SeasonSimpliest.SPRING);
  25. //t.seasonLiving(WINTER+1);no way to put a season not in the SeasonEnum
  26. //t.seasonLiving(new SeasonSimpliest("Five Season"));no way to put a season not in the SeasonEnum

  27. }
  28. }
复制代码


这里面的常量直接用enum修饰,再加上一个名字和所需常量就可以了.
enum SeasonSimpliest {        SPRING,        SUMMER,        AUTUMN,        WINTER}
不过,不要被这种形式所迷惑,以为enum是一个primtive type,与int,boolean一样,那就错了.
让我们编译一下这个文件,再看看编译后的目录
里面除了有TestEnumTiger1.java,TestEnumTiger1.class之外,还有一个TestEnumTiger1$SeasonSimpliest.class,这就暴露了enum的某些行为方式,它在某种意义上是一个class.
在上面的源码中,它成了一个inner-class.

OK.让我们改改代码,把enum作为一个独立个体来处理

  1. //SeasonSimpliest.java
  2. package test;
  3. public enum SeasonSimpliest {SPRING,SUMMER,AUTUMN,WINTER}
复制代码


  1. //enum & static import
  2. package test;
  3. import static test.SeasonSimpliest.*;

  4. public class TestEnumTiger2{

  5. public void seasonLiving(SeasonSimpliest season){
  6. switch(season){
  7. case SPRING:
  8. System.out.println("we BBQ at "+season);
  9. break;
  10. case SUMMER:
  11. System.out.println("we swim at "+season);
  12. break;
  13. case AUTUMN:
  14. System.out.println("we kite at "+season);
  15. break;
  16. case WINTER:
  17. System.out.println("we skate at "+season);
  18. break;
  19. default:throw new AssertionError("something must be wrong,no such a season");
  20. }
  21. }
  22. public static void main(String args[]){
  23. TestEnumTiger2 t = new TestEnumTiger2();
  24. t.seasonLiving(SPRING);
  25. t.seasonLiving(WINTER);
  26. System.out.println("the season is :"+SUMMER);
  27. //t.seasonLiving(WINTER+1);no way to put a season not in the SeasonEnum
  28. //t.seasonLiving(new SeasonSimpliest("Five Season"));no way to put a season not in the SeasonEnum

  29. }
  30. }

复制代码


为了使整个代码显得更加简洁,我引入import static ,稍后再作更详细介绍,现在先来看看enum的好处.
1.避免了使用Const interface
2.很简单的定义方式
3.Type Safe,类型安全的,不会和其他的常量混绕.
4.可以使用switch
5.作为一个Class,它可以有自己Method,Field,也可以implements interface.

为了更好的说明第5点,我给大家展示一个复杂的enum type.


  1. //SeasonComplex.java
  2. //implements interface,owner method & field
  3. public  enum SeasonComplex implements Comparable<SeasonComplex>; {
  4.         SPRING(1),
  5.         SUMMER(2),
  6.         AUTUMN(3),
  7.         WINTER(4);
  8. private final int seasonNumber;
  9. Season(int value){
  10.         seasonNumber=value;
  11.         }
  12. public int seasonNumber(){
  13.         return seasonNumber;
  14. }
  15. public int compare(Season c){
  16. return seasonNumber - c.seasonNumber;
  17. }
  18. public String description(){
  19. return this+":第"+ seasonNumber +"季";
  20. }
  21. };

复制代码


具体的我就不一一写清楚,大家好好体会吧.

时间不早,关于static import 明天再慢慢说.

论坛徽章:
0
15 [报告]
发表于 2004-03-12 13:53 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

static import
static import就是允许在代码中直接引用别的类的static变量和方法(当然,在权限许可范围内),我们可以简单的把它当成import的延续。
它的语法如下:
import static CLASS_NAME.MEMBER_NAME;
或者 import static CLASS_NAME.×;


事实上,Tiger引入static import最主要考虑到两个需要,第一个就是对一些工具性的,常用的静态方法进行直接引用。
比如,java.lang.Math里的一大堆数学方法abs,exp等。
第二个就是对常数变量进行直接引用,其中也包扩对enum的直接引用(参考上一篇文章Season的例子)

  1. //StaticImportTest.java
  2. import static java.lang.Math.*;

  3. public class StaticImportTest{

  4. public static void main(String arsg[]){
  5. System.out.println("1 + 1 ="+(1+1));
  6. System.out.println("abs(-1)="+abs(-1));
  7. System.out.println("exp(1.5)="+exp(1.5));
  8. System.out.println("Pi = "+PI);
  9. System.out.println("E = "+E);

  10. }

  11. }
复制代码

这样的代码不仅省却了Programmer的劳动,在可读性上也是有所增强。

static import的限制和import也基本一样,就是不能出现二义性。
另外,static import不支持先import类,然后import static 类.*(不加package)的形式


  1. import  java.util.*;
  2. import static Calendar.*;
  3. ......
复制代码

就算在同一个包也是如此。

值得注意的是,过多的static import也许可能影响程序的可读性,如:

  1. //StaticImportTest2.java
  2. import static java.lang.Integer.parseInt;
  3. import static java.lang.Double.*;

  4. public class StaticImportTest{

  5. public static void main(String arsg[]){
  6. String iv = "1239";
  7. String dv = "123.3456";
  8. System.out.println(iv+":"+parseInt(iv));
  9. System.out.println(dv+":"+parseDouble(dv));
  10. System.out.println("Double's MaxValue is:"+MAX_VALUE );

  11. }
复制代码

虽然能编译通过,但是却很容易混绕读者视线。

论坛徽章:
0
16 [报告]
发表于 2004-03-12 16:33 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

Variable-Arity Methods(Varargs)
可匹配不同长度的自变量的函数,意思就是说,定义好的同一个Method,可以接收个数不一样的变量,看起来有点类似于过载。
我们还是先来看一个例子吧。


  1. //TestVarargs.java
  2. public class TestVarargs{


  3. //这个方法展示了varargs的基本语法
  4. // 类型(Type),加3个点,再加变量名,中间可以有或无空格
  5. // 而使用该变量时,是以一个Type[]的形式的,等于是一个Array
  6. //public static void out(int...   i){//这种可以
  7. //public static void out(int  ...i){//这种也可以
  8. //public static void out(int  ...  i){//这种也可以
  9. public static void out(int...i){//这种也可以
  10.         System.out.println("method:out(int... i),vararg.length:"+i.length);
  11.         if(i.length==0)
  12.                 return;
  13.         //for-each  featrue
  14.         for(Object ii:i)
  15.                 System.out.print("\t "+ii);
  16.         System.out.println();
  17.         }

  18. //和 out(Object... i) 存在二义性
  19. //public static void out(int i1,int... i){...}


  20. //varargs 只能出现在parameter的最后
  21. //public static void out(int... i,String s){...}

  22. //当然,其他变量可以出现在前面。
  23. public static void out(String s,int... i){
  24.         System.out.println("method:out(String s,int... i),vararg.length:"+i.length);
  25.         if(i.length==0)
  26.                 return;
  27.         //for-each  future
  28.         for(int ii:i)
  29.                 System.out.print("\t "+ii);
  30.         System.out.println();
  31.         }

  32. public static void main(String args[]){
  33.         out(123,1343,4542,677675);
  34.         out(12323,43243,00);
  35.         out("",12);
  36.         out("");
  37.         out();
  38.         }
  39. }
复制代码

该说明的基本上都在源码的注释里头了。
值得一提的是,根据JSR201的说法,对它的支持主要是在complier上,在VM的层面上是不需要支持的。在某种意义上,我们可以把它看作

  1.         out(int...i){};
  2.         out(123,1343,4542,677675);
  3.         ==
  4.         out(int[] i){};
  5.         out(new Int[]{123,1343,4542,677675});
复制代码

论坛徽章:
0
17 [报告]
发表于 2004-03-15 14:14 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

for-each(enhanced for loop )
接下来向你介绍的Tiger新特性,应该是大家比较期待的一个,在前面的例子里已经数次出现。
对了,就是 for-each(enhanced for loop )特性了。

for-each(enhanced for loop ),说得全一点应该是 for each element in the aggregation 。顾名思义,就是在for循环中逐个取出集合中的元素。
它的语法是
for(Type i : 集合){
i ...
}

这里的集合包括两种:
第一种是实现java.lang.Iterable接口的类,第二种就是array(数组)。
java.lang.Iterable是一个Tiger新引入的接口.在Tiger中,java.util.Colletcion 接口直接继承了 Iterable 接口。所以,所有Colletcion的子类都可以用于for-each语法里。同时,由于java.util.Map 接口里有 Collection<V>; values(),Set<Map.Entry<K,V>;>; entrySet() 和 Set<K>; keySet()三个方法返回Collention的子类。所以所有Map的子类也是可以间接的使用在for-each语句里的。
还是先来看一个例子吧.


  1. //TestForEach.java
  2. import java.util.*;
  3. public class TestForEach{
  4. public static void main(String arg[]){
  5. ArrayList list = new  ArrayList();
  6. list.add("asdf");
  7. list.add("fdaf");
  8. list.add("dfafds");
  9. list.add("dsafdsaf");
  10. int i=1;
  11. for(Object s : list){
  12. list.remove(s);
  13. System.out.println("element "+i+"  is:"+s);
  14. i++;
  15. }
  16. i=1;
  17. Object o[] = list.toArray();
  18. for(Object s : o){
  19. System.out.println("element "+i+"  is:"+s);
  20. i++;
  21. }

  22. }
  23. }
复制代码


for-each使我们更方便对集合里的元素进行遍历。实际上,编译器在处理Iterable和array时,分别采用如下的方法进行转换

  1. Iterable:
  2.   for ( Iterator<E>; #i = Expression.iterator(); #i.hasNext(); ) {
  3.   FormalParameter = #i.next();
  4.   Statement
  5.     }


  6. array:
  7. Type[] #a = Expression;
  8. L1: L2: ... Lm://The possibly empty sequence of labels preceding the enhanced for loop is represented by L1: L2: ... Lm. This sequence is moved beyond the assignment to #a so that continue and break statements with labels will work properly.
  9.     for (int #i = 0; #i < #a.length; #i++) {
  10.         FormalParameter = #a[ #i ] ;
  11.         Statement
  12.     }

复制代码



不过,值得注意的是,在Iterable中,for-each遍历是concurrent的,也就是说,在对Iterable进行遍历时,Iterable对象是不能改变的。这意味着我们不可以通过for-each进行移除以及修改的动作.

  1. //TestForEach2.java
  2. import java.util.*;
  3. public class TestForEach2{
  4. public static void main(String arg[]){
  5. ArrayList list = new  ArrayList();
  6. list.add("asdf");
  7. list.add("fdaf");
  8. list.add("dfafds");
  9. list.add("dsafdsaf");
  10. int i=1;
  11. for(Object s : list){
  12. System.out.println("removing element "+i+" :"+s);
  13. list.remove(s);//java.util.ConcurrentModificationException
  14. i++;
  15. }

  16. }
  17. }

  18. //运行
  19. removing element 1 :asdf
  20. java.util.ConcurrentModificationException
  21.         at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
  22.         at java.util.AbstractList$Itr.next(AbstractList.java:420)
  23.         at TestForEach.main(TestForEach.java:11)
  24. Exception in thread "main" Normal Termination
复制代码



创建我们的可以直接用于for-each的类

通常,我们都通过数组或者是Collection/Map的子类来使用for-each语句,当然我们也可以创建自己的for-each类(Iterable)
java.lang.Iterable是一个Tiger新引入的接口,它要求实现的方法只有一个,就是 Iterator<T>; iterator().这就要求我们需要去构造一个Iterator.Iterator接口有三个方法:boolean hasNext(),Type next()和remove(),其中remove为optional opreration,可以不必实现。

下面的例子使用了一个Iterator的内部类,就其意义来说,是实现一组的平方数的一个迭代。(现实中也许永远不需这种用法 :) )

  1. //MyForEach.java
  2. import java.util.*;
  3. public class MyForEach implements Iterable{
  4. int start,end;
  5. int step=1;
  6. public MyForEach(){
  7. start=5;
  8. end=10;
  9. }
  10. public MyForEach(int start){
  11. this.start=start;
  12. end=start+5;
  13. }
  14. public MyForEach(int start,int end){
  15. this.start=start;
  16. this.end=end;
  17. if(start<end)
  18.         step=-1;
  19. }
  20. public Iterator iterator(){
  21. return new Iterator(){//inner class of Iterator
  22.         int currentPos=start;
  23.         public void remove(){
  24.                 //do nothing
  25.                                 throw new UnsupportedOperationException();
  26.         }
  27.         public boolean hasNext(){//check if exceed the end  
  28.                 return (step>;0)^(currentPos>;end);
  29.         }
  30.         public Object next(){
  31.                 if(!hasNext())
  32.                         throw new NoSuchElementException();
  33.                 int ret=currentPos*currentPos;//平方数
  34.                 currentPos+=step;
  35.                 return ret;
  36.                 }
  37.         };
  38. }
  39. public static void main(String args[]){
  40. MyForEach m1 = new MyForEach();
  41. for(Object o:m1)
  42.         System.out.println(o);

  43. }

  44. }

复制代码


还是那句老话,自己好好体会一下吧。

论坛徽章:
1
数据库技术版块每日发帖之星
日期:2015-12-09 06:20:00
18 [报告]
发表于 2004-03-19 00:04 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

luguo

论坛徽章:
0
19 [报告]
发表于 2004-03-21 17:12 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

good pig

论坛徽章:
0
20 [报告]
发表于 2004-03-21 22:57 |只看该作者

老虎来了,你准备好了吗?(增加for-each)

写的不错,我是个新手,刚刚才开始。对于讲的环境变量设置还是有些不太明白,那么CLASSPATH不用设置吗?
   希望你可以给我一个详细指点
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP