JAVA学习笔记5 面向对象三大特性(封装、继承、多态)

面向对象

  • 本质:以类的方式组织代码,以对象的形式封装数据
  • 三大特性:封装、继承、多态

封装(encapsulation)

封装就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作

好处:

  • 隐藏实现细节 方法(连接数据库)<-调用
  • 可以对数据进行验证,保护安全合理

封装的实现步骤:

  1. 将属性进行私有化private (外部不能直接修改属性)
  2. 提供一个公共的(public)set方法,用于对属性判断并赋值
    public void setXxx(类型 参数名){//Xxx表示某个属性
    //加入数据验证的业务逻辑
    属性=参数名;
    }
    //可用快捷键Alt+Insert直接得出模板
  1. 提供一个公共的(public)get 方法,用于获取属性的值
    public 数据类型 getXxx(){//权限判断,Xxxv某个属性
        return xx;
    }
    //可用快捷键Alt+Insert直接得出模板

高内聚 低耦合的特点

//封装举例:
public class encapsulation {
    public static void main(String[] args) {
        Student student = new Student();
        student.name="tom";
        student.setId(12);
        System.out.println(student.id+student.name);//输出为12tom
    }
//类 private:私有(外部不能使用)
    static class Student {
    public String name;//名字公开
    private int id;
    private char sex;

    //提供一些public的get.set方法
    //get 获得数据
    public int getId(){
        return this.id;
    }

    //此后可以在外部使用类的name值
    //set 给数据设值
    public void setId(int id) {
        if(id>0&&id<100)
        this.id = id;
        else {
            System.out.println("ID需要在0到100之间,给你默认id为99");
            this.id=99;//如果输入的id不在范围内则默认id设为99,输出则变成99tom
        }
    }
}

继承(extend)

  • extends 拓展:子类是父类的扩展。子类可以继承父类的所有方法
  • super:调用父类的构造器,且必须要在子类构造器的第一行
  • 提高代码复用性,提高代码的扩展性和维护性

继承的关系图:
继承关系

继承举例:

//人:父类
public class Person{
    pubilc void say(){
    System.out.println("说话");
    }
    private int money=1_000_000;//私有的,不能被继承
    pubilc void print(){
    System.out.println("Person");
    }

}
//学生是人:派生类、子类:学生
public class Student extends Person{
    pubilc void print(){
    System.out.println("Student");
    }
      
    pubilc void test1(){
    print();
    this.print();//访问该类方法
    super.print();//访问父类方法
    }
}
//老师是人:派生类、子类:老师
public class Teacher extends Person{
      
}
//测试函数:
public static void main(String[] args){
    Student student =new Student();
    student.say();//Student类用了Person类的方法,输出:说话
    student.test1();//输出:Student Student Person

}
//ctrl+h 会展现出继承关系
继承的细节
  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供的公共的方法去访问
package extend_;

public class Base {//父类
        public int n1=100;
        private int n2=200;
        public Base(){//无参构造器
            System.out.println("base()...");
        }
        public void test001(){
            System.out.println("text001");
        }
        private  void  test002(){//因为test002为私有所以子类不能直接调用
            System.out.println("test002");
        }
        //父类提供一个public的方法
        public int getN2(){//父类提供一个public访问n2
            return n2;
        }

    }

public class sub extends Base {//子类
    public sub(){//子类的无参构造器
        //super();默认使用该语句,调用父类的无参构造器
        System.out.println("sub()...");
    }
    public void sayOk(){//子类的方法
        //非私有的属性方法可以在子类直接访问;
        System.out.println(n1);
        //System.out.println(n2);
        //test002();
        //报错私有的禁止访问
        System.out.println("n2="+getN2());//子类访问父类public方法即可再访问到n2

    }
}
  1. 子类必须调用父类的构造器,完成父类的初始化
//以1.的父子类关系举例,创造主函数
public class extends02 {
    public static void main(String[] args) {
        sub a= new sub();
        //输出结果为
        //base()...即先调用了父类的base()无参构造器
        //sub()...再调用类子类的sub()无参构造器
    }
}
  1. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作
  • super注意点:
    • super调用父类的构造方法,必须在构造方法的第一个/第一行
    • super必须只能出现在子类的方法或者构造方法中。
    • super和this不能同时调用构造方法,因为this()也只能放在构造器的第一行
  • super和this的区别:
    • 代表的对象不同
      • this:本身调用者这个对象
      • super:代表父类对象的应用
    • 前提
      • this:没有继承也可以使用
      • super:只能在继承条件才能使用
    • 构造方法:
      • this():本类的构造
      • super():父类的构造
  1. 如果希望指定去调用父类的某个构造器,就故意显示地调用一下(平时都是默认调用):super(参数列表)
//举例:
//要调用父类无参构造器,则什么都不写或者写super();
//在创建了子类对象new people("mosun",20)的前提下调用举例
//要调用父类Base(String name)构造器
//super("mosun");
//要调用父类Base(String name,int age)构造器
//super("mosun",20);
  1. Java所有类都是Object类的子类,Object是所有类的祖宗类(基类)

类object
可用ctrl+H 可得出继承关系。

  1. 父类构造器的调用不限于直接父类,将一直往上追溯到Object类

  2. 子类最多只能继承一个父类(直接继承)即java单继承机制

  3. 不能滥用继承,子类和父类必须满足is-a的逻辑关系

