九、JAVA中的抽象类和接口

1. 抽象类

1.1 概念

Java中可以定义没有方法体的方法,该方法由其子类来具体的实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。

抽象类可以理解为是一个只有方法声明没有方法体的特殊类。

举例:水果,东西。

修饰符 abstract 返回值 方法名(参数列表);
 
class A{
       public void eat(){//声明一样,可以提取
              syso("eat...B")    }
}
class B{
       public void eat(){//声明一样,可以提取
       syso("eat。。。A")   }
}            

abstract class C{
              public abstract void eat();
}

1.2 特点

1、 通过java关键字abstract实现

2、 可以修饰方法或者类

3、 抽象类中可以没有抽象方法(由子类去实现)

4、 如果类中有抽象方法,那该类必须定义为一个抽象类

5、 子类继承了抽象类以后,要么还是一个抽象类,要么就把所有抽象方法都重写

6、 多用于多态中

7、 抽象类不可以被实例化

1.3 入门案例

public class TestAnimal {
       public void eat(){
              System.out.println("吃饭饭");
       }
}

/*
 * 每种动物都需要吃,
 * 发现了,方法声明都一样,只是方法体不一样
 *

class Dog extends TestAnimal{
       public void eat(){
             System.out.println("狗吃肉");
       }
}
 
class Cat extends TestAnimal{
       public void eat(){
              System.out.println("猫吃鱼");
       }
}*/
 
//上面的eat()声明都一样,就是方法体不一样,那就只抽取方法声明部分。
//The type Animal must be an abstract class to define abstract methods
 abstract class Animal extends Object{
        //This method requires a body instead of a semicolon
       public abstract  void eat();
}
 
 //继承抽象类,并实现抽象方法
//The type Dog must implement the inherited abstract method Animal.eat()
abstract class Dog extends Animal{
     //可以实现抽象方法,也可以子类再变成一个抽象类
}
 
class Cat extends Animal{
       public void eat() {
              System.out.println("猫吃鱼");
       }      
}

2. 抽象类的用法

2.1 构造函数

抽象类也有构造方法,但是不能本身实例化。

那抽象类的构造函数有啥用?一般用于给子类实例化。

//抽象类的构造方法
abstract class Animal{
       //抽象类可以有构造方法,但是无法实例化
       //用于子类实例化
       public Animal(){
              System.out.println("fu..Animal()");
       }
}

class Zi extends Animal{
      
}
 
class TestAnimal{
       public static void main(String[] args) {
//           Animal a = new Animal();//抽象类无法实例化   
//           Zi z=new Zi();//创建子类实例化对象
 
              Animal a = new Zi();//抽象类多用于多态    
       }
}

2.2 抽象类的成员变量

既可以有变量,也可以有常量。

//成员变量

abstract class Animal{
       //String name;  //1
       //String name="大黄";  //2
       private String name="大黄";  //3
       public final int age=10;
      
       //3.1如果是私有变量想要取值,就提供getXxx()
       public String getName(){
              return name;
       }
}
 
class Zi extends Animal{
      
}
 
class TestDemo{
       public static void main(String[] args) {
              Animal3 a = new Zi3();//抽象类多用于多态
              //System.out.println(a.name());  //1或者2
              System.out.println(a.getName());  //3
              System.out.println(a.age);
             
       }
}

2.3 抽象类的成员方法

抽象类里,既可以有普通方法,有可以有抽象方法。

//成员方法

abstract class Animal{
       //抽象类中的普通方法
       public void speek(){
              System.out.println("fu...speak()");
       }
       //抽象类里的抽象方法
       public abstract void study();
}

 

class Zi extends Animal{
       //重写抽象方法
       public void study(){
              System.out.println("zi...study()");
       }
}
 
class ZiTest{
       public static void main(String[] args) {
              Zi z= new Zi();
              z.speek();//fu...speak()
              z.study();//zi...study()
       }
}

3. 分析案例老师

具体事物:大学老师, 小学老师

共性:讲课

abstract class Teacher{
       private String name;
       private int age;
       public void setName(String name){
              this.name=name;
       }

       public void setAge(int age){
              this.age=age;
       }

       public String getName(){
              return name;
       }

       public int getAge(){
              return age;
       }

       public abstract void teach();
      
       public void print(){
              System.out.println(name+"........"+age);
       }         
}

class HTeacher extends Teacher{

       public void teach() {
              System.out.println("教大学专业课");
       }
}

class LTeacher extends Teacher{
       public void teach() {
              System.out.println("教写字");
       }
}
 
