1 类的继承

        继承是面向对象的重要特性之一,是相对两个类而言的父子关系,子类继承了父类的所有的属性和方法,继承最大的好处是实现了代码的重用,可以重用已经存在的数据和行为,减少代码的重复编写。

2 不同版本的类

        在Python2.2之前,类是没有共同的祖先的,之后,引入了object类,它是所有类的共同祖先类。Python2中为了兼容,分为古典类(旧式类)和新式类。而在Python 3中全部都为新式类,新式类都是继承object类的,并且可以使用super函数(后面会说)。下面是Python2.x中的代码

class A:
pass class B(object):
pass >>> dir(A) # 查看类的__dict__
['__doc__', '__module__']
>>> dir(B)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

在Python2.x中 A和B是不同的两个类。A没有继承,被称为古典类,B继承自object,被称为新式类。不止少了很多方法,连实例对象的属性也是不太相同的。Python 3中的代码如下

class A:
pass class B(object):
pass >>> dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> dir(B)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>

在Python 3中,都为新式类,所以A和A(object)是两个结果相同的不同写法而已 class A:pass == class A(object):pass

更多的区别这里就不在详述,Python 3是未来,忘记旧式类吧。

3 基本概念

Python在类名后使用一对括号来表示继承关系,括号中的类即为父类。先来看看不用继承的例子:

class Animal:

    def shout(self):
print('{} shout'.format(self.__class__.__name__)) class Cat:
def shout(self):
print('{} shout'.format(self.__class__.__name__)) class Dog:
def shout(self):
print('{} shout'.format(self.__class__.__name__)) a = Animal()
c = Cat()
d = Dog() a.shout()
c.shout()
d.shout()

从上面例子来看,虽然猫狗动物都可以叫,但是却分别实现了叫这个动作,那么下一步使用继承来优化

class Animal:

    def shout(self):
print('{} shout'.format(self.__class__.__name__)) class Cat(Animal): pass
class Dog(Animal): pass a = Animal()
c = Cat()
d = Dog() a.shout()
c.shout()
d.shout()

通过继承,猫类、狗类就不用写代码,直接继承了父类Animal类的叫方法了。所以,在上面的例子中:

  • 父类:Animal是Cat和Dog的父类,也成为基类、超类
  • 子类:Cat和Dog是Animal的子类,也成为派生类

4 特殊属性和方法

和继承相关的常用特殊属性和方法如下:

特殊属性和方法 含义 示例
__base__ 类的基类
__bases__ 类的基类们(元组)
__mro__ 方法解析顺序(基类们的元组)
mro() 方法解析顺序(基类们的列表) int.mro()
__subclasses__() 类的子类列表 int.__subclasses__()

5 继承中的访问控制

通过一个例子来看继承中的访问控制

class Animal:
__COUNT = 100 # _Animal__COUNT = 100
HEIGHT = 0 def __init__(self, age,weight,height):
self.__COUNT += 1 # self._Animal_COUNT = self._Animal_COUNT + 1
self.age = age
self.__weight = weight # self._Animal__weight = weight
self.HEIGHT = height def eat(self):
print('{} eat'.format(self.__class__.__name__)) def __getweight(self): # def _Animal__getweight(self):
print(self.__weight) # print(self._Animal__weight) @classmethod
def showcount1(cls):
print(cls)
print(cls.__dict__)
print(cls.__COUNT) # print(cls._Animal__COUNT) @classmethod
def __showcount2(cls): # def _Animal__showcount2(cls):
print(cls.__COUNT) # print(cls._Animal__COUNT) def showcount3(self):
print(self.__COUNT) # print(self._Animal__COUNT) class Cat(Animal):
NAME = 'CAT'
__COUNT = 200 # _Cat__Count = 200 c = Cat(3,5,15)
c.eat() # 1
print(c.HEIGHT) # 2
print(c.__COUNT) # 3
print('c:',c.__dict__)
print('cat:',Cat.__dict__)
print('Animal:',Animal.__dict__)
c.showcount1() # 4
c.showcount2() # 5
c.showcount3() # 6
print(c.NAME) # 7

