`
new_Line
  • 浏览: 9765 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

黑马程序员_java JDK1.5特性

 
阅读更多

------- android培训java培训、期待与您交流! ----------

静态导入:
    JDK1.5的新特性,它用于导入指定类的静态属性或静态方法。
    语法:import static java.包名.类名.*;
    演示:
        package com.itheima;
        import java.util.Calendar;
        import static java.util.Calendar.*;
        public class StaticImportDemo {
            public static void main(String[] args) {
                Calendar cal = getInstance();
                cal.set(DATE, 25);
                System.out.println(cal.getTime());
            }
        }
可变参数:
    JDK1.5的新特性
    特点:1、只能出现在参数列表最后
          2、...位于变量类型和变量名之间,前后有无空格都可以
          3、调用可变参数方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数
    演示:
        package com.itheima;
        public class ChangeArgsDemo {
            public static void main(String[] args) {
                System.out.println(changeArgs(2,4,6,8));
            }
            public static int changeArgs(int ... args)
            {
                int sum = 0;
                for(int i = 0; i < args.length; i++)
                    sum += args[i];
                return sum;
            }
        }
增强for循环:
    JDK1.5之后的新特性。
    语法:
        for(参数类型 变量名 : 数组|集合)
        {
            //迭代部分
        }
    特点:使用增强for循环遍历数组或集合时,无需指定长度,也无需根据索引来访问元素
    注意:增强for循环只能遍历数组或集合,不能改变数组或集合的值
    演示:
        package com.itheima;
        import java.util.Arrays;
        public class EnhanceForDemo {
            public static void main(String[] args) {
                int[] arr = {12,32,24,21,37};
                for(int item : arr)
                {
                    //改变数组元素的值
                    item = item + 2;
                    System.out.print(item + " ");
                }
                //打印员数组
                System.out.println("\n" + Arrays.toString(arr));
            }
        }
    运行结果:14 34 26 23 39
          [12, 32, 24, 21, 37]
枚举类:
    JDK1.5的新特性,新增enum关键字,用以定义枚举类。
    特点:1、枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,
        而不是Object类。其中Enum类实现了Serializable和Comparable接口。
          2、使用enum定义的非抽象枚举类默认使用final修饰,因此非抽象枚举类不能派生子类
         A:为什么抽象枚举类或接口可以派生子类?而非抽象枚举类不可以
            因为抽象枚举类被abstract修饰,而abstract不能和final使用
          3、枚举类的构造方法只能使用private修饰,默认情况也是
          4、枚举类的所有实例必须在枚举类的第一行显示列出,系统会自动添加public static final修饰
             格式:每个枚举值之间以英文逗号隔开,最好以分号结束
             演示:
            public enum SeasonEnum {
                SPRING, SUMMER, FALL, WINTER;
                private SeasonEnum(){}//如果改为public,编译失败。
            }
            //如果把构造器和实例交换位置,编译时出错
          6、所有的枚举类都提供了一个values()方法,刚方法可以遍历所有的枚举值(实例)
         演示:
            package com.itheima.demo;
            public enum SeasonEnum {
                //定义四个枚举实例
                SPRING, SUMMER, FALL, WINTER;
            }
            package com.itheima.demo;
            import com.itheima.season.Season;
            public class Test {
                public static void main(String[] args) {
                    //用数组保存所有的枚举值
                    SeasonEnum[] seas = SeasonEnum.values();
                    for(SeasonEnum item : seas)
                        System.out.print(item);
            运行结果:SPRING SUMMER FALL WINTER
    枚举类无参的实例化过程:
        当在枚举类中给出一个枚举值,就创建了一个枚举类实例,
        通过显示创建无参构造器来证实它的实例化过程。
        演示说明:
            public enum SeasonEnum {
                //列出4个枚举类实例
                SPRING,//public static final SeasonEnum SPRING = new SeasonEnum();
                SUMMER,//public static final SeasonEnum SUMMER = new SeasonEnum();
                FALL,//public static final SeasonEnum FALL = new SeasonEnum();
                WINTER;//public static final SeasonEnum WINTER = new SeasonEnum();
                //看构造器中的代码是否被执行
                private SeasonEnum()
                {
                    System.out.println("构造器被调用了");
                }
            }
            /*测试类*/
            public class SeasonTest {
                public static void main(String[] args) {
                    SeasonEnum s = SeasonEnum.valueOf("SPRING");
                }
            }
            运行结果:构造器被调用了
                  构造器被调用了
                  构造器被调用了
                  构造器被调用了
                通过运行结果可以看出,当在主函数中调用使用枚举类时,先走了构造方法,
            有几个枚举值,构造器就被调用了多少次,就创建了多少个枚举实例,
        结论:枚举类的实例只能是枚举值,不能随意通过new来创建对象,无需显示调用构造器。
    枚举类的带参实例化过程:
        当枚举类显示的定义了带参构造方法时,列出枚举值时就必须对应传入参数
        演示说明:
            package com.itheima.gender;
            public enum GenderEnum {
                //定义两个枚举实例
                 //相当于public static final GenderEnum MALE = new GenderEnum("男");
                MALE("男"),
                //相当于public static final GenderEnum FEMALE = new GenderEnum("女");
                FEMALE("女");
                private GenderEnum(String sex) {
                    this.sex = sex;
                }
                //枚举类通常设置为不可变类,因此它的属性也不应该随便改变
                //所以用private final修饰
                private final String sex;
                public String getSex()
                {
                    return sex;
                }
            }
            package com.itheima.gender;
            /*测试类*/
            public class GenderTest {
                public static void main(String[] args) {
                    GenderEnum male = GenderEnum.MALE;
                    System.out.print(male.getSex() + " ");
                    GenderEnum female = GenderEnum.FEMALE;
                    System.out.print(female.getSex());
                }
            }
            运行结果:男 女
        结论:当枚举类定义了带参构造器时,如果枚举值不匹配对应的参数,编译失败
              枚举值传入参数时,实际上就是调用了带参构造器创建对象,只是它无需
              通过new来创建对象,也无需显示调用构造器
    枚举类的特殊方法:
        int compareTo(E o) 比较此枚举与指定对象的顺序。
        String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
        String toString() 返回枚举常量的名称,它包含在声明中。
        static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
                返回带指定名称的指定枚举类型的枚举常量。
            演示:
                package com.itheima.demo;
                public enum SeasonEnum {
                    SPRING, SUMMER, FALL, WINTER;
                    public void show(SeasonEnum s)
                    {
                        switch(s){
                        case SPRING:
                            System.out.println("春天");
                            break;
                        case SUMMER:
                            System.out.println("夏天");
                            break;
                        case FALL:
                            System.out.println("秋天");
                            break;
                        case WINTER:
                            System.out.println("冬天");
                            break;
                        }
                    }
                }
                package com.itheima.season;
                import com.itheima.demo.SeasonEnum;
                public class SeasonTest {
                    public static void main(String[] args) {
                        //通过给定的字符串常量,获取枚举类实例,
                        //给出的字符串常量必须是枚举实例之一,
                        //否则运行时引发IllegalArgumentException异常
                        SeasonEnum s = SeasonEnum.valueOf("SPRING");
                        System.out.println(s);
                        s.show(s);
                    }
                }
            运行结果:
                SPRING
                春天
        int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
        Class<E> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
    枚举类中的抽象方法:
        如果枚举类实现了一个接口或继承了一个抽象类,如果每个枚举实例调用该方法都具有
        相同功能,那么可以直接在枚举类中重写该方法
        演示:
            public enum EnumClass implements A {
                MALE(1),FEMALE(2);
                private final int x;
                private EnumClass(int x)
                {
                    this.x = x;
                }
                //重写show()
                public void show(){}
            }
            interface A
            {
                public abstract void show();
            }
        如果每个枚举类实例的实现细节不一样,那么可以通过匿名内部类的方式让每个枚举实例
        都重写该方法
        演示:
            public enum EnumClass implements A {
                MALE(1)
                {
                    public void show() {
                        //实现细节
                    }
                   
                },
                FEMALE(2)
                {
                    public void show() {
                        //实现细节
                    }
                   
                };
                private final int x;
                private EnumClass(int x)
                {
                    this.x = x;
                }
            }
            interface A
            {
                public abstract void show();
            }
        如果该枚举类中本身就包含抽象方法,那么每个枚举实例都必须重写该方法。
        注意:枚举类定义抽象方法时,不能使用abstract将类定义成抽象类,
              因为系统会自动添加abstract修饰,这里不能在显示添加
        模拟交通灯练习:
            package com.itheima.lamp;
            public enum TransLamp {
                RED(40) {
                    @Override
                    public TransLamp nextLamp() {
                        return GREEN;
                    }
                },
                GREEN(50) {
                    @Override
                    public TransLamp nextLamp() {
                        return YELLOW;
                    }
                },
                YELLOW(3) {
                    @Override
                    public TransLamp nextLamp() {
                        return RED;
                    }
                };
                private final int time;
                private TransLamp(int time)
                {
                    this.time = time;
                }
                public int getTime()
                {
                    return time;
                }
                public abstract TransLamp nextLamp();
            }
            /*测试类*/
            package com.itheima.lamp;
            public class Test {
                public static void main(String[] args) {
                    TransLamp tlRed = TransLamp.RED;
                    System.out.println(tlRed + " 时间:" + tlRed.getTime()
                    + "s,下一种灯是:" + tlRed.nextLamp());
                    TransLamp tlGreen = TransLamp.GREEN;
                    System.out.println(tlGreen + " 时间:" + tlGreen.getTime()
                    + "s,下一种灯是:" + tlGreen.nextLamp());
                    TransLamp tlYellow = TransLamp.YELLOW;
                    System.out.println(tlYellow + " 时间:" + tlYellow.getTime()
                    + "s,下一种灯是:" + tlYellow.nextLamp());
                }
            }
            运行结果:
                RED 时间:40s,下一种灯是:GREEN
                GREEN 时间:50s,下一种灯是:YELLOW
                YELLOW 时间:3s,下一种灯是:RED
Annotation(注解):
    JDK1.5的新特性。它是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行
    相应的处理。
    Java提供的几个基本Annotation的用法,使用Annotation时要在其前面增加@符号,用于修饰它支持
    的程序元素。
    @Override:限定重写父类方法。它可以强制一个子类必须覆盖父类的方法。
        作用:告诉编译器检查这个方法,避免了重写父类有可能出错带来的麻烦。
    @Deprecated:标记元素已过时,当程序使用已过时的类或方法时,编译器将会给出警告。
    @SuppressWarnings:抑制编译器警告。它会一直作用于该程序元素的所有子元素。通常情况下,
        如果程序使用没有泛型限制的集合将会引起编译警告,为了避免这种警告,就可以使用它。
        演示:
            package com.itheima;
            import java.util.ArrayList;
            @SuppressWarnings(value = "unchecked")
            public class ArrayListTest {
                public static void main(String[] args) {
                    //创建一个不带泛型限制的集合
                    ArrayList al = new ArrayList();
                    al.add("hah");
                }
            }
        通过编译上面程序,当使用@SuppressWarnings来关闭编译器警告时,一定要在括号里使用
        name = "value"的形式为该Annotation的成员设置值,否则编译失败!!!
元注解:
    在java.lang.annotaion包下提供了4个元注解,这4个元注解都只能用于修饰其他的Annotation定义。
    @Retention:
        只能用于修饰一个Annotation定义,用于指定被修饰的Annotation可以保留多长时间,
        @Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时,
        必须为该value指定值:
            RetentionPolicy.CLASS:
                编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不再
                保留Annotation。这是默认值。
            RetentionPolicy.RUNTIME:
                编译器将把Annotation记录在class文件中。当运行Java程序时,JVM也会
                保留Annotation,程序可以通过反射获取该Annotation信息。
            RetentionPolicy.SOURCE:
                Annotation只保留在源代码中,编译器直接丢弃这种Annotation。
        如果需要通过反射获取注解信息,就需要使用RetentionPolicy.RUNTIME
        演示:
            package com.itheima.annotation;
            import java.lang.annotation.Retention;
            import java.lang.annotation.RetentionPolicy;
            //定义下面的MyAnnotation Annotation保留到运行时
            @Retention(RetentionPolicy.RUNTIME)//== @Retention(value=RetentionPolicy.RUNTIME)
            public @interface MyAnnotation {
                public abstract String show() default "hehe";
                public abstract int age() default 32;
            }
    @Target:
        @Target也只能修饰一个Annotation定义,它用于指定自定义Annotation的作用域。它也
        需要指定值:
            ElementType.ANNOTATION_TYPE:只能修饰Annotation
            ElementType.CONSTRUCTOR:只能修饰构造器
            ElementType.FIELD:只能修饰成员变量
            ElementType.LOCAL_VARIABLE:只能修饰局部变量
            ElementType.METHOD:只能修饰方法定义
            ElementType.PACKAGE:只能修饰包定义
            ElementType.PARAMETER:可以修饰参数
            ElementType.TYPE:可以修饰类、接口(包括注解类型)、枚举类
        演示:
            package com.itheima.annotation;
            import java.lang.annotation.ElementType;
            import java.lang.annotation.Retention;
            import java.lang.annotation.RetentionPolicy;
            import java.lang.annotation.Target;
            import javax.lang.model.element.Element;

            @Retention(RetentionPolicy.RUNTIME)
            //指定MyAnnotation只能修饰构造器
            @Target(ElementType.CONSTRUCTOR)
            public @interface MyAnnotation {
                public abstract String show() default "hehe";
                public abstract int age() default 32;
            }

            package com.itheima.annotation;
            import java.lang.annotation.Annotation;
            import javax.xml.ws.Action;
            // @MyAnnotation 如果不注释,编译出错
            public class AnnotationTest {
                //编译通过
                @MyAnnotation
                public AnnotationTest(){}
                @Action
                @Override
                public boolean equals(Object obj)
                {
                    return true;
                }
                @SuppressWarnings(value = "unchecked")
                // @MyAnnotation //如果不注释,编译出错
                public void show()
                {
                   
                }
            }
自定义Annotation:
    定义新的Annotation类型,使用@interface关键字定义一个新的Annotation类型。
    语法举例:
        public @interface MyAnnotation
        {
       
        }
    定义该Annotation之后,就可以在程序的任何地方使用该Annotation。默认情况下,可用于修饰
    类、接口、方法、变量等。
    演示:
        @MyAnnotation
        public class AnnotationTest {
            @MyAnnotation
            public static void main(String[] args) {
                @MyAnnotation
                int a = 30;
            }
        }
    自定义Annotation时,还可以带属性、方法,和定义接口的语法要求基本一样,但是其中的抽象
    方法不能带参数。
    演示:
        public @interface MyAnnotation {
            public static final String name = "haha";
            public abstract String show();
            //public abstract String show(int a);编译不通过
        }
    一旦在Annotation里定义了方法,使用该Annotation时就必须为其方法指定对应的类型参数值,
    否则编译失败!!!
    语法:@自定义Annotation接口(方法名1 = 对应的数据类型值, 方法名2 = 对应的数据类型值)
    演示:
        package com.itheima.annotation;
       
        public @interface MyAnnotation {
            public abstract String show();
            public abstract int age();
        }

        package com.itheima.annotation;
        //使用该Annotation时,给出对应类型的值,并且自定义Annotation中,
        //有几个方法,就必须对应的给出几个对应的key-value对,否则编译失败
        @MyAnnotation(show = "haha", age = 4)
        public class AnnotationTest {
            public static void main(String[] args) {
               
            }
        }
    也可以在定义Annotation的方法时,通过default关键字为其制定初始值,当然初始值也必须
    和所在方法对应的返回值类型相对应,否则编译失败!!!
    演示:
        package com.itheima.annotation;
        @Retention(RetentionPolicy.RUNTIME)
        public @interface MyAnnotation {
            public abstract String show() default "hehe";
            public abstract int age() default 32;
        }

        package com.itheima.annotation;
        @MyAnnotation
        public class AnnotationTest {
            public static void main(String[] args) {
               
            }
        }
    通过上面程序看出:如果为自定义Annotation的方法指定了默认值,在使用Annotation时,
    则可以不为其指定值。当然也可以在使用Annotation时,为其指定值,则默认值就不会起作用。
根据Annotation是否可以包含成员变量,可以把Annotation分为如下两类:
    1:标记Annotation:没有定义成员的Annotation类型被称为标记。这种Annotation仅利用自身
       的存在与否来为我们提供信息,如@Override等
    2:元数据Annotation:包含成员的Annotation,因为可以接收更多的元数据,所以也被称为
       元数据Annotation。
提取Annotation信息:
    Java5在java.lang.reflect包下新增了AnnotateElement接口,该接口代表程序中可以接受注释的
    程序元素。该接口主要有如下几个实现类。
        AccessibleObject, Class, Constructor, Field, Method, Package
    当一个Annotation类型被定义为运行时Annotation后,该Annotation才会在运行时可见,JVM才会
    加载对应的class文件。
    AnnotatedElement接口是所有程序元素(如Class、Method、Constructor等)的父接口,所以程序
    通过反射获取了某个类的AnnotatedElement对象(如Class、Method、Constructor等)之后,程序
    就可以调用该对象的如下几个方法来访问Annotation信息。
        1:<T extends Annotation> T getAnnotation(Class<T> annotationClass)
            如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
        2:Annotation[] getAnnotations() 返回此元素上存在的所有注释。
        3:Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。
        4:boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
            如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
    演示:
        接上面的程序
        package com.itheima.annotation;
        import java.lang.annotation.Annotation;
        public class Test {
            public static void main(String[] args) throws Exception {
                if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class))
                {
                    MyAnnotation ma = (MyAnnotation)AnnotationTest.class.
                    getAnnotation(MyAnnotation.class);
                    System.out.println(ma.age());
                    System.out.println(ma.show());
                }
            }
        }
        运行结果:hehe
              32
泛型:
    JDK1.5的新特性。用于解决安全问题,是一个类型安全机制。
好处:
    1、将运行时期出现的问题(ClassCastException),转移到编译时期,方便程序员解决问题。
      2、避免了强制转换带来的麻烦,增强了程序的健壮性。
格式:通过< >来定义要操作的引用数据类型,其实< >就是用来接收类型的,将要存储的数据类型传递到< >中。
    演示:
        import java.util.*;
        public class CollectionTest
        {
            public static void main(String[] args)
            {
                //ArrayList<String> al = new ArrayList<String>();
                //Java7的菱形语法,Java允许在构造器后不需要带完整的泛型信息
                ArrayList<String> al = new ArrayList();
                al.add("haha");
                al.add("xixi");
                //al.add(3);因为指定了集合只能添加String类型的元素,
                //所以向集合添加其他类型的元素的时候编译出错。
                Iterator<String> it = al.iterator();
                while(it.hasNext())
                {
                    String str = it.next();//因为指定了元素类型,所以不用在强转
                    System.out.println(str);
                }
            }
        }
自定义泛型类、接口:
    什么时候定义泛型类?
          当要操作的引用数据类型不确定的时候
    定义的泛型类作用于整个类中,为了让不同方法操作不同类型,而且类型还不确定,那么可以
    将泛型定义在方法上。所谓泛型方法,就是在声明方法时定义一个或多个类型形参。
    定义泛型方法格式:
        修饰符 <T, S> 返回值类型 方法名(形参列表)
        {
       
        }

       
    特殊之处:静态方法、静态初始化块、静态变量不可以访问类上定义的泛型,如果静态方法操作
    的引用数据类型不确定,可以将泛型定义在方法上。
    示例:
        package com.itheima.generic;
        public class GenericDemo {
            public static void main(String[] args) {
                Demo<String> demo = new Demo<String>();
                demo.show(234); //编译通过,因为该方法定义成立泛型方法
                demo.show("bbd");
                Demo.printW("355");
            }
        }

        class Demo<T>
        {
            //下面代码编译时出错,当创建带泛型声明的自定义类时,构造器不能增加泛型
            //声明,否则编译失败。但调用该构造时,却可以传入实际参数类型。
            public Demo<T>();
            //如果去掉show()方法的泛型定义,编译出错,因为创建对象时,指定了类型
            //而调用该方法时,传入了一个基本数据类型的参数
            public <T> void show(T t)
            {
                System.out.println("show  :" + t);
            }
            //通常泛型方法的参数都会使用类型变量。下面的泛型方法参数就使用类型变量W!
            //在调用者调用这个方法时会给W赋值,那么参数t的类型也就确定了。
            public <W> void print(W t)
            {
                System.out.println("print  :" + t);
            }
            ////如果不加泛型,编译出错,静态方法不可以访问类上定义的泛型
            public static <W> void printW(W t)
            {
                System.out.println("printW   :" + t);
            }
        }
    通过上面程序可以看出,泛型可以定义在类上,也可以定义在方法上。它们的不同是:方法声明
    中定义的泛型形参,只能在该方法里使用,而接口、类声明的泛型形参则可以再整个类中使用。
    与类、接口中使用泛型参数不同的是:方法中泛型参数无须显示传入实际类型参数
从泛型类派生子类:
    定义类、接口、方法时,可以声明类型形参,当使用带泛型声明的父类、接口或方法时,父类和接口
    不能再包含类型形参,应该为类型形参传入实际的参数类型。
    示例:
        public class A<T>{}
        public class B extends A<T>{}//编译失败
    调用方法时必须为所有的数据类型传入参数值,与调用方法不同的是,使用泛型类、接口时,可以
    不为类型形参出入实际参数值。
    示例:
        public class A<T>{}
        public class B extends A{}//没问题,只是有编译器警告
类型通配符:
    当使用泛型时,都应该为这个泛型类传入一个类型参数,如果没有传入将引发编译器警告。如果
    不知道传入的是什么类型,是否可以也用Object类定义呢?
    演示说明:
        package com.itheima.generic;
        import java.util.ArrayList;
        public class GenericTest {
            public static void main(String[] args)
            {
                //创建一个明确泛型声明的集合
                ArrayList<String> al = new ArrayList<String>();
                al.add("haha");
                al.add("hehe");
                test(al);//编译出错
            }
            //下面这个方法,假设我们不知道传入的类型,用一个
            //Object类型来接受
            private static void test(ArrayList<Object> al)
            {
               
            }
        }
    上面程序编译出错,表明ArrayList<String>对象不能被当成ArrayList<Object>对象使用,也就是
    说:ArrayList<String>类不是ArrayList<Object>类的子类!!!带泛型声明的Object类型不是其
    它子类型的父类!!!在使用泛型类创建对象时,左右两边的类型必须一致!!!
    演示:
        ArrayList<String> al = new ArrayList<String>;
使用类型通配符:
    类型通配符是一个"?",它的元素类型可以匹配任何类型,表示各种泛型声明类型的父类。但是,
    它只能出现在引用中。
    举例:ArrayList<?> al = new ArrayList<String>();
          ArrayList<?> al = new ArrayList<?>();//编译失败
    演示:
        package com.itheima.generic;
        import java.util.ArrayList;
        public class GenericTest {
            public static void main(String[] args)
            {
                ArrayList<String> al = new ArrayList<String>();
                al.add("haha");
                al.add("hehe");
                test(al);
            }

            private static void test(ArrayList<?> al)
            {
               
            }
        }
    但这种带通配符的ArrayList仅表示它是各种泛型ArrayList的父类,并不能把元素添加到其中。
    唯一的例外是null,它是所有引用类型的实例
    演示:
        ArrayList<?> al = new ArrayList<String>();
        al.add(null);//没问题
        //下面将引起编译出错
        al.add("haha");
类型上限:
    语法:类名或接口名<?/T extends 类名>,表示该类型只能是指定类或其子类。
    举例:class Factory<T/? extends Person>
类型下限:
    语法:类名或接口名<?/T super 类名>,表示该类型只能是指定类或其父类。
    举例:class Factory<T/? extends Student>
------- android培训java培训、期待与您交流! ----------
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics