抽象类与接口
抽象类:
- 抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体
abstract class A{//定义一个抽象类
public void fun(){//普通方法
System.out.println("存在方法体的方法");
}
public abstract void print();
//抽象方法,没有方法体,有abstract关键字做修饰
}
- 抽象类不能被实例化,无法使用new 关键字来调用抽象类的构造器创建抽象类的实例,即使抽象类里不包含抽象方法,这个抽象类也不能创建实例。
abstract class A{//定义一个抽象类
public void fun(){//普通方法
System.out.println("存在方法体的方法");
}
public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰
}
public class TestDemo {
public static void main(String[] args) {
A a = new A();
//会报错
}
}
- 抽象类可以包含成员变量,方法(普通方法和抽象方法都可以),构造器,初始化块,内部类(接口,枚举)5种成分。抽象类的构造方法不能用于创建实例,主要是用于被其子类调用。
public abstract class Shape {
{
System.out.println("执行Shape的初始化块");
}
interface Inner{
//内部类
}
private String color;
public abstract double calPerimeter();
public String talk(){
return "普通方法";
};
public Shape(){ };
public Shape(String color) {
System.out.println("这是构造器");
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
- 含有抽象方法的类(包括直接定义一个抽象类方法,或继承了一个抽象父类,但没有完全实现父类包含的抽象方法,或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类
比如说:父类是水果一个大类,有水果的名字,食用水果两个方法。其中水果的名字为抽象方法,食用水果为一个普通方法,香蕉和苹果是水果这一大类中的子类,但香蕉必须重写父类水果的名字为香蕉,食用水果方法可以直接调用。对于苹果必须重写父类水果的名字为苹果,食用水果方法可以直接调用。
简单来说就相当于父类是英语范文挖出来一堆的空位置语句,而子类就相当于你和别同学去填写这个模板中的各种空位置的语句,结果是填的不一样,而造成了不一样的的文章,这样就形成了两个不一样的东西。
abstract class A{//定义一个抽象类
public A(){
System.out.println("*****A类构造方法*****");
}
public abstract void print();//抽象方法,没有方法体,有abstract关键字做修饰
}
//单继承
class B extends A{//B类是抽象类的子类,是一个普通类
public B(){
System.out.println("*****B类构造方法*****");
}
@Override
public void print() {//强制要求覆写
System.out.println("Hello World !");
}
}
public class TestDemo {
public static void main(String[] args) {
// 抽象类,不能实例化,必须需要子类进行实例化
A a = new B();//向上转型
}
}
当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法需由子类重写,而final修饰方法不能被重写,因此两者从来不能被同时使用
抽象类的作用:
- 抽象父类可以只定义需要使用的某些方法,把不能实现的部分抽象成为方法,留给其子类去实现;
- 父类中可能包含需要调用其他系列方法的方法,这些被调用即可以由父类实现,也可以有其子类实现。父类里提供的方法只是定义了一个通用算法,其实现也许并不完全有自身实现,而必须依赖于其子类的辅助。
接口的概念:
和类的定义不同,定义接口不再使用class关键字,而是使用了interface关键字,接口的定义语法如下
[修饰符] interface 接口名 extends 父接口1, 父接口2...{
零个到多个常量定义。。。
}
interface Power {
}
- 修饰符可以是public 或者省略,如果省略了public 访问控制符,则默认采用包权限访问控制符,即只有在相同包结构下才可以访问该接口。
- 接口应该于类名采用相同的规范
- 一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。
接口里面定义的内部类,内部接口,内部枚举默认都采用public static两个修饰符,不管定义是否指定这两个修饰符,系统都会自动使用public static 对它们进行修饰。
public interface Output {
int MAX_CACHE_LIME = 50;
//需要重写
void out();
//需要重写
void getData(String msg);
default void print(String... msgs){
for (String msg : msgs){
System.out.println(msg);
}
}
default void test(){
System.out.println("默认的test()方法");
}
static String staticTest(){
return "接口里的类方法";
}
//不能调用
private void foo(){
System.out.println("jdk11以后出现在接口里面有private");
}
private static void bar(){
System.out.println("bar私有静态方法");
}
//只有接口中可以调用私有方法
public static void main(String[] args) {
bar();
}
}
public class S {
//需要重写才可以调用,相对应的方法
@Override
public void out() {
}
@Override
public void getData(String msg) {
}
@Override
public void print(String... msgs) {
Output.super.print(msgs);
}
@Override
public void test() {
Output.super.test();
}
public static void main(String[] args) {
System.out.println(Output.MAX_CACHE_LIME);
System.out.println(Output.staticTest());
}
}
接口的继承:
接口的继承和类继承不一样,接口完全支持多继承,即一个接口可以有多个直接父类。和继承相似,子接口扩展某个父接口,将会获得父接口里定义的锁有抽象方法,常量。
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);
}
}
使用接口:
接口不能用于创建实例,但接口可以用于声明引用类型变量。当使用接口来声明引用类型变量时,这个引用类型变量必须引用到其实现类的对象.除此之外,接口的主要用途就是被实现类实现.归纳起来,接口主要有如下用途:
- 定义变量,也可以用于进行强制类型转换。
- 调用接口中定义的常量
- 被其他类实现。
interface Product{
int getProduceTime();
}
public class Printer implements Output, Product {
private String[] printData
= new String[MAX_CACHE_LIME];
private int dataNum = 0;
public void out(){
while (dataNum>0){
System.out.println("打印机大印: "+printData[0]);
System.arraycopy(printData,1,printData,0,--dataNum);
}
}
public void getData(String msg){
if (dataNum >= MAX_CACHE_LIME){
System.out.println("输出队列已满,添加失败");
}else{
printData[dataNum++] = msg;
}
}
@Override
public int getProduceTime() {
return 45;
}
public static void main(String[] args) {
Output o = new Printer();
o.getData("轻量级Java EE 企业应用实战");
o.getData("疯狂java讲义");
o.out();
o.getData("疯狂Android讲义");
o.getData("疯狂Ajax");
o.out();
o.print("孙悟空","猪八戒","白骨精");
o.test();
Product p = new Printer();
System.out.println(p.getProduceTime());
Object obj = p;
}
}
接口和抽象类
共同特征
- 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
- 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
不同:
- 接口里只能包含抽象方法,静态方法,默认方法和私有方法,不能为普通方法提供方法实现;抽象类则完全可以包含普通方法。
- 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则即可以定义普通成员变量,也可以定义静态常量。
- 接口不包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
- 接口里面不能包含初始化块;但抽象类则可以完全包含初始化块。
- 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补java单继承的不足。
)