分析:

  1. 通过c调用eat方法,c没有eat方法,在类Cat中寻找,Cat中没有,在Cat的父类Animal中寻找,找到eat方法,把c绑定在eat上,执行是把c传入eat,在eat内部self是c,所以self.__class__就是Cat,所以会打印'Cat eat'
  2. 在查找属性时,优先在c.__dict__中寻找,因为c实例化时设置了HEIGHT属性,所以,这里是15
  3. __COUNT是私有属性,定义完毕后会被改名,所以在外部访问时,会提示没有该属性
  4. 使用c调用类方法时,@classmethod会把c的类传入到cls中去,所以cls就是Cat类,cls.__dict__就是Cat.__dict__,而Cat中只定义两个属性,所以值为{'__module__': '__main__', 'NAME': 'CAT', '_Cat__COUNT': 200, '__doc__': None}(魔术方法先不考虑),类方法定义在哪个类中,那么私有变量就会被改成以那个类为前缀的变量名,所以showcount1方法定义在Animal中,__COUNT就变成了_Animal__COUNT。cls.__COUNT就是在寻找cls._Animal__COUNT属性,而Cat类中的__COUNT被改名为_Cat__COUNT,所以最后只能在Animal中找到,所以值为100
  5. 和私有属性相同,私有方法也会被改名为_类名__方法,所以直接从外部访问,会提示没有该属性方法
  6. showcount3定义在Animal中,所以self.__COUNT实际上为self._Animal__COUNT,c在实例化的同时进行了初始化,Cat没了__init__函数,所以继承了父类Animal的__init__,在初始化过程中定义的self.__COUNT,实际上就是self._Animal__COUNT,这里self._Animal__COUNT = self._Animal__COUNT + 1,先算等式右边,在执行时c还没有_Animal__COUNT属性,所以会从Cat类开始找直到Animal类,Cat类的__COUNT改名为了_Cat__COUNT,不是我们想要的,然后找到了Animal的100,然后加1,再赋给实例c(等于c._Animal__COUNT = Animal._Animal__COUNT + 1),所以实例c来说,它自己就已经拥有_Animal__COUNT属性,它的值为101

一般情况下不会这么写,这里只是练习知识点。分析这种情况时,直接把私有变量/方法改名后就非常好分析了。

总结:

  1. 从父类继承,自己没有的,就可以到父类中寻找。
  2. 私有的都是不可以直接在外部进行访问的,但是本质上依然是改了名称后放在这个属性所在的类或实例的__dict__中,如果知道这个新名称,就可以直接找到这个隐藏的变量。不建议使用。
  3. 继承时,公有的,子类和实例都可以随意访问;私有成员被吟唱,子类和实例不可直接访问,但私有变量所在的类内的方法可以直接访问这个私有变量。
  4. 实例属性查找顺序:实例的__dict__ , 类的__dict__ , 父类的__dict__(如果有继承)。

遇到私有变量/方法看定义的位置,直接进行改名就比较好分析了。

6 方法的重写(override)

        方法重写,顾名思义就是重写继承来的方法,Python和其他语言不同的是,在Java中,要重写的方法,参数数量和类型要和原方法完全相同才行,否则会被认为是方法重载。Python由于其动态的语言的特性,只要方法相同,则表示的就是方法重写。

class Animal:

    def __init__(self, name):
