面向对象(进阶)

this关键字

this可以调用:属性、方法;构造器

this调用属性和方法

this 理解为当前对象,也就是说代表调用属性或方法的对象.

this 通常可以省略,但是在属性的名称和形参变量的名称一样的情况下,就必须用this. 标示出成员变量。方法里通常省略this

this调用构造器

使用this(形参列表) 调用当前类中其它的重载的构造器,this(形参列表) 必须声明在当前构造器的首行,所以在一个构造器最多出现一次。

理解:在类中有n个构造器,则最多有n-1个this(形参列表) 结构

面向对象特征之二:继承性

继承的基本概念

继承性的好处:

  • 减少代码冗余,提高复用性

  • 便于功能扩展

  • 产生了is-a的关系,为多态的使用提供了前提

继承性的特点

  • 单继承性:但是一个子类只能有一个父类

  • Java支持多层继承,一个父类可以扩展为多个子类。

  • Java中声明的类,如果没有显式声明其父类,默认继承于java.lang.Object类。

  • Java中子类父类的概念是相对的。

继承的格式

1
2
3
4
5
6
7
class A{

}

class B extends A{

}

上边代码中:
A类:父类、superClass、超类、基类
B类:子类、subClass、派生类

继承的作用

通过这样声明,子类能够获得了父类声明的所有属性和方法

子类继承父类后,还可以扩展自己的功能,要区别于集合和子集的概念。

同时,继承不打破封装性,所以因为封装性,子类不能直接调用父类私有的属性。但可以通过get方法调用。

方法的重写(overwrite/override)

子类对从父类继承过来的方法进行的覆盖、覆写的操作,称为重写(overwrite)

方法重写的规则:

  1. 父类被重写的方法的方法名和形参列表必须相同
  2. 子类重写的权限修饰符不小于父类的修饰符。特例:子类不能重写父类中private的方法
  3. 返回值类型:
    • 父类为void,则子类重写只能是void
    • 父类返回为基本数据类型,则子类同类型
    • 父类返回为引用数据类型,则子类重写的方法的返回值类型相同 或 是引用数据类型的子类
  4. 关于异常类型,子类重写的方法抛出的异常类型可以和父类被重写的方法抛出的异常类型相同,也可以是其子类

super关键字

使用场景:在子类中已经对父类中的方法进行了重写,但是又想要调用父类的方法,这是就要用super关键字
子类与父类定义了同名的属性,使用super可以区分子类和父类的属性。

super可以调用属性、方法;构造器

super调用属性、方法
子类继承父类以后,可以在子类的方法或构造器中调用父类的属性和方法。在满足封装性的前提下,使用super. 表示父类的属性或方法。
一般情况下,我们可以考虑省略super. ,但是如果子类中声明了同名的属性或者重写了父类的方法,就必须用super. 表示父类的属性和方法。对于子类父类的属性要尽量避开重名的情况(编程规范),而方法可能无法避免,就可以用super. 来调用

super调用构造器

  1. 子类继承父类时是不会继承构造器的,可以在子类构造器中用super(形参列表) 调用父类的构造器。
  2. 规定super(形参列表) 必须写在子类构造器的首行,这也就意味着this和super只能出现一个。
  3. 如果没有写super(形参列表)this(形参列表) ,则默认是super()
  4. 由2、3得出结论,子类的任何一个构造器要么调用本类中重载的构造器,要么调用父类中的构造器。
  5. 由4得到,一个类中声明有n个构造器,最多有n-1个构造器使用了this(形参列表) ,剩下那一个一定使用super(形参列表) 。–>在调用子类的构造器时,一定直接或间接调用了父类的构造器,也正因为调用了父类的构造器,我们才会将父类中声明的方法或属性加载到内存中,供子类对象使用。

子类对象实例化的全过程:

从结果来看,体现为类的继承性。

从过程上来讲,当我们通过子类的构造器创建对象时,一定会直接或间接得调用到其父类的构造器,父类也会直接或间接调用其父类的构造器……直到调用了Object类的构造器为止。

面向对象特征之三:多态性

基本概念

多态性使用的前提:1.要用子类的继承关系 2.要有方法的重写

如何理解多态性?

广义上:子类对象的多态性、方法的重写
狭义上:主要指子类对象的多态性

  • Java中多态性主要体现在子类对象的多态性:子类的对象赋给父类的引用。
    Object obj = new String("hello");其中String()是子类的构造器,而Person是String的父类。

  • 多态的优劣:

    • 优点:1. 极大地减少了代码的冗余,不需要定义多个重载的方法,比如equals(Object obj);开闭原则。
      2 .没有多态性,抽象类和接口的存在就没有意义。
    • 弊端:在多态的场景下,创建了子类的对象,也加载了其特有的属性和方法,但因为其声明为了父类,就无法调用其特有的属性和方法。

多态性的应用:虚拟方法调用。编译时,认为方法声明的是父类的方法。执行时,实际执行的是子类重写的方法。编译看左边,运行看右边。

多态仅仅适用于方法不适用于属性,本身也不建议在子类中定义与父类同名的属性

向下转型

类比基本数据类型的自动类型提升和强制类型转换。向上转型即为多态性,向下转型是多态的逆过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//向下转型的使用
public class PolymorphismTest {
public static void main(String[] args) {
Animal dogAni = new Dog();
Dog dog =(Dog) dogAni;//向下转型后dog声明为Dog类
dog.catchMouse();
System.out.println(dogAni==dog);//true,表明二者地址相同
}
}
class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃骨头");
}
public void catchMouse() {
System.out.println("狗抓老鼠");
}
}

向下转型可能出现的问题:类型转换异常(ClassCastException)

为避免出现类型转换异常,建议在向下转型之前使用*instanceof()*进行判断。
格式:a instanceof A判断对象a是否是类A的实例,如果a instanceof A为true,则a instanceof superA也为true,其中A是superA的子类。

Object类及其常见方法使用

Object类是Java类的根父类。
Object类中没有声明属性,Object类提供了一个空参的构造器。

clone()(了解)

再创建一个对象,内容与被克隆的完全一样,但是地址不同。

finalize()(了解)

在GC回收之前,进行finalize中的操作。

equals()(掌握)

任何引用数据类型都可以使用。
自定义的类在使用equals方法没有重写时,调用的就是Object中的equals,比较两个对象的引用地址是否相同。
对于像String、File、Date和包装类等,他们都重写了Object类中的equals方法,用于比较两个对象的实体内容是否相等。

开发中往往要用equals比较两个对象的实体内容是否相等,这时候就要对equals进行重写。

toString()(掌握)

开发中,在没有重写toString()方法时,打印的是类名+@+地址值
像String、File、Date和包装类等Object的子类,它们都已经重写了toString()方法,返回的是对象的实体内容。

开发中往往要用toString打印对象的实体内容,而非地址值。这时候,就要对toString进行重写。