文章目录

  • 面向对象编程
    • 前言
    • 继承
      • 关于protected(继承权限)访问权限
      • super 关键字
        • super 修饰属性
        • super 修饰构造方法
        • super 修饰普通方法
      • final 关键字和继承的联系
      • 类和类的关系
    • 多态
      • 向上转型
      • 方法重写
      • 向上转型
      • 向下转型
        • instanceof 关键字
    • 抽象类
      • 抽象的使用 1
      • 抽象类的使用 2
      • 抽象类的使用 3
      • 抽象类的使用 4
    • 接口
      • 接口允许多实现

面向对象编程

前言

关于访问修饰符

从小到大依次为:

private(私有,当前类的内部可见) < default(啥也不写就是包权限,当前包的内部可见,不包含子包,同级目录可见) < protected(继承,不同包的有继承关系的类之间可见) < public(公有,当前项目可见)

Java中的“包” 就是操作系统的文件夹。

声明一个包使用 package关键字,在实际中,创建package 包,在包的命名时,若存在多个文件夹的嵌套,使用“.”分隔,就会产生嵌套的“包”。(需要在旁边的设置的符号中,取消 Compact Middle Packages 这个选项)

包的存在就是为了解决类同名的问题

如何导入某个包中的某个类

使用import 导入类,import语句只能导入相关包中的某个具体的类


此时若还要用到这个包中的类,不需要一行行写,

import java.util.*;

此时将整个util包下的所有类按需加载,此时导入的还是类,而不是把util文件夹导入!!!

一般不推荐 import .*;,会有歧义,若程序中用到了两个相同名称的类,并且两个类的包都使用 import .*; 直接导入类的包。此时会报错。


在程序中用到了两个相同名称的类,有两种方法:

  1. 使用类的全名称, 包名.类名
  2. import 明确指定导入的是哪个包下的哪个类,例如:import java.util.Date;

静态导入:

import static 可以导入包中的静态方法和静态属性


常见的系统包:

java.lang :JDK的基础类,System,String,Object都在这个包下,JDK1.1之后,这个包下的所有类自动导入

java.lang.reflect: 反射开发包

java.util: 工具包(集合类都在这个包下,Arrays,Linked List,HashMap)

java.io: I/O开发包,文件读取和写入

java.net: 网络编程开发包,Socket

java.sql: 数据库开发需要的包


继承

面向对象一共有三大特性:封装,继承和多态。

封装:具有保护性和易用性(封装就有很多种表达形式)。private实现属性或方法的封装只是封装的其中一种。

那么什么是方法重载呢?

方法重载就是在同一个类中定义了多个方法名称相同,参数列表不同,与返回值无关的一组方法,这样的一组方法就被称之前方法重载。


来看这几个代码:

public class Vehicle {public String name;public void speed(int num){System.out.println(name + "的速度是" + num + "Km/h");}
}
public class Car {public String name;public void speed(int num){System.out.println(name + "的速度是" + num + "Km/h");}
}
public class Airplane {public String name;public void speed(int num){System.out.println(name + "的速度是" + num + "Km/h");}
}

这三个类的代码完全相同,正常来说,所有的交通工具都具有name属性,以及他的speed(速度)属性。

在这三类中,汽车是交通工具,飞机也是交通工具。所以,car 和 airplane 都应该是Vehicle 的子类。

当类和类之间满足一个类(a) is a 另一个类(b),一定存在继承关系。a 继承了b

当一个类继承了另一个类,另一个类中的所有属性和方法(包括静态的属性和方法) 子类就天然具备了。


在java中使用extends表示类的继承。

Car extends Vehicle

Car 就是子类/派生类, Vehicle 就是父类/基类。

那么上面的代码就可以变为

public class Vehicle {public String name;public void speed(int num){System.out.println(name + "的速度是" + num + "Km/h");}
}
public class Car extends Vehicle {}
public class Airplane extends Vehicle{}

注意:不能为了省略代码就简单的使用继承,要想使用继承必须要满足继承的关系,不满足继承关系的类之间千万不能使用继承。


继承的规则

  1. 要能使用继承,必须满足类之间的 is a 关系
  2. 一个子类只能使用extends 继承一个父类。(单继承)