self.name = name def shout(self):
print('Animal shout') class Cat(Animal): def shout(self):
print('miaomiao') c = Cat('daxin')
c.shout()

        上面的例子中,Cat继承了Animal类的shout方法,但是由于Animal中定义的shout不符合Cat的需求,所以在Cat中重写了shout方法,但是需要注意的是,重写不是覆盖,严格来说的话应该算是遮盖,因为Python的类查找顺序是按照当前实例->父类->基类等来的,所以当给Cat类定义shout方法后,实例调用方法shout时,父类中已经包含了shout方法,所以就直接调用了,而Animal中的shout依旧在,只是Cat的shout方法被预先发现了。

        如果我们并不是要改写,而是要增强原方法的功能呢?

class Animal:

    def shout(self):
print('Animal shout') class Cat(Animal): def shout(self):
self.__class__.__base__.shout(self) # 需要手动传入self
print('miaomiao')
c = Cat()
c.shout()

通过查找父类然后传入实例调用,是可以的,但是不建议这样使用,在这种情况下,我们一般会使用super.

6.1 super

        super函数(类)是用于调用父类(超类)的一个方法的。主要的两种写法如下:

super()   # 指代父类
super(type, obj) # 同样指代父类,super接受两个参数,第一个是类型,第二个是实例对象。 super() == super(type, obj)

super(type, obj) 一般写为super(self.__class__, self) 按照上面Animal的例子的话,就为super(Cat, self)

利用super完成增强方法的例子:

class Animal:

    def shout(self):
print('Animal shout') class Cat(Animal): def shout(self):
super(Cat, self).shout()
# super().shout()
print('miaomiao')
c = Cat()
c.shout()

静态方法和类方法都可以被覆盖,原理都相同,都是在属性字典__dict__中搜索。

6.2 继承中的初始化

class Animal:

    def __init__(self, name):
self.name = name def shout(self):
print('Animal shout') class Cat(Animal): def __init__(self, age):
self.age = age def shout(self):
print('miaomiao') c = Cat('daxin',20)
c.shout()
print(c.name)

请问这种情况是可以执行吗?答案是不行的,因为Cat重写了__init__方法,所以在c实例化时,只能访问Cat类的__init__方法,所以,就需要显示的调用父类的__init__方法。

class Animal:

    def __init__(self, name):
self.name = name def shout(self):
print('Animal shout') class Cat(Animal): def __init__(self, name, age):
super(Cat, self).__init__(name) # 等于把实例和name变量,传递给Animal.__init__(self,name)
# super().__init__(name) # 效果相同
self.age = age def shout(self):
print('miaomiao') c = Cat('daxin',20)
c.shout()

需要注意的是,如果有同名属性,那么后执行的会覆盖先执行的。

def __init__(self, name, age):
super(Cat, self).__init__(name)
self.name = age # 覆盖父类初始化的name属性

另外在私有属性继承的情况下,请注意真正的变量名称(因为会改名)。

7 多继承

        一个类继承自多个类就是多继承,它将具有多个类的特征。面向对象的设计的开闭原则(实体应该对扩展开放,而对修改封闭),就可以利用继承来设计,即多用'继承',少修改(并不是一般的多继承,后面会详述)。它的定义个数如下

class MyClass(A,B,...):pass

        Python中的继承关系,分为多继承和单继承,如图所示:

7.1 多继承弊端

        多继承很好的模拟了世界,因为事物很少是单一继承,但是舍弃简单,必然引入复杂性,带来了冲突。举个简单的例子:如果一个孩子继承了来自父母双方的特称,那么到底眼睛像爸爸还是妈妈呢,孩子究竟像谁多一点呢?

多继承的实现或导致编译器设计的复杂度增加,所以现在很多语言也舍弃了类的多继承。

        C++支持多继承,而Java舍弃了多继承。有些人说Java支持的多继承的,其实他说的是接口,在Java中,一个类可以实现多个接口,一个接口也可以继承多个接口。Java的接口很纯粹,只是方法的生命,继承者必须实现这些方法,就具有了这些能力,就能干什么。

        多继承带来的问题,最主要的就是二义性,例如猫和狗都继承自动物类,现在如果一个类继承了猫和狗类,猫和狗都有shout方法,子类究竟继承谁的shout呢?

