《java面向对象(2)》<不含基本语法>

提示:本笔记基于黑马程序员java教程整理,仅供参考

文章目录

前言

1.继承

2.多态

2.1对象多态

2.2行为对象

2.3多态的问题


前言

本文纯笔记,主要记录了java面向对象的高级方法继承与多态


1.继承

        在创建多个对象类时,它们可能会有很多相似的属性,如姓名,身高,体重等,就会造成代码的重复,所以我们可以采用继承的思想,将它们相同的属性放在同一个父类中,而其它作为子类的都可以继承父类的属性,子类本身就只用定义自身独特的属性即可,减少了代码的重复书写。

extends

可以利用extends建立父子关系

public class A extends B

A为子类,B为父类,子类可以继承父类的非私有成员(创建两个java类分开放,不是放在同一个类中哦!)

例:

//父类
public class People {
    private String name; //私有成员,不能继承
    int age;
    String sex;
//自行填写构造方法
//自行填写get  set方法
}


//子类
public class Student extends People{  //可以继承父类的age,sex属性
    private String school;
//......
}

这样可以少写很多重复的get,set方法

        在继承过程中,我们可能会遇到父类中存在private,protect等权限修饰符修饰成员变量,以下是相关介绍

private:表示该成员只能在本类中访问,无法被子类继承

protect:表示该成员变量可以由本类,本包中的类访问,可以被子类继承,无法被其他包访问

特点:(1)可以嵌套继承,即子类可以有且仅能有一个父类,父类还可以有一个父类,子类可以访问这两者的公开的成员变量

          (2)方法也可以继承,但是当子类和父类有一个方法名相同但内容不同的方法时,是调用子类中的方法,叫做方法重写。

        如:父类——鸟,子类——麻雀,父类有一个方法cry表示鸟叫,但麻雀可能不是这么叫的,于是需要在子类中重新定义一个cry方法,表示麻雀叫声。

//父类
public class Bird {
    public void cry()
    {
        System.out.println("鸟叫");
    }
}

//子类
public class Maque extends Bird {
    @Override//加上这个标签可以强制让你重写的内容与父类保持一致,不会出错,如果不加标签,重写的内容不一致,test会调用父类的方法
    public  void cry(){
        System.out.println("吱吱吱");
    }
}

public class Test {
    public static void main(String[] args) {
        Maque maque=new Maque();
        maque.cry();

    }
}

toString方法

//父类
public class Bird {
    private String name;
    int age;
    String sex;
}