  • Person is a Music? X
  • Cat is Animal? √

多态(polymorphic)

动态编译:类型(可拓展性)

  • 大大提高代码的可用性
  • 多态是建立在封装和继承基础之上的
  • 多态是方法的多态,属性没有多态
  • 父类和子类,有联系才可转换,否则类型转换异常(ClassCastException!)
  • 存在条件:继承关系,需要重写,父类引用指向子类对象 Father f1=new Son();

给动物喂食举例:创建食物类(子类为骨头和鱼)、主人、动物类(子类为狗和猫),通过多态减少代码冗余,来实现主人给动物喂食食物的过程

public class Animals {//动物类 父类
    private String name;
    public Animals(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Cat extends Animals{//🐱猫类继承动物类,子类
    public Cat(String name) {
        super(name);
    }
}
public class Dog extends Animals{//🐕狗类继承动物类,子类
    public Dog(String name) {
        super(name);
    }
}
public class Food {//食物类,父类
    private String name;
    public Food(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Fish extends Food{//食物类的子类
    public Fish(String name) {
        super(name);
    }
}
public class Bone extends Food{//食物类的子类
    public Bone(String name) {
        super(name);
    }
}
//以上只是简单重复的创建对象

public class Master {//主人
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
//    //主人给狗喂食骨头
//    public void feed(Dog dog,Bone bone){
//        System.out.println("主人"+name+"给"+dog.getName()+"吃"+bone.getName());
//    }
//    //主人给猫喂食🐟
//    public void feed(Cat cat,Fish fish){
//        System.out.println("主人"+name+"给"+cat.getName()+"吃"+fish.getName());
//    }

    //使用多态机制,统一管理主人喂食问题,代替上面代码
    //animal的编译类型是Animal,所以可以接受Animal子类的对象(Cat/Dog)
    //food的编译类型是Food,可以接受Food的子类的对象(Fish/Bone)
    public  void feed(Animals animal,Food food){//喂食语句
        System.out.println("主人"
        +name+"给"+animal.getName()+"吃"+food.getName());
    }
}
public class Poly01 {
    public static void main(String[] args) {
        Master mosun = new Master("mosun");//创建主人mosun
        Dog doggie = new Dog("doggie");//创建狗类对象doggie
        Bone bone=new Bone("pork bone");//创建骨头类对象pork bone
        Cat tom=new Cat("tom");//创建猫类对象tom
        Fish king = new Fish("king");//创建鱼类对象king
        mosun.feed(doggie,bone);
        mosun.feed(doggie,king);
        mosun.feed(tom,king);
        //输出为
        // 主人mosun给doggie吃pork bone
        // 主人mosun给doggie吃king
        // 主人mosun给tom吃king
    }
}

对象的多态(多态的核心)
  • 一个对象的编译类型和运行类型可以不一致
  • 编译类型在定义对象时,就确定了,不能改变
  • 运行类型是可以变化
  • 编译类型看定义时=号左边,运行类型看=号的右边
Animal animal=new Animal//animal的编译类型是Animal,运行类型也是Animal
Animal animal=new Dog();//animal的编译类型是Animal,运行类型是Dog
animal=new Cat();//animal的编译类型仍然是Animal,运行类型则变成了Cat

对象的多态举例

public class Animal {
    public void cry(){
        System.out.println("动物在叫");
    }
}
public class Cat extends Animal{
    @Override
    public void cry(){
        System.out.println("miao");
    }
}
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("wang");
    }
}
public class PolyObject {
    public static void main(String[] args) {
        Animal animal=new Dog();//编译类型是animal,运行类型是Dog
        animal.cry();//因为运行时,执行到该行时,animal运行类型是Dog,所以cry就是Dog的cry;
        animal=new Cat();//运行到这行时,运行类型变成了Cat,所以cry变成了Cat的cry;
        animal.cry();
        //输出为
        //wang
        //miao
    }
}
多态的细节
  • 多态的前提:两个对象(类)存在继承关系
  • 多态的向上转型
    • 本质:父类的引用指向了子类的对象
    • 语法:父类类型 引用名=new 子类类型();
    • 特点
      • 编译类型看左边,运行类型看右边
      • 可以调用父类中的所有成员(需遵守访问权限eg:子类私有,父类则无法访问)
      • 不能调用子类中特有成员(属性+方法),因为编译阶段能调用哪些成员是由编译类型来决定的
  • 多态的向下转型
    • 语法:子类类型 引用名=(子类类型)父类引用;
    • 只能强转父类的引用,不能强转父类的对象
    • 要求父类的引用必须指向的是当前目标类型的对象
    • 可以调用子类类型中所有的成员
public class Person{
    public void run(){
        System.out.println("run");
    }
}
//学生是人:派生类、子类:学生
public class Student extends Person{
    public void eat(){
        System.out.println("eat");
    }
}
public static void main(){
    //一个对象的实际类型是确定的
    new Student();
    new Person();

    //但是可以指向的引用类型不确定
    Student s1=new Student();
    Person  s2=new Student();//父类型可以指向子类,但是不能调用子类独有的方法
    Object  s3=new Student();//Object是所有类的顶级父亲,也就是始祖
    //s1.run();父类有该方法可以调用
    // s2.eat();父类没有该方法,且不能调用子类的eat方法
    //((Student) s2).eat();强制类型转换,此时就可以用子类方法
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mosun_zgs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值