发新话题
打印

JAVA学堂_____从零开始

第二十七课  继承(4)
读下面程序,分析结果:
class Cleanser{
        private String s=new String("Cleanser");
        public void append(String a){s+=a;}
        public void dilute(){append(" dilute()");}
        public void apply(){append(" apply()");}
        public void scrub(){append(" scrub()");}
        public void print(){System.out.println(s);}
        public static void main(String args[]){
                Cleanser x=new Cleanser();
                x.dilute();
                x.apply();
                x.scrub();
                x.print();
        }
}
public class Detergent extends Cleanser{
        public void scrub(){
                append(" Detergent.scrub()");
                super.scrub();
        }
        public void foam(){
                append(" foam()");
        }
        public static void main(String args[]){
                Detergent x=new Detergent();
                System.out.println("Sub class has:");
                x.dilute();
                x.apply();
                x.scrub();
                x.foam();
                x.print();
                System.out.println("Super class has:");
                Cleanser.main(args);
        }
}
注:1、在子类中,scrub和main被覆盖
2、在设计程序时每个class都可以有一个main以方便调试
3、重载一个方法时,子类方法必需至少具有超类方法的可见性,如果超类方法为public,子类方法必须为public
4、类声明为final时,方法自动为final但不包括变量

TOP

第二十八课 继承(5)
强制类型转换:把一个类强制转换为另一个类,但由一个超类转换为子类时可能会抛出一个异常。
我们通过一个具体的实例来讲解:
import java.text.DecimalFormat;
import javax.swing.JOptionPane;
public class InheritanceTest{
        public static void main(String args[]){
                Point pointRef,p;
                Circle circleRef,c;
                String output;
                p=new Point(30,50);
                c=new Circle(2.7,120,89);
                output="Point p:"+p.toString()+"\nCircle c:"+c.toString();
                pointRef=c;
                output+="\n\nCircle c(via pointRef):"+pointRef.toString();
                circleRef=(Circle)pointRef;
                output+="\n\nCircle c(via CircleRef):"+circleRef.toString();
                DecimalFormat precision2=new DecimalFormat("0.00");
                output+="\nArea of c(via CircleRef):"+precision2.format(circleRef.area());
                if(p instanceof Circle){
                        circleRef=(Circle)p        ;
                        output+="\n\ncast successful";
                }
                else
                  output+="\n\np does not refer to a Circle";
                JOptionPane.showMessageDialog(null,output,"Demonstrating the \"is a\" relationship",JOptionPane.INFORMATION_MESSAGE);
                System.exit(0);
        }
}
class Point{
        protected int x,y;
        public Point(){setPoint(0,0);}
        public Point(int a,int b){setPoint(0,0);}
        public void setPoint(int a,int b){
                x=a;
                y=b;
        }
        public int getX(){return x;}
        public int getY(){return y;}
        public String toString(){return "["+x+","+y+"]";}
        public double area(){return 0.0;}       
        public double volume(){return 0.0;}
        public String getName(){return "Point";}
}
class Circle extends Point{
        protected double radius;
        public Circle(){setRadius(0);}
        public Circle(double r,int a,int b){
                super(a,b);
                setRadius(r);
        }
        public void setRadius(double r){radius=(r>=0?r:0);}
        public double getRadius(){return radius;}
        public double area(){return Math.PI*radius*radius;}
        public String toString(){
                        return "Centur="+super.toString()+";Radius="+radius;
        }
        public String getName(){return "Circle";}
}

TOP

第二十九课  继承(6)
我们再看一个例子来分析强制类的转换问题:
class SuperClass{
        private int x=100;
        public int getX(){
                return x;
        }
}
class Subbie extends SuperClass{
        private int y=200;
        public int getY(){
                return y;
        }
}
public class ObjectConvert{
        public static void main(String args[]){
                SuperClass superA=new SuperClass(),superB;
                Subbie subA=new Subbie(),subB;
                (new ObjectConvert()).useSubAsSuper(subA);
                superB=subA;
                System.out.println("superB.getX():"+superB.getX());
                subB=(Subbie)superB;
          System.out.println("subB.getY():"+subB.getY());
          //System.out.println("subB.getX():"+subB.getX());//不出错误
        }
        public void useSubAsSuper(SuperClass x){
        System.out.println(x.getX()+"!!!!!");
        //System.out.println(x.getY()+"!!!!!");//不可以调用子类对象
        }
}

