一、private实现封装
1.private/ public 这两个关键字表示 “访问权限控制” 。
2.被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
3.被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用
4.换句话说, 类的使用者根本不需要知道, 也不需要关注一个类都有哪些 private 的成员. 从而让类调用者以更低的成本来使用类。

二、继承
基本语法:
class 子类 extends 父类 {
}
使用 extends 指定父类.
(1)Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
(2)子类会继承父类的所有 public 的字段和方法(除构造方法)
(3)对于父类的 private 的字段和方法, 子类中是无法访问的.
(4)子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用

class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}


class Cat extends Animal {
public Cat(String name) {
// 使用 super 调用父类的构造方法.
super(name);
}
}

public class Test {
public static void main(String[] args) {
Cat cat = new Cat("小黑");
cat.eat("猫粮");
}
}

三、多态
1.向上转型
一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型.
(1)向上转型发生的时机:
a.直接赋值

b.方法传参

public class Test {
public static void main(String[] args) {
Bird bird = new Bird("圆圆");
feed(bird);
}
public static void feed(Animal animal) {
animal.eat("谷子");
}
}
// 执行结果
圆圆正在吃谷子
此时形参 animal 的类型是 Animal (基类), 实际上对应到 Bird (父类) 的实例

c.方法返回

public class Test {
public static void main(String[] args) {
Animal animal = findMyAnimal();
}
public static Animal findMyAnimal() {
Bird bird = new Bird("圆圆");
return bird;
}
}
此时方法 findMyAnimal 返回的是一个 Animal 类型的引用, 但是实际上对应到 Bird 的实例

2.动态绑定(运行时绑定)
父类引用指向字类对象,同时通过父类引用调用同名的覆盖方法,此时就会发生动态绑定

public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println("我是一只小动物");
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void eat(String food) {
System.out.println("我是一只小鸟");
System.out.println(this.name + "正在吃" + food);
}
}
// Test.java
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("圆圆");
animal1.eat("谷子");
Animal animal2 = new Bird("扁扁");
animal2.eat("谷子");
}
}
// 执行结果
我是一只小动物
圆圆正在吃谷子
我是一只小鸟
扁扁正在吃谷子

animal1 和 animal2 虽然都是 Animal 类型的引用, 但是 animal1 指向 Animal 类型的实例, animal2 指向Bird 类型的实例.
针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而animal2.eat() 实际调用了子类的方法.
因此, 在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定

3.方法重写
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override)。
注意:

  1. 重写和重载完全不一样. 不要混淆
  2. 普通方法可以重写, static 修饰的静态方法不能重写.
  3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
  4. 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外).

4.理解多态:

class Shape {
public void draw() {
// 方法内什么也没有
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("□");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("♣");
}
}
=========================================

// Test.java
public class Test {
public static void main(String[] args) {
Shape shape1 = new Flower();
Shape shape2 = new Cycle();
Shape shape3 = new Rect();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
// 打印单个图形
public static void drawShape(Shape shape) {
shape.draw();
}
}

在这个代码中, 分割线上方的代码是 类的实现者 编写的, 分割线下方的代码是 类的调用者 编写的.
当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现(和 shape 对应的实例相关), 这种行为就称为 多态

5.super和this的区别和联系

四、抽象类
在刚才的打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstractmethod), 包含抽象方法的类我们称为 抽象类(abstract class)

abstract class Shape {
abstract public void draw();
}

注意事项:
(1)抽象类不可以被实例化
(2)类内的数据成员和普通类无区别
(3)抽象类主要用来被继承
(4)如果一个类继承了抽象类,那么这个类必须重写抽象类中的抽象方法
(5)抽象类A继承抽象类B,A可以不重写B中的方法,但一旦A再被继承,那么一定还要重写这个抽象方法
(6)抽象类或方法不能被final修饰
五、接口
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量。

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 Rect();
shape.draw();
}
}

注意:
(1)接口中的方法都是抽象方法(可以省略 public abstract)
(2)接口中定义的成员变量默认是常量
(3)接口不可以实例化
(4)接口和类的关系:class Cycle implements Shape
(5)为了解决Java中单继承的问题,一个类可以实现多个接口
(6)只要这个类实现了该接口,就可以进行向上转型