java继承.doc

上传人:仙人指路1688 文档编号:2386818 上传时间:2023-02-17 格式:DOC 页数:15 大小:54KB
返回 下载 相关 举报
java继承.doc_第1页
第1页 / 共15页
java继承.doc_第2页
第2页 / 共15页
java继承.doc_第3页
第3页 / 共15页
java继承.doc_第4页
第4页 / 共15页
java继承.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

《java继承.doc》由会员分享,可在线阅读,更多相关《java继承.doc(15页珍藏版)》请在三一办公上搜索。

1、编程需要注意的陷阱:Java继承是有害的发布时间:2007.08.30 06:24? 来源:赛迪网技术社区?作者:dxaw大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends 关系)。实际上80%的代码应该完全用interfaces写,而不是通过extends。“JAVA设计模式”一书详细阐述了怎样用接口继承代替实现继承。这篇文章描述设计者为什么会这么作。Extends是有害的;也许对于Charles Manson这个级别的不是,但是足够糟糕的它应该在任何可能的时候被避开。“JAVA设计模式”一书花了很大的部分讨论用interface继承代替实现继承。好的设计者在他的代码中,大部分

2、用interface,而不是具体的基类。本文讨论为什么设计者会这样选择,并且也介绍一些基于interface的编程基础。接口(Interface)和类(Class)?Jams Gosling(Java之父)做发起人讲话。有人问他:“如果你重新构造Java,你想改变什么?”。“我想抛弃classes”他回答。在笑声平息后,它解释说,真正的问题不是由于class本身,而是实现继承(extends 关系)。接口继承(implements关系)是更好的。你应该尽可能的避免实现继承。失去了灵活性为什么你应该避免实现继承呢?第一个问题是明确的使用具体类名将你固定到特定的实现,给底层的改变增加了不必要的困难

3、。在当前的敏捷编程方法中,核心是并行的设计和开发的概念。在你详细设计程序前,你开始编程。这个技术不同于传统方法的形式-传统的方式是设计应该在编码开始前完成-但是许多成功的项目已经证明你能够更快速的开发高质量代码,相对于传统的按部就班的方法。但是在并行开发的核心是主张灵活性。你不得不以某一种方式写你的代码以至于最新发现的需求能够尽可能没有痛苦的合并到已有的代码中。胜于实现你也许需要的特征,你只需实现你明确需要的特征,而且适度的对变化的包容。如果你没有这种灵活,并行的开发,那简直不可能。对于Inteface的编程是灵活结构的核心。为了说明为什么,让我们看一下当使用它们的时候,会发生什么。考虑下面的

4、代码:f() LinkedList list = new LinkedList();/.g( list );g( LinkedList list )list.add( . );g2( list )现在,假设一个对于快速查询的需求被提出,以至于这个LinkedList不能够解决。你需要用HashSet来代替它。在已有代码中,变化不能够局部化,因为你不仅仅需要修改f()也需要修改g()(它带有LinkedList参数),并且还有g()把列表传递给的任何代码。象下面这样重写代码:f() Collection list = new LinkedList();/.g( list );g( Collect

5、ion list )list.add( . );g2( list )这样修改Linked list成hash,可能只是简单的用new HashSet()代替new LinkedList()。就这样。没有其他的需要修改的地方。作为另一个例子,比较下面两段代码:f() Collection c = new HashSet();/.g( c );g( Collection c )for( Iterator i = c.iterator(); i.hasNext() )do_something_with( i.next() );和f2() Collection c = new HashSet();/.

6、g2( c.iterator() );g2( Iterator i ) while( i.hasNext() )do_something_with( i.next() );g2()方法现在能够遍历Collection的派生,就像你能够从Map中得到的键值对。事实上,你能够写iterator,它产生数据,代替遍历一个Collection。你能够写iterator,它从测试的框架或者文件中得到信息。这会有巨大的灵活性。耦合对于实现继承,一个更加关键的问题是耦合-令人烦躁的依赖,就是那种程序的一部分对于另一部分的依赖。全局变量提供经典的例子,证明为什么强耦合会引起麻烦。例如,如果你改变全局变量的类型

