前言
大噶好我是渣渣辉~
咳错了,我是一名大三学生,迫于生计不得不开始学习java,现在是刚刚入门、勉强维持生计的样子。这里主要通过博客记录并分享自己的所学所得。早就听说社区的人长得又好看,说话又好听,所以我也非常希望可以和走过路过的大佬在留言区交流,如果能得到大佬们的指点,我将不胜荣幸。好了废话不多说了,下面我来聊一下我对java中继承与接口实现的理解。
类与继承
对于熟悉java和c语言的程序员来说,一定明白,同样是面对对象编程的两种语言,很多情况下两者的编程思想是非常相似的。所以大家对于类和继承的概念非常了解。笔者是通信专业的,大学前两年和C++语言打交道较多(当然,和计科、软件专业还是不能比的),因此在上手java、一上来就看到类和继承这两个名词时,便感觉分外亲切。对于类这里就不作赘述了,因为笔者从之前学习C++转到学习Java,这里更多地想和大家探讨一下Java和C++之间的一些区别,所以首先简单总结一下我所了解的Java和C++中继承的不同。
java和C++下继承的区别
其实两种语言中,对于继承的使用很多情况下是相似甚至是相同的,当然,这只是在一些特定的应用场景下。两者最大的不同在于子类继承的父类(或基类)的数量。
对于C++来说,同一个子类是可以继承多个父类的,而java则严格遵守单继承,即一个子类只能继承一个父类。所以C++中的继承可以理解为一个孩子可以同时继承爸爸和妈妈的基因( 这个比喻参考自C++继承与java继承之区别)而对于java来说,继承可以理解为一个孩子只能有一个亲生父亲,这样看来似乎java中的父类更名副其实些。下面通过代码让大家直观感受一下两者之间的区别。
C++中的继承示例
#include<iostream>
using namespace std;
class Parent_1{//父类Parent_1
private:
int x=1;//父类Parent_1的属性
public:
void getX()//通过函数getX()访问父类Parent_1的属性x的值
{
cout<<x<<endl;
}
};
class Parent_2{//父类Parent_2
private:
int y=2;//父类Parent_2的属性
public:
void getY()//通过函数getY()访问父类Parent_2的属性y的值
{
cout<<y<<endl;
}
};
class Child:public Parent_1,Parent_2{
public:
void getX_Y()//同时调用两个父类输出函数输出两个父类的属性值
{
getX();
getY();
}
};
int main()
{
Child child;
child.getX_Y();
return 0;
}
可以看到,对于C++来说,子类可以继承多个父类中的属性,也可以调用多个父类的方法。而java就不存在class child extends A,B这种继承方法,因此只可能继承一个父类的属性与方法。这里也就不贴代码了,反正会报错就是了(ˉ▽ˉ;)…
java和C++下继承的共同点
当然,对于同一个父类,是可以有多个子类的。在这一点上,C++和java达成了一致。就比如王者荣耀(本人是不玩的哈)中有很多英雄,他们都拥有姓名、攻击力等属性,同时有释放技能的方法,所以不同的英雄可以共同继承一个父类“Hero”。但是对于不同的英雄来说,这些属性与方法都是不同的,而一些英雄可能会有新的技能。这就引出了方法的重写以及新增两个概念,即:
- 子类可以重写父类属性与方法;
- 子类可以增加新的属性与方法。
需要注意的是,在重写父类的方法时,返回值类型和参数形式必须相同。简单来说重写方法时要注意以下两点:
- 要重写的方法所在的类与被重写方法所在的类之间要有继承关系;
- 要保证与原函数的返回值类型、函数名与参数完全相同(即Ctrl + C然后Ctrl + V)
我们注意到,一些情况下,可能某个类或对象会使用到多个类或对象里面的方法或属性。C++由于同一子类可以继承多个父类,意味着可以调用多个父类中的方法可以很好地解决这一需求。很明显,Java现有的单继承机制就不能满足要求。那么该如何解决这一问题呢?下面便引出了Java特有的具有更高灵活性的接口(implements)。
接口(interface)与接口的实现(implements)
事实上在Java中,接口和类有很多相似的地方。我们用class定义一个类,用extends去继承一个类,而对于接口,我们用interface去定义一个接口,而通过implements去建立对接口类的实现。
public class C{}//定义class类
public interface I{}//定义接口类
public class Child extends Parents{}//继承
public class Child implements I{}//接口的实现
那么它们的区别在哪里呢?
接口的实现和对象类继承的区别
事实上,接口的实现也是一种继承,所以这里主要探讨的是implements与extends之间的区别。
- 对象可以直接定义对象,而接口不可以。
我们看到在上面的四行示例代码中,只有class+类名的语法,而没有interface+类名的语法。因为接口是抽象类,就像其他抽象类一样,接口是不能直接定义对象的。要想使用接口中的方法,需要通过class类等继承接口并重写其中的方法才能使用。
- 对象类当中的方法(函数)可以写好也可以留空,而接口中的方法必须为空。
class类中我们确定某些函数要实现的功能时可以为该函数,而当我们不确定、或者该方法将来被多个子类继承时需要被重写为多个不同版本的新函数时,我们可以选择将其留空减少代码量。如下:
public class Person{
private int age;
private String name;
public int getAge(){//写好类方法getAge();
return age;
}
public void (){//方法留空,子类继承时如有需要可以重写方法
};
}
而接口则不同,接口中所有方法必须为空。以Java封装好了的监听器MouseMotionListener为例:
public interface MouseMotionListener extends EventListener {
public void mouseDragged(MouseEvent e);//注意,这里是连{}都没有的
public void mouseMoved(MouseEvent e);
}
- 非抽象类实现接口时,所有的方法都要被实现
我们用一个对象类继承另一个对象类时,可以选择不去重写其中的空方法。而当我们用一个非抽象类(如对象类)实现接口时,这些方法是都要重写的——这意味着一些方法即便你用不到,也要写进你实现接口的类中。
public class Mouse implements MouseMotionListener{
@Override
public void mouseDragged(MouseEvent e) {//重写鼠标拖动方法,当鼠标拖动时输出“拖动鼠标”
// TODO Auto-generated method stub
System.out.println("拖动鼠标");
}
@Override
public void mouseMoved(MouseEvent e) {//不会用到的方法也要实现一个空方法
// TODO Auto-generated method stub
}
}
对于系统封装的接口,大可不必担心自己不知道其中有哪些方法。一般来说编译器都会贴心地报错提示你并给出你"add unimplemented methods"(添加未被实现的方法)的选项。
- 一个子类可以实现多个接口,而继承(extends)只能继承一个父类
这一点就是我们在第一部分提到的子类多继承问题。要指出的是,一个类可以在继承一个对象类父类的同时,是可以在实现多个接口的。
public class Mouse extends P implements MouseMotionListener,MouseListener
上面这段代码中,子类Mouse继承了对象类父类P的同时也实现了两个接口。这种机制给了Java很大的灵活性。
- 当父类实现一个接口时,其子类默认实现其接口
另外对于接口的属性,当某一对象类实现一个接口时是可以直接访问其属性的,而这也意味着属性不能为空,在定义含属性的接口时,必须为其属性赋初值。而在使用接口还要注意到,在我们定义接口的时候,如果interface前面加了关键字public,那么这个public接口是可以被可以被任何一个类实现的(跨包)。而如果不加public的话。那么这个接口只能被与该接口同一个包中的类实现,这种接口被称为友好接口。
以上便是我对于继承与接口实现这一块的大致总结吧,第一次写博客,可能思路会有些乱,作为技术小白也可能会出现一些低幼的技术问题,还请各位走过路过的大佬看到后指出。最后,希望可以和大家在评论区中友好交流~
-end-