继承
-
遇到的问题.
多个类具有相同的成员.
a. 复制 粘贴.
-> 代码冗余.
-> 后期的维护不方便.b.使用继承.
-
继承的目的: 儿子类想拥有父亲类中的所有的成员.但是不想自己去定义,而是想凭空拥有.
-
继承的语法: 如何让1个类认另外1个类为爹 因为想拥有爹类中的所有的成员
语法: @interface 类名 : 父亲类的名称 @end
-
继承的效果:
儿子类一旦从父亲类去继承.那么儿子类中拥有了父亲类中的所有的成员. 不用自己定义.
-
几个术语:
@interface Student : Person
1). Student类从Person类继承. Studdent类是Person类的子类 Person类是 Student的父类.
2). Student类从Person类派生. Student类是Person类的派生类.Person类是 Student类的基类.
子类一旦从父类继承 就意味着子类拥有了父类的所有的成员 而不用自己去定义.
-
在新创建类模块的时候 指定父类.
Xcode就会自动的帮助你完成一系列的事情.
-
继承是类在继承.而不是对象在继承.
子类从父类继承.子类中就拥有了父类中定义的所有的成员. 只是类继承.
我们创建对象. 对象与对象之间是毫无关系的.
-
什么时候应该使用继承?
如果发现另外1个类中的成员我也想有 那么这个时候就可以使用继承.
千万不要为了继承而去继承. 不要为了仅仅是得到某个类的成员你就不顾伦理去乱继承.
满足继承的关系
isa
凡是满足
isa
关系的类 就可以拥有继承的关系.当A类是1个B类的时候 那么A类就可以从B类继承
学生 人 学生 狗 X 电风扇 电器 汽车 交通工具. 汽车 蛇.
-
再次的总结:
1). 子类从父类继承,就意味着子类拥有了父类的所有的成员 包括属性 方法.
2). 继承是类在继承.而不是对象在继承.子类对象中拥有父类对象中的同样的成员.
3). 满足继承的关系. isa 只有满足isa关系的类才可以拥有继承关系.
-
如果有1个成员不是所有的子类都拥有的.那么这个成员就不应该定义在父类之中.
因为一旦定义在父类之中.那么所有的子类全都有了.
父类中只定义所有的子类都拥有的.只要不是所有的子类都拥有的 那么就不应该定义在父类之中.
继承的特性
-
单根性
1个类只能有1个父类 不能有多个父类.
-
传递性.
A类从B类继承,B类从C类继承. 那么A类就同时拥有B、C类的成员.
-
NSObject类.
是Foundation框架中的类.在这个类中有1个类方法new
这个方法是用来创建对象的.方法的返回值是创建的这个对象的指针.
也就是说,如果要创建类的对象,就必须要调用这个new方法.
如果我们想要让我们的类具备创建对象的能力,就必须要让我们的类直接的或者间接的从NSObject类继承.
所以.要求: 我们写的类必须直接的或者间接的要NSObject类继承.
如果你不继承,我们的类就无法创建对象. 那么我们的类就毫无意义.
在NSObject类之中 还定义了1个属性. 这个属性叫做isa指针.
所以,每1个子类对象中都有1个叫做
isa
的指针.NSObject类是OC中所有类的祖宗类. 因为OC中的类全部都是直接的或者间接的从它继承,
关于子类和父类同名属性
-
子类中不能存在和父类同名的属性.
因为子类从父类继承,就意味着子类拥有了父类的所有的成员 包括属性和方法.
也就相当于子类中其实已经定义了.
如果子类再定义1个同名的属性 很明显就冲突了.
-
super关键字.
-
可以用在类方法和对象方法之中.
-
在对象方法中可以使用super关键字调用当前对象从父类继承过来的对象方法.(是自己调用而不是父类调用)
-
在类方法中 super关键字可以调用当前类从父类继承过来的类方法.
-
类方法也能被子类继承. 父类中的类方法可以使用父类名来调用 也可以使用子类名调用.
-
在子类的类方法中 可以使用super关键字调用父类的类方法.
-
-
super只能用来调用父类的对象方法或者类方法 不能用来访问属性.
-
-
子类从父类继承.
1). 相当于子类模板中拥有了父类模板中的所有的成员.
2). 创建1个子类对象,仍然是根据子类模板来创建对象.
只不过子类模板中拥有父类模板中的成员.
所以,子类对象中既有子类的成员也有父类的成员.
3). super特指这个方法是从父类继承过来的.
super是指当前类或者对象的这个方法是从父类继承过来的.
访问修饰符
-
访问修饰符: 用来修饰属性.可以限定对象的属性在那1段范围之中访问.
@private:
私有 被@private
修饰的属性只能在本类的内部访问.只能在本类的方法实现中访问.
@protected:
受保护的. 被@protected
修饰的属性只能在本类和本类的子类中访问.只能在本类和子类的方法实现中访问.
@package:
被@package
修饰的属性 可以在当前框架中访问.@public: 公共的.被@public修饰的属性 可以在任意的地方访问.
-
如果不为属性指定访问修饰符 那么默认的就是
@protected
只能在本类和子类的方法实现中访问.
-
子类仍然可以继承父类的私有属性.
只不过,在子类中无法去直接访问从父类继承过来的私有属性.
但是如果父类中有1个方法再为属性赋值或者取值.
那么子类可以调用这个方法间接的访问父类的私有属性
-
访问修饰符的作用域.
从写访问修饰符的地方开始往下.直到遇到另外1个访问修饰符或者结束大括弧为止。
中间的所有的属性都应用这个访问修饰符.
-
使用建议.
1). @public 无论什么情况下都不要使用. 属性不要直接暴露给外界.2). @private 如果属性只想在本类中使用 不想在子类中使用 那么就使用它.
3). @protected: 如果你希望属性只在本类和本类的子类中使用.
推荐使用默认的
@protected
-
访问修饰符只能用来修饰属性 不能用来修饰方法.
私有属性和私有方法
-
我们刚才讲的@private修饰的属性就叫做私有属性.
只能在类的内部访问.
但是在外界的时候,Xcode仍然会提示这个对象中有这个属性 只不过没权访问.
我们想要实现的效果:真私有 让外界不知道对象里面有这么1个属性.
-
其实在@implementaion之中也可以写1个大括弧.
把属性定义在@implementation的大括弧之中.
这里面的属性. 是1个私有属性. 各种访问修饰符无效.
外界根本就不会提示.
将属性定义在@implementation之中 和 将属性定义在@interface之中并标记为@private
唯一的区别: 提示和不提示. 都不能在外界访问.
-
私有方法.
方法不写声明,只写实现. 那么这个方法就是1个私有方法.
只能在本类的其他方法中调用 不能在外界调用.
里氏替换原则
-
里氏替换原则 --- LSP
子类可以替换父类的位置.并且程序的功能不受影响.
为什么?
1). 父类指针迫切的需求要1个父类对象,而我们给了1个子类对象,这是完全没有问题的. 因为子类就是1个父类嘛.
2). 因为父类中拥有的成员 子类都有. 所以不会影响程序的功能.
-
里氏替换原则的表现形式.
当1个父类指针指向1个子类对象的时候,这里就有里氏替换原则.
-
LSP的作用。
1). 1个指针中不仅可以存储本类对象的地址还可以存储子类对象的地址.
2). 如果1个指针的类型是NSObject类型的,那么这个指针中可以存储任意的OC对象的地址.
3). 如果1个数组的元素的类型是1个OC指针类型的 那么这个数组中不仅可以存储本类对象还可以存储子类对象.
4). 如果1个数组的元素是NSObject指针类型 那么意味着任意的OC对象都可以存储到这个数组之中.
5). 如果1个方法的参数是1个对象,那么我们在为这个参数传值的时候.
可以传递1个本类对象 也可以传递1个子类对象.
对方法中的代码不会有丝毫的影响. -
当1个父类指针指向1个子类对象的时候.
这个时候,通过这个父类指针就只能去调用子类对象中的父类成员.
子类独有的成员无法访问.
方法的重写
-
子类从父类继承,子类就继承了父类的方法.
子类继承了父类的方法,就意味着子类拥有了这个功能.
有的时候: 虽然子类也拥有父类的这个行为. 但是这个行为的具体的实现和父类不同.
-
这个时候怎么办?
那么子类就自己按照自己的方式重写这个方法就可以了.
如何重写: 直接在类的实现中将这个方法重新实现一遍就可以了.
-
当1个父类指针指向1个子类对象的时候.
通过这个父类指针调用的方法 如果在子类中重写了.
调用的就是子类重写的方法.
-
这样就引出了一个OC特性:多态.
指的是同1个行为,对于不同的事物具有完全不同的表现形式.
找三个人过来.
医生
演员
理发师cut 指令.
同1个行为 具备多种形态.
方法重写引出了一个方法:desicription
-
%p 打印的是指针变量的值.
%@ 打印的是指针指向的对象. -
如果我们使用%@打印1个对象
输出的格式: `<对象所属的类名:对象的地址>
-
原理:
当我们使用%@打印1个对象的时候, NSLog函数的底层实现.
1). 调用传入的对象的 description方法.
2). 拿到这个方法的返回值 这个返回值是1个字符串.
3). 将这个字符串输出.
-
description方法是定义在NSObject类之中的.
所以每1个OC对象都有这个方法.这个方法在NSObject类中的实现是这样的:
返回的字符串格式
@"<对象所属的类名:对象的地址>"
-
什么时候需要重写description方法呢?
如果你希望使用%@打印1个对象的时候 你希望这个对象打印的个数是我们自定义的.
那么就可以重写这个方法.
网友评论