实现多继承的语言,要解决二义性,主要有两种方法深度优先广度优先

7.2 MRO

        MRO:方法解析顺序,Python使用MRO来解决多继承带来的二义性问题。因为Python 2.x的旧式类和新式类等历史原因(旧式类不会继承object对想),MRO有三个搜索算法:

  1. 经典算法(2.2之前):按照定义从左至右,深度优先策略。左图的MRO为:MyClass、D、B、A、C
  2. 新式类算法(2.2版本):经典算法的升级,深度优先,重复的只保留最后一个。左图的MRO为:MyClass、D、B、C、A、object
  3. C3算法(2.3之后):在类被创建出来的时候,就计算一个MRO有序列表。Python3唯一支持的算法。左图的MRO为:MyClass、D、B、C、A、object

        经典算法有很大的问题。如果C中有覆盖A的方法,就不会访问到C,因为深度优先,会先访问A。新式类算法算法,依然采用了深度优先,解决了重复问题,但是同经典算法一样,么有解决继承和单调性的问题。

单调性:如果在D的解析顺序中,B排在A的前面,那么在D的所有子类里,也必须满足这个顺序。

        C3算法,解决了继承的单调性,它阻止创建之前版本产生的二义性代码,求得MRO是为了线性化,且确定了顺序。关于MRO和C3可以参考:Python的多重继承问题-MRO和C3算法

class A:pass
class B(A):pass
class C(A):pass
class D(B):pass
class MyClass(D,C):pass print(MyClass.mro()) # [<class '__main__.MyClass'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

注意:

  1. MyClass.mro() 和 MyClass.__mro__结果相同,一个是方法,一个是属性。
  2. D的解析顺序中,B在A的前面,那么在D的所有资料,都将保持这个顺序。
  3. 序列是有序的,当执行一个方法,子类不存在时,会按照mro列表开始寻找。

7.3 多继承的建议

当类很多,继承很复杂的情况下,继承路径太多,很难说清什么样的继承路线。Python语法是允许多继承的,但是Python代码是解释执行,只有执行时,才发现错误,如果团队协作开发,并且引入多继承,那么代码将有可能会变得不可控。所以在Python日常开发规范中建议:

  1. 避免多继承
  2. 由于Python语言本身过于灵活,所以最好遵循一定的团队开发规范。

7.4 Mixin

从一个需求开始了解Mixin。现有如下继承关系:



假设已经有了三个类:

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() # raise表示抛出异常,NotImplementedError表示没有被实现。 class Human(Animal):
pass class Monkey(Animal):
pass

解释:

  1. 没有实现的方法称为抽象方法,拥有抽象方法的类,叫做抽象类(抽象类不是用来实例化的,而是用来继承的,所以又叫做抽象基类)
  2. 子类直接执行talk方法时会产生异常(方法没有被实现)

Python中如果采用上面的方式定义抽象方法,子类可以不实现,但是到子类使用该方法的时候才会报错。

        Animal类是抽象基类,基类的方法可以不具体实现,因为它未必适合所有子类,在子类中一般需要重写。Human类和Monkey类属于Animal的子类,现在需要为Human类添加说话的功能,该怎么办呢?如果在Humman类上直接添加,虽然可以,但是却违反了OCP原则,所以我们只能继承了

下面对代码进行改写

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() class Human(Animal):
pass class Monkey(Animal):
pass class TalkHuman(Human): def talk(self):
print('{} say something'.format(self.name)) daxin = TalkHuman('daxin')
daxin.talk()

疑问:看似完成了需求,但是如果Human又要唱歌、跳舞、吃饭等方法呢?每次都要继承吗?这样类会不会太多了?能否用其他的方法呢?

