Java抽象类和接口怎么用

发布时间:2022-02-14 14:33:47 作者:小新
来源:亿速云 阅读:147

这篇文章将为大家详细讲解有关Java抽象类和接口怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

抽象类

什么是抽象类呢?在现实生活中,我们说“人类”,我们无法对应到具体某个人,同样的,“动物类”、“图形类”这些无法映射到具体的对象的类就是抽象类。

抽象类是普通类的超集,意思就是普通类有的抽象类也有,只是它比普通类多了一些抽象方法而已。这些抽象方法可以有一个,也可以有多个。

它存在的意义就是让子类来覆写它的抽象方法,抽象类和抽象方法的实现使用 abstract 关键字实现: 

Java抽象类和接口怎么用

此时Sharp类就是抽象类,可以看到它的图标和普通类都有所不同。

抽象方法

示例:

public abstract void print();

抽象方法所在的类一定是抽象类,抽象方法只有方法声明,没有方法体{}

注意区分没有方法体和方法体为空的情况

public abstract void print();//这是没有方法体

public abstract void print(){  } //这是方法体为空,它是普通方法

抽象类三大原则

1.抽象类无法直接实例化对象。例如上面的 Sharp 类,Sharp  sharp  = new Sharp();//这是错误的

2.子类继承抽象类,必须覆写抽象类中的所有抽象方法(前提是子类是普通类)

Java抽象类和接口怎么用

Triangle是一个普通类,此时没覆写方法就报错了,这时我们使用alt + enter 快捷键,点击第一行,再点击ok,就覆写了父类的抽象方法

Java抽象类和接口怎么用

Java抽象类和接口怎么用

但是当子类依然是抽象类时,可以选择不覆写抽象方法

Java抽象类和接口怎么用

3.final 和 abstract 不能同时使用、private 和 abstract 不能同时使用

Java抽象类和接口怎么用

抽象类存在的最大意义就是被继承,而且它仍然满足继承关系的 is a 原则

abstract class Person

class Chinese extends Person  √  

class Dog extends Person × //因为Dog not is a Person

同时抽象类任然受到单继承的局限,此时我们就引出了接口来打破这两个局限

接口

Java使用 interface 关键字定义接口,接口中只有全局常量和抽象方法(JDK之前)JDK8扩展了default方法。子类使用 implements 实现接口

一般接口的命名使用大写 ' I ' 字母开头,子类命名以 Impl 结尾

全局常量:

public static final int NUM = 10;

抽象方法:

public abstract String msg( );

接口使用原则

1.接口中只有 public 权限,且只有全局常量和抽象方法,所以 abstract、static、final、public这些关键字在接口内部都可以省略

public interface IMassage {
    int NUM = 10;//全局常量
     String msg();//抽象方法
}

2.接口没有单继承限制,子类可以同时实现多个父接口,多个接口之间使用逗号分隔。此时子类必须实现父类接口中所有的抽象方法

public interface IMassage {
    int NUM = 10;//全局常量
    String msg();//抽象方法
}
 interface INews{
    void getNews();
}
 
//子类
public class MessageImpl implements IMassage,INews{
 
    public String msg() {
        return null;
    }
    public void getNews() {
 
    }
}

接口可以使用 extends 继承多个父接口,下面的示例若类要实现接口 C ,就必须覆写 A、B、C中所有的抽象方法

    interface A{
        void testA();
    }
    interface B{
        void testB();
    }
    interface C extends A,B{
        
    }

3.接口依然不能直接实例化对象,需要通过向上转型实现

public class MessageImpl implements IMassage,INews{
 
    public String msg() {
        return "hello JAVA";
    }
 
    public void getNews() {
      System.out.println("hello n~");
 
    }
 
    public static void main(String[] args) {
        IMassage m = new MessageImpl();
        System.out.println(m.msg());
 
    }
}

//输出:hello JAVA

m只能调用msg方法,不能调用INews接口类定义的方法,需要用父类间的相互转换实现调用

        INews n = (INews)m;
        n.getNews();

//输出:hello n~

4.子类若既要继承类又要实现接口,就先继承,后实现接口

public class D  extends A  implements X,Y{  } 

JDK两大内置接口

java.lang.Comparable 比较接口

引入示例:使用排序方法比较Student类中的对象

public class Student {
    private String name;
    private int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Student{" +
    "name=" + name+'\''+ ",age="+ age + '}';
    }
 
