详解Java中的封装、继承、多态
作者:追梦子 发布时间:2022-09-24 06:26:23
封装
在如何理解面向对象这篇文章中,提到所谓的封装就是“功能都给你做好了,你不必去理解它是怎么写出来的,直接使用即可。”。但你得清楚一点,那就是这句话是相对于使用者来说的,而作为开发者,封装就得我们自己来干。
那么作为开发者,我们应该如何去封装呢?其实你应该反过来问,他们应该如何去使用,这样一想会简单很多,作为使用者,自然是希望越简单越好,也就是说,一些复杂的东西,我们不应该让使用者去操作,那也就是说我们应该把复杂的,以及不必要的参数给它封死,不让使用者去操作。
为什么不让使用者去操作?
因为往往使用者是不太专业的,如果暴露太多的接口给他们,就很有可能出现一些稀奇古怪的问题,好比一个不会做水煮鱼的,如果让他去做那肯定是不好的,那怎么办,给他买一包水煮鱼的调料,让他直接放进锅里就好,这样就减少了不必要的麻烦。我们封装程序也是这样,把复杂的代码封死,不让操作者去操作,以免出错。
比如下面这个例子:
class Average{
private int[] fractions = new int[3]; //分数
private int average = 0; //平均分
public void setFraction(int[] fraction){
fractions = fraction;
}
public double getAverage(){
for(int cell:fractions){
average += cell;
}
return (double) (average / fractions.length);
}
}
class app{
public static void main(String[] args){
int[] a = {50,40,50};
Average average = new Average();
average.setFraction(a); //设置分数
double n = average.getAverage(); //获取平均分
System.out.println(average.average); //报错
System.out.println(n); //46.0
}
}
提示:Java通过private设置私有变量,通过public将变量设置成公开的。
这里我们之所以将分数和平均分设置成私有变量是为了防止使用者误操作,而且也不必让使用者知道有这么一个变量,只需要让使用者知道怎么去设置分数,和获取平均分就好了。
当然这只是一个很基础的封装,如果想封装出一个好的程序,还得多费一些心思。
继承
拿猫和狗来说,它们都是动物,而且它们有一些共同点,比如:名字,年龄,声音,吃等。把这段话写成代码就是下面这个样子。
class Animal{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
class Cat extends Animal{
public void voice(){
System.out.println(super.getName() + " 喵");
}
public void eat(){
System.out.println(super.getName() + " fish");
}
}
class Dog extends Animal{
public void voice(){
System.out.println(super.getName() + " 汪");
}
public void eat(){
System.out.println(super.getName() + " Bone");
}
}
class app{
public static void main(String[] args){
Cat cat = new Cat();
cat.setName("猫大王"); //Cat本身没有setName方法,但是它的基类有,所以java解析器会到Cat的基类那里拿
cat.voice();
Dog dog = new Dog();
dog.setName("大黑");
dog.setAge(13);
dog.voice();
System.out.println(dog.getName() + dog.getAge());
}
}
------Output------
猫大王 喵
大黑 汪
大黑13
提示:Java通过extends关键字来实现继承,父类中通过private定义的变量和方法不会被继承,也就是你不能在子类中直接操作父类通过private定义的变量以及方法。
在上面代码中,我们可以看到,Cat和Dog并没有定义setName、setAge、getName、getAge方法,但是我们依然可以在Cat和Dog类中使用,这是因为我们通过extends关键字继承了Animal类,因此在Animal中定义的变量和方法,我们可以在子类中直接使用,除private定义的变量和方法。
反过来说,姓名和年龄是猫和狗的基本信息也是它们的共同特性。
重写父类方法或变量
一般重写父类方法,是因为你把猫当成是一个基类,而将狗继承自猫类。看似这很好笑,但如果你去翻翻你的代码,这种情况多如牛毛。当然,如果你不需要继承,那就另说了。那么如果碰到这种情况,我们怎么重写基类呢?很简单,在子类中定义一个和父类中一样的方法,如下面这样:
class Animal{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
class Dog extends Animal{
public String getName(){
return super.getName() + "2";
}
public void voice(){
System.out.println(super.getName() + " 汪");
}
public void eat(){
System.out.println(super.getName() + " Bone");
}
}
class app{
public static void main(String[] args){
Dog dog = new Dog();
dog.setName("大黑");
System.out.println(dog.getName()); //执行的是Dog中的getName方法
}
}
提示:通过super可以在子类中直接调用父类的方法以及变量,通过this调用当前类。
我觉得把这叫做重写不太好,因为如果从本质来讲,它不算重写,只是Java寻找变量以及方法的规则罢了。Java会先看一下,自己身上有没有某个变量或方法,如果没有,它会接着到父类中找,如果父类中还是没有,那么它又会到更上一级中找,如果一直找上去都没有,那么才报错。
在重写父类时,需要注意一下,重写时,方法的返回值类型必须和父类中定义的一致,如果是数字类型,只要重写时类型不大于父类中定义的,那么也是可以的。比如下面这样就会报错
class Animal{
private String name;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
class Dog extends Animal{
public int getName(){ //和父类中的getName返回值不同,报错
return 123;
}
}
class app{
public static void main(String[] args){
Dog dog = new Dog();
System.out.println(dog.getName());
}
}
另外还需要注意,如果重写时,和父类中的参数不一致,则会发生意想不到的事,比如下面这个
class Animal{
private String name;
public void setName(String name){
this.name = name;
}
public String getName(String hello){
return this.name + hello;
}
}
class Dog extends Animal{
public String getName(){
return "123";
}
}
class app{
public static void main(String[] args){
Dog dog = new Dog();
dog.setName("大黑");
System.out.println(dog.getName("hello"));
}
}
------Output------
大黑hello
可以看到当我们给getName传达了参数时,执行的是Animal中的方法,而非Dog中的getName方法,也就是说如果参数不一致最后执行的可能就不是重写的那个方法。另外也不可将父类公开的方法或变量改成私有(如将public改成private),否则也会报错,我估计是Java有一套覆盖规则,如果没有达到条件就不会进行覆盖。
总结来,覆盖父类方法或变量时,对其只能更宽松,而反过来则不行。
多态
先来几个例子,再讲理论
class Animal{
public int age = 5;
public int getAge(){
return age;
}
}
class Dog extends Animal{
public int age = 8;
public int getAge(){
return age + 2;
}
}
class app{
public static void main(String[] args){
Animal dog = new Dog();
System.out.println(dog.age);
}
}
------Output------
5
看Animal dog = new Dog();这么一句话,可以发现它们的类型并不一样,但却可以正常运行,之所以可以运行是因为,Dog类是Animal的子类,而父类是包括子类的。我们说动物,那么狗是不是就是动物中的一员呢,这是肯定的,而这里之所以如果运行也正是这个理。
不过需要注意一下,通过这种方式创建的对象,在获取实例变量时,获取到的是父类中的实例变量,如果是方法,则看子类中是否存在和父类中同名的方法,如果存在则使用子类中的方法,但是如果子类中有某个方法,而父类中没有,那么就会报错。如下这段代码就会报错
class Animal{
public int age = 5;
public int getAge(){
return age;
}
}
class Dog extends Animal{
public int age = 8;
public int getAge(){
return age + 2;
}
public setAge(int a){
this.age = a;
}
}
class app{
public static void main(String[] args){
Animal dog = new Dog();
System.out.println(dog.setAge(5));
}
}
因为父类中没有setAge这个方法,因此会报错。
也就是说,通过这种方式来写,只能达到覆盖方法的效果,没有其他的功能。
这里所谓的多态,在程序中你可以理解成,一个方法,它可以有不同的效果,那怎么实现不同的效果呢?在java中通过切换类型来实现(不一定正确)。
多态有什么用?
还是再来看几个例子吧
class Animal{
public int age = 5;
public int getAge(){
return age;
}
}
class Dog extends Animal{
public int getAge(){
return age + 2;
}
}
class Cat extends Animal{
public int getAge(){
return age + 3;
}
}
class app{
public static void main(String[] args){
Animal dog = new Dog();
Animal cat = new Cat();
System.out.println(dog.getAge());
System.out.println(cat.getAge());
}
}
------Output------
7
8
可以看到,它会根据自身执行不同的方法。不过话说回来,这并不能代表什么,毕竟我们按照正常情况来创建,效果也可以一样,不过还真有它的用武之处,比如下面这段代码
class Animal{
public int age = 5;
public int getAge(){
return age;
}
}
class Dog extends Animal{
public int getAge(){
return age + 2;
}
}
class Cat extends Animal{
public int getAge(){
return age + 3;
}
}
class app{
public static void main(String[] args){
Animal[] animals = new Animal[2];
animals[0] = new Dog();
animals[1] = new Cat();
System.out.println(animals[0].getAge());
System.out.println(animals[1].getAge());
}
}
------Output------
7
8
这段代码和上面一段差不多,不过这段代码中用的是一个数组,这种情况就比较适合使用多态了,不然好像没有其他办法来弄了吧(初学java,不太懂)。在这里面多态不仅仅只是指一个方法有不同的效果,在这里还指类型的多样性。
来源:http://www.cnblogs.com/pssp/p/6292665.html


猜你喜欢
- 和室友参加的互联网大赛要做一个 APP,涉及到用户的登录注册,于是上网找了许多资料,其中有阿里大于,网易云等等,阿里大于的客服给我说他们不支
- 介绍: Mybatis-Plus(简称MP)
- maven使用过程中无法导入依赖的一些总结作为一名java开发的新手,在学习中难免遇见各种问题,在此总结一下。在使用maven过程中总是碰见
- JPA自定义VO类型转换(EntityUtils工具类)在JPA查询中,如果需要返回自定义的类,可以使用EntityUtils工具类,该类源
- 1、需要引入依赖<dependency> &l
- 界面中控件较多的话,每个控件都设置setOnClickListener(this)是很麻烦的,为此抽出了一个Context的扩展类:fun
- 本文实例为大家分享了Android实现跟随手指画圆的具体代码,供大家参考,具体内容如下首先自己定义一个View子类:package com.
- 二、简介多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力,但频繁的创建线程的开
- 前言Bitmap相信对各位Android开发者们来说都不陌生,用它可以获取图片信息,进行图片剪切、平移、旋转、缩放等操作,并可以指定格式保存
- 引言在高并发的场景下,异步是一个极其重要的优化方向。前段时间,生产环境发生一次事故,笔者认为事故的场景非常具备典型性 。写这篇文章,笔者想和
- 尝试了各种防止中文乱码的方式,但是还是乱码;最后还是细节问题导致;解决方式:以及俩种方式是百度的,我的问题不是这俩块1.在requestMa
- 1、@Valid与@Validated的区别1.1 基本区别@Valid:Hibernate validation校验机制@Validate
- 项目中有几个batch需要检查所有的用户参与的活动的状态,以前是使用分页,一页一页的查出来到内存再处理,但是随着数据量的增加,效率越来越低。
- 1.创建动画控制器,双击打开动画控制器,创建 状态并添加动画片段,并且状态与状态之间进行连线,往返的都要有,在Animator的左上角–Pa
- 本文实例为大家分享了Android实现声音采集回声与回声消除的具体代码,供大家参考,具体内容如下一、回声产生的原因回声(或称回音)是指障碍物
- 数组分页查询出全部数据,然后再list中截取需要的部分。mybatis接口List<Student> queryStudents
- 概述1、邮件相关的标准厂商所提供的 JavaMail 服务程序可以有选择地实现某些邮件协议,常见的邮件协议包括:SMTP(Simple Ma
- 页面报错:后台错误:Field error in object 'user' on field 'birthday&
- 上一节是把大概的流程给过了一遍,但是还有很多地方没有说到,后续的慢慢会涉及到,敬请期待!这次我们说说垃圾收集器,又名gc,顾名思义,就是收集
- Intent是一种运行时绑定(run-time binding)机制,它能在程序运行过程中连接两个不同的组件。通过Intent,你的程序可以