7、,那么所有用到这个变量的函数也许都被影响,所以所有这些代码都要被检查,变更和重新测试。而且,所有用到这个变量的函数通过这个变量相互耦合。也就是,如果一个变量值在难以使用的时候被改变,一个函数也许就不正确的影响了另一个函数的行为。这个问题显著的隐藏于多线程的程序。作为一个设计者,你应该努力最小化耦合关系。你不能一并消除耦合,因为从一个类的对象到另一个类的对象的方法调用是一个松耦合的形式。你不可能有一个程序,它没有任何的耦合。然而,你能够通过遵守OO规则,最小化一定的耦合(最重要的是,一个对象的实现应该完全隐藏于使用他的对象)。例如,一个对象的实例变量(不是常量的成员域),应该总是private。

8、我意思是某段时期的,无例外的,不断的。(你能够偶尔有效地使用protected方法,但是protected实例变量是可憎的事)同样的原因你应该不用get/set函数-他们对于是一个域公用只是使人感到过于复杂的方式(尽管返回修饰的对象而不是基本类型值的访问函数是在某些情况下是由原因的,那种情况下,返回的对象类是一个在设计时的关键抽象)。这里,我不是书生气。在我自己的工作中,我发现一个直接的相互关系在我OO方法的严格之间,快速代码开发和容易的代码实现。无论什么时候我违反中心的OO原则,如实现隐藏,我结果重写那个代码(一般因为代码是不可调试的)。我没有时间重写代码,所以我遵循那些规则。我关心的完全实

9、用?我对干净的原因没有兴趣。脆弱的基类问题现在,让我们应用耦合的概念到继承。在一个用extends的继承实现系统中,派生类是非常紧密的和基类耦合,当且这种紧密的连接是不期望的。设计者已经应用了绰号“脆弱的基类问题”去描述这个行为。基础类被认为是脆弱的是,因为你在看起来安全的情况下修改基类,但是当从派生类继承时,新的行为也许引起派生类出现功能紊乱。你不能通过简单的在隔离下检查基类的方法来分辨基类的变化是安全的;而是你也必须看(和测试)所有派生类。而且,你必须检查所有的代码,它们也用在基类和派生类对象中,因为这个代码也许被新的行为所打破。一个对于基础类的简单变化可能导致整个程序不可操作。让我们一起

10、检查脆弱的基类和基类耦合的问题。下面的类extends了Java的ArrayList类去使它像一个stack来运转:class Stack extends ArrayList private int stack_pointer = 0;public void push( Object article ) add( stack_pointer+, article );public Object pop() return remove( -stack_pointer );public void push_many( Object articles ) for( int i = 0; i artic

11、les.length; +i )push( articlesi );甚至一个象这样简单的类也有问题。思考当一个用户平衡继承和用ArrayList的clear()方法去弹出堆栈时:Stack a_stack = new Stack();a_stack.push(1);a_stack.push(2);a_stack.clear();这个代码成功编译,但是因为基类不知道关于stack指针堆栈的情况,这个stack对象当前在一个未定义的状态。下一个对于push()调用把新的项放入索引2的位置。(stack_pointer的当前值),所以stack有效地有三个元素-下边两个是垃圾。(Java的stack

12、类正是有这个问题,不要用它).对这个令人讨厌的继承的方法问题的解决办法是为Stack覆盖所有的ArrayList方法,那能够修改数组的状态,所以覆盖正确的操作Stack指针或者抛出一个例外。(removeRange()方法对于抛出一个例外一个好的候选方法)。这个方法有两个缺点。第一,如果你覆盖了所有的东西,这个基类应该真正的是一个interface,而不是一个class。如果你不用任何继承方法,在实现继承中就没有这一点。第二,更重要的是,你不能够让一个stack支持所有的ArrayList方法。例如,令人烦恼的removeRange()没有什么作用。唯一实现无用方法的合理的途径是使它抛出一个例

