Java第六章学习心得

本文深入探讨面向对象编程中的关键概念,包括对象间的消息传递、组合与继承的区别及其应用场景。讲解了Java中的运行时多态、自定义equals方法的覆写,以及instanceof运算符的使用。同时,对比了抽象类与接口的异同及适用场景,帮助读者深化对面向对象编程的理解。
摘要由CSDN通过智能技术生成

转眼间就学到了第六章了,作为”面向对象“的最后一个板块,涉及到了很多较为复杂和抽象的知识点,也和C++中的类的知识点有或多或少的联系。今天惜惜就和大家一起回顾一下这一章里的重要知识点叭~

目录

1.如何实现两个对象之间互发消息?

2.组合与继承的区别以及两者的使用场景(即什么时候宜用组合 ?什么时候宜用继承?)

3.Java中的运行时多态的含义是什么?有什么作用?

4.自定义一个类,覆写equals方法,以满足自身业务需求

5.举例说明运算符instanceof的使用场景。

6.谈谈抽象类与接口的异同以及两者的使用场景。

1.如何实现两个对象之间互发消息?

答:使用this指针

事实上this的用法有三种:用法一,表示当前对象引用,常用于形参或局部变量与类的成员变         量同名的情形,使用this.成员名表示当前对象的成员;用法二,表示当前对象,常用于对象的互发消息;用法三,调用当前类的构造方法。这里使用的是第二种用法,即:表示当前对象。

举个栗子~

 先为观众姥爷们端上运行结果

开炮!!!

是的,这里没有“开火”,因为a.invoke();被惜惜注释掉了哦!嘻嘻,嘻嘻,嘻嘻嘻,嘻~

这里输出的“开炮”来源于构造方法。如果我们把这一句的注释取消的话,那么就会出现“开火”这一句了。注意,当执行到A a=new A(ftp)的时候,采用A的构造方法来初始化new出来的对象(后半句)。但是需要注意,此时还没轮到a上场,所有的事情和a没有任何关系,因为这个对象还没有被构造完,也就不能执行左半句。那么没有引用的话,该怎么表示这个对象呢?使用this就可以了,也就是在前面提过的用法二。此后,使用fpp.set(A),将A对象的引用传递给fpp对象,这样fpp有了A的引用;而A的构造方法中,第一句表明了A有了fpp的引用,则两者互相拥有了对方的引用,就好像两个人互相有了对方的电话号码一样,于是就可以互发消息了。

2.组合与继承的区别以及两者的使用场景(即什么时候宜用组合 ?什么时候宜用继承?)

答:组合强调“has-a”的关系,而继承强调“is-a”的关系。

组合是把某个类的对象作为另一个类的成员组合起来,用来实现“另一个”类的功能,使用的时候你看到的是“另一个”类的方法,而不能看到“某个”对象的方法(因为被覆盖了)。因此,通常要在“另一个”类中使用private来修饰“某个”类的对象以防止被修改。

那么就有这样一个疑惑了:组合和继承的区别?

组合强调“has-a”的关系,而继承强调“is-a”的关系。举例,鸟不是飞机,飞机不是鸟,但是鸟和飞机都可以飞,因此“飞”这个属性,就具备被重用的可能,可以不加修改直接被所有能飞的东西统用。假设“飞”这个属性有1000行代码,现在鸟类已经写好,需要写飞机类。显然我们不能使用继承的方法,一方面继承会显得不伦不类,另一方面,有很多属性鸟具有但是飞机不具有,一旦继承,那么鸟类所有的不属于飞机的方法也要写,这是多余而完全没有必要的。

你打算重新写一遍这个“飞”的属性吗?(不许重写,你敢重写我就敢吃了你(╯▔皿▔)╯)

不过,既然有现成的东西,那肯定不能放过。这个时候就体现出来组合的好处了。飞机其他属性照写不误,等到飞的时候,就直接使用鸟类的飞(注意飞机类的数据成员中有鸟类对象)。这样就实现了代码重用。


3.Java中的运行时多态的含义是什么?有什么作用?

答:这个问题在当初学习的时候,曾专门写过一篇理解,这里就不再写一遍辣~惜惜鞠躬~

多态

   多态是指一个程序中,同名不同方法共存的情况。看来计算机区分方法不仅仅依靠方法名,这在之后将会讨论。

   Java中提供两种多态的机制:重载(overloading)与覆写(overriding)

  1. 重载

重载:方法名称相同,参数类型个数不同

编译器视角:

方法签名=方法名称+参数类型+参数个数

组成唯一键。并不以返回值类型不同而区分不同的方法。这比较好理解,不再额外举例。

事实上,同一个类中通常会提供多个重载方法,以供传参情况不同时区别使用。Java内部有一个名为addAll的函数,就有两种形式,第一种,参数只有一个为Collection类的对象c;第二种在第一种的基础上多一个参数为int类的对象index。具体功能与主题无关,这里不展开叙述。

    最后再补充一句,重载只需要一个类即可完成,并不一定需要继承后再重载。

  1. 覆写

