1、接口
什么是接口?
是由抽象类衍生出来的恶一个概念,并由此产生了一种编程方式:面向接口编程。
1、能够最大限度实现解耦合,降低程序耦合性。
2、使程序易于扩展。
3、有利于程序后期维护
面向接口编程就是将程序中的业务模块进行分离,以接口的形式去对接不同的业务模块。
**面向接口编程的优点:**当用户需求变更时,只需要切换不同的实现类,而不需要修改串联模块的接口,减小对系统的影响。
耦合度太高:鼠标直接固定在电脑上而不是通过usb口连接,不灵活,更换不方便。
如何使用接口?
接口在java中时独立存在的一种结构,和类相似,需要创建一个接口文件,用interface来标识接口,基本语法:
public interface 接口名{
public 返回值方法名(参数列表)
}
接口其实就是一个极度抽象的抽象类。抽象类:一个类中存在没有具体实现的抽象方法时,那么该类就必须定位为抽象类,同时抽象类允许存在非抽象方法。
**接口:**不能存在非抽象方法,必须全部是抽象方法。
因为全是抽象方法,所以修饰抽象方法的关键字abstract可以省略。
接口允许定义成员变量,但有如下要求:
- 只能定义public和默认访问权限修饰符的成员变量,不能定义private和protected修饰的成员变量
- 接口中成员变量在定义时就必须完成初始化。
- 接口中的成员变量都是静态常量,即可以直接通过接口访问,同时值不能被修改。
public interface MyInterface {
public int ID = 0;
String NAME = "张三";
public void test();
}
使用接口时,不能直接实例化接口对象,而必须实例化其实现类对象,实现类对象本身就是一个普通的java类,创建实现类的代码如下所示:
public class MyInterfaceImpl implements MyInterface{
@Override
public void test() {
}
}
通过Implements关键字来指定实现类具体要实现的接口,在实现类的内部需要对接口的所有抽象方法进行实现,同时要求访问权限修饰符、返回值类型、方法名和参数列表必须完全一致。
接口和继承:java只支持单继承,但是接口可以多实现(一个实现类可以同时实现多个接口)
public interface MyInterface {
public int ID = 0;
String NAME = "张三";
public void run();
}
public interface MyInterface2 {
public void fly();
}
package com.southwind.test;
public class MyInterfaceImpl implements MyInterface, MyInterface2{
@Override
public void run() {
System.out.println("实现了跑的方法");
}
@Override
public void fly() {
System.out.println("实现了飞的方法");
}
}
package com.southwind.test;
public class Test {
public static void main(String[] args) {
MyInterfaceImpl myInterface = new MyInterfaceImpl();
myInterface.fly();
myInterface.run();
}
}
面向接口编程的实际应用
场景
某工厂生产产品A,产品A主要是由设备A来完成生产,用程序模拟生产过程。
产品B是由设备B来生产的。
public class EquipmentA {
public void work(){
System.out.println("设备A运行,生产产品A");
}
}
public class Factory {
private EquipmentA equipmentA;
public EquipmentA getEquipmentA() {
return equipmentA;
}
public void setEquipmentA(EquipmentA equipmentA) {
this.equipmentA = equipmentA;
}
public void work(){
System.out.println("开始生产...");
this.equipmentA.work();
}
}
public class Test {
public static void main(String[] args) {
// MyInterfaceImpl myInterface = new MyInterfaceImpl();
// myInterface.fly();
// myInterface.run();
//初始化工厂
Factory factory = new Factory();
EquipmentA equipmentA = new EquipmentA();
factory.setEquipmentA(equipmentA);
//开始工作
factory.work();
}
}
当需求发生改变时,就要频繁修改类的内部结构方式是需要避免的,因为扩展性很差,如何修改?使用面向接口编程即可。
1、创建接口Equipment
public interface Equipment {
public void work();
}
2、创建Equipment实现类
public class EquipmentA implements Equipment {
public void work(){
System.out.println("设备A运行,生产产品A");
}
}
public class EquipmentB implements Equipment {
public void work(){
System.out.println("设备B运行,生产产品B");
}
}
3、创建Factory类
public class Factory {
private Equipment equipment;
public Equipment getEquipment() {
return equipment;
}
public void setEquipment(Equipment equipment) {
this.equipment = equipment;
}
public void work(){
System.out.println("开始生产...");
this.equipment.work();
}
}
4、Test
public class Test {
public static void main(String[] args) {
// MyInterfaceImpl myInterface = new MyInterfaceImpl();
// myInterface.fly();
// myInterface.run();
//初始化工厂
Factory factory = new Factory();
EquipmentA equipmentA = new EquipmentA();
EquipmentB equipmentB = new EquipmentB();
factory.setEquipment(equipmentB);
//开始工作
factory.work();
}
}
2、异常
- 什么是异常?
java中的错误大致分为两类:
一类是编译时错误,一般是指语法错误。
另一类是运行时错误
try-catch-finally
try{
//可能会抛出异常的代码
}catch(Exception e){
//对异常进行处理
}finally{
//一定会执行的代码
}
异常类
- Error:系统错误,程序无法处理。
- Exception:程序运行时出现的错误,错误可以处理。
Error和 Exception都是Throwable 的子类,Throwable、Error、Exception都是存放在java.lang包中。
Error常见的子类:VirtualMachineError、AWTError、IOError。
VirtualMachineError的子类: StackOverflowError、OutOfMemoryError,用来描述内存溢出等系统问题。
Exception常见的子类:IOException和 RuntimeException
IOException存放在java.io包中,RuntimeException存放在java.lang 包中。
lOException 常见的子类:FileLockInterruptionException、FileNotFoundException、FilerException,这些异常通常都是处理通过IO流进行文件传输的时候发生的错误。
RuntimeException常见的子类:
-
ArithmeticException:表示数学运算异常。
-
ClassNotFoundException:表类未定义异常。
-
IllelArgumentException:表示参数格式错误。
-
ArraylndexOutOfBounds:表示数组下标越界。
-
NullPointException:表示空指针异常。
-
NoSuchMethodException:表示方法未定义异常。
-
NumberFormatException:表示将其他数据类型转为数值类型发生的类型不匹配异常。
throw和throws
两个常用关键字,都可以用来抛出异常,但是使用的方式和表示的含义完全不同。
Java中抛出异常有3种方式:
- 自动捕获try-catch
- 使用throw是开发者主动抛出异常,即读到 throw代码就一定抛出异常,基本语法:throw newException(),是一种基于代码的逻辑而主动抛出异常的方式。
package com.southwind.test.exception;
public class Test {
public static void main(String[] args) {
int[] array = {1,2,3};
test(array,2);
}
public static void test(int[] array,int index){
if (index >= 3 || index <0){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}else {
System.out.println(array[index]);
}
}
}
- try-catch和throw都是作用于具体的逻辑代码,throws是作用于方法的,用来描述方法可能会抛出的异常。如果方法 throws的是RuntimeException 异常或者其子类,外部调用时可以不处理,JVM会处理。
如果方法 throws的是Exception 异常或者其子类,外部调用时必须处理,否则报错。
public class Test {
public static void main(String[] args) throws Exception{
test("123");
}
public static void test(String str) throws Exception{
int num = Integer.parseInt(str);
}
}
自定义异常
除了使用java异常外,也可以根据需求来自定义异常
public class MyNumException extends Exception{
public MyNumException(String error){
super(error);
}
}
package com.southwind.exception;
public class Test {
public static void main(String[] args) throws Exception{
Test test = new Test();
System.out.println(test.add("a"));
}
public int add(Object object) throws MyNumException{
if (object instanceof Integer){
int num = (int) object;
return ++num;
}else {
String error = "传入的参数不为整数";
MyNumException myNumException = new MyNumException(error);
throw myNumException;
}
}
}
综合练习
封装、继承、多态、抽象、接口、异常完成一个汽车查询系统。
需求描述:共有3种类型的汽车:小轿车、大巴车、卡车,其中小轿车的座位数是4座,大巴车座位数是5座,卡车座位数是2座,要求使用封装、继承、抽象来完成车辆的定义。
可以对车辆信息进行修改,卡车可以运货但是载重量不能超过12吨,使用自定义异常来处理错误,小轿车和大巴车没有此功能,要求使用接口来实现。
car
package com.southwind.car;
public abstract class Car {
private String name;
private String color;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Car(String name, String color) {
this.name = name;
this.color = color;
}
public abstract String seatNum();
}
Sedan
package com.southwind.car;
public class Sedan extends Car{
public Sedan(String name, String color) {
super(name, color);//父类是带参构造,子类也要
}
@Override
public String seatNum() {
return "4座";
}
}
Bus
package com.southwind.car;
public class Bus extends Car{
public Bus(String name, String color) {
super(name, color);
}
@Override
public String seatNum() {
return "53座";
}
}
Truck
package com.southwind.car;
public class Truck extends Car implements Container{
private int weight;
public Truck(String name, String color, int weight) {
super(name, color);
this.weight = weight;
}
@Override
public String seatNum() {
return "2座";
}
@Override
public int getweight() {
return this.weight;
}
}
Container
package com.southwind.car;
public interface Container {
public int getweight();
}
CarException
package com.southwind.car;
public class CarException extends Exception{
public CarException(String error){
super(error);
}
}
Test
package com.southwind.car;
import java.util.Scanner;
public class Test {
private static Scanner scanner;
private static Sedan sedan;
private static Bus bus;
private static Truck truck;
private static Car[] cars;
static {
scanner = new Scanner(System.in);
sedan = new Sedan("小轿车","黑色") ;
bus = new Bus("大巴车","绿色");
truck = new Truck("卡车","蓝色",2);
cars = new Car[3];
cars[0] = sedan;
cars[1] = bus;
cars[2] = truck;
}
public void showCars(){
System.out.println("欢迎使用本汽车管理系统");
System.out.println("车辆名称\t\t车辆颜色\t\t座位数\t\t载重量");
for (Car car:cars){
if (car instanceof Truck){
Truck truck = (Truck)car;
System.out.println(car.getName()+"\t\t\t"+car.getColor()+"\t\t\t"+car.seatNum()+"\t\t\t"+truck.getweight());
}else {
System.out.println(car.getName()+"\t\t"+car.getColor()+"\t\t"+car.seatNum()+"\t\t不能拉货");
}
}
System.out.println("1.小轿车\t2.大巴车\t3.卡车");
System.out.print("请选择要修改的车辆");
int num = scanner.nextInt();
switch (num){
case 1:
update("sedan");
break;
case 2:
update("bus");
break;
case 3:
update("truck");
break;
default:
System.out.println("输入的车辆不存在");
break;
}
}
public void update(String type){
String name = null;
String color = null;
if (type.equals("sedan")){
System.out.print("输入车辆名称");
name = scanner.next();
System.out.print("输入车辆颜色");
color = scanner.next();
Sedan sedan = new Sedan(name,color);
cars[0] = sedan;
}
if (type.equals("bus")){
System.out.print("输入车辆名称");
name = scanner.next();
System.out.print("输入车辆颜色");
color = scanner.next();
Bus bus = new Bus (name,color);
cars[1] = bus;
}if (type.equals("truck")){
System.out.print("输入车辆名称");
name = scanner.next();
System.out.print("输入车辆颜色");
color = scanner.next();
System.out.print("输入载重量");
int weight = scanner.nextInt();
if (weight > 12){
CarException carException = new CarException("卡车的载重量不超过12吨");
try {
throw carException;
} catch (CarException e) {
e.printStackTrace();
return;
}
}
Truck truck = new Truck(name,color,weight);
cars[2] = truck;
}
showCars();
}
public static void main(String[] args) {
Test test = new Test();
test.showCars();
}
}
- 讲解了面向对象的高级部分,包括Object类、包装类、接口和异常。其中Object类是所有Java类的父类,定义了Java体系的基础资料,通过继承传递给Java的每一个类,通过方法重写和多态让整个Java体系具有很强的灵活性。
- 包装类是Java为基本数据类型提供封装的一组类,通过包装类我们可以将基本数据类型转为对象,这一点在面向对象编程中很重要。
- 接口是抽象类的扩展,是Java中实现多态的重要方式,可以降低程序的耦合性,让程序变得更加灵活多变。接口就相当于零件,我们可以自由地将这些零件进行组装、整合。
- 异常是Java中处理错误的一种机制,同样是基于面向对象的思想,将错误抽象成对象然后进行处理,这里需要关注的是对异常相关的几个关键字的使用,try、catch、finally、throw、throws。l