13、外,因为它应该永远不被调用。这个方法有效的把编译错误成为运行错误。不好的方法是,如果方法只是不被定义,编译器会输出一个方法未找到的错误。如果方法存在,但是抛出一个例外,你只有在程序真正的运行时,你才能够发现调用错误。对于这个基类问题的一个更好的解决办法是封装数据结构代替用继承。这是新的和改进的Stack的版本:class Stackprivate int stack_pointer = 0;private ArrayList the_data = new ArrayList();public void push( Object article )the_data.add( stack_poni

14、ter+, article );public Object pop()return the_data.remove( -stack_pointer );public void push_many( Object articles )for( int i = 0; i high_water_mark )high_water_mark = current_size;super.push( article );publish Object pop()-current_size;return super.pop();public int maximum_size_so_far()return high

15、_water_mark;这个新类运行的很好,至少是一段时间。不幸的是,这个代码发掘了一个事实,push_many()通过调用push()来运行。首先,这个细节看起来不是一个坏的选择。它简化了代码,并且你能够得到push()的派生类版本,甚至当Monitorable_stack通过Stack的参考来访问的时候,以至于high_water_mark能够正确的更新。(责任编辑:龚勋)编程需要注意的陷阱:Java继承是有害的发布时间:2007.08.30 06:24? 来源:赛迪网技术社区?作者:dxaw大多数好的设计者象躲避瘟疫一样来避免使用实现继承(extends 关系)。实际上80%的代码应该完

16、全用interfaces写,而不是通过extends。“JAVA设计模式”一书详细阐述了怎样用接口继承代替实现继承。这篇文章描述设计者为什么会这么作。Extends是有害的;也许对于Charles Manson这个级别的不是,但是足够糟糕的它应该在任何可能的时候被避开。“JAVA设计模式”一书花了很大的部分讨论用interface继承代替实现继承。好的设计者在他的代码中,大部分用interface,而不是具体的基类。本文讨论为什么设计者会这样选择,并且也介绍一些基于interface的编程基础。接口(Interface)和类(Class)?Jams Gosling(Java之父)做发起人讲话。

17、有人问他:“如果你重新构造Java,你想改变什么?”。“我想抛弃classes”他回答。在笑声平息后,它解释说,真正的问题不是由于class本身,而是实现继承(extends 关系)。接口继承(implements关系)是更好的。你应该尽可能的避免实现继承。失去了灵活性为什么你应该避免实现继承呢?第一个问题是明确的使用具体类名将你固定到特定的实现,给底层的改变增加了不必要的困难。在当前的敏捷编程方法中,核心是并行的设计和开发的概念。在你详细设计程序前,你开始编程。这个技术不同于传统方法的形式-传统的方式是设计应该在编码开始前完成-但是许多成功的项目已经证明你能够更快速的开发高质量代码,相对于传

18、统的按部就班的方法。但是在并行开发的核心是主张灵活性。你不得不以某一种方式写你的代码以至于最新发现的需求能够尽可能没有痛苦的合并到已有的代码中。胜于实现你也许需要的特征,你只需实现你明确需要的特征,而且适度的对变化的包容。如果你没有这种灵活,并行的开发,那简直不可能。对于Inteface的编程是灵活结构的核心。为了说明为什么,让我们看一下当使用它们的时候,会发生什么。考虑下面的代码:f() LinkedList list = new LinkedList();/.g( list );g( LinkedList list )list.add( . );g2( list )现在,假设一个对于快速查

19、询的需求被提出,以至于这个LinkedList不能够解决。你需要用HashSet来代替它。在已有代码中,变化不能够局部化,因为你不仅仅需要修改f()也需要修改g()(它带有LinkedList参数),并且还有g()把列表传递给的任何代码。象下面这样重写代码:f() Collection list = new LinkedList();/.g( list );g( Collection list )list.add( . );g2( list )这样修改Linked list成hash,可能只是简单的用new HashSet()代替new LinkedList()。就这样。没有其他的需要修改的地

20、方。作为另一个例子,比较下面两段代码:f() Collection c = new HashSet();/.g( c );g( Collection c )for( Iterator i = c.iterator(); i.hasNext() )do_something_with( i.next() );和f2() Collection c = new HashSet();/.g2( c.iterator() );g2( Iterator i ) while( i.hasNext() )do_something_with( i.next() );g2()方法现在能够遍历Collection的派

