Java开发知识之Java的继承多态跟接口*
2018-10-15 17:05
375 查看
Java开发知识之Java的继承多态跟接口
一丶继承
1.继承的写法
在Java中继承的 关键字是 extends 代表一个类继承另一个类.继承的含义以及作用: 继承就是基于某个父类的扩展.制定出来的一个新的子类.子类可以继承父类原有的属性跟方法. 也可以自己增加特有的属性跟方法.
代码例如下:
public class Anmail { public void eat() { System.out.println("父类吃"); } }子类代码:
父类代码
public class Dog extends Anmail { public void eat() { System.out.println("子类吃"); } }通过上面代码.我们可以看到.子类 Dog类. 继承了父类. 使用了关键字 extends
并且子类重写了父类的方法.
2.子类访问父类的方法
上面说了子类继承父类.那么子类也可以调用父类的方法. 我们学过this关键字. this可以区分局部变量跟成员变量.也可以在构造中调用其它构造函数.那么我们还提供了一个关键字. super() super关键字可以访问父类.
代码如下:
父类代码一样.之帖子类代码.
public class Dog extends Anmail { public Dog() { super(); //调用父类构造 调用构造的时候必须放在最上面. super.eat();//调用父类方法. } public void eat() { System.out.println("子类吃"); } }创建子类对象.并且输出.
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015142902200-1644354991.png)
可以看到.在调用构造的时候.他会先访问父类的构造.但因为父类构造我们并没有输出内容.所以没有输出内容,子类继续调用父类的eat方法. eat方法我们输出了.
就是父类吃. 所以在子类构造的时候.会调用父类构造以及父类的方法.
super()的关键字用法限制. super关键字只能调用父类中 公共权限(public) 以及保护全选(protected)的方法
3.重写的概念
子类可以重写父类的方法. 什么是重写.就是子类跟父类的方法是一模一样的. 也就是说,重写是在子类跟父类中才会出现的. 返回值一样. 方法名一样. 参数一样.在J2SE 5.0 以上.支持了新的功能.也就是说返回值可以不一样.但是 方法名 跟 参数必须一样.
JAVA 类编译的流程. java中.创建子类的时候.会自动调用父类的构造方法进行初始化. 我们可以做个例子. 并且重写一个方法.
public class Anmail { public Anmail() { System.out.println("父类构造方法"); } public void eat() { System.out.println("父类吃"); } }子类.
public class Dog extends Anmail { public Dog() { } public void eat() { //重写父类方法 System.out.println("子类吃"); } }创建对象.
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015150803591-1216772410.png)
通过实例可以终结出. 1. 子类重写了父类方法.输出的内容是自己的"子类吃" 2.在给子类实例化的时候.会自动调用父类进行实例化操作.也就是说父类也会被初始化.
PS: 子类实例化的时候.会调用父类的无参构造进行实例化父类.但是并不会自动调用父类的有参构造.这个我们需要使用super关键字才可以.
二丶Object 类
object类是一个比较特殊类的. 位于java.lang.包中. 它是所有类的父类.比如我们以前学习过字符串类. String类. String类中 我们比较两个对象是否相等就是用.equleas()方法. 这个就是object类中的.只不过字符串进行了重写. 我们自定义的类也是继承自object类.只不过是默认继承. 所以任何类都可以重写父类object中的方法.
在object类中 加了final类的方法是不能被重写的. 例如 getClass() notify() notifyAll() wait()等等.
object类的方法介绍.
1.getClass()方法getClass()方法会返回指定是的Class实例. 然后可以使用此时调用getName()获得这个类的名称.
getClass().getName(); 也可以配合toString()方法使用.
2.toString()方法
toString()方法就是返回一串字符串.在object类中,就是讲一个对象返回为字符串形式.实际应用中就是重写这个字符串.返回什么是你自定的.
3.equals()方法;
equals()方法就是比较.当时说过区别. 就是 == 与 equals()的区别. == 是比较地址. equals()是比较你自定的内容.也就是对象的实际内容.通常也是重写.
比较什么你自己定. 如果你写了一个类有一个成员变量是 a; 我们重写equals() 就判断 a 跟 比较对象的a即可. 就是 a 跟 a比较.
三丶对象类型转换.
对象类型转换.包括向上转型.以及向下转型. 通俗理解就是 强转对应的数据类型. 但是你在强转的时候要判断一下是否是这个数据类型.这个就是转型.向上转型以及向下转型就是说 类我们强转为父类. 也可以父类强转为子类.
1.向上转型
子类对象赋值给父类对象称为向上转型. Anmail a = new Dog(): 这个就是向上转型.比如我们有动物对象. 跟 狗对象. 狗对象可以看做是动物对象的一个子类.
还比如 四边形类 跟 平行四边形类. 平行四边形 对象可以看做是 四边形类的一个对象.
如下图:
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015152855998-1832619357.png)
常规的继承图都是父类在上. 子类在下.例如上图. 所以我们将子类看做是父类对象的时候成为向上转型. 也就是平行四边形对象看做是四边形类的对象的时候.
向上转型是具体的类像抽象的类进行的转换.所以它总是安全的. 我们可以说平行四边形是特殊的四边形. 但是不能是四边形是平行四变形.
因为代码写法: 四边形 a = new 平行四变形(); 所以很多人就会说 a就是平行四边形. 其实是错的. a是四边形. 我们只能说a平行四边形是一个特殊的四边形.
如果在C++ 中.内存分配就是 父类占一小块内存. 子类上半部分是父类内存.下半部分是子类特有的成员变量开辟的内存. 子类转为父类. 就是不要子类下边的内存了.
所以总是安全的. 我只要上面的哪块内存.也就是父类的内存.
所以在上边. 子类转为父类. 父类调用方法的时候.并不会调用到子类特有成员变量.
2.向下转型
向下转型就是 抽象的类转为具体的类. 比如 动物是鸟. 动物是抽象的.不能说他是鸟.所以不和逻辑.而且会出现问题.比如父类 Anmail a = new Dog();
Dog b = a; 这样是错误的. 我们不能这样赋值.原因就是不能说 动物是狗.
Dog c = (Dog)a; 这样可以.强转为子类型.写法是正确的.
站在C++的角度:
为什么上面向下转型是错误的. 原因是 a 会有一块内存. 我们可以假定为0x20个字节大小. b是Dog也就是子类对象.他继承了父类.有自己特有的成员方法
以及成员变量. 所以它的头0x20个字节是父类的内存.下面多出的内存是自己了.假设是0x30个字节. 所以我们子类转为父类(向上转型)
其实就是把30个字节的内存转为20个字节的内存.所以不会出问题. 但是 0x20个字节.也就是父类转为子类. 就会出为题. 意思就是说 0x20个字节转为0x30个字节.
首先我们并不知道是转为0x30个字节.这样内存访问就会出错了.但是如果我们强转了.相当于就是父类在强转为子类的时候.按照子类的内存强转.这样就不会有问题了.
也就是上面的我们的 Dog c c的头0x20个字节是父类. 下面的0x10个字节就是自己特有的所以不会出错.
3.使用关键字判断对象类型
上面我们的父类转为子类的时候.必须加上子类的数据类型才可以强转. 原因就是转为子类的时候.内存会按照子类的大小进行扩大.这样就不会出现问题了.但是我们怎么知道 我们的子类.是否是这个父类的子类. 所以有了运算符 instanceof()来判断.
就是判断 子类是否是父类的. 父类中有没有这个子类.如果有就进行转换.
语法:
Myobject instance ExampleClass
1.Myobject 就是某个类的对象引用. 可以理解为是父类填写的是父类引用.
2.ExampleClass 某各类. 可以理解为子类. 填写类名.
例如:
Anmail a = new Anmail(); if (a instanceof Dog) { 判断父类中是否有子类Dog,如果有我就进行转换. Dog d = (Dog) a; d.xxxx; }
四丶方法重载.
1.重载介绍.
重载的含义. 重载就是可以有多个相同函数.重载的参数确定是否重载.我们写过有参构造跟无参构造. 方法名是一样.不一样的就是参数列表不同.
重载的构成:
1.重载的构成是方法名字一样,
2. 参数列表个数不同
3. 参数类型不同
4.参数列表顺序不同
例如:
public void eat();
public void eat(String,int); 重载eat,参数是String,int
public void eat(int,String); 参数顺序不同.构成重载.
public int eat(int,int); 返回值是int. 参数列表是两个int值. 返回值也可以为void不影响重载.
PS: 方法的返回值并不会影响重载.真正影响的是参数列表. 你有两个成员方法.方法命一样.参数列表一样.类型一样.返回值不同.不能构成重载.
特殊的重载:
Java中可以定义不定长的参数类表.
语法如下:
返回值 方法名(参数数据类型 . . . 参数名称) 主要是三个...
其实不定长参数.就是一个一维数组.我们可以当做数组去操作参数.
代码如下:
public void eat(int ... a) { for (int i = 0; i < a.length;i++) { ....... } }
5.多态的概念
在上面我们学过向上转型.就是子类对象可以当做父类对象去使用. 其意思就是我可以当做父类对象去使用. 那么就可以使用子类跟父类的共有的方法跟属性了.因为我们站在内存的角度上也说了.我们用的都是父类的内存.所以我们可以调用父类的方法.跟成员去使用. 但是多态是什么意思.多态就是调用父类的方法的时候.
因为子类重写了父类的方法.所以调用时会调用子类的特有方法.
例如:
Anmail a = new Dog();
a.eat()
输出结果: 子类吃. 按理说应该输出父类吃.不是说向上转型了.我们用的都是父类内存了.子类就不该会被调用. 愿意你是这样了.如果站在C++角度来说.
我们首先会new一个子类的对象实例. 而new子类对象的时候.会先初始化父类. 在初始化自己. 为什么说一下流程.原因是父类有虚表.也就是有一个表.保存着
自己的方法.而子类在实例化的时候.父类的虚表先初始化. 初始化完了之后.子类的再初始化.它会先把父类的虚表拷贝过来.然后覆盖他. 这样我们a调用方法的时候
其实调用的是子类方法.原因就是子类的虚表已经覆盖了父类虚表.
Java中的原理. java中其实也是一样的.只不过给你隐藏了这个步骤了.不用理解的这么复杂.我们只要知道.向上转型之后.调用子类跟父类共有的方法.就能实现多态.
注意: 子类重写了父类方法.那么调用的时候才是子类的方法.原因是子类重写了.才会覆盖父类.
代码例子:
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015161820718-517786972.png)
多态的用法: 多态的好处就是程序员不同定义相同的方法了.避免了相同的大量重复代码的开发.只要实例化一个子类对象.维护这个方法即可.
再举个例子;
我们手机. 有一代手机 二代手机 三代手机 四代手机 ...n代手机.
1代手机 只支持打电话
2代手机 可以发信息了.
3.手机 可以上网了
4.手机 可以拍照了.
此时我们只需要二代手机继承1代手机对1代手机扩展功能. 比如增加发信息的方法. 打电话的方法进行重写.可以打电话.也可以录音了. 而一代手机根本不用动方法.
此时我们的二代手机就可以出手了.第三代手机同样继承第二代手机.增加扩展功能.重写维护的方法. 而不用修改二代的代码.
这样不管我们有第几代手机.只需要继承上一代的类.进行扩展.以及维护即可.
6.抽象类
抽象类就是说一个不可以被存在的类. 比如我们有动物 跟 狗. 而动物是不能被实例化对象的. 狗是一个具体的生物.我们可以实例化.所以抽象就是指 动物. 也就是说我不能让你被实例化.原因就是 动物泛指万千.不能具体为一个动物.
定义抽象类的关键字
abstract
使用abstract 修饰的类称为抽象类.是不能实例化的.
使用 abstract 修饰的方法.称为抽象方法.是不能实现的.比如子类重写. 修饰的方法没有方法体.
反过来说.如果一个类中修饰了成员方法.那么就必须定义这个类为抽象类.
抽象类跟普通类一样.只不过就是不能实例化. 必须要有子类继承.如果有抽象方法.子类必须重写.
抽象类的继承图:
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015162911637-1865822742.png)
代码写法,需要将我们的Anmail类写成抽象类. 并且方法改为抽象方法
//public abstract class Anmail abstract public class Anmail { abstract public void eat() ; public abstract void play(); }abstract 卸载权限修饰符的前边或者后边都可以.不影响.例如类上面加了一行注释.我们也可以写成上面的写法.以及抽象方法.也是两个不同顺序来举例子
public class Dog extends Anmail { @Override public void eat() { // TODO 自动生成的方法存根 System.out.println("狗在吃东西"); } @Override public void play() { // TODO 自动生成的方法存根 System.out.println("狗在玩耍"); } }使用的时候.可以使用向上转型.使用多态的方式. 子类可以自己new自己
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015163559061-829118854.png)
在C++中.也有抽象类的概念.只不过称之为纯虚类. 他的方式就是这个类中的方法定义为纯虚方法(抽象方法)
void eat() = 0; 后面加上 = 0; 跟接口很类似. 一般也是接口
七丶接口的含义
接口就是抽象类的延伸.上面我们定义了一个抽象类.如果这个抽象类是一个父类.有很多子类.但是我们可以这样想一下. 如果子类很多.都要实现这个抽象类中的方法.这样就造成了代码冗余. 我们有的类完全可以不实现抽象类中的抽象方法啊.
比如 play方法. 我们每个子类都要实现.但是有的动物就不会玩我完全可以不实现了.但是按照抽象类.我们必须实现.所以就代码冗余了.
此时接口就出现了. 接口就是说 . 我接口中的方法都是抽象方法. 你要实现play. 就可以实现我这个接口. 如果不需要玩的话.就不用实现我这个接口
例如下图:
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015164228682-352401517.png)
可以看到我们的N边型类.并没有实现接口.我完全可以不用实现Draw方法.虽然我继承了父类.
接口的定义与使用:
1.接口使用intface关键字 修饰. 可以使用权限修饰符修饰
2.接口的实现使用关键字 implements关键字
3.接口中的方法都是抽象方法.而且都没有方法体. 且默认加的关键字就是abstract 而且权限必须是public因为要被实现.其它权限修饰则不被编译器认可.
4.在继承一个类同时.可以实现接口.
5.在接口中定义的 字段(成员变量)都是默认修饰符 static + final修饰的. 也就是说一个静态常量.
代码如下:
定义一个接口
public interface IAnmail { public abstract void Play(); //定义一个抽象方法 }接口的实现.
public class Dog extends Anmail implements IAnmail{ @Override public void eat() { // TODO 自动生成的方法存根 System.out.println("狗在吃东西"); } @Override public void Play() { //实现了接口必须实现他的方法 // TODO 自动生成的方法存根 System.out.println("狗在玩耍"); } }
![](https://img2018.cnblogs.com/blog/1197364/201810/1197364-20181015165134562-1606831211.png)
八丶总结
1.类的继承
类的继承使用 extends关键字注意的问题:
1.不能多继承.
2.子类继承父类自动用于父类的方法以及成员变量
3.子类在构造中可以调用父类构造.(无参或者有参) 使用的是 super();关键字. 也可以调用父类方法 super.xxxx
2.公共父类Object
在Java中每个类都继承了父类Object. Object中提供了常用的方法比较: equeals();
转为字符串表现形式 toString();
这些方法都是可以被重写的.除了加了 final修饰的.
3.对象的类型转换.
在Java中有向上转型跟向下转型1.向上转型: 子类转为父类. Anmail d = new Dog(): 安全的.因为在内存角度来说.使用的部分只有父类部分内存.
2.向下转型: 父类转为子类 Dog c = (Dog) d; 必须加上类型.父类内存转成子类内存,比如给指定子类内存大小.
3.对象类型判断 使用 instanceof
语法 父类引用 instance 子类类名 判断父类是否有这个子类
如果是我们就可以进行转换了.
4.类中的方法重写与重载
重写:1.返回值相同
2.方法名相同
3.参数列表相同
满足以上三点才能是重写.也就是子类跟父类一模一样才是重写.
重载:
1.方法名一样
2.参数列表个数不同
3.参数列表类型不同
4.参数列表顺序不同.
满足以上四点才能构成重载.
特殊重载可以使用 三个点定义为可变参数 public void eat(int ...a); 此时a就是一个数组.我们可以遍历他来获取参数.
5.多态
多态就是父类可以调用子类跟父类共有的方法.比如是子类重写父类才会有不同的结果.使用向上转型
Anmai a = new Dog(); a.eat() ; 狗在吃东西.
内存角度来说. 就是虚表覆盖.
6.抽象类
抽象类使用 abstract关键字进行修饰public abstract class 类名{}'
1.修饰类就是抽象类,不可以被实例化.就是不能创建对象
2.修饰方法就是抽象方法,没有方法体.子类继承比如重写.
3.一个类中有抽象方法.则这个类必须定义为抽象类.
7.接口
接口定义的关键字 Intface public intfact 接口名{}实现接口的关键字 implements public class Anmail Implements 接口名
1.接口中的方法都是抽象方法. 且默认修饰符为 public abstract 权限必须是public 否则编译器不认可.
2.接口中的成员变量都是默认的 static final 修饰的.
相关文章推荐
- java基础(2)-基础类型和语法(static、内部类、final、抽象类、接口、封装)(并将这些基础知识与java的三大特征关联(继承、多态、封装))
- JAVA基础知识:面对对象特性【继承】【 多态】【 封装】【 接口】
- 黑马程序员_Java继承、多态、接口零碎知识总结
- Java 基础一些代码练习笔记(继承+接口+多态)
- java [继承]-[接口]-[抽象类]-[多态]-[Object]
- 【Java学习笔记】基础知识学习10【继承与多态】
- JAVA中用接口实现多继承和多态
- 黑马程序员_java的继承性- 继承-final关键字-抽象类-接口-多态-异常-包-多线程-
- 黑马程序员-自己总结的java学习笔记(5)继承,接口,多态。
- JAVA学习笔记(五)继承时的构造方法、多态、接口、汉诺塔
- 黑马程序员 Java面向对象<二> 继承、多态、接口
- JAVA中如何用接口实现多继承和多态 (非常好)
- java内接口,抽象类,继承实现的一些基础知识和实例
- java基础知识2--抽象 多态,继承等
- java 继承 方法重写 自动转型 多态 接口 抽象类
- 继承,接口,多态练习java
- All About JAVA 继承、多态、抽象类、接口、面向接口编程
- JAVA中几个易混淆关键词的理解:行为,隐藏,组合和继承,覆写和重载,多形(多态)性,动态绑定,上溯造型,抽象类,接口
- 黑马程序员_java面向对象总结【3】(继承、接口和多态)
- Java【多线程知识总结(5)】比较继承Thread类创建线程和实现Runnable接口创建线程这两种方式