欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java面向对象编程的相关

程序员文章站 2022-05-25 20:41:51
...

1.面向对象之继承

1.1什么继承?

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

Java面向对象编程的相关
继承时子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性,或子类从父类继承方法,使得子类具有与父类相同的行为。

(子类会继承父类除构造方法外的所有 注:只是不能直接访问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),向上转型是指子类型转换为父类型,又被称为自动类型转换,向下转型是指父类型转换为子类型,又被称为强制类型转换。

Java面向对象编程的相关
注意:无论是向上转型还是向下转型,两种类型之间必须要有继承关系

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

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

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.眼睛”都是访问的同一块内存空间
Java面向对象编程的相关
super 可以使用在实例方法当中
super 不能使用在静态方法当中,因为super 代表了当前对象上的父类型特征
super 也有这种用法:“super(实际参数列表);”,这种用法是通过当前的构造方法调用父类的构造方法。
注: super()只能出现在构造方法的第一行人,如果没有写会默认调用父类的无参的构造方法
super.也可以访问父类中的实例以及方法(非私有方法)

相关标签: java 多态