面向对象(进阶)

目录

this关键字的使用

最常见的场景:

this的简单理解:

this调用的结构:1.成员变量,方法 2.构造器

针对于方法内的使用情况(非static修饰的方法)

针对于构造器内的使用情况

调用构造器时(最重要)

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

继承性的理解:

继承性的好处

继承的格式:(简单)

 继承中的基本概念:(拿上面图片举例)

有了继承性以后:

默认的父类:

补充说明

方法的重写(overwrite/override)

为什么需要方法的重写?

概念

“重写”遵循的规则

super关键字的使用

使用场景:

使用:super可以调属性,方法,构造器

提醒:

子类对象的实例化(先了解,之后的高级会讲细节)

代码举例

理解

从结果上看:体现了类的继承性

从过程上来看:

疑问?

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

理解:

多态性的体现:

多态使用的前提:

多态的适应性:

多态的好处:

多态的弊端:

向下转型和向上转型(多态)(可以用自动类型提升与强制类型转换的理解来理解它)

理解

instance的使用

Object类的使用

说明:

常用方法

重点方法:equals( ) \ toString( )

equals():

toString( ):

了解方法:clone( ) \ finalize( )

目前不需要关注的:(涉及集合框架,线程)


this关键字的使用

最常见的场景:

        当属性名与形参名相同时,用this来区分

this的简单理解:

        如果出现在方法中:意思就是"当前对象的",如果出现在构造器中意思就是“当前正在创造的对象的”。(因为new是用了构造器才创建了类的对象,你在使用构造器时不就是“正在创建对象”嘛)

this调用的结构:1.成员变量,方法 2.构造器

针对于方法内的使用情况(非static修饰的方法)

        一般情况,我们可以在方法内调用当前对象的属性或方法。此时,我们可以在属性或其他方法前使用this.表示其所属的对象,但我们经常会选择省略this.(因为它本身就是指的是"当前对象的",简单理解里面有介绍)

        特殊情况,形参和属性重名,必须用this.修饰属性。

针对于构造器内的使用情况

        与方法内差不多,只不过不是“当前对象了”,而是“正在创建的对象”。(见简单理解)

调用构造器时(最重要)

        格式:我们可以在构造器中使用this(形参列表)调用当前类中指定的其他构造器。

        要求:必须声明在当前构造器的首行

        结论:this(形参列表)在构造器中最多声明一个。(只能声明在首行,所以一个构造器只能用一个this(形参列表))

        小注意:如果一个类中声明了n个构造器,那么最多有n-1个构造器可以声明有this(形参列表)的结构。(因为会造成循环,仔细想一想,都用了this调用构造器不就是互相调用了)

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

继承性的理解:

生活上的例子:家庭财产的继承,遗传父母颜值的继承。

代码上:

  • 自上而下:定义了一个类A,在定义另一个类B时,发现类B的功能与A相似,考虑类B继承类A。(相当于"先知")
  • 自下而上:定义了一个类B,C,D等,发现B,C,D有类似的属性和方法,则考虑将相同的属性和方法进行抽取,封装到类A中,让类B,C,D继承于类A。(相当于后知)

继承性的好处

  • 减少了代码的冗余,提高代码的复用性。(通俗讲就是写的代码变少了,不用你写太多重复的代码)
  • 更有利于功能的扩展。(子类继承父类,在不想改变父类的情况时,在子类里拓展想要的功能)
  • 让类与类之间产生了”is-a“的关系(就比如Student继承Person-->"学生"是"人")。
  • 一定不能为了继承而继承。(简单理解就是不要懒省事,为了少写代码。就比如:你有两个类“猫”和“狗”,为了懒,把狗当作猫的子类达到少写代码的目的)

继承的格式:(简单)

 继承中的基本概念:(拿上面图片举例)

 类A:父类;superClass;超类;基类。类B:子类;subClass;派生类。

有了继承性以后:

子类得到了什么?

(1)子类就获取到了父类中声明的所有属性和方法

(2)但是由于封装性,可能子类不能直接调用父类中的属性或方法;

(3)子类在继承父类以后,还可以扩展自己特有的功能(增加特有的属性或方法)。

默认的父类:

java中声明的类,如果没有显示的声明其父类时,则默认继承于java.lang.Object。任何一个类的都间接或直接地继承于Object类

补充说明

(1)java支持单继承父类,也就是一个类只能继承一个父类(不能继承多个父类),但是可以支持多层继承(它的父类可以继承另一个父类)也就是直接父类和间接父类。

(2)一个父类可以有多个子类,反之一个子类只能有一个父类。(单继承性)后续可以通过类实现接口的方式解决但继承问题。

方法的重写(overwrite/override)

为什么需要方法的重写?

        子类在继承父类以后获取的一些方法中可能不太适应子类,这时候需要对子类的该方法进行覆盖、覆写操作以让该方法适应子类。

        比如:大学生,高中生都继承于人,人的“睡觉方法”是打印睡了9个小时,这对于大学生和高中生而言当然不合理,所以这时候就使用方法的重写,大学生类中重写为12小时,高中生重写为6小时。