21、生,就像你能够从Map中得到的键值对。事实上,你能够写iterator,它产生数据,代替遍历一个Collection。你能够写iterator,它从测试的框架或者文件中得到信息。这会有巨大的灵活性。耦合对于实现继承,一个更加关键的问题是耦合-令人烦躁的依赖,就是那种程序的一部分对于另一部分的依赖。全局变量提供经典的例子,证明为什么强耦合会引起麻烦。例如,如果你改变全局变量的类型,那么所有用到这个变量的函数也许都被影响,所以所有这些代码都要被检查,变更和重新测试。而且,所有用到这个变量的函数通过这个变量相互耦合。也就是,如果一个变量值在难以使用的时候被改变,一个函数也许就不正确的影响了另一个函数

22、的行为。这个问题显著的隐藏于多线程的程序。作为一个设计者,你应该努力最小化耦合关系。你不能一并消除耦合,因为从一个类的对象到另一个类的对象的方法调用是一个松耦合的形式。你不可能有一个程序,它没有任何的耦合。然而,你能够通过遵守OO规则,最小化一定的耦合(最重要的是,一个对象的实现应该完全隐藏于使用他的对象)。例如,一个对象的实例变量(不是常量的成员域),应该总是private。我意思是某段时期的,无例外的,不断的。(你能够偶尔有效地使用protected方法,但是protected实例变量是可憎的事)同样的原因你应该不用get/set函数-他们对于是一个域公用只是使人感到过于复杂的方式(尽管返

23、回修饰的对象而不是基本类型值的访问函数是在某些情况下是由原因的,那种情况下,返回的对象类是一个在设计时的关键抽象)。这里,我不是书生气。在我自己的工作中,我发现一个直接的相互关系在我OO方法的严格之间,快速代码开发和容易的代码实现。无论什么时候我违反中心的OO原则,如实现隐藏,我结果重写那个代码(一般因为代码是不可调试的)。我没有时间重写代码,所以我遵循那些规则。我关心的完全实用?我对干净的原因没有兴趣。脆弱的基类问题现在,让我们应用耦合的概念到继承。在一个用extends的继承实现系统中,派生类是非常紧密的和基类耦合,当且这种紧密的连接是不期望的。设计者已经应用了绰号“脆弱的基类问题”去描述

24、这个行为。基础类被认为是脆弱的是,因为你在看起来安全的情况下修改基类,但是当从派生类继承时,新的行为也许引起派生类出现功能紊乱。你不能通过简单的在隔离下检查基类的方法来分辨基类的变化是安全的;而是你也必须看(和测试)所有派生类。而且,你必须检查所有的代码,它们也用在基类和派生类对象中,因为这个代码也许被新的行为所打破。一个对于基础类的简单变化可能导致整个程序不可操作。让我们一起检查脆弱的基类和基类耦合的问题。下面的类extends了Java的ArrayList类去使它像一个stack来运转:class Stack extends ArrayList private int stack_poin

25、ter = 0;public void push( Object article ) add( stack_pointer+, article );public Object pop() return remove( -stack_pointer );public void push_many( Object articles ) for( int i = 0; i articles.length; +i )push( articlesi );甚至一个象这样简单的类也有问题。思考当一个用户平衡继承和用ArrayList的clear()方法去弹出堆栈时:Stack a_stack = new S

26、tack();a_stack.push(1);a_stack.push(2);a_stack.clear();这个代码成功编译,但是因为基类不知道关于stack指针堆栈的情况,这个stack对象当前在一个未定义的状态。下一个对于push()调用把新的项放入索引2的位置。(stack_pointer的当前值),所以stack有效地有三个元素-下边两个是垃圾。(Java的stack类正是有这个问题,不要用它).对这个令人讨厌的继承的方法问题的解决办法是为Stack覆盖所有的ArrayList方法,那能够修改数组的状态,所以覆盖正确的操作Stack指针或者抛出一个例外。(removeRange()方

27、法对于抛出一个例外一个好的候选方法)。这个方法有两个缺点。第一,如果你覆盖了所有的东西,这个基类应该真正的是一个interface,而不是一个class。如果你不用任何继承方法,在实现继承中就没有这一点。第二,更重要的是,你不能够让一个stack支持所有的ArrayList方法。例如,令人烦恼的removeRange()没有什么作用。唯一实现无用方法的合理的途径是使它抛出一个例外,因为它应该永远不被调用。这个方法有效的把编译错误成为运行错误。不好的方法是,如果方法只是不被定义,编译器会输出一个方法未找到的错误。如果方法存在,但是抛出一个例外,你只有在程序真正的运行时,你才能够发现调用错误。对于

