Java面向对象编程的相关

1.面向对象之继承

1.1什么继承?

继承是面向对象三大特征之一,封装居首位,封装之后形成了独立体,独立体 A和独立体B 之间可能存在继承关系。其实程序中的继承灵感来自于现实生活,在现实生活中继承处处可见,例如,儿子继承了父亲的财产,儿子不需要努力就很有钱。生活中的继承:

在这里插入图片描述
继承时子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性,或子类从父类继承方法,使得子类具有与父类相同的行为。

(子类会继承父类除构造方法外的所有 注:只是不能直接访问private关键字修饰的方法或者实例变量等)

1.2为什么要使用继承机制?

在不同的类中也可能会有共同的特征和动作,可以把这些共同的
特征和动作放在一个类中,让其它类共享。因此可以定义一个通用类,然后将其扩展为其它多个特定类,这些特定类继承通用类中的特征和动作。继承是 Java 中实现软件重用的重要手段,避免重复,易于维护。

1.3如何继承

语法格式:
class 类名 extends 父类名{
类体;
}

1.4继承的相关特性
① B类继承A类,则称A类为超类(superclass)、父类、基类,B类则称为子类(subclass)、派生类、扩展类。
② java 中的继承只支持单继承,不支持多继承,C++中支持多继承,这也是 java 体现简单性的一点,换句话说,java 中不允许这样写代码:class B extends A,C{ }。
③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,例如:class Cextends B,class B extends A,也就是说,C 直接继承 B,其实 C 还间接继承 A。
④ java 中规定,子类继承父类,除构造方法和被 private 修饰的数据不能继承外,剩下都可以继承。
⑤ java 中的类没有显示的继承任何类,则默认继承 Object类,Object类是 java 语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有 Object类型中所有的特征。
⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它们之间的耦合度非常高,Account 类发生改变之后会马上影响到 CreditAccount 类。

1.5继承后代码的执行顺序

public class Test {
public static void main(String[] args) {
	new H2();
	}
}
class H1{
{
	System.out.println("父类代码块");
	}
public H1(){
	System.out.println("父类构造");
}
static{
	System.out.println("父类静态代码块");
	}
}
class H2 extends H1{
static{
	System.out.println("子类静态代码块");
	}
{
	System.out.println("子类代码块");
}
public H2(){
	System.out.println("子类构造");
	}
}

子类 H2 继承 H1,new H2()执行的时候,会先进行类加载,先加载 H2 的父类 H1,所以 H1 当中的静态代码块先执行,然后再执行 H2 中的静态代码块,静态代码块执行结束之后,不会马上执行构造方法,代码块会先执行,Java 中有一条规则:子类构造方法执行前先执行父类的构造方法,所以父类 H1 的代码块先执行,再执行 H1 的构造方法,然后再执行 H2 的代码块,最后执行 H2 的构造方法。

实例代码块

public class Person {
        private String name;
        private int age;
        //实例代码块
        {
            System.out.println("实例代码块")
        }
}

静态代码块

public class Person {
        private String name;
        private int age;
        //实例代码块
     static{
            System.out.println("静态代码块")
        }
}

静态代码块:
它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量,即static修饰的数据成员。
实例代码块:new对象的时候会先执行实例代码块再调用构造方法

执行顺序
父类静态代码块——>子类静态代码块——>父类实例代码块——>父类构造方法——>子类实例代码块——>子类构造方法

2.方法的覆盖和多态

2.1什么是方法的覆盖

方法的覆盖:就是重写父类中的方法
注:除了方法体改变外其余的均不能改变

2.2什么时候进行方法的覆盖

当父类中的方法不能满足子类要求的时候进行方法的覆盖

2.3方法覆盖的条件及注意事项

① 方法覆盖发生在具有继承关系的父子类之间,这是首要条件;
② 覆盖之后的方法与原方法具有相同的返回值类型、相同的方法名、相同的形式参数列表;
注意事项:
① 由于覆盖之后的方法与原方法一模一样,建议在开发的时候采用复制粘贴的方式,不建议手写,因为手写的时候非常容易出错,比如在 Object 类当中有 toString()方法,该方法中的 S 是大写的,在手写的时候很容易写成小写 tostring(),这个时候你会认为toString()方法已经被覆盖了,但由于方法名不一致,导致最终没有覆盖,这样就尴尬了;
② 私有的方法不能被直接访问,所以不能被覆盖;
③ 构造方法不能被继承,所以也不能被覆盖;
④ 覆盖之后的方法不能比原方法拥有更低的访问权限,可以更高;
⑤ 覆盖之后的方法不能比原方法抛出更多的异常,可以相同或更少;
⑥ 方法覆盖只是和方法有关,和属性无关;
⑦ 静态方法不存在覆盖(不是静态方法不能覆盖,是静态方法覆盖意义不)