7.4.1 利用装饰器新增功能

        前面我们利用装饰器为函数新增了功能,在Python中一切皆对象,函数和类都是对象,那么我们是否可以利用装饰器为类添加新功能呢?答案当然是可以的。使用装饰器为Human类添加talk方法:

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() def talkhuman(cls):
# def talk(self):
# print('{} say I Love You'.format(self.name))
# cls.talk = talk
cls.talk = lambda self: print('{} say I Love You'.format(self.name))
return cls @talkhuman # Human = talk(human)
class Human(Animal):
pass class Monkey(Animal):
pass daxin = Human('daxin')
daxin.talk()

        使用柯里化很容易就可以写出为类添加方法的装饰器,这种装饰器还有一个好处,哪里需要talk功能,直接装饰就好。有多个功能的话,那就写多个装饰器。

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() def talkhuman(cls):
cls.talk = lambda self: print('{} say I Love You'.format(self.name))
return cls def sleephuman(cls):
cls.sleep = lambda self: print('{} will sleep with you'.format(self.name))
return cls @sleephuman
@talkhuman
class Human(Animal):
pass class Monkey(Animal):
pass daxin = Human('daxin')
daxin.talk()
daxin.sleep()

7.4.2 Mixin类

先来看代码:

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() class TalkMixin:
def talk(self):
print('{} say I Love You too'.format(self.name)) class Human(Animal):
pass class Monkey(Animal):
pass class TalkMan(TalkMixin, Human):
pass daxin = TalkMan('daxin')
daxin.talk()

PS: 感觉就是写了一个类给别人继承了?

        Mixin体现的就是一种组合的设计模式,本质上就是多继承实现的。核心思想就是把其它类混合进来,同时带来了类的属性和方法。这里的Mixin看起来和装饰器的效果是一样的,也没什么特别的,但是Mixin是类,它可以继承。

class Animal:

    def __init__(self, name):
self.name = name def talk(self): # 抽象方法,没有真正被实现,需要子类自己去实现
raise NotImplementedError() class TalkMixin:
def talk(self):
print('{} say I Love You'.format(self.name)) class SingMixin(TalkMixin): # 通过继承来添加新的功能
def sing_a_song(self):
print('{} want sing a song'.format(self.name))
super(SingMixin, self).talk()
print('Go out,Now') class Human(Animal):
pass class Monkey(Animal):
pass class TalkMan(TalkMixin, Human):
pass class SingMan(SingMixin,Human):
pass daxin = SingMan('daxin')
daxin.sing_a_song()

使用原则:

  1. Mixin类中不应该显示的出现__init__初始化方法
  2. Mixin类通常不能独立工作,因为它是准备混入别的类中的部分功能实现
  3. Mixin类的祖先类也应该是Mixin类
  4. 使用时Mixin类通常在继承列表的第一个位置

小结:

  1. 在面向对象的设计中,一个复杂的类,往往需要很多功能,而这些功能又来自于不同类的提供,这就需要很多的类组合在一起。
  2. 从设计模式的角度来看,多组合,少继承。
  3. Mixin和装饰器都可以使用,看个人喜好,如果还需要继承,就是用Mixin的方式。

