抽象方法

我先举个例子引出​​抽象方法​​,例如求圆、矩形、三角形、这些图形的面积

Java接口/内部类_抽象类

Java接口/内部类_抽象类_02

????发现的问题

  • 每一个图形计算面积的方式都不一样, 所以每一个类都必须得要覆盖父类当中的​​getArea​​方法, 来去实现不同图形求面积的方式

????带来的问题

  • 怎么样保证子类​​必须​​得要覆盖父类当中定义的方法
  • 父类​​不需要提供方法体​

抽象方法

定义格式:在方法前面添加了一个关键字​​abstract​

????抽象方法的特点

  1. 抽象方法是没有方法体的
  2. 抽象方法必须得要定义在抽象类 或 接口当中
  3. 抽象方法不能是私有的​​private​​​,​​final​​​,​​static​

Java接口/内部类_抽象方法_03

????注意点

  • 子类必须得要去覆盖此方法(定义的抽象方法)
  • 在定义的时候不要有方法体

抽象类

  • abstract修饰的类,就成为了抽象类
  • 抽象类必须得要有子类才行。(抽象类一般都当作父类来继承)

????注意点

  • 抽象类是不能直接创建对象的
  • 抽象类当中,可以有抽象方法 ,也可以有非抽象方法(普通方法:给子类调用的)
  • 子类没有去覆盖抽象方法,会把子类也变成抽象类
  • 构造方法不能定义为私有化(抽象方法必须得要让子类继承之后,才能实现内部的方法体。子类继承的话,先去调用父类的构造方法)
  • 抽象类不能使用final来去修饰

????抽象类与普通的类的区别

  • 普通类你有的(方法 ,字段,构造器),抽象类都有
  • 抽象类不能创建对象。抽象类可以包含抽象方法,也可以包含非抽象方法
  • 抽象类必须有子类才有意义

Java接口/内部类_抽象类_04

Java接口/内部类_抽象方法_05

接口

先来讲讲生活当中的​​物理接口​

  • 指的是两个硬件设备之间的连接方式。硬件接口既包括物理上的接口,比如我们所以说的USB接口

Java接口/内部类_抽象方法_06

????Java当中的接口

  • 在Java中,接口表示一种规范/约束/要求实现者必须遵循该规范,用来约束使用者应该怎么做

????规范和实现相分离的好处

主板上提供了USB插槽,只要一个遵循了USB规范的鼠标,就可以插入USB插槽,并与主板正常通信。至于这个鼠标是谁生产的,内部是如何实现的,主板都不需要关心(只要遵循了USB规范就可以插在主板上使用)。当鼠标坏了的时候,我主板不会坏

Java接口/内部类_抽象类_07

Java定义接口

  • Java接口也是表示一种规范,使用抽象方法来去定义一组功能
  • 实现者必须要给提供的方法实现

接口定义格式

interface 接口名称 {

????注意点

  • 接口是没有构造器,接口是不能创建对象的
  • 接口当中定义变量,都是全局的静态常量
  • 接口当中 定义的方法 都是公共的抽象方法
  • 接口是可以继承,它是可多继承:interface 接口名称 extends 继承的接口名, 继承的接口名

接口实现

实现格式

类名 extends 其它的类(只能继承一个类) implements 其它的接口(接口可以实现多个)

爬行动物规范

public interface Iwalkable {
void walk();
}

水生动物规范

public interface Iswimable {
void swim();
}

两栖动物规范

public interface Iamphibiousable extends Iwalkable, Iswimable {
}

动物类

public class Animal {
String name;
String Color;
}

狗类

public class Dog extends Animal implements Iwalkable {
@Override
public void walk() {
System.out.println("小狗跑");
}

public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "wc";
dog.Color = "黑色";

dog.walk();
}
}

????接口与抽象类的区别

相同点

  • 都是被其它类继承和实现用的
  • 都不能实例化,都不能创建对象
  • 都可以定义抽象方法 ,定义的抽象方法子类都必须得要覆盖

不同点

  • 接口是没有构造器,抽象类当中是有构造器
  • 抽象类可以包含普通方法和抽象方法,接口当中只能有抽象方法,不能有普通方法(带有方法体)
  • 接口当中默认成员变量,要有初始值 都是静态的
  • 方法
  • 接口:当中方法默认public abstract 方法名;
  • 抽象类:默认的权限(default)

