JAVA基础篇——面向对象高级

九、面向对象之继承

2. 继承

2.1 概念:

关键字extends建立一个类与另一个类的父子关系

2.2 写法:

public class B extends A {

}

A被称为父类、基类、超类

B被称为子类、派生类

2.4 特点:

继承父类非私有成员(变量、方法)

2.5 继承后对象的创建:

子类的对象由子类、父类共同完成

2.6 继承的执行原理:

继承计算机执行原理

子类会把子类自己的变量和父类的变量在new的时候都在堆内存中开辟存储空间,只不过public的可以直接用.访问,其他private要通过get、set方法。

2.7 继承的好处:

减少重复代码的编写

Test.java

public class Test {
    public static void main(String[] args) {
        Teacher t1 = new Teacher();
        t1.setName("xx");
        t1.setSkill("Math");
        t1.printInfo();
    }
}

People.java

public class People {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Teacher.java

public class Teacher extends People{
    private String skill;

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public void printInfo() {
        System.out.println(getName() + "的技能是" + getSkill());
    }
}

2.8 权限修饰符

限制类中的成员能够被访问的范围

private:本类中

缺省:本类中,同一个包下的其他类

protected:本类中,同一个包下的其他类,其他包下的子类(不是子类对象)

public:本类中,同一个包下的其他类,其他包下的子类,任意包下的任意类

2.9 单继承、Object类

Java是单继承的,Java中的类不支持多继承(不同的父类相同的方法不知道调用谁),但是支持多层继承

Object类是Java所有类的祖宗

2.10 方法重写

子类为满足自己的需求,定义一个与父类方法名称相同、参数列表一样的方法,覆盖父类的方法

重写后,方法的访问,Java遵循就近原则

重载一般方法功能接近类似,重写会扩展功能

重载的参数列表不同,重写的参数列表相同

重写的注意事项:——按格式顺序思考一遍

使用@Override注解,可以指定java编译器,检查重写的格式是否正确,并且增加代码的可读性

访问权限子类重写时应比父类大(public > protected > 缺省)

返回值子类重写时应比父类小

私有和静态方法不能被重写,否则会报错

技巧:申明不变,重新实现

应用场景:

子类重写Object类的toString()方法,以便返回对象的内容

子类访问成员的特点:

就近原则

访问局部变量:变量名称访问

访问该对象的变量:this关键字

访问该对象的父类中的变量:super关键字

问题:如何访问父类的父类中的变量或方法——其实父类已经完全继承下来了,所以super已经够用了

2.11 子类构造器的特点

全部构造器都会先调用父类的无参数构造器,再执行自己。——子类的构造器会有一行默认代码super(),调用父类的无参构造器;如果父类没有无参构造器,需要手写super(……),指定去调用父类的构造器

应用场景:

数据被拆分在多个类中,要通过各自数据所在类的构造器进行初始化

注意:

子类的无参构造器不使用的话不定义不会报错,如果默认调用父类的无参构造器,父类就必须写了

this(……)调用该类的其他构造器;不能同时使用supper();他俩都应该在第一行

3. 多态

3.1 概念:

在继承/实现情况下的一种现象,表现为对象多态、行为多态(不存在变量多态)

实例: 一个人既可以是学生、也可以是孩子(也就是多重身份),每种身份下的同一种行为可能会存在差异(后续这个例子需要完善)——这个例子有点不确切,能说一个大类下可以分很多小类,每个小类的方法可能存在差别,是大类不同方向的扩充。

前提: 有继承/实现关系;存在父类引用子类对象;存在方法重写(一定)——编译看左边,运行看右边

3.2 好处:

  • 右边对象的随意解耦合
  • 父类类型的范围更大,可以使用父类类型的变量作为形参,可以接收一切子类对象——多态下不能使用子类的独有功能——>多态下的类型转换

3.3 强制类型转换

