Java面向对象的三大特征
面向对象的特征之一:封装性的设计思想
- 程序设计追求“高内聚,低耦合”。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
- 低耦合:仅对外暴露少量的方法用于使用。
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。
- 封装性的体现:
- 将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值。
- 不对外暴露的私有的方法。
- 单例模式。
- 封装性的体现,需要权限修饰符来配合。
- Java 权限修饰符public、protected、private置于
类的成员
定义前,用来限定对象对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
- 对于 class 的权限修饰只可以用 public 和 default(缺省)。
- public 类可以在任意地方被访问。
- default 类只可以在同一个包内部的类访问。
- 四种权限可以用来修饰类及类的内部结构:
属性
、方法
、构造器
、内部类
。
- 修饰类的话,只能使用:缺省、public
- 封装性的体现:
- 将类的属性私有化,同时提供公共的方法来获取和设置属性的值。
- 不对外暴露私有的方法。
- 单例模式(将构造器私有化)。
- 如果不希望类在包外被调用,可以将类设置为缺省的。
面向对象的特征之二:继承性
- extends:延展、扩展。
- 继承性的好处:
- 减少了代码的冗杂,提高了代码的复用性。
- 便于功能的扩展。
- 为多态性的使用,提供了前提。
- 继承性的格式:
class A extends B{}
- A:子类、派生类、subclass
- B:父类、超类、基类、superclass
- 体现:一旦子类 A 继承了父类 B 以后,子类 A 中就获取了父类 B 中声明的结构:所有的属性和方法。特别的:父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只是我因为封装性的影响,使得子类不能直接调用父类的结构而已。
- 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
Java 中关于继承性的规定:
- Java
只支持单继承和多层继承
,不允许多重继承。
- 一个类可以被多个子类继承。
- Java 中类的单继承性:一个类只能有一个父类。
- 子父类是相对的概念。
- 子类直接继承的父类,称为:
直接父类
,间接继承的父类称为:间接父类
。 - 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。
- 如果没有显式地声明一个类地父类的话,则此类继承于 java.lang.Object 类。
- 所有的 Java 类(除 java.lang.Object 类)之外都直接或间接地继承于 java.lang.Object 类。
- 也就意味着,
所有的 Java 类都具有 java.lang.Object 类声明的功能
。
面向对象特征之三:多态性
- 多态性:是面向对象中最重要的概念,可以理解为一个事物的多种形态,在 Java 中体现:
- 对象的多态性:父类的引用指向子类的对象。
- 可以直接应用在抽象类和接口上。
- Java 引用变量有两个类型:
编译时类型
和运行时类型
。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
- 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)。
- 多态情况下:
- 看左边:看的是父类的引用(父类中不具备子类特有的方法)。
- 看右边:看的是子类的对象(实际运行的是子类重写父类的方法)。
- 多态的使用:
虚拟方法调用
。
- 多态的使用前提:
类的继承关系
。方法的重写
。
- 对象的多态性只适用于方法,不适用于属性。
- 多态性的举例:
//AnimalsTest public class AnimalsTest { public static void main(String[] args) { AnimalsTest test = new AnimalsTest(); test.func(new Dog());// 狗吃骨头 狗汪汪汪 System.out.println("*************************");// ************************* test.func(new Cat());// 猫吃鱼 猫喵喵喵 } public void func(Animals animals){ animals.eat(); animals.shut(); } } // Animals public class Animals { public void eat() { System.out.println("动物进食"); } public void shut() { System.out.println("动物在叫"); } } // Dog public class Dog extends Animals { public void eat() { System.out.println("狗吃骨头"); } public void shut() { System.out.println("狗汪汪汪"); } } // Cat public class Cat extends Animals { public void eat() { System.out.println("猫吃鱼"); } public void shut() { System.out.println("猫喵喵喵"); } }
拓展
- 虚拟方法调用(多态情况下):子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为
虚拟方法
,父类根据赋给它不同的子类对象,动态调用属于子类的该方法。这样的方法调用在编译器是无法确定的。
Person e = new Student(); e.getInfo(); // 调用 Student 类的 getInfo() 方法
- 编译时类型和运行时类型:编译时 e 为 Person 类型,而方法的调用是在运行时确定的,所以调用的是 Student 类的 getInfo() 方法。——
动态绑定
- 那如何才能调用子类特有的属性和方法呢?
- 向下转型:使用强制类型转换符。
- 向下转型的常见问题:
- 编译时通过,运行时不通过。
Person p3 = new Woman(); Man m3 = (Man)p3;
编译时通过,运行时也通过。
Object obj = new Woman; Person p = (Person)obj;
编译不过
Man m5 = new Woman; String str = new Date();