    public static void main(String[] args) {
        Student s1 = new Student("张三",18);
        Student s2 = new Student("李四",20);
        Student s3 = new Student("王五",30);
        Student[] students = {s3,s1,s2};
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

运行结果:

Java抽象类和接口怎么用

程序报错,因为Student类是自定义类型,当使用Arrays.sort方法对自定义类型进行排序时,自定义类型需要实现 Comparable 才具有可比较的能力

因此我们将上述示例做如下改动:

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Student{" +
    "name=" + name+'\''+ ",age="+ age + '}';
    }
    @Override
    public int compareTo(Student o) {
        if (this.age == o.age){
            return 0;
        }else if (this.age < o.age){
            return -1;
        }
        return 1;
    }
 
    public static void main(String[] args) {
        Student s1 = new Student("张三",18);
        Student s2 = new Student("李四",20);
        Student s3 = new Student("王五",30);
        Student[] students = {s3,s1,s2};//乱序放入数组
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
 
}

//输出结果:
[Student{name=张三',age=18}, Student{name=李四',age=20}, Student{name=王五',age=30}]

可以看到数组按照年龄的升序排序,达到了预期效果。如果想要按照年龄降序排列,只需要修改 compareTo 方法中的一和负一

Java抽象类和接口怎么用

实现Comparable接口,必须覆写它的compareTo方法,该方法返回的数字:

java.lang.Cloneable 克隆接口

在程序中,克隆是指复制一个新的对象,而这个新对象的属性值是从旧对象中拷贝过来的

Cloneable 接口是一个标记接口,本身没有任何抽象方法,当一个类实现了 Cloneable 接口,就表示该类具备了克隆的能力,这个能力是JVM赋予的,要知道在堆上开辟空间和对象创建都由JVM实现。

我们需要覆写 Object 类的 clone 方法,点击向上转型的图标我们就能看到 Object 提供的该方法

Java抽象类和接口怎么用

Java抽象类和接口怎么用

可以看到,clone 方法没有方法体,用 native 关键字修饰,叫做本地方法,clone方法不是Java语言实现的,而是C++实现的,要知道JVM就是由C++实现的。所以本地方法就表示Java调用了C++的同名方法,此处只是方法声明,具体的方法实现是在C++中。所以虽然它没有方法体,但它并不是抽象方法。

Java抽象类和接口怎么用

这里我们就能知道一个小知识点:没有方法体的方法不一定就是抽象方法

代码示例:

public class Cat implements Cloneable{
    private String name;
 
    @Override
    protected Cat clone() throws CloneNotSupportedException {
        return (Cat) super.clone();
    }
 
    public static void main(String[] args) throws CloneNotSupportedException {
        Cat c1 = new Cat();
        c1.name = "喵喵";
        Cat c2 = c1.clone();
        System.out.println(c1 == c2);
        System.out.println(c2.name);
    }
}

输出结果:

Java抽象类和接口怎么用

可以看到,输出 false表示c1和c2不是同一个地址,也就是说在堆上为c2开辟了一个新空间,将c1的值拷贝给了c2

对象的深浅拷贝

我们先看一个示例:

class A{
    int num;
}
public class B implements Cloneable{
    A a = new A();
 
    @Override
    protected B clone() throws CloneNotSupportedException {
        return (B)super.clone();
    }
 
    public static void main(String[] args) throws CloneNotSupportedException {
        B b1 = new B();
        B b2 = b1.clone();
        System.out.println(b1 == b2);
        System.out.println(b2.a.num);
        b1.a.num = 100;
        System.out.println(b2.a.num);
    }
}

输出:false
0
100

根据结果我们看到,将b1.a的值改为100后,b2.a也随之变化,就是说b1.a 和 b2.a 指向了相同的对象

Java抽象类和接口怎么用

这就是浅拷贝,拷贝出的 b1 对象只是拷贝了 b1 自身, 而没有拷贝内部包含的 a 对象. 此时 b1 和 b2 中包含的 a 引用仍然是指向同一个对象. 此时修改一边, 另一边也会发生改变.

我们将代码做如下修改:

class A implements Cloneable{
    int num;
 
    @Override
    protected A clone() throws CloneNotSupportedException {
        return (A)super.clone();
    }
}
public class B implements Cloneable{
    A a = new A();
 
    @Override
    protected B clone() throws CloneNotSupportedException {
        B b = new B();
        b.a = a.clone();
        return b;
    }
 
    public static void main(String[] args) throws CloneNotSupportedException {
        B b1 = new B();
        B b2 = b1.clone();
        System.out.println(b1 == b2);
        System.out.println(b2.a.num);
        b1.a.num = 100;
        System.out.println(b2.a.num);
    }
}

结果:false
0
0

我们让A类也实现克隆接口,可以看到b1.a的修改没有影响b2.a,说明此时b1和b2内部包含的a对象也是不同的,这种拷贝就叫做深拷贝

在Java中,实现深拷贝的方式有两种:一种是递归实现Cloneable,上述的例子就是递归实现的;另外一种就是通过序列化(Serializable 接口)来进行拷贝。这两种方法现在已经不常用了,现在实现深拷贝是将对象转为json字符串

抽象类和接口的区别

Java抽象类和接口怎么用

关于“Java抽象类和接口怎么用”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

推荐阅读:
  1. 抽象类和接口
  2. java接口和抽象类是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:laravel有哪些缺点

下一篇:swoole如何实现定时任务

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》