当前位置: 首页 > ds >正文

java基础学习(五):对象中的封装、继承和多态

目录

  • 一、封装
    • 1. 访问器
    • 2. 更改器
    • 3. 扩展
    • 4. javaBean类
  • 二、继承
    • 1. 什么是继承?
    • 2. 如何继承?使用什么关键字?
    • 3. 继承链(多级继承或多层继承)
    • 4. 方法重写
    • 5. supper
  • 三、多态
    • 强制类型转换

一、封装

对外隐藏(使用private),外界调用时,可读可写,通过方法控制。

  • 供外界访问的,叫访问器(getter)get
  • 供外界修改的,叫更改器(setter)set
  • private修饰意味着它只能在本类内部被直接访问,其他类不能对其进行访问,类似于对外界隐藏。

1. 访问器

示例1:只提供访问器,只可读取,不可修改

  • 在Cat类中,age属性被private修饰,age属性只能在Cat类中访问,外界(Test类)想要访问,需要提供访问器
  • 由于,只提供了访问器,那么,在Test类中获得了读取age值的公共方法,可以对其进行访问,但不能对其进行修改
    public class Cat {private static int age = 10;//访问器public static int getAge() {return age;}
    }
    
    public class Test {public static void main(String[] args) {Cat cat = new Cat();//读取System.out.println(cat.getAge());
    }//输出:10
    

2. 更改器

示例2:只提供更改器,只可修改,不可读取

  • 在Cat类中,age属性被private修饰,age属性只能在Cat类中访问,外界(Test类)想要修改,需要提供更改器
  • 由于,只提供了更改器,那么,在Test类中获得了修改age值的公共方法,可以对其进行修改,但不能对其进行读取
    public class Cat {private static int age = 10;//更改器public static void setAge(int age) {Cat.age = age;}
    }
    
    public class Test {public static void main(String[] args) {Cat cat = new Cat();//修改cat.setAge(12);//由于只提供了修改器,未提供访问器,所有不能读取
    }
    

示例3:同时提供更改器和访问器,即可修改,又可读取

  • 在Cat类中,age属性被private修饰,age属性只能在Cat类中访问,外界(Test类)想要修改并访问,需要提供更改器和供访问器
  • 那么,在Test类中即可读取age,又可能对其进行修改
    public class Cat {private static int age = 10;//访问器public static int getAge() {return age;}//更改器public static void setAge(int age) {Cat.age = age;}
    }
    
    public class Test {public static void main(String[] args) {Cat cat = new Cat();//读取System.out.println("修改前读取:" + cat.getAge());//修改cat.setAge(12);System.out.println("修改后读取:" + cat.getAge());
    }//输出:修改前读取:10//     修改后读取:12
    

3. 扩展

  1. 基本类型,不提供更改器,是不能进行修改的,因此,基本类型安全。
  2. 引用类型,不提供更改器,可以进行修改,因此,引用类型不安全。
  3. 引用类型中的String类型除外,它是安全的,String本身是不可变数组。

那么,引用类型的数据,不提供更改器,如何修改?
例如:数组

  • 返回为数组地址,将a指向数组地址(浅拷贝),那么a与arr指向的是同一空间,a进行修改,arr指向的数据也被修改。
    public class Cat {private int[] arr = {5,7,4,2,0};public int[] getArr() {return arr;//返回数组地址}
    }
    
    public class Test {public static void main(String[] args) {Cat cat = new Cat();int[] a = cat.getArr();a[0] = 10;a[1] = 100;System.out.println(Arrays.toString(a));System.out.println(Arrays.toString(cat.getArr()));}
    }//输出:[10, 100, 4, 2, 0]//     [10, 100, 4, 2, 0]
    
  • 既然,浅拷贝不行,那么,可以试着使用深拷贝,只把数值给你,不给地址。
    public class Cat {private int[] arr = {5,7,4,2,0};public int[] getArr() {int[] brr = new int[arr.length];for(int i=0;i<arr.length;i++) {brr[i]=arr[i];}return brr;}
    }
    
  • 输出结果:
    [10, 100, 4, 2, 0]
    [5, 7, 4, 2, 0]

4. javaBean类

一种定义类的规范。
类中的属性用private修饰,对外隐藏,并对外提供更改器和访问器,用这样定义的类是javaBean类。

二、继承

1. 什么是继承?

  • 继承是一种允许一个类(称为子类派生类)基于另一个类(称为父类基类超类)来构建的机制。
  • 核心思想:子类会自动获得父类得所有属性和方法,并可以在次基础上进行扩展,添加新的- 属性和方法,或者修改继续来得方法得行为。
  • java中的类仅支持单继承。
  • 单继承:一个子类只能有一个直接父类。
  • 子类可以调用父类的方法,但父类不可以调用子类的方法。

2. 如何继承?使用什么关键字?

  • 例如:有一个父类(Animal类),父类中有品种(variety)属性、年龄(age)属性、run()方法、eat()方法
    public class Animal {String variety;int age;public void run() {System.out.println("酷跑");}public static void eat() {System.out.println("吃肉");}
    }
    
  • 有一个子类(Cat类),要想继承父类,可使用extends关键字继承
    public class Cat extends Animal{……
    }
    
  • 使用测试类(Test类)来测试下Cat类是否正常得继承了Animal类
    public class Test {public static void main(String[] args) {Cat cat = new Cat();//继承父类得属性cat.variety = "狸花猫";cat.age = 2;//继承父类得非静态方法cat.run();//继承父类得静态方法cat.eat();System.out.println("品种:"+cat.variety+","+"年龄:"+cat.age);}
    }//输出:酷跑//     吃肉//     品种:狸花猫,年龄:2
    
  • 注意:
    • private修饰,子类不能继承
    • finale修饰,子类可以继承,但不能重写
    • 将父类的方法重写了,但依然想调用父类的方法,可以使用super()

3. 继承链(多级继承或多层继承)

  • 父类上边有父类,在上边还有父类等,比如:孩子 -> 父亲 -> 祖父 -> 曾祖父…
  • 上面举例使用的:Cat -> Animal -> Object,这就是一条继承链
  • object提供各种各样的方法:
    • equals()
    • clone()
  • 注意:继承链不是多继承,java不支持多继承。

示例:

  • 继承链:Cat -> Animal -> Earth -> Object
  • 祖父类Earth类
    public class Earth {public void affair() {System.out.println("事务");}
    }
    
  • 父类Animal类,Animal类继承Earth类
    public class Animal extends Earth{String variety;int age;public void run() {System.out.println("酷跑");}public static void eat() {System.out.println("吃肉");}
    }
    
  • 子类Cat类,Cat类继承Animal类
    • Cat类既可以调用父类中的各种属性和方法,也可以调用祖父类的各种属性和方法
      public class Cat extends Animal{}
      }
      
  • 测试类Test类
    public class Test {public static void main(String[] args) {//父类继承祖父类Animal animal = new Animal();animal.affair();System.out.println("--------------");//子类继承父类//子类调用父类的属性和方法Cat cat = new Cat();cat.variety = "狸花猫";cat.age = 2;cat.run();cat.eat();//子类调用祖父类的方法cat.affair();System.out.println("品种:"+cat.variety+","+"年龄:"+cat.age);}
    }
    //输出:事务
    //--------------
    //     酷跑
    //     吃肉
    //     事务
    //     品种:狸花猫,年龄:2
    

4. 方法重写

1)重写:发生在父子类中,是指在子类中重新定义从父类继承来的方法,以改变方法的行为

  • 方法签名必须一致,方法名、参数列表、返回类型相同
  • 访问权限不能比父类更严格
  • 一般会加@Override注释

2)例如:

  • 上面的Cat类,想要重写父类Animal类的run()方法
    public class Cat extends Animal{//重写父类run()方法@Overridepublic void run() {System.out.println("轻盈得跑");}
    }
    
  • 既然,在Cat类中重写了run()方法
    (子类继承父类的方法,进行了重写,那么子类不能直接调用父类的方法了,只能调用自己的方法)
  • 那么,测试类Test类中:cat.run();不在是继承父类,而是调用的Cat类中重写的run()方法,输出:轻盈得跑
  • 重写可以隔代,前提中间没有任何对它进行重写
  • 例如:
    • Cat类想要重写祖父类Earth类中的affair()方法
    • 前提是:Animal类没有对Earth类中的affair()方法进行重写
      public class Cat extends Animal{//重写祖父类affair()@Overridepublic void affair() {System.out.println("动物");}
      }
      
    • 在测试类中,cat.affair();不在是继承调用祖父类中的affair()方法,而是,Cat类中重写的affair()方法,输出结果为:动物

5. supper

如果,即对父类中的run()方法重写了,但又想调用父类的该方法

  • 方法一: 可以使用super关键字 -> super.方法名()
    • 在Cat类中使用super.方法名()
    • super.run();写在上面,则先输出父类,在输出子类;写在下面,则先输出子类,在输出父类
      public class Cat extends Animal{@Overridepublic void run() {super.run();System.out.println("轻盈得跑");}
      }
      
    • 那么,测试类Test类中cat.run();会先输出父类字输出子类:输出结果为:酷跑 轻盈得跑
    • 注意:
      • super:静态方法属于类,不能用于静态方法
      • 多层继承中的 supersuper永远指向直接父类,不能跨级调用
  • 方法二: 可以使用super()关键字 -> 调用父类构造方法
    • 在Cat类中调用父类构造方法
      public class Cat extends Animal{public Cat() {super();System.out.println("轻盈得跑");}
      }
      

super.方法名()super()的区别:

方法作用于作用位置参数
super.方法名()子类方法中调用父类被重写的方法在方法的任何地方
super()子类构造函数中调用父类构造函数必须是构造函数中的第一句语句可以有参或无参

三、多态

实现多态,要有三个条件:

  1. 要有继承:父类写的笼统写,子类写的具体实现
  2. 要有重写:子类对父类笼统的方法,重写去书写
  3. 父类的引用指向子类对象

示例:

  • 父类Animal类
    public class Animal {public void run() {System.out.println("动起来");}
    }
    
  • 子类Cat类,继承父类,并重写run()方法
    public class Cat extends Animal {@Overridepublic void run() {System.out.println("酷跑");}
    }
    
  • 子类Bird类,继承父类,并重新run()方法
    public class Bird extends Animal {@Overridepublic void run() {System.out.println("飞");}
    }
    
  • 测试类Test
    public class Test {public static void main(String[] args) {Animal animal;animal = new Cat();//多态,父类的引用指向子类animal.run();//输出:酷跑animal = new Bird();animal.run();//输出:飞}
    }
    

强制类型转换

  1. 基本类型:基本可以进行转换
    基本类型是以bit形式存储,可以进行转换
    int a = 20;
    short b = (short)a;
    
  2. 引用类型:父类和子类的关系,父类转换为子类
    Animal animal = new Animal();
    Bird bird = (Bird)animal;
    
  3. 使用多态,不会报错,但是执行有问题
  • 父类的引用指向子类Cat(),进行强制转换:想要将cat类型转换为bird类型
    Animal animal2 = new Cat();//多态,父类的引用指向子类Cat(),在堆中开辟的是cat类型空间
    Bird bird = (Bird)animal2;//想要将cat类型转换为bird类型,两个毫无关系,转换有问题
    System.out.println(bird);
    
  • 但是如果多态是父类的引用指向是Bird(),可以进行转换
    Animal animal3 = new Bird();
    Bird bird = (Bird)animal3;//转换没问题
    System.out.println(bird);
    
  • 多态是父类的引用指向孙子类NewBird()类,NewBird()类继承Bird()类
    NewBird() -> Bird() -> Animal()
    Animal animal4 = new NewBird();
    Bird bird = (Bird)animal4;//转换没问题
    System.out.println(bird);
    
  • 因此,只有想要转换的类型是目标类型的子孙后代,转换才没问题

如何判断谁是谁的子孙后代呢?
可以使用instanceof

Animal animal4 = new NewBird();
Bird bird;
if (animal4 instanceof Bird) {bird = (Bird)animal4;System.out.println(bird);
}
http://www.xdnf.cn/news/20448.html

相关文章:

  • C++经典的数据结构与算法之经典算法思想:排序算法
  • phpMyAdmin文件包含漏洞复现:原理详解+环境搭建+渗透实战(windows CVE-2014-8959)
  • 吴恩达机器学习(七)
  • 综合安防集成系统解决方案,智慧园区,智慧小区安防方案(300页Word方案)
  • 《2025国赛/高教杯》C题 完整实战教程(代码+公式详解)
  • 关于连接池
  • 【PostgreSQL】如何实现主从复制?
  • 网络原理-
  • 在Ubuntu平台搭建RTMP直播服务器使用SRS简要指南
  • Qt 基础教程合集(完)
  • 分布式数据架构
  • 硬件开发_基于物联网的老人跌倒监测报警系统
  • 数据结构——栈(Java)
  • MySQL数据库约束和设计
  • 附050.Kubernetes Karmada Helm部署联邦及使用
  • C++_哈希
  • 基于阿里云ECS搭建Tailscale DERP中继服务器:提升跨网络连接速度
  • 前端登录鉴权详解
  • C++面试10——构造函数、拷贝构造函数和赋值运算符
  • 西门子S7-200 SMART PLC:编写最基础的“起保停”程序
  • [特殊字符] 从零到一:打造你的VSCode圈复杂度分析插件
  • Linux内核源码获取与编译安装完整指南
  • Java8函数式编程之Stream API
  • 预闪为什么可以用来防红眼?
  • C/C++动态爱心
  • Caffeine Weigher
  • 蓓韵安禧DHA纯植物藻油纯净安全零添加守护母婴健康
  • 基于STM32智能阳台监控系统
  • Unity 如何使用ModbusTCP 和PLC通讯
  • 用 Go + HTML 实现 OpenHarmony 投屏(hdckit-go + WebSocket + Canvas 实战)