面向对象编程的特点:封装、继承、多态

※ 数据隐藏

这里说说的数据主要指的是类中的属性。
如何对属性进行隐藏呢?
在前面封装的属性前面用private修饰,表示该属性不能被其它类访问和修改,它只能被本类访问和修改,范围限制在本类内。

java中封装有两个方面:
属性的封装;
方法的封装。

※ 封装

1)对属性的封装
首先属性可以被一下修饰符修饰:
public protected “default” private(这四种修饰符可以修饰成员变量,也可以修饰方法)
public String name;
protected String name;
private String name;
//这样就是default
String name;

//这样写是错的
default String name;

注: 四种修饰符的作用之后会讨论

对属性的封装:在属性(实例变量)前加private, 然后通过统一的方法访问以及修改这些属性值;
使用get/set方法来访问类中被private修饰的属性。

这样做的目的就是隐藏数据信息,保证数据的安全。

2)方法的封装:(指的是用方法来封装代码)
站在使用的者的角度去考虑,用户只关心方法的使用,不管里面到底怎么实现的细节。
从编程的角度去看的话:为了代码的重用。

※ 方法重载(overload)

有时侯,类的同一种功能有多种实现方式,换句话说,有很多相同名称的方法,参数不同。这给用户对这种功能的调用使用提供了很大的灵活性。
例如:Test类中要求有俩个方法:

     public void print(int i){
        System.out.println("i = "+i);
     }  

     public void print(String s){
        System.out.println("s = "+s);
     }

对于类的方法(包括从父类中继承的方法), 如果有两个方法的方法名相同,但参数不一致,那么可以说,一个方法是另一个方法的重载方法。这种现象叫重载。

重载必须满足以下条件:
1)方法名称相同。
2)参数列表不同(参数类型、个数和顺序)。
注意: 返回类型可以不相同。

在一个类中不允许定义两个方法名相同,并且参数签名也完全相同的方法。因为假如存在这样的两个方法,Java虚拟机在运行时就无法决定到底执行哪个方法。参数签名是指参数的类型、个数和顺序。

※ 子类

1)通过生活中的例子推出Java中继承;

什么是继承呢?生活中不乏这样的例子,张老头有个儿子张小头,张老头健在的时侯,张小头继承了张老头的坏脾气,国字脸,八字脚。张小头只有亲生爸爸张老头,张老头却有包括张小头在内的多个子女。

Java中类与类之间也有生活中类似的继承关系。在Java类继承关系中,对应于父亲的类叫父类,对应于儿子的类叫子类。父子类间的继承关系也叫“is a”关系。这种关系通过类声明上的extends关键字体现。
Person Student
Student is a Person

一个子类只有一个父类,一个父类可有多个子类。

2)为什么要继承?

. 站在巨人的肩膀上;通过继承,我们可以快速构建出一个带有丰富功能的新类;有了张老头,张小头年纪轻轻就可以买上上百万的新房;
. 不修改源代码,修改既有类的行为;通过继承,在子类中构建父类中一样的方法,可以改变父类方法的行为。张老头没有考上大学,通过张小头圆了其上大学的梦。

3)Object类简略介绍

所有的Java类都直接或间接地继承了java.lang.Object类。Object类是所有Java类的祖先,在这个类中定义了所有的Java对象都具有相同行为。

※ 继承

子类继承了父类的属性和方法:

1)父子类同包,子类继承父类中public、protected和默认访问级别的成员变量和成员方法;
2)父子类不同包,子类继承父类中public、protected的成员变量和成员方法;

属性:子类继承父类属性,当子类没有重新定义父类属性赋初值时,子类通过隐式调用(子类通过JVM所给默认无参构造器隐藏调用父类的默认无参构造器)调用父类构造器对父类中该属性进行赋值;
当子类重新定义父类中属性时,通过生成子类对象赋初值时,只会更改子类属性的值,当生成父类指向子类的对象调用的属性是父类的。

方法:子类继承父类方法,当子类没有与父类方法一模一样的方法时,生成的子类对象调用的时父类的该方法;
当子类有与父类方法一模一样的方法时(方法的重写),生成的子类对象,或生成的父类指向子类时对象调用的方法都是子类所重写的方法。

那么继承有哪些细节呢?