28、这个基类问题的一个更好的解决办法是封装数据结构代替用继承。这是新的和改进的Stack的版本:class Stackprivate int stack_pointer = 0;private ArrayList the_data = new ArrayList();public void push( Object article )the_data.add( stack_poniter+, article );public Object pop()return the_data.remove( -stack_pointer );public void push_many( Object arti

29、cles )for( int i = 0; i high_water_mark )high_water_mark = current_size;super.push( article );publish Object pop()-current_size;return super.pop();public int maximum_size_so_far()return high_water_mark;这个新类运行的很好,至少是一段时间。不幸的是,这个代码发掘了一个事实,push_many()通过调用push()来运行。首先,这个细节看起来不是一个坏的选择。它简化了代码,并且你能够得到push(

30、)的派生类版本,甚至当Monitorable_stack通过Stack的参考来访问的时候,以至于high_water_mark能够正确的更新。(责任编辑:龚勋)Java 继承机制 收藏1. 继承的概念如果类 B 具有类 A 的全部属性和方法,而且又具有自己特有的某些属性和方法,则把类 A 称作一般类,把类 B 称作特殊类。在面向对象程序设计中运用继承原则,就是在每个由一般类和特殊类形成的一般 - 特殊结构中,把一般类的对象实例和所有特殊类的对象实例都共同具有的属性和操作一次性地在一般类中进行显式的定义,在特殊类中不再重复地定义一般类中已经定义的东西,但是在语义上,特殊类却自动地、隐含地拥有它的

31、一般类(以及所有更上层的一般类)中定义的属性和操作。特殊类的对象拥有其一般类的全部或部分属性与方法,称作特殊类对一般类的继承。继承所表达的就是一种对象之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。若类 B 继承类 A 时,则属于 B 的对象便具有类 A 的全部或部分性质(数据属性)和功能(操作)。我们称被继承的类 A 为基类、父类或超类,而称继承类 B 为 A 的派生类或子类。继承避免了对一般类和特殊类之间共同特征进行的重复描述。2. 继承的特征继承关系是传递的。继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。继承简化了人们对事物的认识和描述,能清

32、晰体现相关类间的层次结构关系。提供软件复用功能。通过增强一致性来减少模块间的接口和界面,大大增加程序的易维护性。提供多重继承机制。从理论上说,一个类可以是多个一般类的特殊类,它可以从多个一般类中继承属性和方法,这便是多重继承。而 Java 出于安全性和可靠性的考虑,仅支持单重继承,而通过使用接口机制来实现多重继承。3. Java 用 extends 指明继承关系在 Java 程序设计中,继承是通过 extends 关键字来实现的。在定义类时使用 extends 关键字指明新定义类的父类,新定义的类称为指定父类的子类,这样就在两个类之间建立起了继承关系。这个新定义的子类可以从父类那里继承所有非

33、private 的属性和方法作为自己的成员。实际上,在定义一个类而不给出 extends 关键字及父类名时,默认这个类是系统类 Object 的子类。3.1. 数据成员的继承子类可以继承父类的所有非私有的数据成员。3.2. 数据成员的隐藏数据成员的隐藏是指在子类中重新定义一个与父类中已经定义的数据成员名完全相同的数据成员,即子类拥有了两个相同名字的数据成员,一个是继承父类的,另一个是自己定义的。当子类引用这个同名的数据成员时,默认操作是它自己定义的数据成员,而把从父类那里继承来的数据成员“隐藏”起来。当子类要引用继承自父类的同名数据成员时,可使用关键字 super 引导。3.3. 成员方法的继

34、承子类可以继承父类的非私有成员方法。3.4. 成员方法的覆盖(Overload)子类可以重新定义与父类同名的成员方法,实现对父类方法的覆盖。方法的覆盖与数据成员的隐藏的不同之处在于:子类隐藏父类的数据成员只是使之不可见,父类同名的数据成员在子类对象中仍然占有自己独立的内存空间;子类方法对父类同名方法的覆盖将清除父类方法占用的内存,从而使父类方法在子类对象中不复存在。需要注意的是:子类在重新定义父类已有的方法时,应保持与父类完全相同的方法名、返回值类型和参数列表,否则就不是方法的覆盖,而是子类定义自己特有的方法,与父类的方法无关。4. this 与 super4.1. this 的使用场合在方法