Java中不允许多重继承,extends 后面只能跟父类,但是允许多层继承,没办法当儿子,可以当孙子。

满足继承关系的类之间一定是逻辑上垂直的关系

  1. 子类会继承父类的所有属性和方法,显示继承 :public属性 和方法可以直接使用。 隐式继承: private 属性和方法,子类其实继承了这个属性和方法,但是无法直接使用。要看父类是否会提供set get 权限给子类。

    子类继承父类的所有属性和方法,包括静态的属性和方法,区别就在于是通过子类对象访问,还是直接通过类名称进行访问。

    就好比你现在要让你爸告诉你 他银行卡的密码是什么,你作为儿子,你可以知道,但是需要你爸自己愿意告诉你,你才能知道。否则你肯定不会知道。


关于protected(继承权限)访问权限

protected 访问权限:

  1. protected 作用域 :当前类的内部可见,不同包中的有继承关系的类之间可见。

    在不同包的子类中访问protected 权限修饰的方法和属性时,只能通过该子类对象进行访问,其他子类对象和父类对象均无法访问

  2. 同包下的没有关系的类可见

    那为什么protected 继承权限在同包下的没有关系的类中可见呢?

    因为

    ​ private < default(包权限) < protected < public , 既然 protected权限大于包权限,那么包权限可见的范围,protected继承权限一样可见。

注意: protected 权限的属性和方法 在不同包中 没有继承关系的类中 是不可见的


super 关键字

复习一下 this关键字:

  1. 修饰属性,表示直接从当前类中调用同名属性 this.name

  2. 修饰方法,表示直接调用当前类的方法

    调用普通成员方法——this.方法()写不写this都一样,因为不写的话,编译器编译之后会默认加this

    构造方法的互相调用——不同参数的构造方法之间出现了重复的调用,那么这个时候就可以使用this(参数) 调用其他的构造方法

    • this 调用其他的构造方法必须放在当前构造方法的首行。

    • this 调用构造方法不能成”环“。(就是这样规定的)

  3. 表示当前对象的引用

super关键字:

  1. 修饰属性,表示直接从父类中去寻找同名属性
  2. 修饰方法,表示直接从父类中去寻找方法

在学习super关键字之前,我们要了解:

当我们要产生一个子类对象,默认首先产生父类对象。

父类

package InheritTest;
//父类
public class Vehicle {public  Vehicle(){System.out.println("1 Vehicle 的无参构造");}
}

子类

package InheritTest;public class Car extends Vehicle {public Car() {System.out.println("2 Car的无参构造");}
}

测试类

