面向对象三大特征
面向对象的三大特征包括——封装、继承和多态。
封装
封装指的将事物抽象成类,所以封装的实现主要涉及到类和对象。一个类里面包含了这个类设计到的属性和方法。 这个类只会让自己信任的类或对象进行操作,而对其他类和对象实现信息隐藏。
在iOS需要注意:
@interface manager:(Person) { 。 。 。 }
属性封装实例变量,方法封装具体的实现代码。
继承
继承是指子类子类从父类得到所有的属性和方法,并且可以对父类进行扩展。
继承实际上是一个“一般”和“特殊的关系”。
实现继承主要有三种方式:
(1)实现继承:使用父类的接口和方法,无需额外编码
(2)接口继承:使用父类的方法名和属性名,必须要在子类中编写具体的实现代码
(3) 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。(这个没用过)
iOS中的继承很简单,主要的符号是:
例如:
@Interface UserModel:NSObject
USerModel继承至NSObject
另外,子类也可以重写父类的某个函数。
多态
多态是指子类可以将父类对象设置成一个或多个他的子对象相等的技术,父类就可以根据当前给他赋值的子类,进行相应的操作。
简而言之,允许子类类型的指针赋值给父类类型的指针。不同的对象以自己的方式响应消息。
例如有一个类是Animal,表示动物,有一个方法eat(),一个子类dog,也有也有相同的方法eat(),pig也有eat()方法。而子类都只会调用自己对应的eat方法。
但是多态并不是在这么简答。
多态的实现方法主要有两种:
- 覆盖(重写)
覆盖又叫重写,是子类重新定义父类的虚函数。
所谓虚函数:是为了实现多态,在C++中是在函数前加virtual,而Java是没有虚函数这个概念的,Java只要不在前面加上static和final都可以进行动态绑定。
- 重载
重载指的是允许存在多个函数名相同,而参数不同的函数,参数不同具体可以是参数的类型、参数的个数、或者两者均不同)。
严格意义上来说,其实重载不算是面向对象对象编程。他的实现过程主要是:编译器在编译期间,根据函数的不同参数,对函数名进行不同的修饰,这些函数就成为了不同的函数。一个同名的函数,经过编译器修饰之后,他的函数名是不同的,也就是说在编译期间,就确定了对两个函数的调用,因此这是静态的!!!!
而多态一定是动态的,严格来说多态只包括覆盖(重写),当子类重新定义(覆盖)了父类的虚函数,父类指针根据赋值给他的子类指针指向的对象,动态的确定调用哪一个子类的函数,这个函数是在编译期间无法确定的,因此才叫动态绑定。
综上:封装是为了隐藏实现细节,使得代码模块化;继承是使得代码具有更好的扩展性;多态是使得代码的接口能够实现重用。
那么父类是怎么根据赋值给他的子类指针去确定动态的调用哪一个函数呢?
举例说明:
Class A {
public String show(D objec){
return (A and D);
}
public String show(A object){
return (A and A);
}
}
Class B extebds Class A {
public String show(B obj)...{
return (B and B);
}
public String show(A obj)...{
return (B and A);
}
}
class C extends B...{}
class D extends B...{}
问题是:以下输出的结果是什么?
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); ①
System.out.println(a1.show(c)); ②
System.out.println(a1.show(d)); ③
System.out.println(a2.show(b)); ④
System.out.println(a2.show(c)); ⑤
System.out.println(a2.show(d)); ⑥
System.out.println(b.show(b)); ⑦
System.out.println(b.show(c)); ⑧
System.out.println(b.show(d)); ⑨
要解决这个问题,我们就要知道多态的方法调用的优先级
在这个问题中,优先级为
this.show(object) -> super.show(object) -> this.show(super(object)) ->super.show(super(object))
在这个优先级的基础上,我们还要看子类是否覆盖(重写)了父类的方法。
逐个分析;
①应该输出的是 A and A ,a1是A类型,A中没有对应的函数,那么我们就去找参数B的父类,也就是A,那么这个时候函数调用变为了a1.show(super(b)),也就是 a1.show(A object),因此输出自然是A and A.
②和①的分析过程相同,输出结果是A and A
③最简单,直接在类A中可以找到,输出时A and D
④输出结果是B and A。a2是一个引用变量,类型为A,因此this 是a2,所以首先到A里面去找这个函数show(b),发现A中没有,而A已经没有父类,所以参数此时变为b的父类,也就是A,在A中去找show(A object),发现A中是有这个函数的,那么就输出 A and A吗?
这是错误的,因为a2是引用的类B的一个对象,类B里重写了函数show(A object),所以应该输出B and A.
⑤输出结果应该是B and A ,这和④的分析是一样的
⑥结果是A and D,a2是B的一个引用,类型是A,所以首先到A里面去寻找,结果A有这个方法,直接输出
⑦结果是B and B,b就是类B的一个实例,直接在B中可以找打show(B object),直接输出
⑧结果是B and B,b 是一个引用变量,类型是B,this是b,所以到B里面找show(C),没有这个方法,那么接着到B的父类A里面去找,A中也没有,那么接下来就要找参数的父类了,show(super(c)),c的父类是b,也就是show(b),B中有show(B),也就是B and B.