Java学习7(this,继承,方法重写,多态)

Java学习7

心情有问题,兴致不高

this

1.this 是一个关键字,全部小写
2.this是一个变量,是一个引用
一个对象一个this,this保存当前对象的内存地址,指向自身
所以,严格意义上来说,this代表的就是“当前对象”
this存储在堆内存中,存储在对象的内部
3.this只能使用在实例方法中,谁调用这个实例方法,this就是谁,所以this代表的是:当前对象
4. this. 大部分情况下可以省略,省略了还是默认访问当前对象
5. this 代表当前对象,而静态方法的调用不需要对象,矛盾了,所以在静态方法中无法使用this
6. 在实例方法和构造方法中,为了区别实例变量和局部变量,这种情况下,this.不能省略
7. this除了用在实例方法中,还可以用在构造方法中
新语法:通过当前的构造方法1去调用本类另一个的构造方法2,可以做到代码复用,
可以使用以下语法格式:
this(实际参数列表);
对于this()的调用只能使用一次,并且只能出现在构造方法的第一行
在这里插入图片描述

如果方法中直接访问了实例变量,该方法必须是实例方法

总结

到目前为止一个类中可以出现的:

类体{
    实例变量;
    实例方法;
    
    静态变量;
    静态方法;
    
    构造方法;
    
    静态代码块;
    实例语句块;
    
    方法(){
        局部变量;
    }       
}

类加载机制是这样的:在程序执行之前,凡是需要加载的类全部加载到JVM当中,先完成加载才会执行main方法
所有的实例相关的都是先创建对象,通过“引用.”来访问
所有的静态相关的都是直接采用“类名.”来访问

只要负责调用的方法a和被调用的方法b在同一个类当中:
this. 可以省略
类名. 可以省略

当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址
当该类创建对象后,类中的实例方法才分配入口地址,
从而实例方法可以被类创建的任何对象调用执行。

类方法在该类被加载到内存时,就分配了相应的入口地址。
从而类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用。
类方法的入口地址直到程序退出时才被取消。

当我们创建第一个对象时,类中的实例方法就分配了入口地址,当再创建对象时,不再分配入口地址。
也就是说,方法的入口地址被所有的对象共享,当所有的对象都不存在时,方法的入口地址才被取消。

在Java语言中,类中的类方法不可以操作实例变量,也不可以调用实例方法,
这是因为在类创建对象之前,实例成员变量还没有分配内存,而且实例方法也没有入口地址。


继承(extends)

继承的作用:
基本作用:子类继承父类,代码可以得到复用
主要(重要)作用:因为有了继承关系,才有了后期的方法覆盖和多态机制

class A{}
class B extends A{}

继承的相关特性:
1.B类继承A类,则A类为超类(superclass)、父类、基类,
B类则成为子类(subclass)、派生类、扩展类。
2. java中只支持单继承,不允许多继承,但有的时候会产生间接继承的效果
即class C extends A,B 不允许,但是允许class C extends B,class B extends A
3. java中规定,子类继承父类,除构造方法不能继承之外,剩下的都可以继承,但是私有的属性无法在子类中直接访问(父类中private修饰的不能在子类中直接访问,可以通过间接的手段来访问)
4. java中的类,没有显示的继承任何类,则默认继承Object类,Object类是java语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有Object中所有的特征
5. 继承存在一些缺点,即父类和子类的耦合度非常高,父类修改会使子类受到牵连

什么时候使用继承?
凡是采用“is a”能描述的,都可以继承
例如: Dog is a Animal; CreditAccount is a Account

Object

java为什么比较好学?
是因为java内置了一套庞大的类库,实现了很多基本的功能,程序员不需要从0开始写代码,程序员可以基于这套庞大的类库进行“二次开发”

System.out.println(“Hello World”);
System是一个类,直接使用类名System.out,out后面没有括号,说明out是一个静态变量。
Syetem.out返回一个对象,然后采用“对象.”的方式访问println()方法;

当源码当中一个方法以“;”结尾,并且修饰符列表中有“native”关键字,表示底层调用C++写的dll程序(dll动态链接库文件)

大部分Object中的方法看不懂,其中有一个叫做toString,是把对象转化成字符串,
经测试发现System.out.println(引用),当直接输出引用的时候,println()方法会先自动调用“引用.toString”,然后输出toString()方法的执行结果,输出结果为:

  • 类名@16进制的地址

这个地址可以看做是对象在堆内存当中的内存地址,实际上是内存地址经过“哈希算法”得出的十六进制结果

方法重写、覆盖(Override)

也可以叫overwrite
子类继承父类中,有一些“行为”可能不需要改进,有一些“行为”可能面临需要改进,因为父类中继承过来的方法已经不能满足子类的业务需求

回顾方法重载overload:
当在一个类中,如果功能相似的话,建议将名字定义为一样,这样代码美观,并且方便编程

进行方法重写时,最好将父类的方法原封不动的复制过来(不建议手动编写)
方法覆盖后,子类对象调用该方法的时候, 一定执行覆盖之后的方法

