B 类 对象 继承 多态与动态绑定

来源:互联网 发布:程序员公众号 编辑:程序博客网 时间:2024/05/24 04:25

1 .java文件与.class文件

Java中所有的方法,属性都必须以类的形式存在。也就是说,他们必须是类的成员。以Employee类为例,java的源文件名称为Employee.java,在这个源文件中,只能有一个public类,且它的名字为Employee。在一个Java源文件中,只能有一个公有类,但可以有任意数目的非公有类。在编译以后,每一个类将被编译成一个.class文件。


2 类的概念

类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念。先有类,然后由类来生成对象(Object)。对象又叫做实例(Instance)。


3值传递

在Java中进行方法的参数传递时,无论传递的是原生数据类型还是引用类型,参数传递方式统一是传值(pass by value)。Java中没有传引用(pass by reference)的概念。

在引用传递的时候,传递的是地址的值。如果在方法中,改变了传递的地址的值,那将会毫无变化。下面代码可以很好的解释这个问题

class Point{    int x;    int y;}public class Test{        public void changeOne(Point point)    {        point.x=3;        point.y=4;    }    public void changeTwo(Point point)    {        point=new Point();        point.x=3;        point.y=4;    }    public static void main(String[] args)    {        Test test=new Test();        Point point=new Point();        /*test.changeOne(point);*/        test.changeTwo(point);        System.out.println(point.x);        System.out.println(point.y);    }}
因此,在Java中 ,方法参数的使用情况如下

  • 一个方法不能修改一个基本数据类型的参数的。
  • 一个方法可以改变一个对象参数的状态
  • 一个方法不能让对象参数引用一个新的对象

4 重载

表示两个或多个方法名字相同,但方法参数不同。方法参数不同有两层含义:

  • 参数个数不同。
  • 参数类型不同。

对于构造方法重载:只需看参数即可。如果想在一个构造方法中调用另外一个构造方法,那么可以使用this()的方式调用,this()括号中的参数表示目标构造方法的参数。this()必须要作为构造方法的第一条语句,换句话说,this()之前不能有任何可执行的代码。

注意:方法的返回值对重载没有任何影响。方法的名字和参数列表称为方法的签名



5 继承

  • Java是单继承的,意味着一个类只能从另一个类继承(被继承的类叫做父类【基类,base class】, 继承的类叫做子类),Java中的继承使用extends关键字。
  • 当生成子类对象时,Java默认首先调用父类的不带参数的构造方法然后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象,没有父类对象就没有子类对象。比如说:没有父亲,就没有孩子】。
  • 需要使用super()显式调用父类构造方法
  • super关键字:super表示对父类对象的引用。super跟this不一样,不能将super赋给另一个对象变量,它只能指示编译器调用超类的方法。
  • 如果子类使用super()显式调用父类的某个构造方法,那么在执行的时候就会寻找与super()所对应的构造方法而不会再去寻找父类的不带参数的构造方法。与this一样,super也必须要作为构造方法的第一条执行语句,前面不能有其他可执行语句。因为没有父亲,就没有儿子
  • 关于继承父类公有的,子类也有,父类没有的,子类可以增加,父类有的,子类可以改变
  • 继承时生成父对象与子对象两个对象,内存地址相连,引用指向子类。
  • 构造方法不能被继承
  • 方法和属性可以被继承子类的构造方法隐式地调用父类的不带参数的构造方法
  • 当父类没有不带参数的构造方法时,子类需要使用super来显式地调用父类的构造方法,super指的是对父类的引用。如果父类没有不带参数的构造方法,而子类又没有显示地调用父类的构造方法,那么编译器将报错。因为编译器只能帮你调用不带参数的构造方法。


6 构造块与静态块

对于初始化数据域的方法,除了在构造器中赋值以及在声明中赋值以后,还有一种方式,就是使用构造块。在一个类中,可以含有多个构造块,且构造块在每次类的初始化的时候,都会被执行而静态块只会被执行一次。对于继承关系,在初始化子类的时候,它们的执行顺序如下

父类静态块-》子类静态块-》父类构造块-》子类构造块。


7 重写

方法重写(Override):又叫做覆写,子类与父类的方法返回类型一样、方法名称一样,参数一样,这样我们说子类与父类的方法构成了重写关系。这种关系只会发生在父子类之间。

当两个方法形成重写关系时,可以在子类方法中通过super.run()形式调用父类的run()方法,其中super.run()不必放在第一行语句,因此此时父类对象已经构造完毕,先调用父类的run()方法还是先调用子类的run()方法是根据程序的逻辑决定的。

在覆盖一个方法时,子类的方法不能低于超类的方法可见性。

8 多态

一个对象可以指示多种实际类型的现象称为多态。在运行时能够自动地选择调用哪个方法的现象称为动态绑定。

可以理解为父类型的引用可以指向子类的对象。最常用的,面向接口的编程。接口声明的变量指向其实现类的实例。

有一个规则可以用来判断是否为继承关系,就是“is -a”规则,即子类每个对象也是父类的每个对象。在程序中任何出现超类对象的地方,都可以用子类进行替代,这又叫“置换法则”。


动态绑定

Java中,方法的的调用执行以下过程

(1) 编译器查看对象的声明类型和方法名。假设调用x.f(param),且隐式参数x声明为C类的对象。编译器会一一列举所有C类名为f的方法和其超类中访问属性为public且名为f的方法。至此,编译器已获得所有可能被调用的候选方法

(2)接下来,编译器将查看调用方法时提供的参数类型。如果在所有名为f的方法中存在一个与提供的参数类型完全匹配,就选择这个方法。这个过程称为重载解析。至此,编译器已获得需要调用的方法名字和参数类型

(3)如果是private方法、static方法、final方法或者构造器,那么编译器将可以准确地知道要调用哪个方法。这种调用方式称为“静态绑定‘,与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。

(4)当程序运行,并且采用动态绑定时,虚拟机一定调用那个最合适的方法。假设X的实际类型为D,它是C的子类,如果D类存在方法f,就直接调用它;否则将在D类的超类寻找f。

每次调用方法都要进行搜索,时间开销很大,因此虚拟机为每个类创建了方法表,在实际调用的时候,虚拟机仅查找这个表就可以了



9 类的设计技巧

  • 保证数据私有
  • 要对数据进行初始化
  • 不要再类中过多的使用基本数据类型
  • 将职责过多的类进行分解
  • 类名和方法名要能够体现他们的职责










0 0