面向接口编程

  • 把实现类对象赋值给接口类型的变量,也就是多态
  • 多态的好处:屏蔽了不同类之间实现差异,从而达到通用编程

????接口多态

  • 把实现类赋值给接口 运行时, 运行的仍是实现类

USB规范

public interface IUSB {
void swapData();
}

主板类,主要实现了USB的规范就可以和主板传输数据

class MotherBoard {
void pluginIn(IUSB iusb) {
iusb.swapData();
}
}

键盘类,实现了USB规范

class keyBoard implements IUSB {

@Override
public void swapData() {
System.out.println("键盘打字");
}
}

鼠标类,实现了USB规范

class Mouse implements IUSB {

@Override
public void swapData() {
System.out.println("鼠标移动");
}
}
class Demo{
public static void main(String[] args) {
IUSB mouse = new Mouse();
IUSB keyBoard = new keyBoard();

MotherBoard board = new MotherBoard();
board.pluginIn(mouse);
board.pluginIn(keyBoard);
}
}

内部类

  • 定义在类当中 的一个类
  • 内部类可以直接访问外部类当中 的成员

????为什么要有内部类

  • 增强封装,把内部类隐藏在外部类当中,不允许其它类访问这个内部类
  • 增加了代码的一个维护性

内部类分类

Java接口/内部类_内部类_08

实例内部类

  • 直接定义在类当中的一个类,在类前面没有任何一个修饰符,不属于类的,不使用static修饰的类
public class Outter {
String name = "BNTang";

class Innner {
void show() {
System.out.println(name);
}
}
}

实例内部类的创建,想要使用实例内部类,必须得要先创建外部类

class Demo {
public static void main(String[] args) {
Outter outter = new Outter();
Outter.Innner innner = outter.new Innner();
innner.show();
}
}

????实例内部类注意点

  • 想要使用实例内部类,必须得要先创建外部类
  • 在内部类当中可以访问外部类当中的成员
  • 在内部类当中,不能有静态(以static修饰的)的成员
  • 外部类是不能直接访问内部当中 的成员(代码块区域就不同当然不能访问)

Java接口/内部类_抽象方法_09

实例内部类变量的访问

Java接口/内部类_抽象类_10

静态内部类

在内部类前面加上static,属于类的内部类

public class Outter {
static String name = "BNTang";

static class Innner {
void show() {
System.out.println(name);
}
}
}

????静态内部类的创建

class Demo {
public static void main(String[] args) {
Outter.Innner innner = new Outter.Innner();
innner.show();
}
}

静态内部类注意点

  • 静态内部类是不需要创建外部对象的
  • 在静态内部类当中,是没有外部类引用
  • 静态内部类,是可以访问外部类的静态成员
  • 静态内部类当中可以定义静态成员,也可以定义非静态成员

Java接口/内部类_抽象方法_11

静态内部类当中访问外部的普通变量

Java接口/内部类_内部类_12

匿名内部类

就是一个没有名字的局部内部类,只使用一次的时候,来去使用匿名内部类,匿名内部类必须得要有父类才可以, 或者是实现了接口,当然这个可以使用Java8中的Lambda表达式来优化,Java8我后面在写具体的文章来介绍

结构