24 - 面向对象基础-多继承-super-mro-Mixin的更多相关文章

  1. PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)

    前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...

  2. 24 类:组合 继承 super关键字 面向对象的三大性

    组合 组合:自定义类的对象作为另外一个类的属性 class Teacher: def __init__(self, name, age): self.name = name self.age = ag ...

  3. python基础之面向对象的多继承以及MRO算法

    内容梗概: 1. python多继承 2. python经典类的MRO 3. python新式类的MRO C3算法 1.python多继承 class Shen: def fly(self): pri ...

  4. python笔记4 内置函数,匿名函数.递归函数 面向对象(基础, 组合,继承)

    内置函数 eval和exec eval :执行字符串中的代码并将结果返回给执行者,有返回值 exec:执行字符串中的代码,往往用于执行流程语句,没有返回值. s1 = '1+2' s2 = 'prin ...

  5. Python基础:面向对象基础(二) 继承

    子类在继承的时候,在定义类时,小括号()中为父类的名字,父类的属性.方法,会被继承给子类,Python中允许多继承. 多继承 # 父类 Master class Master(object): def ...

  6. python 之 面向对象基础(继承与派生,经典类与新式类)

    7.2 继承与派生 7.21继承 1.什么是继承? 继承是一种新建类的的方式,在python中支持一个子类继承多个父类.新建的类称为子类或者派生类,父类又可以称为基类或者超类,子类会”遗传“父类的属性 ...

  7. Day 18 :面向对象[基础,继承,组合]类的增删改查

    有的人说,编程有3种范式: 1.面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了. 2.面向函数:面向函数是面向过程的升级版,也就是把每个 ...

  8. C# 面向对象基础&封装&继承&多态&加深一下冒泡排序写法

    (一)面向对象是什么? 面向对象是一种编程思想 (二)为什么要用面向对象? 1.结构清晰 2.易于维护 3.方便扩展 (三)new一个对象是什么过程? 实例化构造函数创建对象的过程就是将类实例化的过程 ...

  9. 面向对象:静态属性,静态方法,组合,继承,衍生,继承之mro线性顺序列表,面向对象综合实例

    1.静态属性(附有装饰器) class Room: def __init__(self,name,owner,width,length,height): self.name=name self.own ...

随机推荐

  1. canvas - 简单的神经网络

    1.国际惯例,先上效果图 一下效果图使用三次贝塞尔曲线进行连线,代码中有直接使用直线连线的代码,可直使用. 2.查看演示请看 这里. 3 代码     html: <canvas id=&quo ...

  2. 洛谷 P1231 教辅的组成(网络最大流+拆点加源加汇)

    题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书 ...

  3. Find the hotel HDU - 3193(RMQ)

    题意: 有n个旅馆,从这n个旅馆中找出若干个旅馆,使得这若干个旅馆满足这样的条件:不能从其它和剩下的旅馆中找到一个价格和距离都小于这个旅馆的旅馆... 解析: 按price 排序,若price相同, ...

  4. 【BZOJ4767】两双手(动态规划,容斥)

    [BZOJ4767]两双手(动态规划,容斥) 题面 BZOJ 题解 发现走法只有两种,并且两维坐标都要走到对应的位置去. 显然对于每个确定的点,最多只有一种固定的跳跃次数能够到达这个点. 首先对于每个 ...

  5. ZOJ3899 State Reversing 【线段树 + NTT】

    题目链接 ZOJ3899 题解 比较累,做一道水题 还被卡常= = 我在\(ZOJ\)交过的两道\(NTT\)都被卡常了.. 哦,题意就是求第二类斯特林数,然后线段树维护一下集合数量就可以了 #inc ...

  6. python基础----常用模块

    一 time模块(时间模块)★★★★                                                      时间表现形式 在Python中,通常有这三种方式来表示时 ...

  7. C#调用GDI+1.1中的函数实现高斯模糊、USM锐化等经典效果。

    http://www.cnblogs.com/Imageshop/archive/2012/12/13/2815712.html 在GDI+1.1的版本中,MS加入不少新的特性,其中的特效类Effec ...

  8. Git之git push不手动输入用户名和密码

    每次git push时都要输入用户名和密码,感觉很啰嗦,总结了网上的解决办法,有的发现不可以(原因未知),记录一个对我自己可用的方式,我的是windows. 1:添加环境变量 2:在%HOME%目录下 ...

  9. sloop公共程序之初始过程及启动

    1:sloop_init() 初始化主要是初始化静态sloop_*** 结构体和填充struct sloop_data 结构体中的成员. //初始化静态存储区给sloop_***结构体 static ...

  10. Hibernate学习(3)- *.hbm.xml详解

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBL ...