JAVA中的抽象类与接口的使用

一、抽象类

1.抽象类的含义

在了解抽象类之前我们要先知道什么是普通类。普通类具有完整的类功能,不但可以直接产生实例化对象,而且在普通类中可以包含有构造方法、普通方法、static(静态)方法、常量和变量等内容。而抽象类是指在普通类的结构里面增加抽象方法的组成部分。
那么什么叫抽象方法呢?在所有的普通方法上面都会有一个“{}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰。而拥有抽象方法的类就是抽象类,抽象类要使用abstract关键字声明。
**注意:abstract修饰符
1.abstract修饰的类为抽象类,此类不能有对象,(无法对此类进行实例化,说白了就是不能new);
2.abstract修饰的方法为抽象方法,此方法不能有方法体(就是什么内容不能有);
范例:定义一个抽象类

abstract class student{//定义一个抽象类	
	public void sleep(){//普通方法
		System.out.println("我喜欢学习");
	}	
	public abstract void play();//抽象方法,没有方法体,有abstract关键字做修饰	
}

2.抽象类的使用原则

在这里我们先看一个例子:

package Work;
abstract class Student{//定义一个抽象类
    public void sleep(){//普通方法
        System.out.println("学生喜欢学习");
    }
    public abstract void paly();//抽象方法,没有方法体,有abstract关键字做修饰
}
public class Work11_111 {
    public static void main(String[] args) {
        Student Me= new Student();
    }
}

运行结果:
在这里插入图片描述
由此可知,Student是抽象的,无法直接进行实例化操作。什么是实例化?当一个类实例化之后,就意味着这个对象可以调用类中的属性或者方法,但在抽象类中存在抽象方法,而抽象方法没有方法体,没有方法体就无法进行调用。既然无法进行方法调用的话,自然无法产生实例化对象。
进而·可以得到抽象类的使用原则:
(1)抽象类不能直接使用,需要子类去实现抽象类,然后使用其子类的实例。(需要依靠子类采用向上转型的方式处理)
(2)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
(3)抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
(4)子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。);
*注:
在这里插入图片描述
重写范例:

package Work;
abstract class Student{//定义一个抽象类
  public void sleep(){//普通方法
      System.out.println("学生喜欢学习");
  }
  public abstract void paly();//抽象方法,没有方法体,有abstract关键字做修饰
}
class People extends Student{
  @Override
  public void paly() {
      System.out.println("我喜欢学习");
  }
}
public class Work11_111 {
  public static void main(String[] args) {
      Student Me= new People();
      Me.paly();
      Me.sleep();
  }
}

运行结果如下:

我喜欢学习
学生喜欢学习

3.抽象类使用限制

1)抽象类不可以用final声明:因为抽象类必须有子类,而final定义的类不能有
子类。
2)抽象类中存在有构造方法:抽象类里会存在一些属性,所以抽象类中一定存在构造方法,其存在目的是为了属性的初始化。并且子类对象实例化的时候,依然满足先执行父类构造,再执行子类构造的顺序。
3)抽象类能否使用static声明?
先看一个关于外部抽象类的范例:

package Work;
 static abstract class Student{//定义一个抽象类
    public void sleep(){//普通方法
        System.out.println("学生喜欢学习");
    }
    public abstract void paly();//抽象方法,没有方法体,有abstract关键字做修饰
}
class People extends Student{
    @Override
    public void paly() {
        System.out.println("我喜欢学习");
    }
}
public class Work11_111 {
    public static void main(String[] args) {
        Student Me= new People();
        Me.paly();
        Me.sleep();
    }
}

运行结果:
在这里插入图片描述
再看一个关于内部抽象类:

package Work;
abstract class Student{//定义一个抽象类
     static abstract class B{//static定义的内部类属于外部类
         public abstract void play();
     }
     //抽象方法,没有方法体,有abstract关键字做修饰
}
class People extends Student.B{
    @Override
    public void play() {
        System.out.println("我喜欢学习");
    }
}
public class Work11_111 {
    public static void main(String[] args) {
        Student.B Me= new People();
        Me.play();
    }
}

运行结果:

我喜欢学习

由此可见,外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称。

二、接口

1.接口的含义

Java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。接口可以看作是抽象类的变体,接口中所有的方法都是抽象的。接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
我们使用interface关键字定义接口,一般使用接口声明方法或常量,接口中的方法只能是声明,不能是具体的实现,这一点和抽象类是不一样的。接口是更高级别的抽象。接口的定义格式是:

public interface 接口名称{
    //可以定义常量
    //方法只有方法声明,而且是公共的。
    public void 方法名称();
    ...
}

类要实现接口,只需要使用implements关键字,实现类必须要实现接口中的所有的方法

public class 实现类名 implements 接口{
    //实现接口的方法
}

2.接口的实现

(1)定义接口

示例代码如下:

// 定义方法的接口
public interface People {
  // 定义程序使用的常量的接口,接口中只能有常量。
  public static final double count = 1314.00;
  public static final int age = 5;
  //接口中所有的方法都没有方法体。
  public void add(int x, int y);
  public void volume(int x,int y, int z);
}

(2)实现接口

代码如下:

//实现     接口
public class Student implements People {
    @Override
    public void add(int x, int y) {
    }
    @Override
    public void volume(int x, int y, int z) {
    }
}

一个类是可以实现多个接口,因为java是单继承的,这点接口可以弥补。我们可以再定义一个接口,如下:

public interface People2 {
    public void num();
}

修改上面的实现类,要实现多个接口,可以使用逗号隔开,当然所有的接口的方法都要实现。

//实现       接口1,接口2
public class Student implements People ,People2{
    @Override
    public void add(int x, int y) {
    }
    @Override
    public void volume(int x, int y, int z) {
    }
    @Override
    public void num() {
    }
}

(3)利用接口实现计算机的四则运算

代码如下:

package Work;
interface Computer{
    int count(int n,int m);
}
//加法
class Add implements Computer {
    @Override
    public int count(int n, int m) {
        return n + m;
    }
}
//减法
class Sub implements Computer {
    @Override
    public int count(int n, int m) {
        return n - m;
    }
}
//除法
class Div implements Computer{
    @Override
    public int count(int n, int m) {
        if(m!=0){
            return n/m;
        }
        else {
            System.out.println("分母不能为0");
            return 0;
        }
    }
}
//乘法
class Mul implements Computer{
    @Override
    public int count(int n, int m) {
        return n*m;
    }
}
//接口是不能直接实例化的,需要定义一个实现类,将接口的引用作为example的参数,利用Realize类实现接口。
class Realize{
    public void example(Computer s,int n, int m){
        System.out.println(s.count(n,m));
    }
}
public  class TestDemo11_2 {
        public static void main (String[] args){
            Realize s=new Realize();
            s.example(new Add(),1,2);
            s.example(new Sub(),1,2);
            s.example(new Div(),4,2);
            s.example(new Mul(),1,2);
        }
}

3.接口与类的区别

  • 接口不能用于实例化对象。
  • 接口中所有的方法必须是抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

4.抽象类和接口的区别

1)抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
3)接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

5.使用接口注意事项

1)不能够new创建对象
2)如果要去创建一个接口对应的对象,则需要通过它的具体实现类, 使用implements关键字去实现接口 。
3) 接口被编译之后也会产生对应的字节码文件
4)接口之间也是可以相互继承 extends
5) 接口对应是多实现 eg.class C implements A,B
6) 抽象类中设置的都是通用的方法,功能与实体都是一种"是"的关系,接口中功能与实体都是一种"有"的关系
7)接口中定义的属性为什么是static final的?
static 原因主要是接口的实现是多实现,为了区分不同接口当中的相同变量
final 原因是因为如果是变量,接口的存在就失去其意义,同时接口来说指的 是统一的协议,Java设计者直接规定接口中的属性只能是public static final的。
8)接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。

6.比较器接口

(1)内部比较器(Comparable接口)

*注意:内部比较器位于 java.lang包下
下面看看Comparable接口的源码:

public interface Comparable<T>
{
    public int compareTo(T o); 
1)如果此对象(调用比较器方法的对象)大于指定对象(目标比较对象),返回正整数   
2)如果此对象小于指定对象,返回负整数   
3)如果此对象等于指定对象,返回零 
}

Comparable接口的使用:

package Work;
class Student implements Comparable<Student>{
    private String name;
    private int age;
    private float score;//得分
    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    public String toString()
    {
        return name+"\t\t"+age+"\t\t"+score;
    }
    @Override
    public int compareTo(Student o) {
        if(this.score>o.score)//score是private的,为什么能够直接调用,这是因为在Student类内部
            return -1;//由高到底排序
        else if(this.score<o.score)
            return 1;//当后一个对象比当前对象大,返回结果值为1时,前后交换,说明是倒序排列。(从高到低)
        else{
            if(this.age>o.age)
                return 1;//当后一个对象比当前对象小,返回结果值为1时,前后交换,说明是升序排列。(从低到高)
            else if(this.age<o.age)
                return -1;
            else
                return 0;
        }
    }
}
public class Blog {
    /**
     * @name 博客
     *  先比较score在比较age
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Student stu[]={new Student("zhangsan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu);//Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,可以直接调用。
        for(Student s:stu)
        {
            System.out.println(s);
        }
    }
}

运行结果为:

sunliu		22		100.0
wangwu		20		99.0
zhangsan		20		90.0
lisi		22		90.0

(2)外部比较器(Comparator接口)

注意:Comparator位于包java.util下。
下面看看Comparator接口的源码:

package java.util;
public interface Comparator<T> {  

int compare(T o1, T o2);  

  1)如果o1大于o2,则返回正整数; 
  2)如果o1小于o2,则返回负整数 
  3)如果o1等于o2,则返回零   
  }

Comparator的使用:

package Work;
import java.util.*;
class Student {
    private String name;
    private int age;
    private float score;

    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public float getScore() {
        return score;
    }
    public void setScore(float score) {
        this.score = score;
    }
    public String toString()
    {
        return name+"\t\t"+age+"\t\t"+score;
    }
}
class StudentComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        // TODO Auto-generated method stub
        if(o1.getScore()>o2.getScore())
            return -1;
        else if(o1.getScore()<o2.getScore())
            return 1;//当后一个对象比当前对象大,返回结果值为1时,前后交换,说明是倒序排列。(从高到低)
        else{
            if(o1.getAge()>o2.getAge())
                return 1;//当后一个对象比当前对象小,返回结果值为1时,前后交换,说明是升序排列。(从低到高)
            else if(o1.getAge()<o2.getAge())
                return -1;
            else
                return 0;
        }
    }

}
public class Blog {
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Student stu[]={new Student("zhangsan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu,new StudentComparator());
        for(Student s:stu)
        {
            System.out.println(s);
        }
    }
}

运行结果如下:

sunliu		22		100.0
wangwu		20		99.0
zhangsan		20		90.0
lisi		22		90.0

(3)Comparable与Comparator的区别

1)Comparator位于包java.util下,而Comparable位于包 java.lang下
2)Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口)而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。

(4)Arrays.sort()用法理解

Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,可以直接调用。具体使用方法可以参照下面这篇文章。

https://blog.csdn.net/weixin_43761659/article/details/97442067Arrays.sort()用法理解

7.Cloneable 标记接口

如果一个类实现了Cloneable接口,就表示该类中的对象是可以被clone的,同时实现Cloneable则需要重写Object.clone方法。
具体实现可以参考如下文章:

https://blog.csdn.net/qq_37113604/article/details/81168224?Cloneable接口的作用与深入理解深度克隆与浅度克隆

面试题:为什么clone方法在Object类中定义为protected,而不是public?

  • protected受保护成员,分为与父类在同一包内和不在同一包内的子类,不在同一个包中 的子类,只能访问从父类继承而来的受保护成员,而不能访问父类实例本身的受保护成员, 在相同包内则没有以上的限制。并不是所有的对象都可以被克隆,如果子类对象可被克隆,则必须实现Cloneable接口并且重写clone方法。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~四时春~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值