1.封装
把数据和方法包装进类中,以及具体实现的隐藏,常共同被称作是是封装。其结果是一个同时带有特征和行为的数据类型。
所谓具体实现的隐藏是通过访问权限控制实现的。
JAVA 子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符要比父类的更大,也就是更加开放,假如我父类是protected修饰的,其子类只能是protected或者public,绝对不能是friendly(默认的访问范围)或者private,当然使用private就不是继承了。还要注意的是,继承当中子类抛出的异常必须是父类抛出的异常的子异常,或者子类抛出的异常要比父类抛出的异常要少。
- private,表示成员是私有的,只有自身可以访问;
- deafult,表示包访问权限(friendly, java语言中是没有friendly这个修饰符的,这样称呼应该是来源于c++ ),同一个包内可以访问,访问权限是包级访问权限;
- protected,表示受保护权限,体现在继承,即子类可以访问父类受保护成员,同时相同包内的其他类也可以访问protected成员。
- public,表示成员是公开的,所有其他类都可以访问;
(上述修饰词按照访问程序依次升高排序)
2.继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”,在Java中,Object类所有类的基类。
Java通过在基类名称后的extends关键字来实现继承。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
- 实现继承:使用基类的属性和方法而无需额外编码的能力;(extends)
- 接口继承:仅使用属性和方法的名称、但是子类必须提供实现的能力;(implments)
- 可视继承:子窗体(类)使用基窗体(类)的外观和实现代码的能力。
两个类之间的关系可以是“属于”(IS-A)关系。例如,Employee 是一个人,Manager 也是一个人,这两个类都可以继承 Person 类。
public class Person{}
public class Manager extends Person{}
public class Employee extends Person{}
但是Leg类却不能继承Person类,因为腿并不是一个人。这种可以定义为”从属”(HAS-A)关系。
public class Animal{}
public class Leg{}
public class Person extends Animal{
private Leg lg;
}
抽象类仅定义将由子类创建的一般属性和方法,创建抽象类时,请使用关键字 Interface 而不是 Class。
3.多态
多态的作用是消除类型之间的耦合关系。也可以管多态叫做动态绑定(运行时绑定、后期绑定)
在Java编程中,有一种行为叫做“向上转型”,即将某个对象的引用视为对其基类类型的引用,如:Person p = new Manager();
但Manager和Employee都只是打工的,都需要领工资getSalary,如果我们写的话,会有getSalary(Manager m)和getSalary(Employee e)两个方法,那如果再来新的级别,例如BigManager怎么办,继续添加新的方法?
NO!我们不如写这样一个方法getSalary(Person p)。这样无论什么级别的员工要领薪水,都是出自他作为一个人类的行为,可能这个比喻不太恰当,大家理解就好。
但是你怎么知道这个Person的级别呢?没关系,JVM会帮你搞定这件事情。
Person p = new Manager();
p.getSalary()
这样程序执行Manager的getSalary方法。
这就是多态的作用了,将一个方法调用同一个方法主体关联起来称作绑定,运行时绑定就是在运行时根据对象的类型进行绑定,与编译时绑定(静态绑定、后期绑定)相区别。
通过上面的例子我们可以看出,多态可以改善代码的组织结构和可读性,并且可以创建可扩展的程序,即使我们添加新的类,可以从通用的基类集成出新的数据类型,从而添加一些新的功能,那些操纵基类接口的方法不需要任何改动就可以应用于新类。换句话说,多态是一项让程序员“将改变的事物与围边的事物分离开来”的重要技术。
Java的多态性体现在两个方面:由方法重载实现的静态多态性(编译时多态)和方法重写实现的动态多态性(运行时多态)。
注:但是根据《Java编程思想》中的意思是仅有运行时多态,也就是说重写和多态有关,重载和多态无关。严格意义上的多态就是运行时绑定
编译时多态:在编译阶段,具体调用哪个被重载的方法,编译器会根据参数的不同来静态确定调用相应的方法。
运行时多态:由于子类继承了父类所有的属性(私有的除外),所以子类对象可以作为父类对象使用。程序中凡是使用父类对象的地方,都可以用子类对象来代替。一个对象可以通过引用子类的实例来调用子类的方法。
- 重载(Overloading)
方法重载是让类以统一的方式处理不同数据类型的手段。
一个类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义(重载体现且仅体现在参数列表上)。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法。
返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准。 - 重写(Overriding)
子类对父类的方法进行重新编写。如果在子类中的方法与其父类有相同的的方法名、返回类型和参数表,我们说该方法被重写 (Overriding)。
如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
子类函数的访问修饰权限不能低于父类的。
4.总结
根据个人的理解:
- 封装:代码模块化。
- 继承:复用代码。
- 多态:扩展程序。
三者不能孤立的看待,而是互相影响,构成了我们的OOP世界。
参考资料:
《Thinking In Java》
OOPs in Java- Encapsulation, Inheritance, Polymorphism, Abstraction
Understanding Object Oriented Programming
如此理解面向对象编程(上一个链接的中文译文)
面向对象编程常见问题
Java 继承