抽象类
1.抽象类是对问题领域进行分析后得出的抽象概念,是对一批看上去不同,但本质上相同的具体概念的抽象。
例如:定义一个动物类Animal,该类提供一个行动方法action(),但不同的动物行动方式是不一样的,马儿是跑,鸟儿是飞,此时就可以将Animal定义成抽象类,该类既能包含action()方法,又无须提供其方法实现(没有方法体)。这种只有方法声明,没有方法实现的方法称为“抽象方法”。
语法(抽象类和抽象方法编写使用“abstract”关键字来修饰):
[访问符] abstract class 类名 {
[访问符] abstract <返回类型> 方法名([参数列表]);
......
}
定义抽象类和抽象方法的规则如下:
(1)有抽象方法的类只能被定义成抽象类,但抽象类中可以没有抽象方法。
(2)抽象方法没有方法体。
(3)抽象类不能被实例化,即无法使用new关键字直接创建抽象类实例,即使抽象类中不包含抽象方法也不行。
(4)一个抽象类中可以包含多个抽象方法,也可以含有已实现的方法(有方法体)。
(5)抽象类可以包含:成员变量,构造方法,抽象方法,普通方法等;但抽象类不能通过构造方法创建实例,构造方法可在子类创建实例时调用。
(6)定义抽象类有三种情况:直接定义一个抽象类;或继承一个抽象类,但没有完全实现父类包含的抽象方法;或实现一个接口,但没有完全实现接口中包含的抽象方法。
注意:
abstract关键字不能用来修饰成员变量和构造方法,即没有抽象变量和抽象构造方法的说法。abstract关键字修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体,因此抽象方法不能定义为private,即private和abstract不能同时修饰方法。abstract也不能和static、final或native同时修饰同一方法。
抽象类的使用:
Animal类(抽象类):
public abstract class Animal {
String name;
Animal() {
}
Animal(String name) {
}
public abstract void eat();//定义抽象方法eat()
public abstract void call();//定义抽象方法call()
Dog子类继承Animal:
/**
* 抽象类不能直接实例化,因此需要子类继承并完全实现其中的抽象方法
*/
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("Dog吃肉");
}
@Override
public void call() {
System.out.println("汪汪汪汪汪汪");
}
}
Cat子类继承Animal:
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("Cat吃鱼");
}
@Override
public void call() {
System.out.println("喵喵喵喵喵喵");
}
}
AminalDemo类:
public class AnimalDemo {
public static void main(String[] args) {
Animal cat=new Cat();//new一个Animal对象变量指向子类Cat对象
//多态的体现
cat.eat();
cat.call();
Animal dog=new Dog();//new一个Animal对象变量指向子类Dog对象
dog.eat();
dog.call();
}
}
运行结果:
接口
1.接口定义了某一批类所需要遵守的公共行为规范,只规定这批类必须提供的某些方法,而不是提供任何实现。接口体现的是规范和实现分离的设计哲学让规范和实现分离正是接口的好处,让系统的各模块之间面向接口耦合,是一种松耦合的设计,从而降低各模块之间的耦合,增强系统的可扩展性和可维护性。
语法(java类只能单一继承,但接口可以多继承):
[访问符] interface 接口名 [extends 父接口1,
父接口2...] {
//接口体
}
(1)接口可以包含:静态常量、抽象方法、内部类、内部接口、枚举、默认方法(default)、类方法(static)。
(2)接口中定义的成员变量都与接口相关,系统自动为成员变量增加public static final 进行修饰,即接口中定义的成员变量都是静态常量。
(3)系统自动为普通方法增加public abstract 进行修饰,即接口中定义的普通方法都是抽象方法,不能有方法体。
(4)默认方法必须使用default 关键字进行修饰,通过接口的实现类的实例对象来调用默认方法。
(5)类方法必须使用static关键字修饰,必须有方法实现,可以直接通过接口来调用类方法
(6) 接口不能直接实例化,但接口可以被实现类实现,一个类可以实现一个或多个接口。
实现类的语法:
[访问符] class 类名 implements 接口1
[,接口2...]{
//类体 }
(1)implements关键字用于实现接口;
(2)一个类可以实现多个接口,接口之间使用逗号进行间隔;
(3)一个类在实现一个或多个接口时,这个类必须完全实现这些接口中定义的所有抽象方法,否则该类必须定义为抽象类;
(4)一个类实现某个接口时,该类将会获得接口中定义的常量、方法等,因此可以将实现接口理解成一种特殊的继承,相当于实现类继承了一个彻底抽象的类。
接口的使用:
Inter1接口:
public interface Inter1 { //定义抽象方法 int sum(int...a); }
Inter2接口:
public interface Inter2 { //定义抽象方法 int jc(int i); }
Inter接口:
public interface Inter extends Inter1,Inter2{ //该接口继承了Inter1,Inter2接口 public static final int a=12; public abstract int pf(int i); default int lf(int i){ return i*i*i; } static void show(){ System.out.println("helloworld"); } }
InterImpI接口实现类:
public class InterImpI implements Inter { //该类实现了接口Inter,即实现Inter接口中所有的抽象方法pf(),sum(),jc() @Override public int pf(int i) { return i * i; } @Override public int sum(int... a) { int sum = 0; for (int i : a) { sum += i; } return sum; } @Override public int jc(int i) { int b = 0; for (int a = i; a >= 0; a--) { if (a == 0) { return b = 1; } else { return b=i * jc(--i); } } return b; } }
接口测试类InterDemo:
public class InterDemo {
public static void main(String[] args) {
//直接new接口等价于创建一个内部匿名类,可以使用lambda表达式代替匿名类,提高程序运行效率
Inter inter = new Inter() {
@Override
public int pf(int i) {
return i * i;
}
@Override
public int sum(int... a) {
int sum = 0;
for (int i : a) {
sum += i;
}
return sum;
}
@Override
public int jc(int i) {
int b = 0;
for (int a = i; a >= 0; a--) {
if (a == 0) {
return b = 1;
} else {
return b = i * jc(--i);
}
}
return b;
}
};
System.out.println("立方和:"+inter.lf(2));
System.out.println("平方和:"+inter.pf(2));
System.out.println("数组各元素和:"+inter.sum(1, 2, 3, 4, 5));
System.out.println("1到n的阶乘:"+inter.jc(5));
Inter.show();
System.out.println("===============================");
//
Inter inter1 = new InterImpI();
//new一个接口的实现类对象,通过该对象inter1调用已经实现的抽象方法
System.out.println("平方和:"+inter1.pf(9));
System.out.println("立方和:"+inter1.lf(4));
System.out.println("a="+inter1.a);
System.out.println("数组各元素和:"+inter1.sum(1, 2, 3, 4, 5));
System.out.println("1到n的阶乘:"+inter1.jc(5));
}
}
运行结果: