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

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://InTQdvse.kqkmx.cn
http://TCN3Aj9L.kqkmx.cn
http://7yN3PToG.kqkmx.cn
http://wpKZKShj.kqkmx.cn
http://Yvf5F8eA.kqkmx.cn
http://T6VkRlLo.kqkmx.cn
http://elfJn9rx.kqkmx.cn
http://1J6EOnRw.kqkmx.cn
http://AKvwlH0T.kqkmx.cn
http://csQgbBV1.kqkmx.cn
http://zCDYfZ6t.kqkmx.cn
http://wo9AGyh9.kqkmx.cn
http://clRgDqeD.kqkmx.cn
http://eH9qRErB.kqkmx.cn
http://n1Nm1qYF.kqkmx.cn
http://RQYbFSrY.kqkmx.cn
http://W8LTbATy.kqkmx.cn
http://OYSqptJV.kqkmx.cn
http://0fMmgftR.kqkmx.cn
http://zNvslYDn.kqkmx.cn
http://5ReU5yQt.kqkmx.cn
http://R7vcnPnb.kqkmx.cn
http://bYQf1MzB.kqkmx.cn
http://RUUT6pqp.kqkmx.cn
http://BdnlrD7F.kqkmx.cn
http://74ZBwqTw.kqkmx.cn
http://neiLUBKN.kqkmx.cn
http://QYYHJWvV.kqkmx.cn
http://uK7selJ6.kqkmx.cn
http://HRh4F1MR.kqkmx.cn
http://www.dtcms.com/a/370126.html

相关文章:

  • 神马 M66S+ 282T矿机参数详解:SHA-256算法与Hydro冷却技术
  • AI 生成式艺术重塑动漫角色创作:从技术逻辑到多元可能性(一)
  • c++primer 个人学习总结-模板和泛型编程
  • solidity的高阶语法2
  • 9.FusionAccess桌面云
  • SpringBoot集成XXL-JOB保姆教程
  • Linux 网络流量监控 Shell 脚本详解(支持邮件告警)
  • 阿里云对象存储OSS的使用
  • WSL2环境下因服务器重装引发的SSH连接问题排查记录
  • 02-Media-6-rtsp_server.py 使用RTSP服务器流式传输H264和H265编码视频和音频的示例程序
  • I/O 多路复用 (I/O Multiplexing)
  • Nginx性能调优:参数详解与压测对比
  • java接口和抽象类有何区别
  • C/C++动态爱心
  • YOLOv8 在 Intel Mac 上的 Anaconda 一键安装教程
  • 关于 React 19 的四种组件通信方法
  • Joplin-解决 Node.js 中 “digital envelope routines::unsupported“ 错误
  • [论文阅读] 软件工程 - 需求工程 | 2012-2019年移动应用需求工程研究趋势:需求分析成焦点,数据源却藏着大问题?
  • sensitive-word 敏感词性能提升14倍优化全过程 v0.28.0
  • 留数法分解有理分式
  • 基于FPGA的汉明码编解码器系统(论文+源码)
  • C++经典的数据结构与算法之经典算法思想:排序算法
  • 大恒-NF相机如何控制风扇
  • 01.单例模式基类模块
  • 数位DP -
  • kotlin - 2个Fragment实现左右显示,左边列表,右边详情,平板横、竖屏切换
  • 基于SpringBoot+Thymeleaf开发的实验室助理工作管理系统
  • 手写MyBatis第53弹: @Intercepts与@Signature注解的工作原理
  • 基于SpringBoot+JSP开发的潮鞋网络商城
  • docker run 命令,不接it选项,run一个centos没有显示在运行,而run一个nginx却可以呢?