Java-接口与抽象类
抽象类
如果编写一个类时,我们只想为该类定义一些方法,但是具体的实现交给继承它的子类来实现的话,我们可以考虑使用抽象类
抽象方法与抽象类
抽象方法与抽象类都必须使用abstract来修饰
-
有抽象方法的类只能被定义为抽象类
-
抽象类里面可以没有抽象方法
规则:
-
抽象方法与抽象类都必须使用abstract来修饰,抽象方法不能有方法体
-
抽象类不能实例化
-
抽象类可以包含成员变量,方法(普通或者抽象方法都可以),构造函数,初始化块,内部类5种成分
-
含有抽象方法的类只能被定义为抽象类
public abstract class Shape {
{
System.out.println("执行Shape的初始化块...");
}
private String color;
// 定义一个计算周长的抽象方法
public abstract double calPerimeter();
// 定义一个返回形状的抽象方法
public abstract String getType();
// 定义Shape的构造器,该构造器并不是用于创建Shape对象,
// 而是用于被子类调用
public Shape(){}
public Shape(String color)
{
System.out.println("执行Shape的构造器...");
this.color = color;
}
// 省略color的setter和getter方法
public void setColor(String color)
{
this.color = color;
}
public String getColor()
{
return this.color;
}
}
public class Triangle extends Shape{
// 定义三角形的三边
private double a;
private double b;
private double c;
public Triangle(String color , double a
, double b , double c)
{
super(color);
this.setSides(a , b , c);
}
public void setSides(double a , double b , double c)
{
if (a >= b + c || b >= a + c || c >= a + b)
{
System.out.println("三角形两边之和必须大于第三边");
return;
}
this.a = a;
this.b = b;
this.c = c;
}
// 重写Shape类的的计算周长的抽象方法
public double calPerimeter()
{
return a + b + c;
}
// 重写Shape类的的返回形状的抽象方法
public String getType()
{
return "三角形";
}
}
public class Circle extends Shape{
private double radius;
public Circle(String color , double radius)
{
super(color);
this.radius = radius;
}
public void setRadius(double radius)
{
this.radius = radius;
}
// 重写Shape类的的计算周长的抽象方法
public double calPerimeter()
{
return 2 * Math.PI * radius;
}
// 重写Shape类的的返回形状的抽象方法
public String getType()
{
return getColor() + "圆形";
}
public static void main(String[] args)
{
Shape s1 = new Triangle("黑色" , 3 , 4, 5);
Shape s2 = new Circle("黄色" , 3);
System.out.println(s1.getType());
System.out.println(s1.calPerimeter());
System.out.println(s2.getType());
System.out.println(s2.calPerimeter());
}
}
注意:
-
static和abstract不能同时修饰某个方法
-
priva和abstract不能同时修饰方法
接口
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更加彻底,那么就可以引出接口了
接口概念
接口是从多个相似类中抽象出来的规范,接口不提供任何实现,接口体现的是规范和实现分离的设计哲学
接口定义的基本语法:
[修饰符] interface 接口名 extends 父接口1,父接口2...
{
0-n个常量定义...
0-n个抽象方法定义...
0-n个内部类、接口、枚举定义...
0-n个私有方法、默认方法、类方法定义...
}
-
修饰符可以是public或者省略,省略的话默认采用包权限访问控制符
-
一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类
接口中不能包含构造函数以及初始化块定义,可以包含成员变量(只能是静态常量),方法(只能是抽象实例方法、类方法、默认方法、私有方法),内部类(内部接口、枚举)定义
接口里面的常量、方法、内部类、内部枚举都是public访问权限,定义时可以省略访问控制修饰符,如果指定的话只能用public
接口里定义的静态常量系统会自动为这些变量增加static和final修饰符
接口里定义的成员变量只能在定义时指定默认值
接口里面如果不是定义默认方法、类方法、私有方法,系统自动为普通方法添加abstract修饰符,接口里面普通方法不能有方法实现;但是类方法、默认方法、私有方法都必须有方法实现
定义一个接口:
public interface Output {
// 接口里定义的成员变量只能是常量
int MAX_CACHE_LINE = 50;
// 接口里定义的普通方法只能是public的抽象方法
void out();
void getData(String msg);
// 在接口中定义默认方法,需要使用default修饰
default void print(String... msgs)
{
for (String msg : msgs)
{
System.out.println(msg);
}
}
// 在接口中定义默认方法,需要使用default修饰
default void test()
{
System.out.println("默认的test()方法");
}
// 在接口中定义类方法,需要使用static修饰
static String staticTest()
{
return "接口里的类方法";
}
// // 定义私有方法(要java9及其以上才可以)
// private void foo()
// {
// System.out.println("foo私有方法");
// }
// // 定义私有静态方法
// private static void bar()
// {
// System.out.println("bar私有静态方法");
// }
}
接口的继承
接口的继承和类继承不一样,接口完全支持多继承,即一个接口可以有多个之间父接口,和类继承相似,子接口扩展某个父接口将会获得父接口里面定义的所有抽象方法,常量
一个接口继承多个父接口时,多个父接口排在extends关键字后面
interface InterfaceA
{
int PROP_A = 5;
void testA();
}
interface InterfaceB
{
int PROP_B = 6;
void testB();
}
interface InterfaceC extends InterfaceA, InterfaceB
{
int PROP_C = 7;
void testC();
}
public class InterfaceExtendsTest
{
public static void main(String[] args)
{
System.out.println(InterfaceC.PROP_A);
System.out.println(InterfaceC.PROP_B);
System.out.println(InterfaceC.PROP_C);
}
}
使用接口
接口不能用于创建实例,但是接口可以用于声明引用类型变量,此时这个引用类型变量必须引用到其实现类的对象
类实现接口语法:
[修饰符] class 类名 extends 父类 implement 接口1,接口2...
implement部分必须放置在extends后面
一个类实现了接口后,必须完全实现这些接口里面所定义的全部抽象方法,否则该类必须定义为抽象类
// 定义一个Product接口
interface Product
{
int getProduceTime();
}
// 让Printer类实现Output和Product接口
public class Printer implements Output , Product
{
private String[] printData
= new String[MAX_CACHE_LINE];
// 用以记录当前需打印的作业数
private int dataNum = 0;
public void out()
{
// 只要还有作业,继续打印
while(dataNum > 0)
{
System.out.println("打印机打印:" + printData[0]);
// 把作业队列整体前移一位,并将剩下的作业数减1
System.arraycopy(printData , 1
, printData, 0, --dataNum);
}
}
public void getData(String msg)
{
if (dataNum >= MAX_CACHE_LINE)
{
System.out.println("输出队列已满,添加失败");
}
else
{
// 把打印数据添加到队列里,已保存数据的数量加1。
printData[dataNum++] = msg;
}
}
public int getProduceTime()
{
return 45;
}
public static void main(String[] args)
{
// 创建一个Printer对象,当成Output使用
Output o = new Printer();
o.getData("hello");
o.getData("world");
o.out();
o.getData("test");
o.getData("case");
o.out();
// 调用Output接口中定义的默认方法
o.print("孙悟空" , "猪八戒" , "白骨精");
o.test();
// 创建一个Printer对象,当成Product使用
Product p = new Printer();
System.out.println(p.getProduceTime());
// 所有接口类型的引用变量都可直接赋给Object类型的变量
Object obj = p;
}
}
实现接口方法时,必须使用public修饰符
接口与抽象类之间的区别:
-
接口只能有抽象方法、静态方法、默认方法、私有方法,不可以为普通方法提供实现;抽象类完全可以包含普通方法
-
接口里只可以定义静态常量,不准出现普通成员变量;抽象类可以定义普通成员变量以及静态常量
-
接口无构造函数,抽象可可以有
-
接口里不包含初始化块,抽象类可以包含
-
一个类最多有一个直接父类,包括抽象类,一个类可以实现多个接口
网友评论