抽象类、抽象方法
某个父类只知道子类因该包含什么样的方法,无法知道这些子类如何实现这些方法。抽象类包含该方法但没有对该方法的具体实现。
有抽象方法的类只能被定义为抽象类,抽象类里可以没有抽象方法。
抽象方法和抽象类的规则:
- 抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰抽象方法不能有具体的方法体
- 抽象类不能被实例化,无法使用new关键字来调用抽象类构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例
- 抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
- 抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要用于被其子类调用
- 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法的三种情况)只能被定义成抽象类。
public abstract class Shape {
{
System.out.println("执行Shape的初始化块...");
}
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//定义一个计算周长的抽象方法
public abstract double cal();
//定义一个返回形状的方法
public abstract String getType();
//定义Shape的构造器,该构造器并不是用于创建Shape对象
//而是用于被子类调用
public Shape(String color){
System.out.println("执行shape的构造器...");
this.color=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) {
// TODO Auto-generated constructor stub
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;
}
@Override
public double cal() {
// TODO Auto-generated method stub
return a+b+c;
}
@Override
public String getType() {
// TODO Auto-generated method stub
return "三角形";
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color,double radius) {
super(color);
// TODO Auto-generated constructor stub
this.radius =radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double cal() {
// TODO Auto-generated method stub
return 2*Math.PI*radius;
}
@Override
public String getType() {
// TODO Auto-generated method stub
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.cal());
System.out.println(s2.getType());
System.out.println(s2.cal());
}
}
抽象类的作用:抽象类是从多个具体的类中抽象出来的父类,为多个子类的通用模板,具有跟高层次的抽象,避免了子类设计的随意性。
接口
[修饰符] interface 接口名 extends 父接口1,父接口2...
{
零个到多个常量定义
零个到多个抽象方法定义
零个到多个内部类、接口、枚举定义...
零个到多个私有方法、默认方法或类定义方法...
}
- 修饰符可以是public或者省略,如果省略了public访问控制符,则默认访问包权限访问控制符,只有在相同包结构下才可以访问该接口。
- 接口名应与类名采用相同的命名规则。
- 一个接口可以有多个直接父类接口,但接口只能继承接口,不能继承类。
- 接口里的方法只能是抽象方法、类方法、默认方法和私有方法。
public interface Output {
//接口里定义的成员变量只能是常量
int Line=50;
//接口里定义的普通方法只能是public抽象方法
void out();
void getData(String msg);
//在接口中定义默认方法,需要使用default修饰
default void test(){
System.out.println("默认的test()方法");
}
//在接口中定义类方法,需要使用static修饰
static String staticTest(){
return "接口里的类方法";
}
//定义私有方法
static void foo() {
System.out.println("foo私有的方法");
}
//定义私有静态方法
static void bar() {
System.out.println("bar私有的静态方法");
}
}
接口不能用于创建实例,但接口可以用于声明引用类型变量。当使用接口来声明引用类型变量时,这个引用类型变量必须引用到其实现类的对象。除此之外,接口的主要用途就是被实现类实现。接口用途如下:
- 定义变量,也可用于进行强制类型转换
- 调用接口中定义的常量
- 被其他类实现
使用接口
- 一个类实现某个接口时,该类将会获得接口中定义的常量(成员变量)、方法等
- 一个类实现一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽象方法);否则该类将保留从父接口继承的抽象方法,该类也必须定义成抽象类。
public class Printer implements Output,Product{
private String[] printData=new String[Line];
//用于记录当前需打印的作业数
private int dataNum=0;
@Override
public void out() {
// TODO Auto-generated method stub
//只要还有作业,就继续打印
while(dataNum>0){
System.out.println("打印机打印"+printData[0]);
//把作业队列整体前移一位,并将剩下的作业数减1
System.arraycopy(printData, 1, printData, 0, --dataNum);
}
}
@Override
public void getData(String msg) {
// TODO Auto-generated method stub
if(dataNum>=Line){
System.out.println("输出队列已满,添加失败");
}else{
//把打印数据添加到队列里,已保存数据的数量+1
printData[dataNum++]=msg;
}
}
@Override
public int getProduceTime() {
// TODO Auto-generated method stub
return 45;
}
public static void main(String[] args) {
//创建一个Printer对象,当成Output使用
Output o=new Printer();
o.getData("123");
o.getData("456");
o.out();
o.getData("777");
o.getData("888");
o.out();
//调用Output接口中定义的默认方法
o.print("enen..","oo..","aa..");
o.test();
//创建一个printer对象,当成Product使用
Product p=new Printer();
System.out.println(p.getProduceTime());
//所有接口类型引用变量都可以直接赋值给Object类型的变量
Object obj=p;
}
}
接口和抽象类的区别
- 接口里只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类可以完全包含普通方法。
- 接口里只能定义静态常量,不能定义普通成员变量;抽象类里既可以定义普通成员变量,也可以定义静态常量。
- 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器不是用于创建对象,而是让其子类调用这些构造器来完成属性抽象类的初始化操作
- 接口里不能包含初始化块,但抽象类则可以包含初始化块
- 一个类最多只能有一个直接父类,包括抽象类。但一个类可以直接实现多个接口,通过实现多个接口弥补JAVA单继承的不足。