面向对象

包 (package) 是组织类的一种方式.
使用包的主要目的是保证类的唯一性.
导入包中的类

Java 中已经提供了很多现成的类供我们使用. 例如

java.util.Date date = new java.util.Date();

可以使用 java.util.Date 这种方式引入 java.util 这个包中的 Date 类.但是这种写法比较麻烦一些, 可以使用 import 语句导入包.

import java.util.Date;

如果需要使用 java.util 中的其他类, 可以使用 import java.util.*

import java.util.*;

容易出现冲突的情况,不建议
使用 import static 可以导入包中的静态的方法和字段.
常见的系统包

  1. java.lang:系统常用基础类(String、Object)
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

继承

目的:达到代码重用的效果.
被继承的类, 我们称为 父类 , 基类 或 超类, 继承父类的类, 我们称为 子类, 派生类
和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果.
基本语法:

class 子类 extends 父类 {
    
}
  • 使用 extends 指定父类.
  • Java 中一个子类只能继承一个父类
  • 子类会继承父类的所有 public 的字段和方法.
  • 对于父类的 private 的字段和方法, 子类中是无法访问的.
  • 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用.
    Java 中对于字段和方法共有四种访问权限
    private: 类内部能访问, 类外部不能访问
    默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
    protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
    public : 类内部和类的调用者都能访问
    在这里插入图片描述
    什么时候下用哪一种呢?
    我们希望类要尽量做到 “封装”, 即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者.因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限. 例如如果一个方法能用 private, 就尽量不要用public.
    final 关键字
    1.修饰一个变量或者字段的时候, 表示 常量 (不能修改).
final int a = 10;
a = 20; // 编译出错

2.final 关键字也能修饰类, 此时表示被修饰的类就不能被继承.

final public class Animal {

}
public class Bird extends Animal {

}
// 编译出错

final 关键字的功能是 限制 类被继承

组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.

public class Student {
    ...
}
public class Teacher {
    ...
}
public class School {
    public Student[] students;
    public Teacher[] teachers;
}

组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段.这是我们设计类的一种常用方式之一.

组合表示 has - a 语义

继承表示 is - a 语义

多态

向上转型
一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型.(UML 图)

Bird bird = new Bird("圆圆");
Animal bird2 = bird;
// 或者写成下面的方式
Animal bird2 = new Bird("圆圆");

向上转型发生的时机:

  • 直接赋值(如上)
  • 方法传参
public class Test {
    public static void main(String[] args) {
        Bird bird = new Bird("圆圆");
        feed(bird);
    }
    public static void feed(Animal animal) {
        animal.eat("谷子");
    }
}
  • 方法返回
public class Test {
    public static void main(String[] args) {
        Animal animal = findMyAnimal();
    }
    public static Animal findMyAnimal() {
        Bird bird = new Bird("圆圆");
        return bird;
    }
}

动态绑定
在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定.
方法重写
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).
注意事项:

  1. 重写和重载完全不一样.
  2. 普通方法可以重写, static 修饰的静态方法不能重写.
  3. 重写中子类的方法的访问权限不能低于父类的方法访问权限
    针对重写的方法, 可以使用 @Override 注解来显式指定.有了这个注解能帮我们进行一些合法性校验.
    重载和重写的区别.
    在这里插入图片描述
    多态顾名思义, 就是 “一个引用, 能表现出多种不同形态”

使用多态的好处是什么?

  1. 类调用者对类的使用成本进一步降低.(封装是让类的调用者不需要知道类的实现细节.多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可.因此, 多态可以理解成是封装的更进一步)
  2. 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
  3. 可扩展能力更强.
    向下转型
    向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象.
    对于 Animal animal = new Bird(“圆圆”) 这样的代码,
    编译器检查有哪些方法存在, 看的是 Animal 这个类型.
    执行时究竟执行父类的方法还是子类的方法, 看的是 Bird 这个类型.
    示例:
Bird bird = (Bird)animal;
bird.fly();

但是这样的向下转型有时是不太可靠的.所以, 为了让向下转型更安全, 我们可以先判定一下看看 animal 本质上是不是一个 Bird 实例, 再来转换.instanceof 可以判定一个引用是否是某个类的实例. 如果是, 则返回 true. 这时再进行向下转型就比较安全了.

Animal animal = new Cat("小猫");
if (animal instanceof Bird) {
    Bird bird = (Bird)animal;
    bird.fly();
}

super 关键字
如果需要在子类内部调用父类方法怎么办? 可以使用 super 关键字.
super 表示获取到父类实例的引用. 涉及到两种常见用法.

  1. 使用了 super 来调用父类的构造器
public Bird(String name) {
    super(name);
}
  1. 使用 super 来调用父类的普通方法
super.eat(food);

如果在子类的 eat 方法中直接调用 eat (不加super), 那么此时就认为是调用子类自己的 eat (也就是递归了). 而加上 super 关键字, 才是调用父类的方法.
super 和 this
在这里插入图片描述
尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题.
多态的核心是让调用者不必关注对象的具体类型. 这是降低用户使用成本的一种重要方式.

抽象类

像没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class).

abstract class Shape {
    abstract public void draw();
}
  • 抽象方法没有方法体(没有 { }, 不能执行具体代码)
  • 对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.
    注意事项
  1. 抽象类不能直接实例化.(要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.)
  2. 抽象方法不能是 private 的
  3. 抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用
    **抽象类存在的最大意义就是为了被继承.**使用抽象类相当于多了一重编译器的校验.

接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量.

interface IShape {
    void draw();
}
class Cycle implements IShape {
    @Override
    public void draw() {
        System.out.println("○");
    }
}
public class Test {
    public static void main(String[] args) {
        IShape shape = new Cycle();
        shape.draw();
    }
}
  • 使用 interface 定义一个接口
  • 接口中的方法一定是抽象方法, 因此可以省略 abstract
  • 接口中的方法一定是 public, 因此可以省略 public
  • Cycle 使用 implements 继承接口. 此时表达的含义是 “实现”
  • 在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.
  • 接口不能单独被实例化
    扩展(extends) vs 实现(implements)
    扩展指的是当前已经有一定的功能了, 进一步扩充功能.
    实现指的是当前啥都没有, 需要从头构造出来.
    接口中只能包含抽象方法. 对于字段来说, 接口中只能包含静态常量(final static).
interface IShape {
    void draw();
    public static final int num = 10;
}

其中的 public, static, final 的关键字都可以省略. 省略后的 num 仍然表示 public 的加粗样式静态常量.
实现多个接口
有的时候我们需要让一个类同时继承自多个父类. 这件事情在有些编程语言通过 多继承 的方式来实现的.
然而 Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果.
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值