栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

JavaSE进阶21天---第八天---JavaSE(static关键字、继承、super关键字、this关键字、多态、(成员变量、静态成员方法、实例成员方法)在多态中的调用情况)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaSE进阶21天---第八天---JavaSE(static关键字、继承、super关键字、this关键字、多态、(成员变量、静态成员方法、实例成员方法)在多态中的调用情况)

static关键字、继承、super关键字、this关键字、多态、(成员变量、静态成员方法、实例成员方法)在多态中的调用情况

活动地址:CSDN21天学习挑战赛

学习内容

​static关键字及应用

继承、多态

static关键字
  • static是静态的意思,可以用来修饰成员变量、成员方法。
  • static修饰成员变量之后称为静态成员变量(类变量),修饰方法之后称为静态方法(类方法)。
  • static修饰后的成员变量,可以被类的所有对象共享(访问、修改)。

 静态成员变量

  • 有static修饰,属于类、加载一次,内存中只有一份。
  • 表示被类的所有对象共享的信息。

实例成员变量

  • 无static修饰,属于对象,且每个对象的该信息不同。

静态成员方法

  • 有static修饰,属于类。
  • 用类名访问(建议),也可以用对象访问。
  • 如果该方法是以执行一个通用功能为目的,或者需要方便访问,则可以申明成静态方法

实例成员方法

  • 无static修饰,属于对象。
  • 只能用对象访问。 
  • 表示对象自己的行为的,且方法中需要直接访问实例成员,则该方法必须申明成实例方法。

 访问注意事项

  • 静态方法只能访问静态的成员,不可以直接访问实例成员。
  • 实例方法可以访问静态的成员,也可以访问实例成员。
  • 静态方法中是不可以出现this关键字的。
  • main方法中不能直接使用非静态成员的

分析静态方法、构造方法、初始化程序块的先后执行顺序

父类(Person)

package moming;

public class Person {
    private String name;

    public Person() {
        System.out.println("父类无参构造");
    }
    public Person(String name) {
        System.out.println("父类有参构造");
    }

    static {
        System.out.println("父类静态程序块");
    }
    {
        System.out.println("父类初始化程序块");
    }
}

子类(User)

package moming;

public class User extends Person{
    private String name;

    public User() {
        //super("name");
        //super()//默认存在
        System.out.println("子类无参构造");
    }

    static {
        System.out.println("子类静态程序块");
    }
    {
        System.out.println("子类初始化程序块");
    }
}

测试类(Test)

package moming;

public class Test{
    public static void main(String[] args) {
        User user = new User();
        System.out.println("-------------");
        User user1 = new User();
    }
}
父类静态程序块
子类静态程序块
父类初始化程序块
父类无参构造
子类初始化程序块
子类无参构造
-------------
父类初始化程序块
父类无参构造
子类初始化程序块
子类无参构造

可以看到静态程序块先执行,且只执行一次,之后是父类的初始化程序块、构造方法,再到子类的初始化程序块、构造方法。

继承

继承:是指子类拥有父类的全部特征和行为,这是类之间的一种关系。Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。

继承设计规范:

  • 子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的的属性和行为应该定义在子类自己里面。
  • Java是单继承模式:一个类只能继承一个直接父类。 Java不支持多继承、但是支持多层继承,父类可以有多个子类。
  • Java中所有的类都是Object类的子类。

继承的特点:

  • 继承要有一定的层次结构,而且还要具备一定的可传递性。
  • 子类继承了父类的所有属性和方法,但是不包括私有属性(private)和构造方法。
  • 若父类包含抽象方法,子类在继承时必须进行方法重写。
  • 子类继承父类的属性和方法同时也可以有自己的属性和方法。
  • 继承可以减少重复代码、提高了复用性和维护性。
  • 继承让类与类之间产生了关系,类的耦合性增强了,父类发生变化子类也会跟着改变。

父类(Animal)(基类或超类)

package cn.moming1;

public abstract class Animal {
    public String name="哺乳动物";    //父类实例成员变量
    private static String anmial1="动物类";//私有属性子类不能继承

    public Animal() {       //无参构造子类不能继承
    }
    public Animal(String name) {    //有参构造子类不能继承
        this.name = name;
    }

    public abstract void survive();     //父类抽象方法