子类对父类的同名方法(方法名称相同,参数相同,返回类型相同)重新进行定义,即在子类中定义与父类中已定义同名而内容不同的方法。

此外,覆写时子类的返回类型可以向上转型到父类的返回类型。

我们约定,在java代码中,如果你对父类的某一个方法进行了覆写,则需要在覆写的地方进行标注“@Override”

这里的理解需要花一点时间,详细可参见对本节代码图片的解释。(多态1,2,3)

多态1:正常代码,作为覆写的示例。传进去的参数无意义,仅仅用于调用正确的函数,而子类实现了对父类的覆写,因此最终结果为8.

多态2:出现错误,名称为“正在尝试分配更低的访问权限”

多态3:仍可正常运行。

(暂时不存在的多态4:)如果不在一个包内,那么由于父类无修饰符,只有包访问权限,因此子类将无法访问父类,更无法继承,代码必将报错。

现在我们给出覆写需要满足的条件:

  1. 子类的访问修饰符权限应等于或大于父类,不能变小(如多态2中错误所示)

2.子类的返回类型能够向上转型成为父类的返回类型(如多态3中所示)

3.异常也要能向上转型为父类的异常

4.方法名、参数类型及个数必须严格一致

注意:

覆写只能针对非静态、非final、非构造方法

在JDK中,很多父类的方法被子类重新覆盖,赋予了不同的含义,如Object类中的boolean equals(Object obj)方法

4.自定义一个类,覆写equals方法,以满足自身业务需求

从前有一个非常热心善良而且喜欢吃(zuo)小(gong)孩(yi)的小姑娘叫妤溪,有一天她要帮自己上幼儿园大班的弟弟宇西写家庭作业,作业的任务是判断给定的一个数的奇偶性是否和约定的数相等。老师布置了10000道题,然而妤溪写了3道题就觉得太无聊了,所以她写了一个小小的程序来帮自己解决这个棘手的问题,然后她去看动画片惹~

 听说你们想知道后续?

后续就是妤溪和羽惜一起看她们最喜欢的《精灵梦叶罗丽》

别问我宇西去哪里了hhh

5.举例说明运算符instanceof的使用场景。

答:instanceof是java的一个关键字,使用方法是:a instanceof (class)b。其中a是某个对象的引用,b是某个类名,返回值是boolean类型,用于判断a是否是b类的对象或b类的子类的对象。如果是,就返回true,否则返回false。通常用于在对象的强制类型转换的时候,进行判断。

上图~

 

 6.谈谈抽象类与接口的异同以及两者的使用场景。

答:这个依然是使用之前已经写过的一版,有点点长,见谅啦~惜惜鞠躬~

抽象类:用abstract修饰的类称为抽象类,用abstract 修饰的成员方法称为抽象方法。

当然,抽象类也有自己的规矩。

1.抽象类中可以有零个或多个抽象方法,也可以包含非抽象方法只要有(至少)一个抽象方法,那这个类就是抽象类,类前就必须有abstract修饰。

2.抽象类不能创建对象,(例如,Shape类是抽象类,那么不可以写“Shape s=new Shape();”因为这样创建了一个抽象类的对象。)创建对象由具体子类来实现,但可以有声明(同样是上面的Shape类,写“Shape s;”就是可以的),声明能引用所有具体子类的对象。(例如Shape类派生出具体的子类Rect,Circ,Tria,那么,在写了“Shape s;”之后以下的写法都是正确的:s=new Rect;s=new Circ;s=new Tria;)

3.对于抽象方法,在抽象类中只指定方法名及类型,而不写实现代码。抽象类必定要派生子类,若派生的子类是具体类,则具体子类必须实现抽象类中定义的所有抽象方法(覆写)。

4.在抽象类中,非抽象方法可以调用抽象方法

5.abstract不能与final并列修饰同一个类(产生逻辑矛盾);

abstract 不能与private ,static(因为static修饰的方法必然被直接调用),final或native并列修饰同一个方法。

有了抽象类之后,就可以很好的解决代码冗余的问题。比如,要编程求解长方形,三角形,圆形的周长和面积,则可以设计一个名为图形的抽象类,其中含有统一设置的数据成员,抽象方法“计算面积”和“计算周长”,还有打印方法。

再次强调,抽象类可以有自己的数据成员,也可以有自己的构造方法。这是与接口很不一样的地方。

注意对抽象类的设计,尽可能抽出他们的共同点进行设计,否则会对派生出来的子类有着或多或少的不好影响。

接口

接口有两种含义:一是可以被引用调用的方法(public方法或同包中的protected方法或默认方法),举例,比如一个类中可能有一些私有数据成员不允许外界直接访问,但是设置了公有函数,且return值为私有成员的值,这个时候我们就说这个公有函数就是外部和类交互的接口。二是同“类”概念地位相当的专有概念interface, interface是方法说明的集合。