35、内借助 this 来明确表示引用的是类的数据成员,而不是形参或局部变量,从而提高程序的可读性。简单地说,this 代表了当前对象的一个引用,可将其理解为对象的另一个名字,通过这个名字可以顺利地访问对象、修改对象的数据成员、调用对象的方法。this 的使用场合主要有以下三种:用来访问当前对象的数据成员:this.数据成员用来访问当前对象的成员方法:this.成员方法(参数)当有重载的构造方法时,用来引用同类的其他构造方法:this(参数)4.2. super 的使用场合super 表示的是当前对象的直接父类对象,是当前对象的直接父类对象的引用。所谓直接父类是相对于当前对象的其他“祖先”类而言。若

36、子类的数据成员或成员方法名与父类的数据成员或成员方法名相同时,当要调用父类的同名方法或使用父类的同名数据成员,则可用关键字 super 来指明父类的数据成员和方法。super 的使用场合有三种:用来访问直接父类隐藏的数据成员:super.数据成员用来调用直接父类中被覆盖的成员方法:super.成员方法(参数)用来调用直接父类的构造方法:super(参数)5. 构造方法的重载与继承5.1. 构造方法的重载一个类的若干个构造方法之间可以相互调用。当一个构造方法需要调用另一个构造方法时,可以使用关键字 this,同时这个调用语句应该是整个构造方法的第一个可执行语句。使用关键字 this 来调用同类的

37、其他构造函数时,优点同样是可以最大限度地提高对已有代码的利用程度,提高程序的抽象度和封装性,减少程序的维护工作量。5.2. 构造方法的继承子类可以继承父类的构造方法,构造方法的继承遵循以下的原则:子类无条件地继承父类的不含参数的构造方法。如果子类自己没有构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;如果子类自己定义了构造方法,则在创建新对象时,它将先执行继承自父类的无参数构造方法,然后再执行自己的构造方法。对于父类含参数的构造方法,子类可以通过在自己的构造方法中使用 super 关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句。6. 向方法传递对象传递给方法的参

38、数可以是表达式(如常量、变量)、对象等。传递给方法的参数若是变量,则只能由实参传递给形参,而不能由形参带回,它是一种单向值传递。在方法的引用过程中,对于形参变量值的修改并不影响实参变量的值。但是,传递给方法的参数若是对象,则方法可以对其做永久性修改。7. 类转换类转换就是指父类对象与子类对象之间在一定条件下的相互转换。父类对象与子类对象之间相互转换规则如下:父类对象与子类对象之间可以隐式转换(也称默认转换),也可以显式转换(也称强制转换)。处于相同类层次的类的对象不能进行转换。子类对象可以转换成父类对象,但对数据成员的引用必须使用强制转换。类转换格式如下:(子类)父类或(父类)子类8. 继承与

39、封装的关系在面向对象系统中,封装性主要指的是对象的封装性,即将属于某一类的一个具体对象封装起来,使其数据和操作成为一个整体。在引入了继承机制的面向对象系统中,对象依然是封装得很好的实体,其他对象与它进行通讯的途径仍然只有一条,那就是发送消息。类机制是一种静态机制,不管是基类还是派生类,对于对象来说,它仍然是一个类的实例,既可能是基类的实例,也可能是派生类的实例。因此,继承机制的引入丝毫没有影响对象的封装性。继承和封装机制还具有一定的相似性,它们都是一种共享代码的手段。继承是一种静态共享代码的手段,通过派生类对象的创建,可以接收某一消息,启动其基类所定义的代码段,从而使基类和派生类共享了这一段代码。封装机制所提供的是一种动态共享代码的手段,通过封装,我们可将一段代码定义在一个类中,在另一个类所定义的操作中,我们可以通过创建该类的实例,并向它发送消息而启动这一段代码,同样也达到共享的目的。本文来自CSDN博客,转载请标明出处:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 项目建议


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号