在代码级别上怎么构成方法覆盖?
条件一:两个类必须要有继承关系
条件二:重写之后的方法必须和之前的方法具有相同的方法名、返回值类型、参数列表
条件三:访问权限不能更低,可以更高
protected表示受保护的,没有public开放,所以用protected去修饰的方法覆盖public修饰的方法时,会报错
条件四:重写之后的方法不能比之前的方法抛出更多的异常,可以更少

条件五:对于返回值类型是基本数据类型来说,必须一致;
对于返回值类型引用数据类型,子类中重写之后的返回值类型变小,编译可以通过,但意义不大;反之不行(没有用,一般方法重写都是复制粘贴)

注意1:方法覆盖只是针对于方法,和属性无关
注意2:私有方法无法覆盖
注意3:构造方法不能被继承,所以构造方法也不能够被覆盖
注意4:方法覆盖只针对于“实例方法”,“静态方法覆盖”没有意义(这是因为方法覆盖通常是和多态联合起来)

关于Object类中toString()方法的覆盖?
toString()方法存在的作用就是:将java对象转换成字符串的形式
大多数的java类中的toString()方法都是需要覆盖的,因为Object类中提供的此方法输出的是一java个对象的内存地址。至于怎么覆盖,格式可以自己定义。

多态

父类型的引用指向子类型的对象,即
Animal a2 = new Cat();
a2是父类型的引用,new Cat() 是一个子类型的对象

java中允许向上转型,也允许向下转型,但是两种类型之间必须有继承关系。
向上转型:子类转换成父类(自动类型转换) (upcasting)
Animal a5 = new Cat(); //子类猫转换成父类动物
向下转型:父类转换成子类(强制类型转换,需要加强制类型转换符) (downcasting)
Cat x = (Cat)a5; //父类动物强制转换成子类猫

向下转型有风险吗?
容易出现ClassCastException(类型转换异常)
什么时候使用向下转型?
不要随便做强制类型转换,如果你想使用的方法是子类中特有的方法,就必须进行向下转型

a5.move(); //调用的是子类中的move()方法,这就是多态

什么是多态?
多种形态,多种状态
分析上一条代码的运行原理:
对于编译器来说,编译器只知道a2的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找move()方法,找到了,绑定上move()方法,编译通过,静态绑定成功(编译阶段属于静态绑定)
在运行阶段的时候,实际上在堆内存中创建java对象是Cat对象,所以move的时候,真正参与move的对象是一只猫,所以运行阶段会动态执行Cat对象的move()方法,这个过程属于运行阶段绑定(运行阶段绑定属于动态绑定)

多态指的是:
父类型引用指向子类型对象,包括编译阶段和运行阶段
编译阶段:绑定父类的方法
运行阶段:动态绑定子类对象的方法

当要将鸟类型的变量a1强制转换成猫类型的时,虽然编译器能通过,但运行时会报错,会出现:
java.lang.ClassCastException :类型转换异常
(和 java.lang.NullPointException :空指针异常 一样重要)

怎么避免ClassCastException异常的发生?

instanceof
第一:instanceof 可以在运行阶段动态判断引用指向的对象的类型
第二: instanceof 语法:
引用 instanceof 类型
第三: instanceof 运算符的运行结果只能是: ture/false
假设(c instanceof Cat)为true表示:
c引用指向的堆内存中的java对象是一个Cat
假设(c instanceof Cat)为false表示:
c引用指向的堆内存中的java对象不是一个Cat

任何时候,任何地点,对类型进行向下转型时,一定要使用instanceof 运算符进行判断,这样可以很好的避免:ClassCastException

多态在开发中的作用

非常重要:
面向父类型编程,面向更加抽象进行编程,不建议面向具体编程,因为面向具体编程会让软件的扩展性很差。
软件在扩展过程中,修改的越少越好,修改的越多,系统的稳定性越差,未知的风险就越多
软件开发原则,其中有一条最基本的原则:OCP(开闭原则)
即对扩展开放(可以额外添加),对修改关闭;在软件扩展过程中,修改的越少越好

总结:
降低程序的耦合度,提高程序的扩展力

public class Master{
    public void feed(Dog d){}
    public void feed(Cat c){}
}
以上代码中,MasterDog以及Cat的关系很紧密(耦合度高),导致扩展力很差
public class Master{
    public void feed(Pet pet){}
}

以上的代码表示,Master和Dog以及Cat的关系就脱离了,Master关注的是Pet类,这样Master和Dog和Cat的耦合度就降低了,提高了软件的扩展性

如果没有多态机制,只有方法覆盖机制,那么方法覆盖可有可无,如果父类方法无法满足子类业务需求的时候,子类完全可以定义一个全新的方法

静态方法存在方法覆盖吗?
方法覆盖和多态不能分开,多态和对象有关系,而静态方法的执行不需要对象,所以一般而言,我们会说静态方法“不存在”方法覆盖,不探讨静态方法的覆盖

私有方法不能覆盖

对于方法覆盖的返回值类型:
对于返回值类型是基本数据类型来说,必须一致;
对于返回值类型引用数据类型,子类中重写之后的返回值类型变小,编译可以通过,但意义不大;反之不行(没有用,一般方法重写都是复制粘贴)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值