java学习笔记: 基础知识: day07: 继承、多态

====

day07
java学习笔记: 基础知识: day07: 继承、多态

一、继承inheritance
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,多个类继承这个类就行了。
继承:子类继承父类,子类就可以拥有父类的成员变量和成员方法。构造方法不能继承。
1.格式:public class 子类名 extends 父类{}
注意:构造方法不能继承。

2.继承的好处
A.提高了代码的复用性。
B.提高了代码的可维护性。
C.让类与类之间产生了关系,是多态的前提。

3.继承的弊端:让类与类之间产生了关系。也就让类的耦合性增强了。

4.开发的原则:高内聚,低耦合。
内聚:就是自己完成某件事的能力。
耦合:类与类的关系。
高内聚:一个类或一个方法只完成一个功能,并且不依赖于其它的类或方法。就是自己完成某件事的能力。
低耦合:修改完一个方法后,其它的方法基本不需要动代码,维护起来很方便。类与类的关系尽量减少。

5.java中类的继承特点:
(1)java中类只支持单继承,不支持多继承。
(2)支持多层继承。

6.Java继承中成员变量的特点
(1)成员变量名称不一样,使用的时候非常简单。
(2)成员变量名称相同时:在子类方法中访问变量采取就近原则。
(3)成员方法的特点:就近原则。
子类方法和父类声明一致时,先找子类方法,再找父类方法。

7.就近原则:成员变量名称相同时,在子类方法中访问变量,
  (1)在方法的局部范围找,如果有就使用。
  (2)在子类的成员范围找,如果有就使用。
  (3)在父类的成员范围找,如果有就使用。
  (4)如果还找不到,就报错。


二、super关键字以及继承中的方法覆盖override
1.this和super
  (1)this代表本类对象的引用。super代表父类的存储空间,也可以理解为代表父类对象的引用。
  (2)用法:
    A.访问成员变量:this.成员变量。super.成员变量
    B.访问构造方法:this(...)  调用本类的构造方法。super(...)  调用父类的构造方法
    C.访问成员方法:this.成员方法。super.成员方法

2.java继承中构造方法的访问特点
  (1)子类构造方法执行前,都会先执行父类的无参构造方法。
为什么呢?
简而言之,
因为子类会继承父类的成员方法,父类必须先初始化好了,子类才能继承。
展开来说,
因为子类继承父类,会继承父类的非私有成员。
而子类在初始化的时候,可能会使用父类的数据。如果父类数据没有初始化,子类就不能使用这些数据,即子类无法继承。
所以,在子类初始化以前,一定要先完成父类数据的初始化,即先调用父类的构造方法。

  (2)在子类的构造方法中,默认第一行有一条语句super(),即必须在构造方法的第一行。
如果子类没有写super(),系统会默认加上一条。如果我们写了构造方法,系统就不会给我们提供构造方法了。
问题:如果父类中没有无参构造方法,怎么办呢?
回答:A.在父类中添加一个无参构造方法。(推荐)B.可以通过super去访问父类的带参构造方法。
我们在写构造方法的时候,最好写上无参构造方法和全参构造方法。

3.java继承中成员方法的访问特点:也是就近原则
  (1)子类中方法和父类中方法的声明相同时(这叫方法的覆盖override),调用的是子类中的方法。
  (2)就近原则:通过子类对象调用方法时,A.在子类中找,有就使用。B.在父类中找,有就使用。C.如果没有就报错。
  (3)Object是所有类的根类。所有类都直接或者间接地继承Object类。

4.重载overload:在同一个类中出现的方法名相同的情况
  覆盖override:子类中出现了和父类中一模一样的方法声明的情况
方法覆盖override的应用:当子类需要父类的功能,而功能主体子类又有自己的特有内容的时候,就考虑使用方法覆盖。这样既保证了父类的功能,还添加了子类特有的功能。

5.方法覆盖override的注意事项
  (1)@override注解  标记一个方法,表名该方法是覆盖父类的方法
  (2)父类私有private的方法不能被覆盖
  (3)子类覆盖父类方法时,访问权限不能更低。
子类覆盖父类时,建议访问权限一模一样。

6.访问权限
private<默认修饰符friendly<protected<public
public:本类、别的包的类、本包的类
protected:本包中的类、其他包子类中
friendly:只能在本包中的类
private:只能在本类中

7.分析案例的时候是从子类分析到父类,写代码的时候是从父类写到子类。


三、多态polymorphism
多态,即事物的多种形态。
同一个对象,在不同时刻体现出来的不同状态。
举例:猫:是猫,是动物。水:液体、固体、气体。

1.java多态的前提
  (1)有继承关系
  (2)有方法覆盖override(不是必须的)
  (3)有父类引用指向子类对象  Fu f=new Zi();
Dog dog = new Dog();//我说这只狗是狗
Animal ani = new Dog();//我说这只狗是只小动物

2.多态中成员访问的特点
  (1)成员变量:编译看左边,运行看左边
  (2)成员方法:编译看左边,运行看右边