//子类
public class Maque extends Bird {
    String name;
    public Maque(String name,int age,String sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    //自行构造set,get方法

    @Override
    public String toString() {//重写toString方法
        return name+age+sex;
    }
}

public class Test {
    public static void main(String[] args) {
        Maque maque=new Maque("小青",2,"雌");
        System.out.println(maque);
    }
}

当我们在test文件中创建完对象后,我们希望能通过直接输出得到其信息,此时System.out.println(maque);是默认调用toSring方法输出,toString方法是系统本身有的方法,但是我们此时输出得到的是maque的地址而不是数据,因此我们需要在子类中重写方法来输出数据。

构造器

当test中调用子类的构造器时,会先调用其父类的构造器,然后再调用子类的构造器,顺序很重要

super

实际上,在子类中会有一个super()方法,只是没有写出来,它用来查找父类中的构造器,这也是为什么当test中调用子类的构造器时,会先调用其父类的构造器,然后再调用子类的构造器的原因。

//父类
public class Bird {
    private String name;
    private int age;
    public Bird(){}
    public Bird(String name,int age)
    {
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


//子类
public class Maque extends Bird {
    String sex;
    public Maque(String name,int age,String sex){
        super(name,age);   //用来找父类的构造器为name和age赋值
        this.sex=sex;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}


public class Test {
    public static void main(String[] args) {
        Maque maque=new Maque("小青",2,"雌");
        System.out.println(maque.getName()+" "+maque.getAge()+" "+maque.getSex());
    }
}

解释:当我们给父类中的成员变量私有时,我们在测试类(test)中调用子类的有参构造器为对象赋值,此时我们会发现,当我们输出时age和name的数据为空,那是因为这两个成员变量在父类中私有,无法直接赋值,于是我们可以构造super(),在其中加入父类中私有的成员变量(这样可以利用super来找父类中相关的有参构造器),然后在父类中创建一个包含这些成员变量的有参构造器为age和name赋值。

this调用兄弟构造器

在对象类中我们创建了一个有参构造器为对象赋值,比如

public class Bird {
    private String name;
    private int age;
    private String sex;
    public Bird(){}
    public Bird(String name,int age,String sex)
    {
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    //自行构造无参构造器和get/set方法
}

当我们需要重新构造一些对象,但是它们的性别固定是雌性,我们可能需要重新写一个有参构造器,然后类比上一个有参构造器,将this.sex=sex改为this.sex="雌“。但是这样就会造成代码重复度太高,所有我们会采用this调用兄弟构造器的方法减少代码重复度。

public Bird(String name,int age){
    this(name,age,“雌”)
}

注意:super()和this()必须写在构造器的第一行,并且不能同时存在

2.多态

2.1对象多态

大范围到小范围定义对象

2.2行为对象

定义的对象,它们的行为不同

public class DuoTai {
    public static void main(String[] args){
        People a=new Teacher();   //People的范围更大,可以这样创建对象(对象多态)
        a.learn();                //编译看左,运行看右
        System.out.println(a.name)//编译看左,运行也看左
        People b=new Student();
        b.learn();                //学生和老师的学习行为不同(行为多态)
    }
}

public class People {
    private String name;
    private int age;
    private String sex;
    public People(){}//无参构造
    public void learn(){
        System.out.println("人都学习");
    }
}

public class Teacher extends People {
    private String skill;
    public  Teacher(){}

    @Override
    public void learn() {
        System.out.println("老师在教课中学习");
    }
}

public class Student extends People{
    public Student(){}

    @Override
    public void learn() {
        System.out.println("学生在课堂中学习");
    }
}

 People a=new Teacher(); 如果用对象多态的方法定义对象,那么在调用learn方法时a.learn(),编译看左边,运行看右边,即先在People类中查找是否存在learn()方法,存在则编译,不存在则报错,而运行时还是运行Teacher中的重写的learn方法

如果用对象多态的方法定义对象,对于成员变量而言,System.out.println(a.name)编译看左,运行也看左,即运行People中的定义name结果(未写入代码)

多态优势:便于软件解耦合, People a=new Teacher(); a.learn()此处表示people和teacher是解耦合的,当Teacher类我们需要更换时,可以随时将其更换成其它类,进而改变所进行的业务a.learn(),这样更便于扩展和维护

例如:A公司可以与B,C,D公司合作,B,C,D三家公司的业务名称一致,但是内容有所不同,A首先与B合作,如果B不行,可以直接更换合作公司,并且不需要重新告诉要做什么业务,可以直接拿上一个公司的模板来做,即不需要重新编写方法

public class DuoTai {
    public static void main(String[] args){
        People a=new Teacher();  
        test(a);
        People b=new Student();  
        test(b);           
    }
}

public class People {
    public People(){}//无参构造
    public void learn(){
        System.out.println("人都学习");
    }
}

public class Teacher extends People {
    public  Teacher(){}

    @Override
    public void learn() {
        System.out.println("老师在教课中学习");
    }
}

public class Student extends People{
    public Student(){}

    @Override
    public void learn() {
        System.out.println("学生在课堂中学习");
    }
}

public void test(People p){
    p.learn();
}

        通过上述代码,我们发现, 主函数调用test方法,而test接收的是People p,这就是多态的运用,好处是当我们有多个不同的对象调用同一个方法时,不需要将People p改成对应的Teacher p或Student p,如果我们采用常规创建对象的方法Teacher a=new Teacher();Student b=new Student();那么在其调用test方法时,我们需要将括号中的参数修改2次,或者创建两个test方法,这样显然会导致代码重复度过高,造成代码冗余,所以在编写代码时,我们常常会将多态方法设为编写代码的必然要求

2.3多态的问题

        在多态状态下,不能调用子类独有的功能,因为对于方法,编译看左边,运行看右边,如果父类中没有这个方法,那么当我们采用a.eat()等方式调用子类独有功能时就会报错。

        解决方法:强制类型转换

        如:People a=new Teacher();我们可以添加代码Teacher  t=(Teacher) a,这样就表示强制转换,此时t就代表将a转换成了Teacher对象,可以用t调用Teacher的独有功能。

public class Fangfa {
    public void test(People p){
        if(p instanceof Teacher){            //判断p是否是Teacher对象
            Teacher t=(Teacher)p;
            t.teach();
        }
        else if(p instanceof Student){       //......
            Student s=(Student)p;
            s.study();
        }
    }
}

如果在Fangfa中调用对象的独有方法,我们需要先判断是哪一个对象,然后再对其进行强制转换,然后再调用方法。

你可能感兴趣的:(java,开发语言)