继承封装多态

一、封装

封装就是公开代码的对外接口,隐藏具体的实现。使用者不关心内部的具体实现步骤和方法,只要能够使用并操作即可。就像我们生活中的手机、电脑、电视、洗衣机等,我们不关心它的构造和工作原理,只要知道如何操作就可以。

1.封装的意义
  • 保护或者防止代码被破坏
  • 保护成员属性,不让改类以外的程序直接访问修改
  • 隐藏方法细节,只留出开放的方法接口供其它程序使用

对方法实现者:类的成员属性只有本类中的方法才可以直接访问并修改。其它类访问成员属性和方法时,只能通过本类预留的公共方法来访问本类的成员属性和方法。

对方法调用者:不关心方法内部如何实现,只要能够使用类中的方法,能通过方法访问类中成员属性即可。

2.封装的实现

Java中通过访问限定修饰符来实现类的封装

访问范围private默认无修饰符protectedpublic
同一个包中的同一个类
同一个包中的不同类
不同包中的子类
不同包中的非子类
3.代码示例
class BankUser{
    private String userName;  //私有成员属性,只能被改类中的方法访问修改
    private int userAge;
    private int userMoney;
    private String userPhone;
            int date;  //注册日期,无修饰符

    public String getUserName() {  //public公开的方法,可以提供给方法调用者使用,get方法获取属性值
        return userName;
    }

    public void setUserName(String userName) {  //set方法设置属性值
        this.userName = userName;
    }

    public int getUserAge() {
        return userAge;
    }

    public void setUserAge(int userAge) {
        this.userAge = userAge;
    }

    public int getUserMoney() {
        return userMoney;
    }

    public void setUserMoney(int userMoney) {
        this.userMoney = userMoney;
    }

    public String getUserPhone() {
        return userPhone;
    }

    public void setUserPhone(String userPhone) {
        this.userPhone = userPhone;
    }

    @Override
    public String toString() {  //重写的toSting()方法,输出示例的各种属性
        return "BankUser{" +
                "userName='" + userName + '\'' +
                ", userAge='" + userAge + '\'' +
                ", userMoney=" + userMoney +
                ", userPhone='" + userPhone + '\'' +
                '}';
    }
}
public class Packaging {
    public static void main(String[] args) {
        BankUser bankUser = new BankUser();  //创建实例
        //bankUser.userName = "王"  
        //成员属性被private修饰,其他类无法直接访问修改该属性,只能通过公开的方法修改
        bankUser.setUserName("王");
        bankUser.setUserAge(23);
        bankUser.setUserMoney(20000);
        bankUser.setUserPhone("131-9999-2131");
        bankUser.date = 2020;  //无修饰符的,可以在包内被直接访问修改
        System.out.println(bankUser.toString());
    }
}

二、继承

1.继承的意义
  • 继承可以使代码更简洁
  • 能提高代码的复用性
2、继承的实现

Java中的继承是单继承,使用extends来实现继承

class Animal{
    protected String name;  //protected关键字修饰
    public Animal(String name ) {  //构造方法
        this.name = name;
    }
    public void eat(){
        System.out.println("吃东西");
    }
}
class cat extends Animal{  
    public cat(String name) {  //显式调用,super()调用父类构造方法
        super(name);
    }

    @Override
    public void eat() {  //重写父类同名方法
        System.out.println("cat::eat()");
    }
}
class bird extends Animal{
    public bird(String name) {
        super(name);
    }
    @Override
    public void eat() { //重写父类同名方法
        System.out.println("bird::eat()");
    }
    public void fly(){  //自己的方法
        System.out.println(this.name+"fly()");
    }
}

public class ExtendsEx {
    public static void main(String[] args) {
        cat cat = new cat("咪咪");
        cat.eat();
        bird bird =new bird("小鸟");
        bird.eat();
        bird.fly();
        Animal animal = new cat("咪咪");  //向上转型
        animal.eat(); //结果输出cat::eat()
    }
}

子类继承了父类除构造方法外的所有东西,子类只能用super()显式调用父类的构造方法,子类也继承了父类的成员属性(包括private修饰的成员属性),只是子类不能使用。

3、super

super:表示父类对象的引用,在子类中引用父类的成员属性和方法

  • super.data :调用父类的成员属性
  • super.func() :调用父类的方法
  • super() :调用父类的构造方法
4、protected关键字

之前的表中已经介绍过protected关键字的范围,这里演示一下

package Code;  //Code包

public class Animals {
    protected String name;  //protected修饰
    public Animals(String name){
        this.name = name;
    }
    public void eat() {
        System.out.println("吃东西");
    }
}
package extendsPack;  //不同包

import Code.Animals;

/**
 *@ClassName: frog
 *@Description protected例子
 *@Author PandaChan1
 *@Date 2020/10/26
 *@Time 21:25
 */


class frog extends Animals {  //子类继承

    public frog(String name) {
        super(name);
    }

    @Override
    public void eat() {
        System.out.println(this.name + " frog::eat()");  //访问修改
    }

    public void jump() {
        System.out.println(this.name + " frog::jump()");
    }

    public void swim() {
        System.out.println(this.name + " frog::swim()");
    }
}

public class ProtectedTestDemo {
    public static void main(String[] args) {
        frog frog = new frog("呱呱");
        frog.eat();
        frog.jump();
        frog.swim();
    }
}

删除protected之后,另一个包会报错,即protected修饰的成员变量可以被其不同包的子类访问
在这里插入图片描述在这里插入图片描述