  • 概念: 子类 变量名 = (子类)父类变量 Teacher t = (Teacher) p;
  • 前提: 存在继承/实现关系
  • 注意: 如果对象的真实类型与强转后的类型不同,会报类型转化异常(ClassCastException)
  • 解决: 使用instanceof关键字判断当前对象的这怎是类型,再进行强转

4. final关键字

可以修饰类、方法、变量

修饰类:该类被称为最终类,不能被继承了——场景:工具类

修饰方法:该方法被称为最终方法,不能被重写了——但是可以重载

修饰变量:该变量只能被赋值一次,定义是时候就必须进行赋值(局部变量,修饰静态成员变量相当常量——通常来记录配置信息,修饰实例成员变量没有意义——每个对象成员变量都不相同)

常量记录系统配置信息的优势、执行原理:常量+宏定义——出现常量的地方在程序编译之后会全部替换成字面量,保证性能

5. 抽象类

abstract修饰

抽象方法: 必须用abstract修饰,只有方法签名,一定不能有方法体——也就是没有具体实现所以是抽线的

抽象类: abstract修饰的类

注意:

  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类——只要用abstract修饰的类就是抽象类,即使内部都不是抽象方法,也不能创建对象;不使用abstract修饰,内部就不能定义抽象方法
  • 抽象类中有全部类该有的成员
  • 主要特点是:不能创建对象,只能作为一种特殊的父类,让子类继承并实现
  • 一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类

好处:

更好地支持多态——不用类型转换就能实现调用子类方法

场景:模板方法 设计模式

解决方法中存在重复代码的问题

抽象类的话两个子类的方法没有相同的地方;重写的话可以保留相同的地方

**建议使用final修饰模板方法!!**防止被子类重写

6. 接口

6.1 概念

接口是一种特殊结构,用interface关键字修饰,不能创建对象(有抽象方法的类是抽象类,不能创建对象)

public interface 接口名{

​ // 成员变量(常量)——通过类名访问

​ // 成员方法(抽象方法)——其他方法存在方法体,与抽象方法是违背的

}

6.2 实现

Test被称为实现类

class Test implements A, B{

​ 实现A,B接口的全部抽象方法 / 把Test类设置成抽象类

}

6.3 好处

  • 弥补了单继承的不足,一个类可以同时实现多个接口
  • 让程序面向接口遍程,可以灵活切换各种业务实现

一个人有多重身份,通过接口就知道有哪些身份

在这里插入图片描述

之后添加功能方便,总代码简单不需要定义很多变量就可以产生不同的效果。——灵活切换实现方案

6.4 细节

JDK8开始,接口中新增的三种方法:

public interface A {
    // 1. 默认方法——实例方法
    // 使用实现类的对象访问,通过实例对象就可以访问
    // 如果之后每个实现类都要新增一个方法,可以在接口中新增一个default方法就行
    default void test1() {
        System.out.println("=====默认方法=====");
        test2();
    }

    // JDK 9之后
    // 私有方法:必须使用private修饰,类内访问
    private void test2() {
        System.out.println("=====私有方法=====");
    }

    // 静态方法:static修饰,默认会被public修饰,通过接口名访问
    static void test3() {
        System.out.println("=====静态方法=====");
    }
}

6.5 接口的多继承

一个接口可以同时继承多个接口,可以把多个接口合并成一个接口,便于实现类实现

public interface C extends B, A {

}

7. 内部类

概念: 如果一个类定义在另一个类的内部,这个类就是内部类

格式:

public class Car {
	// 内部类
	public class Engine {
	
	}
}

场景:

一个类的内部包含一个完整事物,但这个事物没有必要单独设计

分类:

成员内部类:都可以定义类中的东西,但是静态成员是从JDK16之后才可以定义的。Outer.Inner in = new Outer().new Inner();

静态内部类:类有的静态内部类都可以。Outer.Inner in = new Outer.Inner();

局部内部类:

**匿名内部类:**特殊的局部内部类,不需要有名字

7.1 匿名内部类

本质是一个子类,并会立即创建出一个子类对象。不是自己主动要用,而是用别人的需要用。

格式:

new 类或接口 (参数值) {

​	类体(一般是方法重写);

}

应用场景:

通常作为一个参数传输传输给方法

实例1:

public class Test {
    public static void main(String[] args) {
        Swim s = new Swim() {
            @Override
            public void swim() {
                System.out.println("这个是小狗");
            }
        };
        go(new Swim() {
            @Override
            public void swim() {
                System.out.println("这个是小猫");
            }
        });

    }