class TestDemo{
       public static void main(String[] args) {
              HTeacher ht=new HTeacher();
              ht.teach();//教大学专业课
              ht.setName("大炮");
              ht.setAge(20);
              ht.print();
       
              LTeacher lt=new LTeacher();
              lt.teach();//教写字
              lt.setAge(30);
              lt.setName("大佬");
              lt.print();
             //多态、向上转型
              Teacher t = new HTeacher();
              t.teach();
              t.setName("jack");
              t.setAge(10);
              t.print();
       }
}

4. 接口

4.1 概念

Java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。

Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为java结构层次上的顶层。

interface 接口名{ 
 		代码… 
}

4.2 特点

1、 接口中都是抽象方法

2、 通过interface关键字创建接口

3、 通过implements让子类来实现

4、 可以理解成,接口是一个特殊的抽象类

5、 接口突破了java的单继承的局限性

6、 接口和类之间可以多实现,接口和接口之间可以多继承

7、 接口是对外暴露的规则,是一套开发规范

8、 接口提高了程序的功能扩展,降低了耦合性

4.3 入门案例

public class T {
       public static void main(String[] args) {
              Zi z = new Zi();
              z.study();
              z.teach();
       }
}

interface Fu{
       public abstract void study();
       public abstract void teach();
}

//实现+重写
class Zi implements Fu{
       public void study(){
              System.out.println("Zi..study()");
       }

       public void teach(){
              System.out.println("Zi..teach()");
       }
}

5. 接口的用法

5.1 构造方法

接口里是没有构造方法的。

在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。

interface Fu{//定义一个接口
       public abstract void show();
       //Interfaces cannot have constructors
       /*public Fu(){
              System.out.println("Fu.Fu()");
       }*/
}

5.2 成员变量

接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上
public static final

//构造函数,成员方法,成员变量
interface Fu{//定义一个接口
      
       //int num=10;//1,成员变量
       //static int num=10;//2,默认就是静态的
       //final static int num=10;//3,默认就是final的
       public final static int num=10;//4,默认就是public的
 }
 
class Zi implements Fu{
 
}
 
class TestDemo{
       public static void main(String[] args) {
              Zi z= new Zi();
              //The final field Fu2.num cannot be assigned
              //z.num=30;//默认是final的,不能修改值
              System.out.println(z.num);
              System.out.println(Fu.num);
       }
}

5.3 接口的成员方法

接口里的方法,默认就都是抽象的,如果你不写明是abstract的,那会自动补齐

例如:public abstract void save();

//这个类用来测试接口的使用
public class TestUseInter {
    public static void main(String[] args) {
       //测试
//     Inter in = new Inter();//3、接口不能创建对象
       Inter in = new InterImpl();
//     in.count = 20 ;//4、是最终的,The final field Inter2.count cannot be assigned
       System.out.println(  in.COUNT   );
       System.out.println(  Inter.COUNT );//5、是静态的
      
       in.get();
       in.update();
    }
}

//创建接口
interface Inter{
    //1、接口里可以有构造方法吗?   ---  不能!!
//  public Inter() {}
   
    //2、接口里可以有成员变量吗?   ---   没有!!
//public static final  int count = 10;
//简写,接口会为变量自动拼接  public static final
    int COUNT = 10 ; 
   
    //3、接口里可以有成员方法吗?  --- 可以,但都是抽象方法!!
    //public abstract void update() ;
     // 简写,接口会为方法自动拼接 public abstract
    void update() ; // 简写,接口会为方法自动拼接 public abstract
    void get() ;
}

class InterImpl  implements  Inter{
    @Override
    public void update() {
       System.out.println("update()...");
    }
    @Override
    public void get() {
       System.out.println("get()...");
    }
}

6. 接口的复杂用法

Java中单继承的局限性通过接口可以解决。

接口可以多继承也可以多实现,甚至可以继承的同时多实现。

//这个类用来测试接口的复杂用法:多继承多实现
public class TestComInter {
    public static void main(String[] args) {
       Interface1 in = new Interface1Impl();
       in.save();
       in.update();
    }
}

//创建接口1
interface Interface1{
    void save();
    void update();
}

//创建接口2
interface Interface2{
    void get();
    void delete();
}

//1、打破了java单继承的局限性,因为接口之间可以多继承,多个接口之间逗号隔开
interface Interface3 extends Interface1,Interface2{
    void add();
}

//3、接口还可以多实现吗??---可以多实现,只不过接口之间逗号隔开
class ManyImpl implements  Interface1,Interface2{
    public void save() {}
    public void update() {}
    public void get() {}
    public void delete() {}
}