5、final关键字
  1. final修饰类时,表明改类不能被继承,如果一个类不想让其他类继承,就可以用final关键字修饰。final类中的所有成员方法都会被隐式指定为final方法

  2. final修饰方法时,把方法锁定,以防任何继承类修改它。即父类的final方法是不能被子类覆盖(重写)的

  3. final修饰变量,final成员变量(属性)表示常量,只能被赋值一次,赋值后不能再更改,且该成员变量(属性)必须要显式初始化,两种初始化方法

    class Person{
    //private final int age = 0;  //1、在声明时初始化
        private final int age;
    public Person(){
        this.age = 0;    //2、声明时不初始化,但在构造函数中必须初始化
    }
    }
    
  4. final修饰基本数据类型的值时,表示该基本类型的值一旦在初始化后不可以再改变

  5. final修饰引用类型时,则在对其初始化后便不能再指向其他对象了但是引用所指向的对象的内容是可变的

    class Person{
        protected int a = 0;
    }
    public class Test{
        public static void main(String[] args) {
           final Person person = new Person();
            System.out.println(++person.a);   //1
        }
    }
    

在这里插入图片描述

6、向上转型

向上转型发生在子类和父类之间,指用父类接收子类的实例化对象(应该是这样理解,错误请指出)

看代码,更容易理解

public class ExtendsEx {
    public static void main(String[] args) {
        cat cat = new cat("咪咪");
        cat.eat();
        bird bird =new bird("小鸟");
        bird.eat();
        bird.fly();
        Animal animal = new cat("咪咪");  //父类的引用指向子类的对象
        animal.eat();
    }
}

向上转型的三种方式:

  1. 直接赋值

    Animal animal = new cat("咪咪");
    
  2. 方法的传参

      public static void whatsAnimal(Animal animal) {  //传参的过程中发生了向上转型
            animal.eat();
        }
        public static void main(String[] args) {
            Cat cat = new Cat("咪咪");
            whatsAnimal(cat);
        }
    
  3. 方法的返回值

       public static Animal whatAnimal(Cat cat) {  //方法返回值中向上转型
            return cat;
        }
        public static void main(String[] args) {
            Cat cat = new Cat("咪咪");
            whatAnimal(cat).eat();
        }
    
7、动态绑定

动态绑定是指在运行期间判断所引用对象的实际类型,并根据其实际类型来调用相应的方法。

前提:父类引用子类的对象,同时通过父类去调用父类和子类的同名覆盖方法(重写后的方法,在程序运行时,会去调用子类重写后的同名方法。

示例:

public class ExtendsEx {
     public static void whatsAnimal(Animal animal) {
        animal.eat();
    }
    public static void main(String[] args) {
        Animal animal = new cat("咪咪");  //发生了向上转型
         whatsAnimal(animal);
    }
}

可以看到,我们在创建cat对象时用cat的父类Animal接收该实例对象,在这个过程中发生了向上转型。在whatsAnimal()方法中,参数为Animal类型,调用eat()方法。那么这里调用的是cat中重写的eat()方法还是父类Animaleat()方法呢?

在这里插入图片描述

结果显示调用的方法为cat中的方法,那么动态绑定在什么时候发生的呢?

在这里插入图片描述

反编译生成的class字节码文件得到如下信息,其中invokespecial一般表示调用构造方法,invokevirtual表示调用对象的方法,invokestatic表示调用静态方法。可以看到在main方法中我们调用了whatsAnimal()这个静态方法,这个方法的参数类型为Animal。然后在whatsAnimal()方法中,看到箭头所指的位置,调用的是Animaleat()方法。可是最后我们的得到的输出调用的是cat重写的方法。可以得出结论:编译时不会发生动态绑定,运行时才发生动态绑定,且动态绑定发生的前要发生向上转型,并调用父类和子类的同名覆盖方法

三、多态

多态就是同一种行为,表现出不同的形式。即同一个接口,使用不同实例执行不同的操作。

1、多态的意义

多态可以简化代码,减少代码量;便扩展具有很好的灵活性和可扩充性。

2、多态的实现
2.1多态发生的条件
  • 继承
  • 重写
  • 父类引用指向子类对象

就像之前写的:

public class ExtendsEx {
     public static void whatsAnimal(Animal animal) {
        animal.eat();
    }
    public static void main(String[] args) {
        Animal animal = new cat("咪咪");  //发生了向上转型
         whatsAnimal(animal);
    }
}

main方法中Animal的引用指向子类的对象,然后在whatsAnimal()中调用父类和子类的同名覆盖方法。

CatBird中重写的父类方法只有eat()方法,对不共有的方法,使用instanceOf判断再执行相应的方法。

public class ExtendsEx {
     public static void whatsAnimal(Animal animal) {
        animal.eat();
         if(animal instanceOf Bird) {  //instanceOf判断一个对象是不是属于某个类
             Bird bird = (Bird)animal;
             bird.fly();
         }b
    }
    public static void main(String[] args) {
        Animal animal = new cat("咪咪");  //发生了向上转型
        Animal animal1 = new Bird("小鸟");
        whatsAnimal(animal);
        whatsAnimal(animal1)
    }
}

imal) {
animal.eat();
if(animal instanceOf Bird) { //instanceOf判断一个对象是不是属于某个类
Bird bird = (Bird)animal;
bird.fly();
}b
}
public static void main(String[] args) {
Animal animal = new cat(“咪咪”); //发生了向上转型
Animal animal1 = new Bird(“小鸟”);
whatsAnimal(animal);
whatsAnimal(animal1)
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值