package InheritTest;public class Test {public static void main(String[] args) {Car car = new Car(); // 产生一个子类对象}
}

此时的输出结构是:

1 Vehicle 的无参构造
2 Car的无参构造

当调用new Car 无参构造一个子类对象之前,默认先调用父类的构造方法产生父类对象,才会执行子类的构造方法


来看这个代码应该输出多少?

父类:

package Question;public class B {public B(){System.out.println("1 B 的构造方法");}{System.out.println("2 B 的构造块");}static {System.out.println("3 B 的静态块");}
}

子类:

package Question;public class D extends B{public D(){System.out.println("4 D 的构造方法");}{System.out.println("5 D 的构造块");}static {System.out.println("6 D 的静态块");}public static void main(String[] args) {System.out.println("7 main开始执行");new D();new D();System.out.println("8 main 结束执行");}
}

输出结果是:

3 B 的静态块
6 D 的静态块
7 main开始执行
2 B 的构造块
1 B 的构造方法
5 D 的构造块
4 D 的构造方法
2 B 的构造块
1 B 的构造方法
5 D 的构造块
4 D 的构造方法
8 main 结束执行

解答:

由于main方法在子类中,要执行main方法就要加载子类,

加载子类时 要首先加载父类,此时执行父类的静态块(3),

然后加载子类,执行子类的静态块(6),

main方法开始执行,打印7,

new D(); 产生一个子类,产生子类对象先要产生一个父类对象,产生父类对象时,先调用构造块(2)

因为静态块只在类加载的时候执行一次,后面不在执行

构造块每次在产生一个对象是都要执行

然后再调用构造方法(1),父类对象产生

产生子类对象时,也是先调用构造块(5),再调用构造方法(4),子类对象产生。

又new D(); 重复上面的步骤,2 1 5 4

最后打印8。

所以结果就是 3 6 7 2 1 5 4 2 1 5 4 8


super 修饰属性

super修饰属性:表示在父类中寻找同名属性

当在有继承关系的类中,this关键字默认先在当前类中寻找同名属性,若没有找到,继续向上寻找父类中是否有同名属性。


若此时有继承关系的子类中有一个name属性为 儿子,父类中也有一个name属性为父亲,那么在子类中直接打印name, 打印的是子类中的儿子,那我们怎么能够打印父类中的父亲呢,这时就可以使用 super 关键字,直接在父类中寻找name属性。

看看代码会更好理解:

父类

package SuperTest;public class Father {protected String name = "父亲";
}

子类

package SuperTest;public class Son extends Father{public void fun(){System.out.println(this.name);}public static void main(String[] args) {Son son = new Son();son.fun();}
}

此时的子类使用this关键字来打印子类中的name属性,但是子类中没有name属性,就从父类中去寻找name属性,输出结果就是

父亲

再看这个代码:

父类

package SuperTest;public class Father {protected String name = "父亲";
}

子类

package SuperTest;public class Son extends Father{public String name = "儿子";public void fun(){System.out.println(this.name);}public static void main(String[] args) {Son son = new Son();son.fun();}
}

此时的子类代码中已经有了name属性,就直接从子类中找到了name属性,输出结果就是

儿子

那此时我们想在这个子类在访问到父类的name属性,我们就是使用super关键字,把this.name 改为 super.name,此时 子类就访问到了 父类的name属性。


注意:

super 先从直接父类中寻找同名属性,若不存在再向上寻找

this 直接从当前类中直接寻找,若不存在再向上寻找


super 修饰构造方法

用法:

  1. super(父类构造方法的参数);
  2. super();
    super 的位置和this 一样,也要处于构造方法的首行

若父类中不存在无参构造,则子类构造方法的首行必须使用 super(有参构造)

但是若父类存在无参构造,则子类构造方法不需要再写 super(); 调用无参构造,JVM会默认调用(隐式调用)

还要注意,在一个构造方法中,无法显式的使用 this()和super() 同时出现。两个都要在构造方法的首行,会产生矛盾。

当产生子类对象时,默认先产生父类对象,若父类对象还有父类,继续向上先产生祖类对象。


当我们在父类中写一个有参的构造方法,此时父类的无参构造就不在产生。那我们在在new 一个只有无参构造的子类对象时,先要产生父类对象,但是找不到父类的无参构造,此时就会出现编译报错

那我们此时就要在子类无参构造的首行写入 super(参数); ,让子类能够找到父类的构造方法,产生父类对象


看正确的代码

父类

package SuperTest;public class Father {protected String name = "父亲";public Father(String name){this.name = name;System.out.println("Father 的有参构造");}
}

子类

package SuperTest;public class Son extends Father{public String name = "儿子";public Son(){super("爸爸");System.out.println("Son 的无参构造");}public static void main(String[] args) {Son son = new Son();}
}

如果不加 super(“爸爸”); 就会编译报错,


super 修饰普通方法

super 修饰普通方法和修饰属性一样,直接从父类中寻找同名方法。

当在有继承关系的类中,this关键字默认先在当前类中寻找同名方法,若没有找到,继续向上寻找父类中是否有同名方法。

父类

package SuperTest;public class Father {protected String name = "父亲";public Father(String name){this.name = name;System.out.println("Father 的有参构造");}public void fun(){System.out.println("Father 的fun 方法");}
}

子类

package SuperTest;public class Son extends Father{public String name = "儿子";public void fun(){System.out.println("Son 的fun方法");}public void test(){super.fun(); //调用父类的 fun方法this.fun();  //调用子类的 fun方法,若子类没有System.out.println(this);  //打印当前对象的引用System.out.println(super); //会报错,必须是 super.name  直接使用super 是错误的}public Son(){super("爸爸");System.out.println("Son 的无参构造");}public static void main(String[] args) {Son son = new Son();son.test();}
}

super 可以访问父类的属性和方法,必须是super.name, 不能直接使用super


final 关键字和继承的联系

final 关键字:

  1. 修饰属性,表示属性值不能变,常量,值定义之后无法被修改
  2. 修饰类,表示这个类无法被继承。

类和类的关系

类和类直接除了继承关系(狗 is a 动物),还有组合关系(has a),以及没有任何关系。



多态

多态:一个引用可以表现出多种行为或者特性就是多态性

最主要的多态:继承 + 方法重写

向上转型

正常我们new一个对象时,都是 类名称 类引用 = new 该类对象();

但是当我们在有继承关系的类之间时,我们可以 这样 父类名称 父类引用 = new 子类对象();,因为子类继承了父类,那么父类就可以指代所有的子类。就是向上转型。

向上转型发生在有继承关系的类之间,父类名称 父类引用 = new 子类实例();,不一定是直接子类,也可以是孙子类,子子孙孙无穷尽。

向上转型最大的意义在于参数统一化,降低使用者的使用难度


父类

package InheritTest;public class Vehicle {protected String name = "123";public void fun(){System.out.println("Vehicle的fun方法");}
}

子类

package InheritTest;public class Car extends Vehicle {public void fun(){System.out.println("Car的fun方法");}
}

子类

package InheritTest;public class Airplane extends Vehicle {public void fun(){System.out.println("Airplane的fun方法");}
}

测试类:

package InheritTest;public class Test {public static void main(String[] args) {funs(new Vehicle());funs(new Car());funs(new Airplane()); //扩展的,添加子类后,直接在使用时 用就即可,fun方法不需要做任何改变,因为最顶层的父类引用可以指代所有的子类对象}//只要是Vehicle 及其子类,都是天然的Vehicle对象,都满足 is a 关系//通过Vehicle最顶层的父类引用,可以指代所有的子类对象public static void funs(Vehicle vehicle){vehicle.fun();}
}

有向上转型后,最顶端的父类引用可以指代所有的子类对象。当父类有新的子类时,是非常容易扩展的!!!

那这个代码的输出是:

Vehicle的fun方法
Car的fun方法
Airplane的fun方法

funs中vehicle局部变量的引用调用fun方法时,当传入不同的对象时,表现出来了不同的fun方法行为,就是多态性。


同一个引用(变量名称),同一个方法名称,根据对象的不同表现出来了不同的行为,就是多态


那为何会出现多态这种情况呢?

就是方法覆写的问题。


方法重写

方法重载(overload):在一个类的内部,有多个方法名称相同的,参数列表不同,与返回值无关的一组方法。

方法重写(覆写)(override):发生在有继承关系的类之间,子类定义了和父类除了权限不同,其他全部相同的方法,这样的一组方法就是方法重写。

 Vehicle ve1 = new Car();Vehicle ve2 = new Airplane();fun(ve1);fun(ve2);public static void fun(Vehicle vehicle){vehicle.fun();}

在调用时 调用的是谁的方法呢?

不需要看前半部分,只需要看当前new 的是哪个类的对象,new Car()就是new 了一个Car类的对象,若Car类重写了相关的方法,则调用的是Car类中重写后的方法,若没有重写,则调用的是直接父类的方法。就近匹配原则。


当发生重写时, 子类权限 >= 父类权限才可以重写。 小于的话编译时就会报错

private < default < protected < public

那么父类方法中使用了private 权限,子类方法在使用public 权限,public > private,是否可以重写呢

不能重写。private权限不包含在内。出了这个类,子类根本不知道有这个方法。


Java中有一个注解 @Override ,使用这个注解写在重写方法之前,帮你校验你的方法是否符合重写规则。


能否重写static 方法呢?

多态的本质就是因为调用了不同子类对象,这些子类对象所属的类 覆写相应的方法,才能表现出不同的行为。 而static 方法和对象无关,不能重写。

方法重写只发生在普通方法中


重写的方法返回值类型完全相同或者至少是向上转型类的返回值。


向上转型

向上转型发生的时机:

  1. 方法传参
  2. 直接赋值
Vehicle ve = new Car();
  1. 方法返回值
public static Vehicle test(){  //返回值为父类Car car = new Car();return car;  //实际返回的类型是子类
}

当此时子类对象时,要先产生父类对象,若产生父类对象时,调用父类的构造方法内存在 子类覆写的方法,此时调用的是子类覆写后的方法,而不是子类覆写前的方法。


总结:

向上转型

父类名称 父类引用 = new 子类对象();

这是天然发生的向上转型,使用父类引用调用普通方法时,若子类重写了该方法,则调用该对象所在子类覆写后的方法。

注意: 类名称 引用名称 = new 类实例();

引用名称.方法名称();

能通过"."访问的方法是由 类名称说了算,能访问的这些方法必须在类中定义过,编译器会先在类中查找是否包含指定方法,若没有,会报错。

这个通过"." 访问的方法到底表现出哪个类的样子,是由new 的类实例所在的类说了算。

简单来说就是,能 . 哪些方法 前面说了算,至于 . 之后这方法有什么行为,后面new的对象所在的类说了算。


向下转型

来看这个例子:

Animal 是父类, Dog是子类

Animal animal = new Dog();

animal.play();

此时父类中的没有play()方法,在子类中拓展一个play()方法,直接使用父类引用是无法调用子类的拓展方法。

我们要使用子类的拓展方法就要把他还原为子类引用,通过子类引用来访问子类的拓展方法,就是向下转型。

//子类名称 子类引用 = (子类名称)父类引用
Dog dog = (Dog)animal;

将父类引用强制类型转化为子类引用,就是向下转型。

要发生向下转型,先要发生向上转型。

Animal animal = new Animal();
//animal 就是一个 Animal类产生的对象的引用,和其他的类毫无关系
Dog dog = (Dog)animal;

这个是会报错的,毫无关系的两个类直接没办法强制类型转换。

ClassCastException 就是类型转换异常。


        Vehicle vehicle1 = new Car();System.out.println(vehicle1);Car car = (Car)vehicle1;System.out.println(car);

打印父类引用 和 向下转型后的子类引用,会发现他们的输出地址都一样,说明只有一个对象,发生改变的只是引用的名字。


instanceof 关键字

当发生向下转型时会有风险,出现类型转换异常,那我们就可以使用 instanceof关键字。

引用名称 instanceof 类 -> 就会返回一个布尔值,表示该引用名称指向的本质是不是该类的对象。

例子:

使用instanceof关键字的返回值 搭配的分支语句进行类型转换。

package InheritTest;public class Test {public static void main(String[] args) {Vehicle vehicle1 = new Car();//Car 继承了 VehicleVehicle vehicle2 = new Vehicle();if(vehicle1 instanceof Car){Car car = (Car) vehicle1;System.out.println("转换成功");}else {System.out.println("vehicle1 本质指向的不是Car这个类的引用");}if(vehicle2 instanceof Car){Car car = (Car) vehicle1;System.out.println("转换成功");}else {System.out.println("vehicle2 本质指向的不是Car这个类的引用");}}
}

输出结果:

转换成功
vehicle2 本质指向的不是Car这个类

总结:

只有在某个特殊的情况下,需要使用子类拓展的方法,才需要将原本向上转型的引用 进行向下转型 还原为子类引用。


抽象类

若需要强制要求子类覆写方法,就要用到抽象类。

其实现实生活中有很多的 抽象类,这些类都是概念化的,没法具体到某个实例,描述这一类对象共同的属性和行为。

交通工具 —> 抽象,没法对应具体的某个或者某一类的工具,汽车、自行车、飞机、火车等等

抽象类是普通类的"超集",只是比普通类多了一些抽象方法而已。普通类有的抽象类全都有!

抽象方法所在的类必须是抽象类,子类若继承了抽象类,必须覆写所有的抽象方法。(子类是普通类,子类若是抽象类,就不需要进行覆写)

Java中定义抽象类或者抽象方法使用 abstract关键字。


抽象的使用 1

抽象方法所在的类必须使用abstract声明为抽象类.

抽象方法指的是使用abstract关键字声明,只有函数声明,没有函数实现的方法,称之为抽象方法。

package Abstract;public abstract class Vehicle {  //声明为抽象类public abstract String name(); //抽象方法
}

抽象方法:使用关键字abstract声明,只有方法声明,没有方法体( “{}”)的方法。

抽象方法在抽象类中没有具体实现,延迟到子类实现。


来做一个判断题

java中,没有方法体的方法就是抽象方法。 error

因为本地方法也没有方法体,但他不是抽象方法。


抽象类的使用 2

若一个类使用abstract 关键字声明为抽象类,无法直接通过该类 实例化对象,哪怕该类中一个抽象方法也没有。

当一个类是抽象类,不管他有没有抽象方法,这个类本身就是一个抽象的概念,就没有办法具体到某个特定的实例,只能通过 子类 向上转型变为抽象父类的引用。

抽象类虽然没有办法直接实例化对象,子类仍然满足 is a 原则, 子类和抽象父类直接仍然是满足 继承树的关系

//此时Vehicle 是抽象类
Vehicle vehicle = new Car(); //这是正确的
Vehicle vehicle = new Vehicle(); // 这是错误的

抽象类的使用 3

子类继承了抽象类,就必须强制子类(子类是普通类)覆写 抽象类中的所有抽象方法(包括抽象类继承另一个抽象类中的方法),也满足单继承局限,一个子类只能继承一个抽象类。

package Abstract;
abstract class A{public abstract void add();
}
//抽象类 可以不覆写或者选择性的覆写父类中的抽象方法
abstract  class B extends A{public abstract void del();
}
//普通类,必须覆写B中的所有抽象方法(包括继承来的抽象方法)
//若B中选择性覆写了他继承的抽象类的抽象方法,则B 覆写了的抽象方法,B的子类可以不进行覆写。!!!!!!!
public class Vehicle extends B{@Overridepublic void del() {}@Overridepublic void add() {}
}

若B中选择性覆写了他继承的抽象类的抽象方法,则B 覆写了的抽象方法,B的子类可以不进行覆写!!!!!!!

抽象类的使用 4

抽象类是普通方法的超集(普通类有的内容,抽象类都有),只是比普通类多了一些抽象方法而已,抽象类虽然没有办法直接实例化对象,但是也可以存在构造方法,子类在实例化对象时,仍然遵从继承的规则,先调用父类(抽象类)的构造方法,而后调用子类的构造方法!!

package Abstract;abstract class A{public abstract void add();public A(){System.out.println("A 的构造方法");this.add();}
}
public class Vehicle extends A{@Overridepublic void add() {System.out.println("num = " + num);}private int num = 10;public static void main(String[] args) {new Vehicle();}
}

输出是:

A 的构造方法
num = 0

在主方法中new Vehicle(); 时,先调用父类(抽象类)的构造方法,构造方法中又调用add()方法,子类中覆写了add方法,所以这个add 方法是子类的,由于还没有执行子类的构造方法,所以num 还没有初始化 为 10。


若一个需求既可以使用抽象类的,也可以使用接口,那我们优先使用接口。抽象类仍然是单继承局限。


接口

一般来说,接口的使用表示两种场景

1 接口表示具备某种能力或行为,子类实现接口时 不是 is a, 而是具备这种行为或者能力。

”跑“ —> 是能力或者行为,狗满足跑接口,猫也满足跑接口。

2 接口表示一种规范或标准。USB接口、5G标准


接口中只有全局常量和抽象方法 —> 更加纯粹的抽象概念。其他东西统统没有

接口使用关键字 interface声明接口(创建新的 java Class 文件时,选择interface ),子类(普通类)使用implements实现接口。


接口和类的关系:
1 接口和接口之间也存在继承关系,接口坚决不能继承一个类。

若一个接口同时继承 了多个父接口,则这个接口也继承了所有的抽象方法,子类在实现这个接口时,必须覆写所有的抽象方法。

2 如果一个类既需要继承一个类,同时实现多个接口时, 先使用 extends 继承一个类,而后使用 implements 实现多个父接口。

class China extend 类名称 implements 接口名称{}

USB接口

package Interface_test;
//接口使用interface 关键字定义,只有全局常量(1%接口才有)和抽象方法(99%)
public interface USB {//插入public abstract void plugIn();//工作public abstract void work();
}

子类使用 implements实现接口, 必须覆写所有的抽象方法

鼠标、键盘这些都属于USB接口的子类。

package Interface_test;public class Mouse implements USB{@Overridepublic void plugIn() {System.out.println("鼠标驱动正在安装...");}@Overridepublic void work() {System.out.println("鼠标驱动安装成功!!!");}
}
package Interface_test;public class KeyBoard implements USB{@Overridepublic void plugIn() {System.out.println("键盘驱动正在安装...");}@Overridepublic void work() {System.out.println("键盘驱动安装成功!!!");}
}

那么电脑这个类算不算USB接口的子类呢?

所有带USB线插入到电脑的设备都应该满足USB规范。 电脑应该叫做USB规范的使用者。

package Interface_test;public class Computer {public static void main(String[] args) {Computer computer = new Computer();Mouse mouse = new Mouse();computer.fun(mouse);KeyBoard keyBoard = new KeyBoard();computer.fun(keyBoard);}public void fun(USB usb){usb.plugIn();usb.work();}
}

此时为何方法的参数用的是USB接口引用?

fun方法就模拟电脑的接口,对于电脑的使用者和生产者来说,根本不关心到底哪个具体设备插到电脑上,只要满足了USB接口,就能够被电脑识别。就可以实现,一个接口可以接收无数种设备。兼容所有的USB对象。

假如fun方法的参数是(Mouse mouse),那么电脑的这个接口就只能插鼠标,电脑总不能设置很多个接口吧。


若此时电脑多了一个新的USB的子类,对于电脑这个类来说,一点都不影响,一行代码都不会改变。

这就是开闭原则,所有的设计模式的核心思想:程序应该对扩展开放,对修改关闭。 方便扩展,不能影响已经写好的程序。


接口允许多实现

接口表示能力,允许多实现,一个类可能具备多个能力,同时实现多个父接口

若实现多个父接口,子类(普通类)需要覆写所有的抽象方法。

package Interface_test.RunJump;
//跑的接口
public interface Run {public abstract void run();
}
package Interface_test.RunJump;
//跳的接口
public interface Jump {public abstract void jump();
}

子类实现多个父接口,多个父接口直接使用","分开

package Interface_test.RunJump;
//子类 猫 具有 跑和跳的能力,实现多个父接口,多个父接口直接使用","分开
public class Cat implements Run,Jump{@Overridepublic void jump() {System.out.println("猫会跳");}@Overridepublic void run() {System.out.println("猫会跑");}
}
package Interface_test.RunJump;
//测试
public class Test {public static void main(String[] args) {Run catRun = new Cat();  //向上转型catRun.run(); //通过父类接口引用访问子类对象方法Jump catJump = new Cat();catJump.jump();}
}

接口也不能直接实例化对象,需要向上转型,


由于接口中只有全局常量和抽象方法,因此在接口中 public abstract 抽象方法

static final 全局常量,这些关键字都可以省略。

以后在接口声明中,这些关键字都不需要写,只保留最核心的方法返回值,方法参数列表,名称即可。


要是对大家有所帮助的话,请帮我点个赞吧。

【Java学习—(13)看完这篇文章,这些继承、多态、抽象、接口就是小儿科】相关推荐

  1. java与python难度对比_Python和Java的区别,看完这篇文章你就清楚啦

    众所周知,在数不清的编程语言中Java自诞生之日起长盛不衰,可谓是神话般的存在.随着人工智能时代的到来,Python迅速席卷全球,作为当下最热门的编程语言,因其简单实用且应用场景广泛备受青睐. 一个是 ...

  2. java 铺地板问题_客厅铺地板后悔了?看完这篇文章再说...

    原标题:客厅铺地板后悔了?看完这篇文章再说... 最近有网友说客厅铺木地板很后悔, 其实通铺了木地板的客厅, 真的很温馨,家的港湾莫过于此. 对于喜欢光脚在家的人来说, 客厅如果是铺地砖, 冰冰凉凉, ...

  3. 运维学python用不上_作为运维你还在想要不要学Python,看完这篇文章再说!

    原标题:作为运维你还在想要不要学Python,看完这篇文章再说! 本文由马哥教育Python自动化实战班5期学员推荐,转载自简书,作者为Li.Yingjie,内容略经小编改编和加工,观点跟作者无关,最 ...

  4. Dart语言基础,看完这篇文章就够了(二)

    文章内容是我在学习Flutter过程中对知识点的梳理和总结.如有不对的地方,欢迎指出. 本文承接Dart语言基础,看完这篇文章就够了(一),进一步了解Dart语法知识. 文章目录 1 流程控制语句 2 ...

  5. python装饰器原理-看完这篇文章还不懂Python装饰器?

    原标题:看完这篇文章还不懂Python装饰器? 1.必备 2.需求来了 初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作.redis调用.监控API等功能.业务部门 ...

  6. 手把手教你完成CSDN对接百度统计 看完这篇文章你还不会对接 欢迎您提刀顺着网线来砍我!!!!

    大家好,我是:じ☆ve朽木,开发经验都是一步一步慢慢积累的,没有谁生来就具有的,只要我们付出了努力,肯定就会有收获!进入我的博客,带你了解Java知识,js小技巧,带你玩转高端物联网.博客地址为:じ☆ ...

  7. [转帖]看完这篇文章你还敢说你懂JVM吗?

    看完这篇文章你还敢说你懂JVM吗? 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用 ...

  8. JVM难学?那是因为你没认真看完这篇文章

    JVM难学?那是因为你没认真看完这篇文章 一:虚拟机内存图解 JAVA程序运行与虚拟机之上,运行时需要内存空间.虚拟机执行JAVA程序的过程中会把它管理的内存划分为不同的数据区域方便管理. 虚拟机管理 ...

  9. 看完这篇文章知道有什么英语录音翻译成中文的软件

    英语是我们从小到大九年义务必学的科目,但是到了上大学的时候不同专业学习大学英语的时间并不一样,可能是一学期也可能是两个学期,所以很多人都开始通过网课来学习英语或者听外国英语录音,从而帮助我们通过雅思. ...

最新文章

  1. 传海思砍台积电第三季度一半手机订单
  2. DUILib 中的通知事件
  3. 一天学完spark的Scala基础语法教程七、数组(idea版本)
  4. python 工资管理软件_4_python之路之模拟工资管理系统
  5. 在 .NET 中加载椭圆曲线 (EC) 密钥
  6. java ready_Java PushbackReader ready()用法及代码示例
  7. Java 计算两个日期相差的天数
  8. Mongo之架构部署(Replica Sets+Sharding)
  9. @ResponseBody与@RestController的作用与区别
  10. 旧板与IO板之间的连接
  11. 安卓-利用android studio制作简单的QQ登陆login界面
  12. bodymovin输出Json动画为黑白的解决方案
  13. matlab数值分析作业答案,Matlab作业3(数值分析)答案
  14. fontawesome 助手
  15. 隐藏在网络邻居背后的协议,快来看看你家网络有几种?
  16. 通过财务报表读懂美股
  17. 统计学的Python实现-019:任意正态分布计算概率
  18. 为什么我的 WordPress 网站被封了?
  19. Android开发--更换字体
  20. ASP 五年总结精华源码

热门文章

  1. 数据结构(一):入门
  2. 元宇宙的几大核心问题
  3. 计算机类和信息与计算科学专业有什么区别,信息与计算科学专业主要学什么
  4. 开迅雷后浏览不了网页的问题
  5. Sprin_使用注解进行属性注入和整合Mybatis
  6. socks5 mysql认证_sock5代理服务器-SS5篇
  7. Eclipse4.7.2 Nodeclipse1.0.2 CodeMix3
  8. 励志成为优产的母猪--------猜数游戏 ,历史记录,pickle保存,队列deque
  9. 黑马程序员,黑马论坛----Java+云计算4期,100%全部就业,平均薪水6965元!
  10. Swift学习之:设置渐变色