概念

        子类通过父类继承过来的方法进行的覆盖、覆写的操作,就称为方法的重写

“重写”遵循的规则

  • 重写的格式:权限修饰符 返回值类型 方法名(形参列表)[throws 异常类型]{//方法体}
  • 父类被重写的方法与子类重写的方法的方法名和形参列表必须相同
  • 子类重写方法的权限修饰符不小于父类被重写的方法的权限修饰符。
    • 特例:如果父类的被重写方法的权限修饰符为private,子类不能重写它。可以这样理解:private修饰的方法是私有化的,出本类就不能调用了(正常情况下)
  • 返回值类型要求
    • 父类被重写的方法的返回值是void,则子类重写的方法的返回值类型必须也是void
    • 父类被重写的方法的返回值类型是基本数据类型,子类重写的方法的返回值类型必须与其类型相同
    • 父类被重写的方法的返回值类型是引用数据类型(比如String类),则子类重写的方法的返回值类型可以和它相同或者是被重写的方法的返回值类型的子类。
  • 子类重写的方法抛出的异常类型可以与父类被重写的方法抛出的异常类型相同或者是父类被重写的方法抛出的异常类型的子类。

super关键字的使用

理解:为了区分父类和子类里相同名字的属性,或者想要使用子类重写父类方法之前的方法。

更简单理解:凡是在写代码时遇见了super,就代表"父类的"

使用场景:

在子类继承父类之后。

使用:super可以调属性,方法,构造器

  • 属性或方法(属性不会被覆盖,方法可能被覆盖)
    • 子类中调用父类中的方法和属性时(+this/不加都一样)都是从本类开始找该属性或方法,找不到的话找他父类中的该属性或方法,一直向上。(遵循就近原则)如果+super就直接从他的父类开始找。就比如有一个Person类和Student类(两者继承关系)如果两者都定义了睡觉的方法(人睡8小时,学生睡5小时),如果子类Stuedent调用sleep方法时,先是从本类开始找,找不到的话才去父类找。如果在调用方法的前面加上super就指直接从父类开始找
    • 一般情况下调用父类中的方法或属性时,可以忽略不用super,两者有的只是过程上的区别,结果都是一样的。(因为结果都会找到父类中的方法或属性)
    • 特殊情况,调用子类中重写的方法或重名的属性时,必须用super显示的调用父类中被重写的方法和重名的属性(就比如第一个例子,我本来想调用父类中的sleep,却因为没有加super导致调用的是子类中的sleep,这就是简单的特殊情况)
  • 调构造器
    • 1.子类继承父类时不能继承父类的构造器。只能通过“super(形参列表)”的方式调用父类中的构造器
    • 2.super(形参列表)必须声明在构造器首行。
    • 3.我们前面也记录过,this调用形参列表时也必须声明在构造器首行,所以“super(形参列表)”和“this(形参列表)”只能二选一。
    • 4.如果在子类构造器中既没有显示调用this(形参列表)也没有super(形参列表),此时子类构造器默认调用super(),即父类中的空参构造器。
    • 5.结合3和4,子类中任何一个构造器,要么会调用本类中重载的构造器,要么会调用父类中的构造器。
    • 6.之前我们知道如果一个类中声明在了有n个构造器,就最多有你n-1个用了this(形参列表),那么剩下的那个一定使用super(形参列表)。
    • 由前面的总结得:我们在通过子类的构造器创建对象时,一定会直接或者间接的调用到父类的构造器。正因为调用过父类的构造器,我们才会将父类中声明的属性或者方法加载到内存中,供子类对象使用。

提醒:

        自己做的小测试:定义Person类,里面没有写构造器,那么他就会默认有个空参构造器,定义子类学生Student,也没有构造器,默认有一个空参构造器,因为子类的构造器中没有显示this(形参列表)和super(形参列表),所以就会默认调用super()父类中的空参列表。但如果此时,父类中有已经重新定义的构造器(不为空参),那不就是没有空参列表,所以就没有super()父类中的空参列表,所以就会报错。

        所以要养成每定义一个类就随时构建空参构造器的习惯

子类对象的实例化(先了解,之后的高级会讲细节)

代码举例

class Creature{//生物类

//声明属性、方法、构造器

}
class Animal extends Creature{//动物类

//…………

}
class Dog extends Animal{//狗类

//…………

}
class DogTest{
     public static void main(String[ ] args){
         Dog dog=new Dog(  );
         dog.xxx(  );
         dog.xxx=……;
     }
}

理解

从结果上看:体现了类的继承性

        当我们创建子类对象后,子类对象就获取了其父类中声明的所有的属性和方法,在权限允许的情况下,可以直接调用他们。

从过程上来看:

  • 当我们通过子类的构造器创建对象时,子类的构造器一定会直接或间接地调用到其父类的构造器,而其父类的构造器同样会直接或间接地调用其其父类的父类的构造器……直到调用到Object类中的构造器为止。
  • 正因为我们调用过子类所有的父类的构造器,所以我们就会将父类中声明的属性、方法加载到内存中,供子类对象使用
  • 那么回归最初,创建子类对象的过程中,一定会调用父类中的构造器吗? YES!

​​​​​​​疑问?

创建子类对象时 ,内存中到底有多少个对象? 

就只有一个,即为当前new后面构造器对应的类的对象。(可以理解为,new一次才创建了一个对象)

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

理解:

理解为一个事物的多种形态

多态性的体现:

  • (狭义上的理解)子类对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
  • (广义上的理解)子类对象的多态性 方法的重写 (甚至有方法的重载)
  • 比如:Person p2=new Man( );这里的Man是Person的子类
  • 多态的应用:虚拟方法调用
    • 在多态的场景下调用方法时。
      • 编译时:认为方法是左边声明的父类的类型的方法。
      • 执行时:实际执行的是子类重写父类的方法
      • 简称为:编译看左边,运行看右边

多态使用的前提:

①要有类的继承关系。②要有方法的重写

多态的适应性:

只适用于方法不适用于属性。在满足前提,属性同名调用时,调用的是左边声明的类中的属性也就是父类(这里的Person父类里面id1001,子类1002,Person p2=new Man( );)

多态的好处:

1.极大的减少代码的冗余,不需要去定义多个重载的方法。举例:比如账户信用卡,和储蓄卡都继承于卡,两个子类里面都有方法的重写。

2.开闭原则ocp:对扩展开放,对修改关闭。在不修改原来代码的基础上引入新的功能!

3.多态无处不在,讲完 接口 和 抽象类以后,会有更好的理解!

多态的弊端:

在多态的场景下,我们创建了子类的对象也加载了子类特有的属性和方法,但是由于声明为父类的引用导致我们没有办法直接调用子类特有的属性和方法。

问题:Person p2=new Man( );内存里面加载了Man中特有的属性和方法吗? 加载了!但是能直接调用M他特有的吗? 不能!

解决方法:多态的逆过程-->向下转换

向下转型和向上转型(多态)(可以用自动类型提升与强制类型转换的理解来理解它)

理解

多态对应的就是向上转型,向下转型必须在(多态)对象名前加上“(子类名)”也就是强转符。

向下转型时也可能造成类型转换异常(ClassCastException),这里的Woman本来是Person,被强转man类型使用man中的方法,编译器不会报错,运行时才会报错。语法上没有问题。

instance的使用

  • 所以一般建议在向下转型之前使用instanceof进行判断避免出现类型转换异常。
  • 格式: a instanceof A:判断对象a是否是类A的实例。返回值类型时boolean类型。
  • 如果a instanceof A返回值为true,那么a instanceof superA返回值也是ture,其中A是superA的子类。(可以这样理解,a是woman,A是woman,superA是人)

Object类的使用

说明:

  • 这里说的类是java.lang.Object;
  • 任何一个Java类(除了Object类)都直接或者间接的继承于Object类
  • Object类称为java类的根父类
  • Object类中声明的结构(属性、方法、构造器等)都有通用性
    • Object类中没有声明属性。
    • 这个类就提供了一个空参的构造器
    • Object类中的方法是重点

常用方法

重点方法:equals( ) \ toString( )

equals():
  • 适用性:任何引用数据类型都可以使用
  • 子类使用说明:
    • 自定义类在没有重写Object中的equals()方法的情况下,调用的就是Object里面的equals()方法,比较的是存的值(也就是跟“==”一样的效果)
    • 对于像String、File、Date和包装类等,它们都重写了Object类中的equals()方法,用于比较两个对象的实体内容是否相等。
    • 所以自定义类中一般直接对equals()方法重写,这个可以自己写也可以IDEA自动实现
      • 在重写的时候,一般只比较属性是否相同。
  • 高频面试题:equals和==有什么区别
    • ==:运算符
      • ①使用范围:基本数据类型,引用数据类型
      • 基本数据类型:判断数据值是否相等
      • 引用数据类型:比较两个引用变量地址值是否相等。
    • equals:方法
      • 上面有!!!!(把上面的答下来)
toString( ):
  • 返回值是String类型
  • Object类中的定义(就只是打印地址而已)

  • 平常使用场景:System.out.println()打印对象引用变量时,其实就调用了toString()
  • 使用说明:
    • 自定义类:再没重写它的情况下默认返回当前对象所属的类和地址值
    • String、File、Date或包装类等Object的子类都重写了这个方法,调用时返回试题内容
  • 开发时:习惯上,我们自定义类时也希望用toString()来显示对象内容的实体内容,而非地址值,所以就需要重写这个方法。
    • 手动生成或者IEAD自动生成

了解方法:clone( ) \ finalize( )

  • finalize( ) 可能会出现内部循环引用
  • clone( ) 复制内容给一个新的对象

        不过多介绍,基本不用

目前不需要关注的:(涉及集合框架,线程)

getClass( ) \ hasCode( ) \ notify( ) \notifyAll( ) \ wait( ) \wait(xx) \ wait(xx,yy)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈奈朵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值