Java接口/内部类
抽象方法
我先举个例子引出抽象方法
,例如求圆、矩形、三角形、这些图形的面积
🐤发现的问题
- 每一个图形计算面积的方式都不一样, 所以每一个类都必须得要覆盖父类当中的
getArea
方法, 来去实现不同图形求面积的方式
🐸带来的问题
- 怎么样保证子类
必须
得要覆盖父类当中定义的方法 - 父类
不需要提供方法体
抽象方法
定义格式:在方法前面添加了一个关键字abstract
🐬抽象方法的特点
- 抽象方法是没有方法体的
- 抽象方法必须得要定义在抽象类 或 接口当中
- 抽象方法不能是私有的
private
,final
,static
🐤注意点
- 子类必须得要去覆盖此方法(定义的抽象方法)
- 在定义的时候不要有方法体
抽象类
- abstract修饰的类,就成为了抽象类
- 抽象类必须得要有子类才行。(抽象类一般都当作父类来继承)
🐥注意点
- 抽象类是不能直接创建对象的
- 抽象类当中,可以有抽象方法 ,也可以有非抽象方法(普通方法:给子类调用的)
- 子类没有去覆盖抽象方法,会把子类也变成抽象类
- 构造方法不能定义为私有化(抽象方法必须得要让子类继承之后,才能实现内部的方法体。子类继承的话,先去调用父类的构造方法)
- 抽象类不能使用final来去修饰
🦄抽象类与普通的类的区别
- 普通类你有的(方法 ,字段,构造器),抽象类都有
- 抽象类不能创建对象。抽象类可以包含抽象方法,也可以包含非抽象方法
- 抽象类必须有子类才有意义
接口
先来讲讲生活当中的物理接口
- 指的是两个硬件设备之间的连接方式。硬件接口既包括物理上的接口,比如我们所以说的USB接口
🦄Java当中的接口
- 在Java中,接口表示一种规范/约束/要求实现者必须遵循该规范,用来约束使用者应该怎么做
🐬规范和实现相分离的好处
主板上提供了USB插槽,只要一个遵循了USB规范的鼠标,就可以插入USB插槽,并与主板正常通信。至于这个鼠标是谁生产的,内部是如何实现的,主板都不需要关心(只要遵循了USB规范就可以插在主板上使用)。当鼠标坏了的时候,我主板不会坏
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);
}
}
内部类
- 定义在类当中 的一个类
- 内部类可以直接访问外部类当中 的成员
🐤为什么要有内部类
- 增强封装,把内部类隐藏在外部类当中,不允许其它类访问这个内部类
- 增加了代码的一个维护性
内部类分类
实例内部类
- 直接定义在类当中的一个类,在类前面没有任何一个修饰符,不属于类的,不使用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修饰的)的成员
- 外部类是不能直接访问内部当中 的成员(代码块区域就不同当然不能访问)
实例内部类变量的访问
静态内部类
在内部类前面加上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();
}
}
静态内部类注意点
- 静态内部类是不需要创建外部对象的
- 在静态内部类当中,是没有外部类引用
- 静态内部类,是可以访问外部类的静态成员
- 静态内部类当中可以定义静态成员,也可以定义非静态成员
静态内部类当中访问外部的普通变量
匿名内部类
就是一个没有名字的局部内部类,只使用一次的时候,来去使用匿名内部类,匿名内部类必须得要有父类才可以, 或者是实现了接口,当然这个可以使用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("鼠标移动");
}
});
}
}
枚举
引出枚举
- 枚举:比如:季节(春,夏,秋,冬)
- 星期:周一到周日
- 性别:男女
- 表示一个事件固定状态
定义枚举
[修饰符] 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);
}
}
枚举创建源码分析
UML中接口实现画法
- 线条样式选择第二个再加三角空心箭头就表示实现的关系
工厂设计模式
- 工厂模式是为了
解耦
,就是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();
}
}
工厂设计模式的选择
- 对于简单工厂和工厂方法来说,两者的使用方式实际上是一样的
- 如果对于产品的分类和名称是确定的,数量是相对固定的,推荐使用简单工厂模式
- 抽象工厂用来解决相对复杂的问题,适用于一系列、大批量的对象生产