1、构造器不能被继承,可以隐式调用父类的构造器。原理相当于在子类构造器第一行代码写了super(); super调用父类的构造器,必须为第一行
2、方法和实例变量可以被继承
3、子类构造器隐式地调用父类的默认无参构造器;
4、如果父类中没有定义无参构造器,只定义了有参构造器,那么子类构造器则必须显式地调用父类的有参构造器(通过super(…)),且必须放置在第一条语句,否则会有语法错误。
5、this()和super()在构造器中都必须为第一条语句,两者不能同时出现。
6、当一个子类继承了一个父类后,父类中所有的字段和方法都被子类继承拥有,子类可以任意的支配使用,每个子类对象中都拥有了父类中的所有字段。当构造一个子类的实例对象时,该对象的实例变量包括了子类本身以及父类中的所有实例变量,实例方法也包括了子类和父类中的所有实例方法。
7、子类构造器用来初始化子类中所有的实例变量,而父类构造器super(实参)用来初始化父类中所有的实例变量。
所以在堆中为子类实例对象分配的内存区域中包括了子类和父类中所有初始化后的实例变量

如果父类有私有属性不能被继承,但是因为构建子类对象的时候子类构造器会隐式调用父类构造器(构造器给全局变量赋值的过程是不考虑修饰符的)
子类构造器可以通过显示的调用父类构造器对父类了私有属性赋值
注意:父类提供了有参数的构造器,也要提供无参数的构造器

※ 方法覆盖(重写)

1.方法覆盖只存在于子类和父类(包括直接父类和间接父类)之间。把父类中能继承的方法原样在子类构建一模一样的方法
(修饰符 返回值 方法名(参数不变))

在同一个类中方法只能被重载(修饰符 返回值 方法名(参数改变),不能被覆盖;

2.静态方法:
不能覆盖;
a. 父类的静态方法不能被子类覆盖为非静态方法 //编译出错
b. 子类可以定义与父类的静态方法同名的静态方法(但是这个不是覆盖)
例如:A类继承B类 A和B中都一个相同的静态方法test
B a = new A();
a.test();//调用到的时候B类中的静态方法test
A a = new A();
a.test();//调用到的时候A类中的静态方法test
可以看出静态方法的调用只和变量声明的类型相关
这个和非静态方法的重写之后的效果完全不同
c. 父类的非静态方法不能被子类覆盖为静态方法;//编译出错

静态的属性,方法可以被继承
注意:静态的东西都属于类的,非静态的东西是属于对象的
子类出现了一个和父类一米一样的静态方法,不叫重写,子类父类中的方法是各自的属于各自类,(隐藏)

3.私有方法:
不能被子类覆盖

       class Base {
             private String showMe() {
                  return "Base";
             }

             public void print() {
                  System.out.println(showMe());
             }
       }

       public class Sub extends Base {
             private String showMe() {
                  return "Sub";
             }

             public static void main(String args[]) {
                  sub sub = new Sub();
                  sub.print();            
          //打印出结果"Base", 因为print()方法在Base类中定义,因此调用在Base类中定义的
                  //private类型的showMe(). 如将private换成public类型,其它代码不变,打印"Sub";
             }
       }      

4.抽象方法:(之后会详细讨论抽象方法)
可以覆盖:
a. 父类的抽象方法可以被子类覆盖为非抽象方法: 子类实现父类抽象方法;
b. 父类的抽象方法可以被子类覆盖为抽象方法: 重新声明父类的抽象方法;
c. 父类的非抽象方法可以被子类覆盖为抽象方法;

※ 多态

多态的俩中描述:
1.一个父类类型的引用可以指向他任何一个子类的对象;
2.[相同]类域的[不同]对象执行[同一]方法的时候会有[不同]的表现。

多态是出现在具有继承关系的两个类的对象之间,所以它不像方法重载(发生在一个类中)在编译期间发生(也就是确定下来),而是在运行期间发生(确定下来)。
Java中的方法是在代码运行时动态绑定的。

注:编译时多态(重载)与运行时多态(重写)。

※ 类型转换

转换:
1)先使用instanceof 识别类型:
obj instanceof 类名
obj instanceof 接口名
2)子类型隐式地扩展到父类型(自动转换)
3)父类型必须显式地缩小到子类型

转换规则:被转换的实际对象类型一定是转换以后对象类型的自身或者子类。
Person p = new Person();
Student s = (Student)p; 编译不会错,运行时错误

Person p2 = new Student();//父类显示缩小到子类
Student s = (Student)p2 或者 Person p = (Student)p2; 正确

猜你喜欢

转载自blog.csdn.net/qq_42857603/article/details/81627433