    public void eat(){                      //实例成员方法
        System.out.println("动物吃东西");
    }
    public void breathe(){                  //实例成员方法
        System.out.println("动物吃东西");
    }

}

子类(Cat)(派生类)

package cn.moming1;

public class Cat extends Animal{
    String name="加菲猫";              //子类自己的属性

    public void eat(){                        //子类重写父类实例方法
        System.out.println("猫吃鱼");
    }

    @Override
    public void survive() {                 //子类必须重写父类抽象方法
        System.out.println("猫抓老鼠");
    }

    public void call(){             //子类自己的实例方法
        System.out.println("猫叫");
    }
}

子类(Dog)

package cn.moming1;

public class Dog extends Animal{
    public Dog() {
        //super();  //默认存在,调用父类的无参构造
    }

    public Dog(String name) {
        //super();   //默认存在,调用父类的无参构造
        //this.name=name;
        super(name); //调用父类有参构造,效果和this.name=name; 一样
        //super 可以用来直接调用父类中的构造方法,使编写代码也更加简洁方便。
    }

    public void eat(){         //子类重写了父类实例方法
        super.eat();    //调用父类中的方法
    }

    @Override
    public void survive() {             //子类必须重写父类抽象方法
        System.out.println("狗护家");
    }
}

测试类(Test)

package cn.moming1;

public class Test {
    public static void main(String[] args) {
        //Cat类
        Cat cat = new Cat();//实例化Cat类,获取cat对象;
                            //子类没有构造方法时,系统默认会分配一个无参构造,调用父类无参构造,super()默认存在
        cat.eat();//调用重写的eat方法
        cat.survive();//调用重写的survive抽象方法
        cat.breathe();//(子类没有重写)就去父类找,调用继承父类的breathe方法
        System.out.println(cat.name);//获取子类的属性
        cat.call();//调用子类自己的实例方法call
        System.out.println("===================");

        //Dog类
        Dog dog = new Dog();//子类有构造方法,这里调用了子类无参构造,又因为super()默认调用父类无参构造
        System.out.println(dog.name);//子类没有去父类获取
        dog.eat();//因为用super关键字调用了父类的eat
        dog.survive();//调用重写的survive抽象方法
        Dog dog1 = new Dog("哈士奇");//子类有参构造调用了父类的无参构造后,执行自己的构造方法体(this.name=name;或者super(name);),将哈士奇传进去
        String name = dog1.name;
        System.out.println(name);


    }
}
猫吃鱼
猫抓老鼠
动物吃东西
加菲猫
猫叫
===================
哺乳动物
动物吃东西
狗护家
哈士奇
总结 

访问特点

在子类方法中访问成员(成员变量、成员方法)满足:就近原则

先子类局部范围找 然后子类成员范围找 然后父类成员范围找,如果父类范围还没有找到则报错。 如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类的, 可以通过super关键字,指定访问父类的成员。

方法重写

  • 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
  • 私有方法不能被重写。
  • 子类重写父类方法时,访问权限必须大于或者等于父类 。
  • 子类不能重写父类的静态方法,如果重写会报错的。

@Override重写注解

  • @Override是放在重写后的方法上,作为重写是否正确的校验注解。
  • 加上该注解后如果重写错误,编译阶段会出现错误提示。

子类继承父类后构造方法的特点

  • 子类中所有的构造方法默认都会先访问父类中无参构造方法,再执行自己。
  • 子类构造方法的第一行语句默认都是:super(),不写也存在。
  • 子类构造方法中可以通过书写 super(…),手动调用父类的有参数构造方法
 super关键字

super:代表父类存储空间的标识。

由于子类不能继承父类的构造方法,因此,如果要调用父类的构造方法,可以使用 super 关键字。super 可以用来访问父类的构造方法、普通方法和属性。

super 关键字的用法:

  • super() 必须是在子类构造方法的方法体的第一行。
  • super.父类属性名:调用父类中的属性
  • super.父类方法名:调用父类中的方法
  • super():调用父类的无参构造方法
  • super(参数):调用父类的有参构造方法

编译器会自动在子类构造方法的第一句加上super(); 来调用父类的无参构造方法,必须写在子类构造方法的第一句,也可以省略不写。通过 super 来调用父类其它构造方法时,只需要把相应的参数传过去。

this关键字

this:代表本类对象的引用。

可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。