2.4多态
多态就是“同一个行为”发生在“不同的对象上”会产生不同的效果。

在 java 中允许这样的两种语法出现,一种是向上转(Upcasting),一种是向下转型(Downcasting),向上转型是指子类型转换为父类型,又被称为自动类型转换,向下转型是指父类型转换为子类型,又被称为强制类型转换。

在这里插入图片描述
注意:无论是向上转型还是向下转型,两种类型之间必须要有继承关系

向上转型:
子类访问父类中的方法(也可以说是自己的方法因为已经继承过来了,就像富二代继承了他父亲的遗产,那么这个遗产就是这个富二代的了,这里还有个概念就是动态绑定)

动态绑定发生在:
父类的引用指向子类的对象,然后使用父类的引用访问子类重写父类方法的时候;

public class Animal{
    public String name;
    public  Animal(){}
    public Animal(String name){
        this.name=name;
    }
    public void move(){
        System.out.println("动物在移动!");
    }
}
class Cat extends Animal{
    public Cat(String name){
        super(name);
    }
    public void move(){
        System.out.println(this.name+"在走猫步!");
    }

}
class Test8{
    public static void main(String[] args) {
        Animal a=new Cat("咪咪");
        a.move();
    }
}

在编译的时候代码 a.move();因为a呢Animal类型,所以编译器会查看Animal中是否有move方法,而在运行过程中因为子类重写了move方法,这个过程就发生了动态绑定,将之前的Animal中的move方法换成了Cat类中重写过得move方法。

向下转型
当父类的引用要访问子类中特有的方法的时候就需要向下转型
这里就有一个instenceof

业务需求例如在传参的时候参数是一个Animal,当传入一个Bird时候,却要调用Cat中的catchMouth的方法是就会发生错误。将Bird转换为Cat的时候会发生ClassCastException(类型转换异常)
所以instanceof就尤为重要了,它可以判断这个对象是不是你要的对象,如果是,在转换,进而调用子类中的方法。
例如:

public class Animal{
    public String name;
    public  Animal(){}
    public Animal(String name){
        this.name=name;
    }
    public void move(){
        System.out.println("动物在移动!");
    }
}
class Bird extends Animal{
    public Bird(String name){
        super(name);
    }

    public void fly(){
        System.out.println("鸟儿在飞翔");
    }
}
class Cat extends Animal{
    public Cat(String name){
        super(name);
    }
    public void move(){
        System.out.println(this.name+"在走猫步!");
    }
    public void catchMouth(){
        System.out.println("猫在抓老鼠");
    }
}
class Test8{
    public static void act(Animal a){
        if(a instanceof Cat){
            Cat cat=(Cat)a;
            cat.catchMouth();
        }
        if(a instanceof Bird){
            Bird b=(Bird)a;
            b.fly();
        }
    }
    public static void main(String[] args) {
        Animal a=new Cat("咪咪");
        act(a);
    }
}

3.super
3.1super是什么?
严格来说,super 其实并不是一个引用,它只是一个关键字,super代表了当前对象中从父类继承过来的那部分特征。this 指向一个独立的对象,super 并不是指向某个“独立”的对象,假设张大明是父亲,张小明是儿子,有这样一句话:大家都说张小明的眼睛、鼻子和父亲的很像。那么也就是说儿子继承了父亲的眼睛和鼻子特征,那么眼睛和鼻子肯定最终还是长在儿子的身上。假设this指向张小明,那么 super 就代表张小明身上的眼睛和鼻子。换句话说 super 其实是 this 的一部分。如下图所示:张大明和张小明其实是两个独立的对象,两个对象内存方面没有联系,super 只是代表张小明对象身上的眼睛和鼻子,因为这个是从父类中继承过来的,在内存方面使用了super 关键字进行了标记,对于下图来说“this.眼睛”和“super.眼睛”都是访问的同一块内存空间
在这里插入图片描述
super 可以使用在实例方法当中
super 不能使用在静态方法当中,因为super 代表了当前对象上的父类型特征
super 也有这种用法:“super(实际参数列表);”,这种用法是通过当前的构造方法调用父类的构造方法。
注: super()只能出现在构造方法的第一行人,如果没有写会默认调用父类的无参的构造方法
super.也可以访问父类中的实例以及方法(非私有方法)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值