文章目录
前言
在讲述本章内容时,我们先来观察以下java中的两则代码:
所谓继承:就是对共性的一个抽取,从而实现代码的复用,就比如我们可以从上述两个类中将相同的属性抽取出来实现,如下图所示:
提示:子类/派生类不用必须有自己的特性,但若是没有,那么这个类和继承的意义也就没多大意义
一、继承
1.1 继承语法
修饰符 子类 extends 父类
1.2 继承的方式
1.单继承
2.多层继承
3.不同类继承同一个类
4.不支持多继承
1.3 继承中的访问限定符
访问权限大小:
public > protected > default > private
public :公开的,任何地方都能访问
prorected :同一个包中的子类、不同包中的子类都可以访问(也叫继承权限)
default :同一种包中的同一类,同一种包中的不同类
privete: 同一种包中的同一类
private访问权限代码实例
1.4 final关键字
>编写代码时,不希望定义的类被继承或者自己定义的常量被修改,可以用final修饰
代码示例:
二、如何访问成员变量和成员方法
2.1 父类的成员变量和成员方法的访问
1.通过实例化对象 父类名 对象名 = new 父类名();
去访问父类自己中的成员变量和成员方法方法
class Annimals{
public String name;
public int age;
public void eat(){
System.out.println(this.name+"正在吃");
}
}
public class Demo {
public static void main(String[] args) {
Annimals annimals = new Annimals(); //父类自己实例化对象
annimals.name = "haha"; //引用父类自己的成员变量
annimals.age = 23;
annimals.eat(); //引用父类自己的成员方法
}
}
2.也可以通过子类实例化对象访问父类的成员和成员变量
子类名 对象名 = new 子类名();
【注意】父类不可以通过实例对象访问子类中的成员变量和成员方法
2.2 子类和父类中有相同的成员变量和成员方法时访问
看到这个标题时,我们会想到这样两个问题:
1.子类和父类中可以有相同的成员变量和成员方法么?
答案是可以的,因为他们是两个类,只是是继承的关系
2.子类和父类既然可以有相同的成员变量和成员方法,那么子类访问父类中的成员变量和成员方法时,访问的是自己的还是父类中的?
接下来我们就用代码运行来验证这个问题的答案
class Annimals{
public String name;
public int age;
int a = 100;
public void eat(){
System.out.println(this.name+"正在吃"+"父类的");
}
}
class Dog extends Annimals{
int a = 23;
public void eat(){
System.out.println(this.name+"正在吃"+"子类的");
}
public void run(){
System.out.println(this.name+"正在跑");
}
}
下图将上面的代码块中代码用子类实例化了一个对象dog去访问父类和子类中名字相同的成员变量和成员方法,有运行结果我们得出如下结论:当子类和父类中有相同的成员变量和成员方法时,子类实例化对象访问时,优先访问自己的成员变量和成员方法。也就是就近原则,自己有优先访问自己的,没有就从父类中找,都没有则编译报错。
那么如果我们想通过子类方法中去访问父类中相同的成员变量和成员方法时,我们又应该如何访问呢?
回答这个问题前,我们现来介绍一个关键字 super,它有三种用法:
>1.super.data; ——当子类和父类中有相同成员变量时,想通过子类方法中访问父类中的成员变量使用;
2.super.func(); ——当子类和父类中有相同成员变量时,想通过子类方法中访问父类中的成员方法使用;
3.super(); ——子类构造方法时使用
通过super我们可以实现子类访问父类中相同成员变量的成员方法,如何使用,我们通过代码演示:
代码运行结果
【注意】
super只能在非静态方法中使用
只能是子类方法中访问父类的成员方法和成员变量
三、子类构造方法
3.1 super( )是什么?
1.在子类的构造方法中我们将会使用到super();它是当子类没有给出构造方法时编译器自动给出的一个不带参的构造方法,且必须放在子类方法中的第一行,若子类给出了构造方法,则编译器不会在自动给出;
2.若是要给子类构造方法必须先给父类也构造方法;因为子类实例对象时要先引用父类的构造方法,再引用自己的
当子类没有写构造方法时,如图所示:
当子类写了构造方法时
3.2 继承中代码块和构造方法执行的顺序
我们都知道在没有继承的情况下,先执行静态代码块,在执行实例代码块,最后执行构造方法,且静态代码块只执行一次,那么在继承中他们之间的顺序又是怎样的呢?我们通过代码来验证:
class A{
static{
System.out.println("父类静态代码块");
}
{
System.out.println("父类实例代码块");
}
public A(){
System.out.println("父类构造方法");
}
}
class B extends A{
static{
System.out.println("子类静态代码块");
}
{
System.out.println("子类实例代码块");
}
public B(){
System.out.println("子类构造方法");
}
}
public class demo1 {
public static void main(String[] args) {
B b = new B();
System.out.println("============");
B c = new B();
}
}
代码执行结果如下,通过代码验证我们知道
五、多态
5.1 多态的概念
多态是一种思想,它通过父类引用不同的子类对象,得到不同子类对象所表现出来的不一样的行为。
5.2 多态的实现条件
1.向上转型
2.发生重写,也就是父类和子类中有同名的方法
3.通过父类调用这个重写的方法(动态绑定)
5.2.1 向上转型和向下转型
什么是向上转型?
父类引用子类对象
向上转型的用法
1.直接赋值
2.作为方法的返回值
3.作为方法的参数
1.直接赋值
2.作为方法的返回值
3.作为方法参数
【注意】
向上转型可以通过父类引用对象不能访问子类的特有的成员方法
5.2.1 重写
重写就是父类和子类中的有一个方法,它的方法名相同、参数列表相同、返回值相同,代码实例:
@Override 表示重写方法
【注意】避免在构造方法中使用重写方法,容易发生动态绑定
5.2.3 通过父类引用调用重写方法
重写方法运行时才知道调用哪一个(子类或者父类中的)
5.3 多态实例
class Card{
public void Shape(){
System.out.print("形状");
}
}
class G extends Card{
@Override
public void Shape() {
System.out.print("♠");
}
}
class F extends Card{
@Override
public void Shape() {
System.out.print("♥");
}
}
class Y extends Card{
@Override
public void Shape() {
System.out.print("♣");
}
}
class H extends Card{
@Override
public void Shape() {
System.out.print("♦");
}
}
public class TestDemo2 {
public static void doShape(Card card){ //定义一个方法,传父类的对象
card.Shape();
}
public static void DOSjape(){
G g = new G();
F f = new F();
Y y = new Y();
H h = new H();
Card[] cards = {g,f,y,y,h,f,h,g}; //数组打印想要的顺序
for (Card card:cards) {
card.Shape();
}
}
public static void main(String[] args) {
doShape(new F());
doShape(new G());
doShape(new H());
doShape(new Y());
DOSjape();
}
}
5.4多态的优缺点
优点:
1.有效避免使用大量if-else,降低了圈复杂度(一段代码中的循环和if-else个数)
2.可扩展能力强
缺点:
降低了代码的运行效率