this 关键字的用法:

  • 当局部变量和成员变量发生冲突时,使用this.进行区分。
  • this.属性名:表示当前对象的属性
  • this.方法名(参数):表示调用当前对象的方法
  • this( ) 用来访问本类的构造方法
  • this( ) 不能在普通方法中使用,只能写在构造方法中。
  • 在构造方法中使用时,必须是第一条语句。

super 和 this 关键字的区别

  1. 子类和父类中变量或方法名称相同时,用 super 关键字来访问。可以理解为 super 是指向自己父类对象的一个指针。在子类中调用父类的构造方法。
  2. this 是自身的一个对象,代表对象本身,可以理解为 this 是指向对象本身的一个指针。在同一个类中调用其它方法。
  3. this 和 super 不能同时出现在一个构造方法里面,因为 this 必然会调用其它的构造方法,其它的构造方法中肯定会有 super 语句的存在,所以在同一个构造方法里面有相同的语句,就失去了语句的意义,编译器也不会通过。
  4. this( ) 和 super( ) 都指的是对象,所以,均不可以在 static 环境中使用,包括 static 变量、static 方法和 static 语句块。
  5. 从本质上讲,this 是一个指向对象本身的指针, 然而 super 是一个 Java 关键字。

父类

package cn.moming3;

public class Animal {
    public String name; // 父类名字
}

子类

package cn.moming3;

public class Cat extends Animal {
    private String name; // 子类名字

    public Cat(String name1, String name2) {    //有参构造
        super.name = name1; // 通过super关键字来访问父类中的name属性
        this.name = name2; // 通过this关键字来访问本类中的name属性
    }

    public String toString() {      //重写toString方法,方便打印
        return "父类的名字" + super.name + ",子类的名字" + this.name;
    }

}

测试类

package cn.moming3;

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat("Animal", "Cat");
        System.out.println(cat);
    }
}
父类的名字Animal,子类的名字Cat
多态

多态就是同一函数在不同类中有不同的实现。

  • 面向对象的多态性,即“一个接口,多个方法”。
  • 多态性体现在父类中定义的属性和方法被子类继承后,可以具有不同的属性或表现方式。
  • 多态性允许一个接口被多个同类使用,弥补了单继承的不足。

测试类

package cn.moming1;

public class Test {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        animal1.eat();
        Animal animal2 = new Cat();
        animal2.eat();
    }
}
狗吃骨头
猫吃鱼

多态的前提和体现

  • 有继承/实现关系
  • 有方法重写
  • 有父类引用指向子类对象 

多态中成员访问特点

  • 成员变量:编译看左边,执行看左边
  • 静态成员方法:编译看左边,执行看左边
  • 非静态成员方法:编译看左边,执行看右边 

父类

package cn.moming5;

public class Animal {
    public int age = 1;//非静态成员变量
    public static String name="动物";//静态成员变量
    public void eat(){      //非静态成员方法
        
        System.out.println("动物吃东西");
    }
    public static void sleep(){     //静态成员方法
        System.out.println("动物睡觉");
    }
}

子类

package cn.moming5;

public class Cat extends Animal{
    public int age = 2;//非静态成员变量
    public static String name = "猫";//静态成员变量
    public void eat(){      //非静态成员方法
        System.out.println("猫吃鱼");
    }
    public static void sleep(){     //静态成员方法(将父类静态成员方法隐藏了,这不是重写)
        System.out.println("猫不睡觉");
    }
}

测试类

package cn.moming5;

public class Test {
    public static void main(String[] args) {
        Animal a = new Cat();   //多态
        int age = a.age;        //父类引用去获得被隐藏的成员变量
        System.out.println(age);
        String name = a.name;   //父类引用去获得被隐藏的成员变量
        System.out.println(name);

        a.eat();    //非静态成员方法,编译看左,运行看右
        a.sleep();  //静态成员方法,编译看左,运行看左
    }
}
1
动物
猫吃鱼
动物睡觉

为什么成员变量和非静态成员方法的访问不一样呢?

因为非静态成员方法有重写,而成员变量没有。

为什么静态成员方法和非静态成员方法的访问不一样呢?

