【Java学习—(13)看完这篇文章,这些继承、多态、抽象、接口就是小儿科】
文章目录
- 面向对象编程
- 前言
- 继承
- 关于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 .*; 直接导入类的包。此时会报错。
在程序中用到了两个相同名称的类,有两种方法:
- 使用类的全名称, 包名.类名
- 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{}
注意:不能为了省略代码就简单的使用继承,要想使用继承必须要满足继承的关系,不满足继承关系的类之间千万不能使用继承。
继承的规则:
- 要能使用继承,必须满足类之间的 is a 关系
- 一个子类只能使用extends 继承一个父类。(单继承)
Java中不允许多重继承,extends 后面只能跟父类,但是允许多层继承,没办法当儿子,可以当孙子。
满足继承关系的类之间一定是逻辑上垂直的关系
子类会继承父类的所有属性和方法,显示继承 :public属性 和方法可以直接使用。 隐式继承: private 属性和方法,子类其实继承了这个属性和方法,但是无法直接使用。要看父类是否会提供
set get
权限给子类。子类继承父类的所有属性和方法,包括静态的属性和方法,区别就在于是通过子类对象访问,还是直接通过类名称进行访问。
就好比你现在要让你爸告诉你 他银行卡的密码是什么,你作为儿子,你可以知道,但是需要你爸自己愿意告诉你,你才能知道。否则你肯定不会知道。
关于protected(继承权限)访问权限
protected 访问权限:
protected 作用域 :当前类的内部可见,不同包中的有继承关系的类之间可见。
在不同包的子类中访问protected 权限修饰的方法和属性时,只能通过该子类对象进行访问,其他子类对象和父类对象均无法访问
同包下的没有关系的类可见
那为什么
protected
继承权限在同包下的没有关系的类中可见呢?因为
private < default(包权限) < protected < public , 既然
protected
权限大于包权限,那么包权限可见的范围,protected
继承权限一样可见。
注意: protected
权限的属性和方法 在不同包中 没有继承关系的类中 是不可见的
super 关键字
复习一下 this
关键字:
修饰属性,表示直接从当前类中调用同名属性 this.name
修饰方法,表示直接调用当前类的方法
调用普通成员方法——this.方法()写不写this都一样,因为不写的话,编译器编译之后会默认加
this
,构造方法的互相调用——不同参数的构造方法之间出现了重复的调用,那么这个时候就可以使用
this(参数)
调用其他的构造方法this 调用其他的构造方法必须放在当前构造方法的首行。
this 调用构造方法不能成”环“。(就是这样规定的)
表示当前对象的引用
super
关键字:
- 修饰属性,表示直接从父类中去寻找同名属性
- 修饰方法,表示直接从父类中去寻找方法
在学习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 修饰构造方法
用法:
- super(父类构造方法的参数);
- 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 关键字:
- 修饰属性,表示属性值不能变,常量,值定义之后无法被修改
- 修饰类,表示这个类无法被继承。
类和类的关系
类和类直接除了继承关系(狗 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 方法和对象无关,不能重写。
方法重写只发生在普通方法中
重写的方法返回值类型完全相同或者至少是向上转型类的返回值。
向上转型
向上转型发生的时机:
- 方法传参
- 直接赋值
Vehicle ve = new Car();
- 方法返回值
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)看完这篇文章,这些继承、多态、抽象、接口就是小儿科】相关推荐
- java与python难度对比_Python和Java的区别,看完这篇文章你就清楚啦
众所周知,在数不清的编程语言中Java自诞生之日起长盛不衰,可谓是神话般的存在.随着人工智能时代的到来,Python迅速席卷全球,作为当下最热门的编程语言,因其简单实用且应用场景广泛备受青睐. 一个是 ...
- java 铺地板问题_客厅铺地板后悔了?看完这篇文章再说...
原标题:客厅铺地板后悔了?看完这篇文章再说... 最近有网友说客厅铺木地板很后悔, 其实通铺了木地板的客厅, 真的很温馨,家的港湾莫过于此. 对于喜欢光脚在家的人来说, 客厅如果是铺地砖, 冰冰凉凉, ...
- 运维学python用不上_作为运维你还在想要不要学Python,看完这篇文章再说!
原标题:作为运维你还在想要不要学Python,看完这篇文章再说! 本文由马哥教育Python自动化实战班5期学员推荐,转载自简书,作者为Li.Yingjie,内容略经小编改编和加工,观点跟作者无关,最 ...
- Dart语言基础,看完这篇文章就够了(二)
文章内容是我在学习Flutter过程中对知识点的梳理和总结.如有不对的地方,欢迎指出. 本文承接Dart语言基础,看完这篇文章就够了(一),进一步了解Dart语法知识. 文章目录 1 流程控制语句 2 ...
- python装饰器原理-看完这篇文章还不懂Python装饰器?
原标题:看完这篇文章还不懂Python装饰器? 1.必备 2.需求来了 初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作.redis调用.监控API等功能.业务部门 ...
- 手把手教你完成CSDN对接百度统计 看完这篇文章你还不会对接 欢迎您提刀顺着网线来砍我!!!!
大家好,我是:じ☆ve朽木,开发经验都是一步一步慢慢积累的,没有谁生来就具有的,只要我们付出了努力,肯定就会有收获!进入我的博客,带你了解Java知识,js小技巧,带你玩转高端物联网.博客地址为:じ☆ ...
- [转帖]看完这篇文章你还敢说你懂JVM吗?
看完这篇文章你还敢说你懂JVM吗? 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用 ...
- JVM难学?那是因为你没认真看完这篇文章
JVM难学?那是因为你没认真看完这篇文章 一:虚拟机内存图解 JAVA程序运行与虚拟机之上,运行时需要内存空间.虚拟机执行JAVA程序的过程中会把它管理的内存划分为不同的数据区域方便管理. 虚拟机管理 ...
- 看完这篇文章知道有什么英语录音翻译成中文的软件
英语是我们从小到大九年义务必学的科目,但是到了上大学的时候不同专业学习大学英语的时间并不一样,可能是一学期也可能是两个学期,所以很多人都开始通过网课来学习英语或者听外国英语录音,从而帮助我们通过雅思. ...
最新文章
- 传海思砍台积电第三季度一半手机订单
- DUILib 中的通知事件
- 一天学完spark的Scala基础语法教程七、数组(idea版本)
- python 工资管理软件_4_python之路之模拟工资管理系统
- 在 .NET 中加载椭圆曲线 (EC) 密钥
- java ready_Java PushbackReader ready()用法及代码示例
- Java 计算两个日期相差的天数
- Mongo之架构部署(Replica Sets+Sharding)
- @ResponseBody与@RestController的作用与区别
- 旧板与IO板之间的连接
- 安卓-利用android studio制作简单的QQ登陆login界面
- bodymovin输出Json动画为黑白的解决方案
- matlab数值分析作业答案,Matlab作业3(数值分析)答案
- fontawesome 助手
- 隐藏在网络邻居背后的协议,快来看看你家网络有几种?
- 通过财务报表读懂美股
- 统计学的Python实现-019:任意正态分布计算概率
- 为什么我的 WordPress 网站被封了?
- Android开发--更换字体
- ASP 五年总结精华源码
热门文章
- 数据结构(一):入门
- 元宇宙的几大核心问题
- 计算机类和信息与计算科学专业有什么区别,信息与计算科学专业主要学什么
- 开迅雷后浏览不了网页的问题
- Sprin_使用注解进行属性注入和整合Mybatis
- socks5 mysql认证_sock5代理服务器-SS5篇
- Eclipse4.7.2 Nodeclipse1.0.2 CodeMix3
- 励志成为优产的母猪--------猜数游戏 ,历史记录,pickle保存,队列deque
- 黑马程序员,黑马论坛----Java+云计算4期,100%全部就业,平均薪水6965元!
- Swift学习之:设置渐变色