声明格式:

public interface InterfaceA {

   public static final int ON = 1;

   public abstract void a();

}

public interface InterfaceB {

   public abstract void b();

}

public interface InterfaceC extends InterfaceA, InterfaceB {//接口可以多重继承

   public abstract void c();

}

当一个接口想要被实现的时候,使用Implements

当一个接口需要继承其他接口的时候,使用extends

注意事项:

  1. 接口定义用关键字interface,而不是用class;interface前的修饰符要么为public,要么为缺省
  2. 在类中,用implements关键字来实现接口。一个类可以实现多个接口,在implements后用逗号隔开多个接口的名字。一个接口也可被多个类来实现。
  3. 接口具有继承性,可通过extends关键字声明接口的父接口列表。
  4. 接口定义的数据成员全是public final static(静态常量),即使没有修饰符。存储在该接口的静态存储区域内,使用接口名.字段或实现类.字段均可访问。
  5. 接口中没有构造方法所有的方法都是抽象方法,且都是public abstract 方法(与抽象类有所不同)。即使没有修饰符,其效果完全等效。注:方法前不能修饰为final。(显而易见,final要求这个方法不能被修改,但是接口中的方法都是抽象方法,抽象方法要求被具体实现,也就是被修改,自相矛盾。)
  6. 如果实现某接口的类不是abstract修饰的抽象类,则在类的定义部分必须实现接口的所有抽象方法,而且方法头部分应该与接口中的定义完全一致。
  7. 如果实现接口的类是abstract类,则它可以不实现该接口的所有方法。但对于抽象类的任何一个非抽象的子类而言,接口中的所有抽象方法都必须实现。(与6实际上说的是一样的。)
  8. 类在实现接口的抽象方法时,必须显式使用public修饰符,否则将被警告为缩小了接口中定义的方法的访问控制范围。

接口有什么用?

接口扮演将实现者和使用者有机联系到一起的角色。

下面我们来定义并实现一个接口:

public interface  Washer {//接口定义用关键字interface修饰符要么为public,要么为缺省,这里为public,没问题。

    public static final int ON = 1 ;

    public static final int OFF = 0 ;

    abstract void startUp();     //启动  

    abstract void letWaterIn();  //进水

    abstract void washClothes(); //洗衣

    abstract void letWaterOut(); //排水

abstract void stop();        //停止

注意,如果没有修饰符,那么就和public修饰符等效。因此,可以发现所有的方法都是抽象方法,且都是public abstract 方法

}//至此接口定义完成。

下面写一个类来实现这个接口:

class RoseBrand implements Washer{

    public  void //类在实现接口的抽象方法时,必须显式使用public修饰符startUp(){ System.out.println("startUp");}

    public  void letWaterIn(){System.out.println("letWaterIn");}

    public  void washClothes(){System.out.println("washClothes");}

    public  void letWaterOut(){System.out.println("letWaterOut");}

public  void stop(){System.out.println("stop");}

//到这里这个具体类已经实现了接口的所有抽象方法

    public  void dehydrate(){System.out.println("dehydrate ");}//脱水

}

实现以后,来使用这个接口:

public class Consumer {

  public static void main(String args[]){

      //接口声明引用实现接口的RoseBrand类的对象。

      Washer  w = new RoseBrand();

      w.startUp();

      w.letWaterIn();

      w.washClothes();

      w.letWaterOut();

      w.stop();

      //w.dehydrate ();当通过接口调用玫瑰洗衣机类独有的,  

                     //接口未定义的功能方法,编译会报错。

  }  

}

我们可以理解为:一切物体都是由数量极为庞大的属性组中选择几个属性组合起来而形成的。例如,这个世界,有“飞”的属性——一些东西可以飞;有“吃”的属性——一些东西可以吃别的东西;有“打电话”的属性;有“脱水”的属性。。。

现在,我们发现某两个物体之间,并没有继承关系,但是他们却又有很多相似甚至相同的属性。那么,相同就应该想办法用函数来替代,但是因为不适合继承使得无法通过多态来实现,那么,为了解决这种问题,接口就诞生了。

鸟可以飞。飞机可以飞。鸟和飞机都可以飞。但是鸟和飞机之间不适合用继承,所以将飞作为属性抽象出来。这样的好处在于,如果某一个实例化对象失效了,并不影响其他对象对共同方法的复用,毕竟他们的“共同的祖先”是“虚无的”,是“永恒的”也就不会失效,顶多是“子类”不再全部拥有这些属性。

接口可以多重继承,这是它比抽象类最大的好处。

好啦!这一章就分享到这里辣~

六千多字属实不易,所以可以动动小手点个关注嘛?(超乖)

惜惜鞠躬~溪溪鞠躬~西西鞠躬~

下回再见啦,拜拜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值