//4、接口可以继承的同时,多实现?? --可以,如果父类中重写了,可不重写接口中方法
class MoreImple extends ManyImpl  implements Interface1,Interface2  {

}

//2、创建实现类,使用3号接口的功能,需要重写几个方法呢??---同时重写1号和2号和3号接口里的所有功能
class Interface3Impl  implements Interface3{
    @Override
    public void save() {  }
    @Override
    public void update() {  }
    @Override
    public void get() {  }
    @Override
    public void delete() {   }
    @Override
    public void add() {  }
}

//TODO 创建实现类
class Interface1Impl implements Interface1{
    @Override
    public void save() {
       System.out.println("save()...");
    }

    @Override
    public void update() {
       System.out.println("update()...");
    }
}

7. 总结

1、类和类的关系:继承 extends / 单继承 / 单根继承
    -- 继承的意义:为了提高代码的复用性,减少了代码的编写提高开发效率。
    -- 方法重写的意义:在不修改父类源码的前提下,在子类中重写业务,从此使用的就是重写后的功能。
       -- 要求子类的方法声明和父类一样,只要改方法体。
    -- 有了继承有了重写就产生了多态,多态的意义:为了统一程序的调用标准,标准就是父类。
    -- 多态 也就是向上转型/向上造型。
    -- 向下造型的意义:很少用,相当于想要使用子类的特殊功能,还不如直接创建子类对象简单。
    -- class A extends B
    -- 其中,AB都是类,A是子类,B是父类,A就拥有了B的所有功能(除了私有的和构造方法)
 
    -- 其他知识点:thissuper  ,构造方法,各种代码块...见博客oop专题

2、类和接口关系:实现implements  / 单实现 / 多实现
    -- class A implements B,C
    -- 其中,A是实现类,BC是接口
    -- 要求A 可以把 BC 接口里的所有 抽象方法 都重写掉,否则 A 就是抽象类
    -- 接口不能创建对象
    -- 接口里没有构造方法,接口里都是常量,接口里都是抽象方法
 
3、接口和接口关系:继承extends / 单继承 / 多继承
    -- 接口的多继承的关系,打破了java单继承的局限性
    -- interface A  extends  B,C
    -- 其中,A B C 都是接口,A是子接口,同时拥有BC接口里的所有功能
    -- class AImpl implements  A
    -- 要求AImpl需要重写A接口里的所有方法(是包含BC接口的所有方法),否则就是抽象类
 
4、接口和抽象类的区别!!!
    -- 相同点:都是抽象层,都不能实例化                      
    -- 不同点:
       -- 1、抽象类用abstract关键字描述,接口用interface
       -- 2、子类和抽象类之间是extends关系,实现类和接口之间是implements关系
       -- 3、抽象类中 可以  有构造方法 ,接口里 不能 出现 构造方法
       -- 4、抽象类里可以有 变量,接口里没有变量全都是静态的常量
       -- 5、接口里定义常量的语法:public static final String NAME="jack",会为变量自动拼接public static final
       -- 6、抽象类里 可以有普通方法  也可以有 抽象方法,接口都是抽象方法
       -- 7、抽象类和子类之间是继承关系,而且java中,只支持单继承
       -- 8、接口突破了java单继承的局限性,因为接口可以多继承也可以多实现,甚至可以继承的同时多实现
       -- 9、接口的复杂用法
           -- 多继承: interface A  extends  B,C  其中A是子接口,同时拥有自己的和BC的功能
           -- 多实现: class AImpl implements M,N,O,P 其中AImpl是实现类,需要同时重写MNOP的所有抽象方法,否则就是一个抽象类
           -- 继承的同时多实现: class AImpl extends Object implements M,N 一定是先继承后实现

8. 拓展

8.1 abstract注意事项

抽象方法要求子类继承后必须重写。那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。

1、 private:被私有化后,子类无法重写,与abstract相违背。

2、 static:静态的,优先于对象存在。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。

3、 final:被final修饰后,无法重写,与abstract相违背。

8.2 接口和抽象类的区别

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

2、抽象类要被子类继承,接口要被类实现。

3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

7、抽象类里可以没有抽象方法,如果要扩展抽象类的新方法,子类将很容易的就能得到这些新方法。

8、如果一个类里有抽象方法,那么这个类只能是抽象类

9、抽象方法要被实现,所以不能是静态的,也不能是私有的。

10、接口可继承接口,并可多继承接口,但类只能单根继承。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值