TOP

第三十课  继承(7)
这节课我们主要讲一下多态的概念
多态:是指在一棵继承树中的类中可以有多个同名但不同方法体及不同形参的方法。
多态的两种情况:覆盖和重载
覆盖:是在子类中直接定义相同的属性和方法,但重新编写了方法体,即子类与父类方法的形参与返回值都相同,而内部处理不同,这种方法在使用过程中,JAVA虚拟机会根据调用该方法的类来确定哪个方法被调用。
重载:在同一个类中定义多个同名的方法,但有不同的形参,而且每个方法有不同的方法体,调用时根据形参的个数和类型来决定调用哪个方法。
我们来看覆盖,这是一种比较简单的多态,它是扩大对象灵活性的一种有效手段。
Public class A{
·
·
·
  public String toString(){
    return “类名A”
  }
}
Public class B extends A{
·
·
·
  public String toString(){
    return “类名B”
  }
}
这时候子类方法和超类同名,子类方法覆盖父类的同名方法,当想要执行父类中的toString时,可以用super.toString()。
涉及到重载的时候就比较复杂了一些,其中有一个很重要的原因就是构造函数,这个我们在以前的时候已经接触到了,构造函数重载的目的是以不同的方法对类进行初始化。
Public class Student{
  int studentFlag;        //值1表示在校生,值0表示在职生
  int sNo;              //编号
  String sName;         //姓名
  Char sSex;            //性别
  private Date sBirthday  //出生日期
  Date enrollDay;       //报到日期
  int classNo;           //班号
  int departmentNo;      //系号
  float tuition;           //学费
  static double sStartNo1;  //在校生编号的起始号
  static double sStartNo2;  //在职生编号的起始号
  static {               //静态初始化器
    sStartNo1=991001;
    sStartNo2=992001;
  }
  public Data getsBirthday(){
    return sBirthday;
  }
  public setsBirthday(Data x){
    sBirthday=x;
  }
那么我们可以为这个类定义多个构造函数,以对应不同的情况
Student (){}
//判断是在职生还是在校生,然后给出学生编号
Student(int $studentFlag){
  if($studentFlag==1)  sNo=sStartNo1++;
  else if($studentFlag==0)  sNo=sStartNo2++;
  else system.out.println(studentFlag wrong!);
}
//给出学生编号并输入姓名和性别
Student(int $studentFlag,String $sName,char $sSex){
  if($studentFlag==1)  sNo=sStartNo1++;
  else if($studentFlag==0)  sNo=sStartNo2++;
  else system.out.println(studentFlag wrong!);
  sName=$sSname;
  sSex=$sSex;
}
//给出学生编号并输入姓名、性别、系名和班级
Student(int $studentFlag,String $sName,char $sSex){
  if($studentFlag==1)  sNo=sStartNo1++;
  else if($studentFlag==0)  sNo=sStartNo2++;
  else system.out.println(studentFlag wrong!);
  sName=$sSname;
  sSex=$sSex;
  departmentNo=$departmentNo;
  classNo=$classNo;
}
以上是一个类中多个构造函数重载的定义,这些重载函数的使用方法如下:
Student astudent=new Student();
Student astudent=new Student(1);
Student astudent=new Student(1,”tom”,m);
Student astudent=new Student(1,”tom”,m,10,11);
当然我们看到这三个构造函数有很多重复的地方,我们可以用this来代表函数名,以进行简化。
//判断是在职生还是在校生,然后给出学生编号
Student(int $studentFlag){
  if($studentFlag==1)  sNo=sStartNo1++;
  else if($studentFlag==0)  sNo=sStartNo2++;
  else system.out.println(studentFlag wrong!);
}
//给出学生编号并输入姓名和性别
Student(int $studentFlag,String $sName,char $sSex){
  this($studentFlag);
  sName=$sSname;
  sSex=$sSex;
}
//给出学生编号并输入姓名、性别、系名和班级
Student(int $studentFlag,String $sName,char $sSex){
  this($studentFlag,$sName,$sSex);
  departmentNo=$departmentNo;
  classNo=$classNo;
}

TOP

第三十一课  继承(8)
下面我给出个程序,大家仔细读一下:
import javax.swing.JOptionPane;
import java.text.DecimalFormat;
public class TestEmployee{
        public static void main(String args[]){
                Employee ref;
                String output="";
                Boss b=new Boss("Richard","Zhang",800.00);
                CommissionWorker c=new CommissionWorker("Dexter","Li",400.0,3.0,150);
                PieceWorker p=new PieceWorker("Matrix","Wang",2.5,200);
                HourlyWorker h=new HourlyWorker("Drodan","ma",13.75,40);
          DecimalFormat precision2=new DecimalFormat("0.00");
          ref=b;  //把父类的引用ref赋值为子类的Boss对b的引用
          output+=ref.toString()+"工资¥"+precision2.format(ref.earnings())+"\n"+b.toString()+"工资¥"+precision2.format(b.earnings())+"/n";
          ref=c;  //把父类的引用ref赋值为子类普通员工对c的引用
          output+=ref.toString()+"工资¥"+precision2.format(ref.earnings())+"\n"+c.toString()+"工资¥"+precision2.format(c.earnings())+"/n";
          ref=p;  //把父类的引用ref赋值为子类计件工人对b的引用
          output+=ref.toString()+"工资¥"+precision2.format(ref.earnings())+"\n"+p.toString()+"工资¥"+precision2.format(p.earnings())+"/n";
          ref=h;  //把父类的引用ref赋值为子类计时工人对b的引用
          output+=ref.toString()+"工资¥"+precision2.format(ref.earnings())+"\n"+h.toString()+"工资¥"+precision2.format(h.earnings())+"/n";
          JOptionPane.showMessageDialog(null,output,"Demonstrating Polymorphism",JOptionPane.INFORMATION_MESSAGE);
          System.exit(0);
        }
}

abstract class Employee{
        private String firstName;
        private String lastName;
        //构造函数
        public Employee(String first,String last){
                firstName=first;
                lastName=last;
        }
        //返回姓
        public String getFirstName(){return firstName;}
        public String getLastName(){return lastName;}
        public String toString(){
        return firstName+' '+lastName;
}
  //Employee抽象方法earnings()
  //将被其每个子类以实例继承
  public abstract double earnings();
}
final class Boss extends Employee{
        private double weeklySalary;
        //经理Boss类的构造函数
        public Boss(String first,String last,double s){
                super(first,last);
                setWeeklySalary(s);
        }
        //经理Boss类的工资
        public void setWeeklySalary(double s){
        weeklySalary =(s>0?s:0);
        }
        //确定Boss的薪水
        public double earnings(){return weeklySalary;}
        //打印姓名
        public String toString(){
                return "经理"+super.toString();
        }
}
final class PieceWorker extends Employee{
        private double wagePerPiece;  //生产量
        private int quantity;         //工作周数
        public PieceWorker(String first,String last,double w,int q){
                super(first,last);
                setWage(w);
                setQuantity(q);
        }
        //确定工资
        public void setWage(double w){wagePerPiece=(w>0?w:0);}
        //确定工作数量
        public void setQuantity(int q){quantity=(q>0?q:0);}
        //确定计件工人的工资
        public double earnings(){
          return quantity*wagePerPiece;
        }
        public String toString(){
                return "计件工人:"+super.toString();
        }
}
final class HourlyWorker extends Employee{
        private double wage;  //每小时工资
        private double hours; //每周工作时间
        public HourlyWorker(String first,String last,double w,double h){
                super(first,last);
                setWage(w);
                setHours(h);
        }
        //确定工资
        public void setWage(double w){wage=(w>0?w:0);}
        //确定工作时间
        public void setHours(double h){hours=(h>=0&&h<168?h:0);}
        //确定计时工人的工资
        public double earnings(){return wage*hours;}
        public String toString(){
                return "计时工人:"+super.toString();
        }
}
final class CommissionWorker extends Employee{
        private double salary;    //每周的底薪
        private double commission;  //每周奖金
        private int quantity;       //销售额
        //普通员工类的构造函数
        public CommissionWorker(String first,String last,double s,double c,int q){
                super(first,last);
                setSalary(s);
                setCommission(c);
                setQuantity(q);
        }
        //确定普通员工的每周底薪
        public void setSalary(double s){salary=(s>0?s:0);}
        //确定普通员工的每周奖金
        public void setCommission(double c){commission=(c>0?c:0);}
        //确定普通员工销售额
        public void setQuantity(int q){quantity=(q>0?q:0);}
        //确定普通员工收入
        public double earnings(){
        return salary+commission*quantity;}
        //打印普通员工姓名
        public String toString(){return "普通员工:"+super.toString();
        }}

TOP

第三十二课  继承(9)
一、Object类
Object类:所有类的超类,每一个类都是从Object继承而来的,但不用明确给出Object超类:
   class A extends Object;
上面书写方式是不需要的,如果不明确给出超类,默认超类就是Object,你可以使用Object类型的变量指向任何类型的对象:
Object obj=new Employee(“Richard”,”Zhang”);
但反过来的时候我们就需要强制转换了:
   Employee e=(Employee)obj;
二、Object类提供的Equals和toString方法
1、Equals方法用于测试两个对象是否相等,但只能实现判断是否在同一片内存区域中,这没什么用,所以如果想测试对象是否相同,需要重载equals方法:
class Employee{
  public Boolean equals(object  otherObject){
//判断两个对象是否是同一对象
if(this==otherObject) return true;
//如果参数为null则返回false
if(otherObject==null)return false;
//判断两个对象是否相等,至少应该两个对象属于同一个类
if(getClass()!=otherObject.getClass())  return false;
//非空对象,进行强制转换
Employee other=(Employee)otherObject;
//判断各个属性是否相同
return firstname.equals(other.firstname)&&lastname.equals(lastname);
}
}
2、toString方法:返回代表该对象的字符串,但几乎每个类都会重载该方法,以便返回对象的正确状态,例如:
public String toString(){
  return “Employee[firstname=”+firstname+”,lastname=”+lastname+”]”;
}
当然我们也可以用getClass方法取得类名
public String toString(){
  return getClass().getName()+“[firstname=”+firstname+”,lastname=”+lastname+”]”;
}
我们建议在每个类中都要重载toString方法,可以方便调试
三、Object与其他类型的转换
数字、字符和布尔型的变量不能作为对象,其它的所有值可以和Object类型的变量相互替代。
Object obj=”Hello”;
当然数组也可以赋给Object
Employee[] person=new Employee[10];
object obj=person;
obj=new float[10];
四、对象的包装
在JAVA中所有的基本数据类型都有与之匹配的类,这种类称为对象包装器,它们分别是:Integer、Long、Float、Double、Short、Byte、Character、Void、Boolean
比如设计一个整型的数组:
ArrayList array=new ArrayList();
我们用add方法为数组添加成员,这里面注意add方法要求的是一个对象,所以下面的是错误的
array.add(200);
我们可以通过如下方法来实现
array.add(new Integer(200));
另外对象包装器还有一个用处,就是可以放置某些基本方法,如把字符串转换成整型数据
int I=Integer.parseInt(s);

TOP

第三十三课  面向对象的高级特性(接口1)
一、接口的定义
在JAVA中不采用C++的多重继承机制,使得编程我加简单,但这里面同时也带来了一个问题。比如说汽车来自车辆类,客机来自飞机类,汽车和客机来自各自的父类,但同时二者又全部都是燃油的,那么如果燃油的一些特性如果我们在二者各自的类中来定义的话,那么又会有许多重复的内容出现,所以在JAVA中采用了接口(interface)这一概念,来解决这一问题。
接口是用来实现类似多重继承功能的一种结构,它在语法上和类很相似,它也有属性和方法,接口间也可以形成继承关系,但它的属性都是常量,方法都是抽象方法,没有方法体。
接口只是一个口,里面是空的。在上面的例子中,JAVA允许定义一个接口:燃油,它可以有一些常量属性和抽象方法,然后在汽车、客机中分别具体化接口的方法,这样就相当于实现了多重继承。
接口的特点:
1、接口用关键字interface来定义,而不是class
2、接口中定义的变量全部是静态变量,而且都是最终的静态变量
3、接口没有自身的构造方法,而且定义的方法都是抽象的方法,即只提供方法的定义,而不提供具体的实现。
4、接口采用多重继承机制,而不是采用类的单重继承机制
它的定义格式为:
[public] interface 接口名 [extends 父类接口名1,父类接口名2……]{
   [public static final]属性数据类型  属性名1=值;
   ·
   ·
   ·
  [public abstract][native]返回值类型  方法名(形参表)[throws 异常名列表];
   ·
   ·
   ·
}
接口的属性必须用public static final来修饰,但这是默认的可以不写;接口的方法系统默认为public abstract,也可以不写,后面不写大括号,直接以分号结束;throws后面我们会介绍到。
例如:要编一个播放器的程序,先实现了关于播放的动作的一个接口
public interface PlayClip{
  int time=1;
  void play();
  void loop();
  void stop();
}
二、调用接口
由于接口中的方法都是抽象方法,所以接口定义完之后,必须在某个类中对接口的方法进行具体化,就是在类中重新定义接口的所有方法,这时的方法就不能是抽象的了,称这个过程为某个类实现了某个接口。
一个类要实现某个接口,必须在定义时用关键字implements来声明,同时注意以下几点:
1、一个类能实现多个接口,多个接口间用逗号隔开
2、一个接口可以被多个类实现
3、一个类声明实现某个接口后,必须实现该接口的全部方法
4、被实现的方法的访问控制符必须显式地使用public修饰,因为接口的方法都是public
我们用一个具体的类来实现上面的接口
public class MyClass implements PlayClip{
int time=1;
void play(){
  //具体实现
}
void loop(){
  //具体实现
}
void stop(){
  //具体实现
}
}

TOP

第三十四课  面向对象的高级特性(接口2)
  由于一个类实现一个接口的时候必须实现它的全部方法,所以在对接口进行改动的时候必须小心。比如我们在刚才的那个接口中增加一个功能
public interface PlayClip{
  int time=1;
  void play();
  void loop();
  void stop();
  void a();
}
这时,所有实现这个接口的类都将出错,因为这些类没有实现它的新增加的方法,这会很麻烦。那么我们可以增加一个子接口,在子接口中增加所要的方法:
  public interface PlayClipAdd extends PlayClip{
void A();
  }
*****这个我们通常叫接口的扩展,但当两个父接口都有一个具有相同特征的方法,也就是说两个方法的名字和形式参数都相同,则它们必须具有相同的返回值类型。*****

实现接口必须实现它所有的方法,这种特性在很多情况下都非常不方便,而抽象类就不需要实现所有的方法,因此,当只需要使用某个接口中的少部分方法时,可以继承与之相对应的抽象类。JAVA类库为所有的接口都提供了与之相对应的抽象类,称之为适配器(adapter),使用适配器可以节省大量无用工作,使程序结构更加清晰,不过前提是该类不需要继承其他类,否则还要使用接口,因为只有接口才能在一定程序上实现多态继承    。
我们看下面如何实现部分方法
public abstract class MyClass implements PlayClip{
  void play(){
  //具体实现
}
void loop(){
  //具体实现
}
void stop();
}
这里面MyClass 只实现了play和loop方法,但stop方法没有实现,所以MyClass必须声明为抽象类。

另外还有一个问题,接口不是类,所以不能用new实例化,象下面是错误的:
x=new PlayClip();
但可以声明一个接口变量,该变量必须指向一个实现了该接口的类的对象
PlayClip x;
x=new MyClass();

TOP

第三十五课  面向对象的高级特性(内部类)
一、定义:将类定义在另一个类内,称为(非静态)内部类(Inner Class),若为static 则称为静态内部类或是嵌套类,而包含这些内部类的为外部类,如果将内部类定义在一个方法内,称为局部内部类。
  内部类可无条件存取该类中声明的成员,而其它外部类也能存取内部类中的成员(非private);局部内部类完全隐藏在方法中,甚至连同一个类的其他方法也无法使用。
例如:
public class Person{
  int count;
  public class Student{
    String name;
    public void output(){
    System.out.println(this.name);}
  }
}
这时将产生两个类一个名为:Pers on.class另一个内部类的名称为:Person$Student.class
那么其它类在生成内部类的对象时则需要声明:
Person.Student aa=new Person().new Student();
二、定义内部类的好处:
1、一个内部类的对象能够访问创建它的对象的实现——包括私有数据
2、对于同一包中的其他类来说,内部类能够隐藏起来。
3、匿名内部类可以很方便地定义回调
4、使用内部类可以非常方便地编写事件驱动的程序
三、局部内部类
1、局部类不用访问指示符(如public或private)声明,它的范围总是被限定在声明它们的程序块内
2、局部类能够对外部完全隐藏
3、局部类不仅能够访问外部类的字段,甚至可以访问局部变量,但必须声明为final
public class Person{
  int count;
  public class Student{
          String name;
    public void output(){
            class aa{
                    int  b=1;
                    }
            }
  }
}
四、匿名类:没有名称的内部类,它可以省去类命名的麻烦。由于匿名类没有名称,所以它没有构造函数。它只适于包含简短的程序,过度地使用往往会造成程序不易理解
五、静态内部类:如果只需要把一个类隐藏在另一个类中,但是同时该内部类不需要对外部类的引用,这种情况下可以通过把内部类声明为static.
public class Person{
        public static class Student{
                static int count;
                String name;
                int Number;
                public Student(String n){
                        name=n;
                        count++;
                        Number=count;
                }
                public void output(){
                        System.out.println(this.name+" number="+this.Number);
                }
        }
                public static void main(String args[]){
                        Person.Student stu1=new Person.Student("A");
                        stu1.output();                }        }

+++++++++读程序
public class InnerClassDemo{
        public static void main(String[] args){
                InnerClassDemo demo=new InnerClassDemo();
                //非静态内部类
                InnerClassDemo.Inner inner=demo.new Inner();
                inner.innerMethod();
                System.out.println("Data in inner class:"+inner.value);
                //静态内部类
                InnerClassDemo.StaticInner staticInner=new InnerClassDemo.StaticInner();
                staticInner.innerMethod();
                System.out.println("Data in static inner class:"+StaticInner.staticValue);
                //或者使用staticInner.staticValue
        }
        public String outerMethod(){
                return "outer method.";
        }
        public class Inner{
                private int value=1;
                public Inner(){
                        System.out.println("Inner class is created.");
                }
                public void innerMethod(){
                        System.out.println("Inner class is calling "+outerMethod());
                        //访问静态成员变量或内部类
                        System.out.println("Inner class accesses data in static inner class:"+StaticInner.staticValue);
                }
        }
        public static class StaticInner{
                static int staticValue=10;
                public StaticInner(){
                        System.out.println("Static inner class is created.");
                }
                public void innerMethod(){
                        System.out.println("Static inner class is called.");
                }
        }
}

TOP

第三十六课  面向对象的高级特性(抽象类)
一、抽象类
抽象类:某些方法只对某个特定类型的对象才有意义,这些方法在这个类中是不能实现的,在这个类中没有包含足够的信息来描绘一个具体的对象。抽象类往往用来表征在对问题领域进行分析、设计中得出的抽象概念。所谓的抽象类指不能直接被实例化的类,因此一般作为其他类的超类。
抽象类的属性和方法都是它的子类的公共属性和方法的集合,所以定义抽象类还有一个特点,就是改变它的属性和方法一定会改变它的所有子类的该属性和方法。
例:
abstract class Vehicle{
  float speed;
   ·
   ·
   ·
  void start(){
   ·
   ·
   ·
  }
  void stop(){
   ·
   ·
   ·
  }
  void acceleration(){
   ·
   ·
   ·
  }
}
当我们相要给各个子类的加速度方法传递加速度值,只需要把Vehicle类的方法改一下,那么其它的子类都将改成以上形式:
  void acceleration(float a){
   ·
   ·
   ·
  }
}
二、抽象类—抽象方法
抽象方法:以abstract修饰的方法称抽象方法,所有的抽象方法必须在抽象类或者接口中,抽象方法只有方法头而无方法体,具体实现需要定义他的子类的任务
抽象方法的继承是通过覆盖的形式来实现继承的,子类必须实现所有的抽象方法,如果子类没有实现全部的抽象方法就必须仍定义为抽象类。
实例:
abstract class AbstractSuper{
        public void a(){
                System.out.println("Method a() of super");
        }
        public abstract void b();
}
class AbstractSub extends AbstractSuper{
        public void b(){
                System.out.println("Method b() of super");
        }
        public void c(){
                System.out.println("Method c() of subbie");
        }
}
public class InstanceofAbstract{
        public static void main(String args[]){
                AbstractSuper anInstance=new AbstractSub();
                AbstractSub another=new AbstractSub();
                anInstance.a();
                anInstance.b();
                anInstance.c();
                another.c();
        }
}

TOP

发新话题