抽象类概念:
用关键字 abstract 修饰的类就是抽象类(abstract 类);
如:public abstract class A{ ... }
1、抽象类中可以有抽象方法,也可以没有抽象方法;
2、抽象类中可以有非抽象方法,如 实例方法,static 方法,final 方法 ;
3、子类继承抽象类,则需要重写抽象类中全部的抽象方法;(重写时,去掉关键字 abstract,加上方法体{ } )
4、子类继承抽象类,可以决定是否重写抽象类中非抽象方法;(没有重写的非抽象方法,则被子类继承)
5、抽象类不能实例化对象,则不能通过 new运算符 创建对象;
6、抽象类可以通过子类创建上转型对象;
如下代码↗:
//抽象类
public abstract class Animal {
//抽象方法,动物的叫声
abstract void cry();
//抽象方法,动物的名字
abstract void getAnimalName();
void method(){
System.out.println("我是抽象类中非抽象方法,被子类继承或者重写");
}
}
//子类继承抽象类
public class Cat extends Animal{
//重写抽象类中抽象方法
void cry() {
System.out.println("喵喵瞄~~~");
}
void getAnimalName() {
System.out.println("猫");
}
//重写抽象类中非抽象方法
void method(){
System.out.println("重写了抽象类中非抽象方法");
}
public static void main(String[] args){
//创建子类对象
Cat cats = new Cat();
System.out.println("子类对象cats的引用:"+cats);
//创建子类上转型对象
Animal ani;
ani = cats;
System.out.println("上转型对象ani的引用:"+ani);
}
}
代码输出结果:
子类对象cats的引用:Chapter_FiveTwo.Cat@7852e922
上转型对象ani的引用:Chapter_FiveTwo.Cat@7852e922
需要注意的是:
抽象类的子类也可以是抽象类,这种情况下,子类可以不 重写抽象类的抽象方法,而是选择 继承抽象方法;
如下代码↗:
//抽象类
public abstract class Animal {
//抽象方法,动物的叫声
abstract void cry();
//抽象方法,动物的名字
abstract void getAnimalName();
void method(){
System.out.println("我是抽象类中非抽象方法,被子类继承或者重写");
}
}
//抽象类继承抽象类
public abstract class Cat extends Animal{
//可以选择 重写抽象类中抽象方法,也可以选择 继承抽象方法
void cry() {
System.out.println("喵喵瞄~~~");
}
//重写抽象类中非抽象方法
void method(){
System.out.println("重写了抽象类中非抽象方法");
}
}
代码中,抽象类 Cat 继承了 抽象类 Animal,选择重写了 抽象方法 cry() , 继承了 抽象方法 getAnimalName() ;
抽象方法概念:
用关键字 abstract 修饰的方法就是抽象方法(abstract 方法);
如: abstract void method();
1、抽象方法没有方法体{};
2、抽象方法不能和 static 关键字一起使用;如:abstract static void method(); //是错误的
3、抽象方法不能和 final 关键字一起使用;如:abstract final void method(); //是错误的
接口的定义:
用关键字 interface 来定义一个接口;
如:public interface Printable{ } //public 访问权限的接口
interface Printable{ } //友好 访问权限的接口
1、JDK1.7以及以下JDK版本中,接口体只有常量的声明和抽象方法两部分;
2、JDK1.8以及以上JDK版本中,接口体还可以声明 static 方法 ;
3、接口体中所有常量的访问权限都是 public ,而且是 static 常量;
如:public static final double variable = 11.11 ;
(允许省略 public static final 不写,如:double variable = 11.11 ; )
4、接口体中所有抽象方法的访问权限都是 public ;
如:public abstract void method() ;
(允许省略 public abstract 不写,如:void method() ; )
5、接口体中的 static 方法,只能通过类名进行调用,接口变量 和 实现类创建的对象 都不能进行调用接口的 static 方法;
接口的实现:
接口需要使用关键字 implements 来实现;
如:public class A implements InterfaceFa { } //类A实现了接口InterfaceFa
1、一个类(抽象类,非抽象类),可以通过 implements 实现多个接口;
如:public class A implements InterfaceFa , InterfaceCh { } //怎么非抽象类A就要重写这两个接口的全部抽象方法
2、一个非抽象类,实现了某个接口,那么这个类必须要重写这个接口中全部抽象方法;
如:public class A implements InterfaceFa { } //怎么非抽象类A就要重写接口 InterfaceFa 的全部抽象方法
3、一个抽象类,实现了某个接口,那么这个抽象类就可以重写接口中的方法,也可以直接拥有接口中的方法;
如:public abstract class A implements InterfaceFa { }
4、一个接口可以通过 extends 继承另外一个接口,或者多个接口,那么这个接口就拥有了所继承接口的全部抽象方法和常量;
如:public interface A extends InterfaceFa , InterfaceCh { }
5、对于接口中的常量,可以在实现类中直接调用,也可以通过 接口名 . 常数名、接口变量 . 常数名 进行调用 ;
如下代码↗:
//接口变量操作接口中的常数
System.out.println("接口变量操作接口中常数"+ifa.valiablesFa);
//接口名操作接口中的常数
System.out.println("接口名操作接口中的常数"+interfaceFa.valiablesFa);
//实现类中直接操作接口中的常数
System.out.println("实现类中直接操作接口中的常数"+(valiablesFa+12));
6、如果一个类的父类实现了某个接口,那么这个类也默认地实现了这个接口;
接口回调、接口变量的实现:
接口属于引用型变量,接口变量中可以存放类的对象引用,通过接口变量就可以实现接口回调;
简单的说:将类对象的引用赋值给接口变量后,该接口变量就可以回调类重写的接口方法;
如下代码↗:
public class interfaceCh implements interfaceFa {
//创建接口变量
static interfaceFa ifa ;
//重写接口抽象方法
public void importsFa() {
System.out.println("importsFa");
}
public static void main(String[] args){
System.out.println(ifa); //输出为 NULL
//进行接口回调,通过接口回调创建的变量,可以调用实现类重写接口的方法
interfaceCh ich = new interfaceCh();
ifa = ich ; //接口变量存放对象的引用
System.out.println(ich); //输出的引用一样
System.out.println(ifa);
//分别使用 接口变量 和 实现类对象 调用重写方法;
ifa.importsFa(); //接口回调
ich.importsFa();
}
}
代码中 接口变量 ifa 通过接口回调,调用了被实现类重写的接口方法,但是接口变量不能调用 实现类自己原有的方法;
接口与多态:
接口与多态的关系就是:不同的类分别实现一个接口时,这些类通过方法重写,就可以具有不同的实现方式,那么接口变量在回调这些接口方法时就可以具有多种形态了;
接口参数(方法参数类型为接口类型):
接口参数指:一个方法的参数类型是接口类型的,这样就可以将任何实现该接口的类的对象引用传递给该接口参数;
接口参数作用:通过接口参数,可以回调类重写的接口方法了;
如下代码↗:
public class interfaceCh implements interfaceFa {
//重写接口的方法
public void importsFa() {
System.out.println("importsFa");
}
//接口参数,回调实现类重写的接口方法importsFa
public void methodParameter(interfaceFa itf){
itf.importsFa();
}
public static void main(String[] args){
//创建实现类对象,进行方法传参
interfaceCh ich = new interfaceCh();
ich.methodParameter(ich);
}
}
抽象类与接口的比较:
相同点:
1、抽象类与接口中 都有抽象方法;
2、抽象类与接口中 都有常量;
3、一般类继承抽象类与实现接口时,都要重写它们中的抽象方法 ;
不同点:
1、抽象类中可以有非抽象方法,接口没有;(除了JDK1.8及以上版本声明的接口)
2、抽象类中可以有变量,接口没有;
3、一般类只能继承一个抽象类,但可以实现多个接口;
需要注意的是:
JDK1.8及以上版本的接口,除了可以声明 static 方法,还可以声明 默认方法 (default 方法);
如下代码↗:
public interface inter{
//声明 默认方法 (default 方法)
default void print(){
System.out.println("我是一辆车!");
}
}
对于默认方法的使用,总结了下面两点:
一、一个接口继承了另外一个接口,就可以重写继承接口中的默认方法了;
二、一般类实现了某个接口,一般类中的实例方法可以通过 接口名 . super . 默认方法名 ; 进行调用;
void methods( ){
interfaceFa.super.print();
}
对于以上定义,我们应该什么时候使用 抽象类,什么时候使用 接口呢?
要根据子类的需求进行考虑,
当子类除了需要重写父类的 抽象方法外,还需要从父类继承一些 非抽象方法时,就可以考虑使用 抽象类了,
当子类不需要继承,只是需要某些重要的 抽象方法的实现细节,就可以考虑使用 接口了 ;