    public static void go(Swim s) {
        s.swim();
        System.out.println("go wayong!");
    }
}

interface Swim {
    public void swim();
}

GUI界面场景:

import javax.swing.*;
import java.awt.event.ActionEvent;

public class Test {
    public static void main(String[] args) {
        // GUI编程
        // 1. 创建窗口
        JFrame win = new JFrame("登录界面");
        JPanel panel = new JPanel();  // 自适应布局
        win.add(panel);

        JButton btn = new JButton("登录");
        panel.add(btn);

        // 给按钮绑定单击事件监听器
//        btn.addActionListener(new AbstractAction() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                JOptionPane.showMessageDialog(win, "登陆啦!!");
//            }
//        });
        // 最终目的是简化代码
        btn.addActionListener(a -> JOptionPane.showMessageDialog(win, "这样也能登录呀~~"));

        win.setSize(400, 400);
        // 居中
        win.setLocationRelativeTo(null);
        // 关闭窗口退出程序
        win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        win.setVisible(true);

    }

}

8. 枚举

8.1 概念

枚举是一种特殊的类

8.2 格式

修饰符 enum 枚举类名{

​ 名称1,名称2 ,……;

​ 其他成员……

}

public enum A {
    X,
    Y,
    Z;

    private String name;

    private A() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在这里插入图片描述

  • 枚举类的构造器是私有的,不能对外创建对象
  • 枚举类的第一行都是常量,记住的是枚举类的对象
  • 枚举类提供了一些额外的API:拿到全部对象

8.3 抽象枚举

构建对象的时候要重写就行

8.4 应用场景

用来表示一组信息,然后作为参数进行传输

public class Test {

    public static void main(String[] args) {
        // 枚举的应用场景——信息标志和分类
        check(Constant2.GIRL);
//        check(Constant.BOY);

    }

    public static void check(Constant2 sex) {
        switch (sex) {
            case BOY:
                System.out.println("男孩子嗷");
                break;
            case GIRL:
                System.out.println("女孩子嗷");
                break;
        }
    }

//    public static void check(int flag) {
//        switch (flag) {
//            case Constant.BOY:
//                System.out.println("男孩子嗷");
//                break;
//            case Constant.GIRL:
//                System.out.println("女孩子嗷");
//                break;
//        }
//    }
}
public class Constant {
    public static final int BOY = 0;
    public static final int GIRL = 1;
}
public enum Constant2 {
    BOY, GIRL;
}

9. 泛型

9.1 概念

定义类、接口、方法时,同时声明了一个或者多个类型变量(),称为泛型类、泛型接口、泛型方法,他们统称为泛型。

9.2 作用

在编译阶段约束所能操作的数据类型,并自动进行检查!这样可以避免强制类型转换、及可能出现的异常。

本质: 把具体的数据类型作为参数传给了类型变量

9.3 自定义

泛型类格式:

修饰符 class 类名<类型变量, 类型变量, ……> {

}

public class MyClass2<E, T> {
    public void put(E e, T t) {

    }
}
public class Test {
    public static void main(String[] args) {
        MyClass2<Cat, String> c2 = new MyClass2<>();

    }
}

泛型方法格式:

修饰符 <类型变量, 类型变量, ……> 返回值类型 方法名(形参列表) {

}

使用已有泛型的时候可以使用<?>表示任意类型,要想给他增加限制,例如:上限<? extends 类名>,只能访问本类及子类;下限<? super 类名>,只能访问本类及父类。

为什么通常用E, T, K, V关键字

  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element

9.4 注意事项

泛型擦除: 泛型工作是在编译阶段,一旦编译完成,class文件中就不存在泛型了——底层还是Object类型的,只不过多了强制类型转换

泛型不支持基本数据类型,只能支持对象类型(引用数据类型)——要使用其对应的类

public class Test {
    public static void main(String[] args) {
        String rs = test("java");
        System.out.println(rs);
        ArrayList<Integer> list1 = new ArrayList<>();
    }

    // 泛型方法
    public static <T> String test(T t) {
//        return t;
        return "泛型";
    }
}
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值