3.为什么成员变量和成员方法的访问不一样呢?
因为成员方法有覆盖override,而成员变量没有覆盖override。

4.多态的缺点:父类不能访问子类特有的方法。解决办法:向下转型。
多态的优点:提高了程序的扩展性。
具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
fun(Animal a){...}
Cat c = new Cat();
调用:.fun(c);//等价于Animal a=new Cat();

5.多态中的转型问题
  (1)A.向上转型:从子到父,父类引用指向子类对象。Animal ani=new Dog();
     B.向下转型:从父到子,父类引用转为子类对象。
     注:强制转换可能会发生ClassCastException类型转换异常
  (2)在做向下转型之前,要先做判断
if(ani instanceof Dog){
  Dog dog=(Dog)ani;
  dog.lookDoor();
}
instanceof左边的对象应该是右边类的父类或同类对象。

6.多态转型的内存图解
图片:见“多态转型问题内存图解.bmp”

代码:
//file name: Animal.java
package com.itheima_05;

public class Animal {
    public void eat() {
        System.out.println("吃东西");
    }
}


//file name: Cat.java
package com.itheima_05;

public class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}


//file name: Dog.java
package com.itheima_05;

public class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃骨头");
    }
}


//file name: DuoTaiDemo.java
package com.itheima_05;

public class DuoTaiDemo {
    public static void main(String[] args) {
        //向上转型
        Animal a = new Cat();
        a.eat();
        
        //向下转型
        Cat c = (Cat) a;
        c.eat();
        c.playGame();
        
        //向上转型
        a = new Dog();
        a.eat();
        
        //向下转型
        Cat cc = (Cat) a; //ClassCastException 类型转换异常
        cc.eat();
        cc.playGame();
    }
}


7.正确的向上转型、向下转型代码
图片:见“向下转型之父类和子类的关系.bmp”

核心代码:
//向上转型
Animal ani = Dew Dog();
ani.eat();//狗吃东西
if(ani instanceof Dog){
  Dog dog = (Dog)ani;//向下转型
  dog.lookDoor();//狗看门
}


未修改前的完整代码:
//file name: Animal.java
package com.itheima_06;

public class Animal {
    public void eat() {
        System.out.println("吃东西");
    }
}


//file name: Cat.java
package com.itheima_06;

public class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    
    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}


//file name: Dog.java
package com.itheima_06;

public class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃骨头");
    }
    
    public void lookDoor() {
        System.out.println("狗看门");
    }
}


//file name: DuoTaiTest.java
package com.itheima_06;

/*
 * 动物:
 *     eat()
 * 猫:
 *     eat()
 *     playGame()
 * 狗:
 *     eat()
 *     lookDoor()
 */
public class DuoTaiTest {
    public static void main(String[] args) {
        Animal a = new Cat();
        a.eat();
        
        Cat c = (Cat) a;
        c.eat();
        c.playGame();
        
        a = new Dog();
        a.eat();
        
        Dog d = (Dog) a;
        d.eat();
        d.lookDoor();
    }
}

8.静态成员变量:随着类的加载而加载,随着程序的消失而消失。以后会学集合、数组,假如集合、数组被static修饰了,如果你的这个集合或数组比较庞大,占用内存比较大,那么在程序结束之前,它始终会占据着内存空间。如果内存比较小的话,就会出现内存溢出异常。解决的办法:1.加内存;2.不要用static来修饰这种比较占内存的集合。


9.构造器原理、多态原理
核心知识点:
有参构造拿到属性值后不能给成员变量赋值,因为name和age属性是父类中的,并且 用private修饰,不能直接 赋值,所以这里调用父类的构造方法把name和age这两个属性值传递给父类的有参构造,让父类去进行初始化。

代码:
//file name: Person.java
package com.itheima.gxff;

public class Person {
    private String name;
    private int age;

    public Person() {
        //这里调用的是Person类的有参构造 
        this("孙老师",18);
    }

    public Person(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;
    }

}


//file name: Teacher.java
package com.itheima.gxff;

public class Teacher extends Person {

    public Teacher() {
    }

    public Teacher(String name, int age) {
        //有参构造拿到属性值后不能给成员变量赋值,因为
        //name和age属性是父类中的,并且 用private修饰
        //不能直接 赋值,所以这里调用父类的构造方法把name和age这两个属性值
        //传递给父类的有参构造,让父类去进行初始化
        super(name, age);
    }

}


//file name: Test.java
package com.itheima.gxff;

public class Test {
    public static void main(String[] args) {
//        Person per = new Person();//这里调用的是Person的无参构造
//        //打印的是默认值
//        /*
//         * 我想给Person类一个好的默认值,该怎么办呢?
//         * 我可以利用Person类的构造方法解决问题
//         */
//        System.out.println(per.getName());
//        System.out.println(per.getAge());
        
        Teacher tea = new Teacher("天海老师", 20);
        //这里我调用的是Teacher类的有参构造方法,把天海老师和20这两个属性值传过去
    }
}


====

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值