当静态时,父类的所有函数跟随父类加载而加载了。也就是父类的函数(是先于对象建立之前就存在了,无法被后出现的子类对象所重写的,所以没发生重写,就算子类重写了也没有意义。

测试类代码解析

Animal a = new Cat();

声明类型为Animal的a变量,然后建立一个子类对象new Cat()赋值给了a,在测试代码中是通过类型为Animal的引用变量a去调用属性和方法的,也就是父类引用调用属性和方法。

成员变量:编译看左,运行看左

首先记住一句话:成员变量不能被重写。

  • 在一个类中,子类中的实例成员变量如果和父类中的实例成员变量同名,那么即使他们类型不一样,只要名字一样。父类中的实例成员变量都会被隐藏。在子类中,父类的实例成员变量不能被简单的用引用来访问。而是,必须通过父类的引用获得父类被隐藏的实例成员变量,而在测试类中就是通过父类引用去获得被隐藏的成员变量。
  • 换句话说就是若子类和父类均定义了同样名称的成员变量,则对于子类来说这是两个不同的变量。
  • 而静态成员变量属于类,不能被重写。子类可以继承父类的静态成员变量和静态成员方法

静态成员方法:编译看左,运行看左

  • 因为class文件在被类加载器加载时,如果有static方法,此时会分配内存。也就是说,静态方法在类加载时就已经加载了,在类实例对象建立前就已经存在了,所有无法被后出现的子类对象进行重写。
  •  静态方法的调用不需要实例化,而是直接通过父类引用去调用就行,不实例化也就不能用多态了,也就没有所谓的父类引用指向子类实例。
  • 子类可以继承父类的静态方法,但不能重写。如果父类中定义的静态方法在子类中被重新定义,那么在父类中定义的静态方法将被隐藏而非重写。
  • 父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性

非静态成员方法(实例成员方法):编译看左,运行看右

  • 前面提了在多态条件下将子类对象new Cat()赋值给了a,也就是说只有子类的函数覆盖了父类的函数这一个变化,但是a肯定是Animal这个类的引用。所以a所代表的是函数被重写后的Animal类(多态的意义)。
  • 谁的引用去调用的方法就是谁的,如果被重写就调用重写后的方法。

补充

  • Java中函数就是方法,是定义在类中的一段独立的代码块,用来实现某个功能;作用是提高代码的复用性和可读性。
  • 函数的语法格式:
    修饰符 返回值类型 函数名(形式参数类型1 参数名1...){
        函数体语句;
        return 返回值;
    }
    

 多态的好处

提高了程序的扩展性,具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。

多态的弊端

不能使用子类的特有功能

多态中的转型 

  • 向上转型 :从子到父 父类引用指向子类对象
  • 向下转型 :从父到子 父类引用转为子类对象 
package cn.moming1;

public class Test {
    public static void main(String[] args) {
        //向上转型
        Animal animal2 = new Cat();
        animal2.eat();
        //向下转型
        Cat cat = (Cat) animal2;
        cat.eat();
    }
}
猫吃鱼
猫吃鱼
  • 向下转型其实就是强制类型转换,向下转型前应该保证转型的健壮性,转型之前必须使用instanceof关键字进行判断。
package cn.moming1;

public class Test {
    public static void main(String[] args) {
        //向上转型
        Animal animal2 = new Cat();
        animal2.eat();
        System.out.println("============");
        //向下转型
        if(animal2 instanceof Dog){
            Cat cat = (Cat) animal2;
            cat.eat();
        }else {
            System.out.println("类型转换失败!");
        }
        System.out.println("============");
        if(animal2 instanceof Cat){
            System.out.println("类型转换成功!");
            Cat cat = (Cat) animal2;
            cat.eat();
        }else {
            System.out.println("类型转换失败!");
        }
    }
}
猫吃鱼
============
类型转换失败!
============
类型转换成功!
猫吃鱼
  • 在进行子类特有方法使用时,要进行向下转型,转型之前一定要先判断,否则容易发生ClassCastException
package cn.moming1;

public class Test {
    public static void main(String[] args) {
        //向上转型
        Animal animal2 = new Cat();
        animal2.eat();
        System.out.println("============");
        //向下转型
        Dog dog = (Dog) animal2;        //报错类型不匹配
        dog.eat();
    }
}        

猫吃鱼
============
Exception in thread "main" java.lang.ClassCastException: class cn.moming1.Cat cannot be cast to class cn.moming1.Dog (cn.moming1.Cat and cn.moming1.Dog are in unnamed module of loader 'app')
	at cn.moming1.Test.main(Test.java:30)
转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037637.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号