继承
- 为什么要继承呢?
- 继承的语法
- 继承的概念
- 子类中访问父类性质
- Java的单继承
- super和this
- 子类构造方法
- protected中super的使用
- final关键字
今天我们来说说面向对象的又一特征:继承!
为什么要继承呢?
class Dog{
public String name;
public int age;
public void eat(){
System.out.println(this.name+"正在干饭");
}
public void wangwang(){
System.out.println(this.name+"正在狗叫");
}
}
class Bird{
public String name;
public int age;
public void eat(){
System.out.println(this.name+"正在干饭");
}
public void fly(){
System.out.println(this.name+"正在辉");
}
}
兄弟们应该可以理解,我在这里面创建了两个与动物相关的类,不难发现,无论是狗还是鸟,都有名字年龄属性,都有eat这个方法。此时我们的代码中就会因为有着无效重复而显得有点冗余。因此我们试图把这两个类中的共性抽取出来,给它放到一个新类中:
class Animal{
public String name;
public int age;
public void eat(){
System.out.println(this.name+"正在干饭");
}
}
class Dog{
public void wangwang(){
System.out.println(this.name+"正在狗叫");
}
}
class Bird{
public void fly(){
System.out.println(this.name+"正在辉");
}
}
兄弟们可能看不到具体的效果:
因为目前我们只是把共性抽取了出来,并没有做出进一步的操作,所以我们艾阿猫阿狗类中就只剩下了自己特有的性质了,那怎么办呢?
继承的语法
我标题中的Extends 并不是继承的英文,而是我们在表示继承关系中用到的关键字!
class Bird extends Animal{
class Dog extends Animal{
加上这两行,就算是磕过头敬过茶认了干爹了!
虽然看上去简洁,但是我们还是需要对继承的语法进行一定的讲解 :
A extends B可以读作:子类继承了父类,也可以理解成:A is B——狗是动物,这句话天王老子来了都没毛病吧……
A叫做子类,也可以叫做派生类;B是父类,也可以叫做基类、超类。
看到没兄弟们,本来我们的子类中是没有姓名年龄属性的,但是我们继承了Anima这个父类之后,就会自动继承父类中的属性和方法,这里当然也是继承了eat方法啦,就不给兄弟们演示了。
继承的概念
我们现在已经是可以上使用继承了,那么兄弟们能不能试着描述一下继承呢?
其实我们完全可以用自己的话来组织一下:继承其实就是对子类中一些共性的抽取,那么在子类中只保留了它独特的性质,从而达到了代码复用的效果!
子类中访问父类性质
Dog dog=new Dog();
dog.name="cyt";
System.out.println(dog.name);
我们由简入难,现在我们的子类中没有和父类同名的属性方法,一句话:我们使用子类对象的引用想要点出来一些性质的时候,优先在子类中寻找,在子类中确定了没有这个性质就去父类中康康有没有继承过来,如果连父类中都不存在,那么就会编译错误。
对于不重名的只要牢记这个性质就足矣。
那么对于那些重名的呢?
class Animal{
public String name="animal";
public int age;
public void eat(){
System.out.println(this.name+"animal的正在干饭");
}
}
class Dog extends Animal{
public String name="dog的";
public void wangwang(){
System.out.println(this.name+"正在狗叫");
}
public void eat(){
System.out.println(this.name+"dog的正在干饭");
}
}
我们从结果中可以很清楚地看到,无论是属性还是方法,我们使用的统统都是在子类中跟父类重名的那个,所以连编译器都在告诉我们:做人要自私一点,要多为自己想想,那你为什么还放不下早就不在的那个人呢?
在这边阿涛学艺不精,不是很会我老师搞得那一套,他是直接三两下搞到了底层,然后在蓝色的框框里面给我们看编译的具体过程,我给兄弟们描述一下吧:在编译的时候,显示出来的我们使用的仍然还是父类的属性和方法,因此我们说的现在的情况可以用运行时绑定来解释。
Java的单继承
我猜测啊,看到这篇博客的也会有不少的C++选手,对于他们来说,一个子类可以继承多个父类,是多继承的,但是我们Java选手多专一啊,我们誓死不做三姓家奴,我们就用单继承!
也就是说我们一个子类只可以有一个父类,只可以extends一个父类;但是千万不要以为所有家庭都是独生子女,我们一个父类可以有多个子类,就比如刚才的阿猫阿狗不都是继承了一个Animal父类嘛?
super和this
兄弟们还记不记得我们的this 老铁,this表示的是当前对象的引用,我们是不是常在类中的方法中使用this来区分重名的变量?其实this也就是告诉你我们要使用的这个性质啊,就是属于我们所在的这个类的对象的!
那么如果是就按照我们刚才所说说的,子类的优先级永远比父类高,那如果我们硬着头皮就是想要访问父类的性质,那又该如何?
我们可以暂时把super理解为当前对象父类的引用:
class Dog extends Animal{
public String name="dog的";
public void wangwang(){
System.out.println(super.name+"正在狗叫");
}
public void eat(){
System.out.println(super.name+"dog的正在干饭");
}
}
public static void main(String[] args) {
Dog dog=new Dog();
System.out.println(dog.name);
dog.eat();
dog.wangwang();
我们现在使用dog访问子类中的方法就会使用到他父类中的性质了。
那为什么我们说现在我们只能说把super理解为当前对象父类对象的引用呢?因为我们从始至终都是没有实例化一个父类对象的,连对象都没有那又何谈对象的引用呢?所以其实super就只是一个关键字,它可以提醒你现在我们即将使用的就是我们父类中的一些性质了!
那么我们之前在讲解this的时候说过的一些话,现在我再次告知一下兄弟们:
在静态方法中是无法使用this和super 的,我们想一想就能知道,this和super都是和对象息息相关的,但是静态方法是不依赖对象的,一般来说也不会有人无聊到在静态方法里面再实例化一个对象,所以在静态方法里面你连对象的影子都是看不到的,那么和谈对象的引用呢?
那么在这里我在给兄弟说一说我自己学习的时候遇到的困惑还有我自己的心得:
不是说我们的this和super是当前对象和当前对象父类对象的引用嘛?在class外面不可以使用我还可以理解,但是此时我们明明是在class内部,为什么还是不可以使用这父子俩呢?
之前我们同样说过,一个对象的实例化分为分配内存还有调用构造方法两步,那么现在这两代码如此突兀地出现在class内部,我们只能理解为这两行代码是属于我们类的,但是事实上我们的super和this都是极其依赖对象的,所以这里会有报错,那为什么在类中的方法(构造方法和普通方法都是)却可以肆无忌惮地使用呢?兄弟们想一想,我们的方法现在是不加static的,也就是说我们的方法此时此刻是不属于类的,而是是属于通过new实例化出来的对象的,那么只要我们想要访问这个方法,势必有一个对象的引用.对象的方法
这一步,所以不是没有对象,甚至于对象都是你自己亲手创建出来的,只是你忽略了而已……
我自认为关于这个this和super我讲解的已经算比较好的,比较能够解决我自己百思不得其解的问题了,不知道兄弟们懂了没……
子类构造方法
之前讲到类和对象的时候我们是比较详细地说过了构造方法这个概念,现在我们再来盘一盘。
回忆一下,我们之前说的构造方法的作用是什么:我理解中的构造方法就是可以在实例化的时候直接对我们对象的属性进行初始化:那么请问在我们继承之中是否有什么需要关注的呢?我们直接上代码:
首先呢,我给兄弟们说一下报错的原因:我们在构造子类构造方法之前,不需要先帮助我们的父类进行构造,这就叫做孝道,老子还没落座呢你就先夹上菜了?这不行。
但是我们之前也说过,如果你自己不动手写构造方法的时候,编译器会自动给你一个不带参数的构造方法,那么此时在子类构造方法的第一行,编译器也是会自动帮助你加上这样的字样的:
public Bird(String name,int age){
super();
this.name=name;
this.age=age;
}
请注意我这里说的是第一行,使用super帮助父类进行构造的时候必须要把super()放到第一行:
不然就报错!
所以说有的时候既然我们自己接手了那么就要负责到底。
public Animal(){
}
public Animal(String name,int age){
this.name=name;
this.age=age;
}
事实上根据我们业务的需求不同,我们可以写出好多好多个构造方法的,这些构造方法函数名一样,参数列表不尽相同,对于返回类型不做要求,那么这些构造方法之前是不是就是构成了我们所说的重载?
我们只能在子类的构造方法中帮助父类进行构造,可千万不敢滥用我们的super(),super的使用已经有了不少的限制,而我们的super()更是被加上了厚重的枷锁。
protected中super的使用
我们在之前讲解访问权限修饰符的时候落下了一个protected没有进行讲解,现在我们来说一下其中不同包下使用protected修饰的数据如何进行访问:
不是说的通过继承就可以在不同的包里面使用protected修饰的数据吗?莫非情报有误?
其实不然,我们看下面的:
class Main extends Test3{
public Main(){
super.a=20;
}
}
虽然好像没有我i们想象中的那么方便,但是这确实也没有打到我们的脸!
final关键字
我们之前就说过的:final的作用类似于我们C语言中constant的作用,修饰一个变量,表示这个变量的值不可被修改。
那如果我们用final修饰一个类,那么这个类就不可以被继承。
如果我们用final修饰一个方法,那么这个方法就不可以被重写。
总而言之,我们的final就相当于给修饰的对象加上了一层常属性。
好的,那么我们关于继承的知识点我能想到的我能讲明白的也就这么多了,希望我的这篇博客能够多多少少帮助到兄弟们!
还是那句话,百年大道,你我共勉!