new 父类的构造器 或 接口(){
内部写的代码(在new时候就会自动执行)
public interface IUSB {
void swapData();
}
class MotherBoard {
void pluginIn(IUSB iusb) {
iusb.swapData();
}
}
class Demo{
public static void main(String[] args) {
MotherBoard board = new MotherBoard();
board.pluginIn(new IUSB() {
@Override
public void swapData() {
System.out.println("键盘打字");
}
});
board.pluginIn(new IUSB() {
@Override
public void swapData() {
System.out.println("鼠标移动");
}
});
}
}

枚举

引出枚举

Java接口/内部类_内部类_13

  • 枚举:比如:季节(春,夏,秋,冬)
  • 星期:周一到周日
  • 性别:男女
  • 表示一个事件固定状态

定义枚举

[修饰符] enum 枚举的名称 {
常量1,常量2,常量3,...
public enum Sex {
MAN,
FEMALE
}

Person.java

public class Person {
Sex name;
}
public class Demo {
public static void main(String[] args) {
Person person = new Person();
person.name = Sex.MAN;

System.out.println(person.name);
}
}

枚举创建源码分析

Java接口/内部类_内部类_14

Java接口/内部类_抽象类_15

Java接口/内部类_抽象类_16

UML中接口实现画法

  • 线条样式选择第二个再加三角空心箭头就表示实现的关系

Java接口/内部类_抽象类_17

Java接口/内部类_抽象类_18

工厂设计模式

  • 工厂模式是为了​​解耦​​,就是class A 想调用 class B,那么A只是调用B的方法,而至于B的实例化,就交给工厂类
  • 工厂模式可以降低​​代码重复​​,如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码,我们可以把这些创建对象B的代码放到工厂里统一管理,既减少了重复代码,也方便以后对B的创建过程的修改和维护
  • 因为工厂管理了对象的创建逻辑,使用者并不需要知道具体的创建过程,只管使用即可,减少了使用者因为创建逻辑导致的错误

简单工厂设计模式

定义一个接口

public interface Fruit {
void show();
}

定义两个水果类

public class Apple implements Fruit {
@Override
public void show() {
System.out.println("苹果");
}
}
public class Pear implements Fruit {
@Override
public void show() {
System.out.println("梨");
}
}

创建工厂

public class FruitFactory {
public Fruit createFruit(String type) {
if (type.equals("apple")) {
return new Apple();
} else if (type.equals("pear")) {
return new Pear();
} else {
return null;
}
}
}
public class Demo {
public static void main(String[] args) {
FruitFactory fruitFactory = new FruitFactory();
Apple apple = (Apple) fruitFactory.createFruit("apple");
apple.show();
Pear pear = (Pear) fruitFactory.createFruit("pear");
pear.show();
}
}

工厂方法设计模式

定义一个接口

public interface Fruit {
void show();
}

定义两个水果类

public class Apple implements Fruit {
@Override
public void show() {
System.out.println("苹果");
}
}
public class Pear implements Fruit {
@Override
public void show() {
System.out.println("梨");
}
}

创建FruitFactory接口

public interface FruitFactory {
Fruit createFruit();
}

用到什么类, 就写什么工厂

AppleFactory

public class AppleFactory implements FruitFactory{
@Override
public Fruit createFruit() {
return new Apple();
}
}

PearFactory

public class PearFactory implements FruitFactory{
@Override
public Fruit createFruit() {
return new Pear();
}
}

Demo.java

public class Demo {
public static void main(String[] args) {
AppleFactory appleFactory = new AppleFactory();
PearFactory pearFactory = new PearFactory();
Apple apple = (Apple) appleFactory.createFruit();
apple.show();
Pear pear = (Pear) pearFactory.createFruit();
pear.show();
}
}

抽象工厂设计模式

Cpu

public interface Cpu {
void run();

class Cpu600 implements Cpu {
@Override
public void run() {
System.out.println("Cpu600---run");
}
}

class Cpu800 implements Cpu {
@Override
public void run() {
System.out.println("Cpu800----run");
}
}
}

Screen

public interface Screen {
void size();

class Screen5 implements Screen {
@Override
public void size() {
System.out.println("Screen5----size");
}
}

class Screen8 implements Screen {
@Override
public void size() {
System.out.println("Screen8---size");
}
}
}

PhoneFactory

public interface PhoneFactory {
Cpu getCpu();
Screen getScreen();
}

HongMiFactory

public class HongMiFactory implements PhoneFactory{
@Override
public Cpu getCpu() {
return new Cpu.Cpu800();
}
@Override
public Screen getScreen() {
return new Screen.Screen8();
}
}

Demo.java

public class Demo {
public static void main(String[] args) {
HongMiFactory hongMiFactory = new HongMiFactory();
Cpu cpu = hongMiFactory.getCpu();
Screen screen = hongMiFactory.getScreen();

cpu.run();
screen.size();
}
}

工厂设计模式的选择

  • 对于简单工厂和工厂方法来说,两者的使用方式实际上是一样的
  • 如果对于产品的分类和名称是确定的,数量是相对固定的,推荐使用简单工厂模式
  • 抽象工厂用来解决相对复杂的问题,适用于一系列、大批量的对象生产