首页 > 编程语言 >【Java】你真的了解抽象类和接口?

【Java】你真的了解抽象类和接口?

时间:2023-05-29 21:01:15浏览次数:47  
标签:Java name age 接口 Student 抽象类 public String

一、抽象类

在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法**,抽象方法不用给出具体的实现体**。

public class TestDemo {
    public static void main(String[] args){
        Circle c = new Circle();
        c.setR(5);
        c.getArea();
        Squre s = new Squre();
        s.setLength(10);
        s.getArea();
    }
}
//抽象类
abstract class Shape{
    private int size;
    //抽象方法
    abstract public void getArea();
}
class Circle extends Shape{
    private int r;
    public int getR() {
        return r;
    }
    public void setR(int r) {
        this.r = r;
    }
    //重写抽象方法
    @Override
    public void getArea() {
        double  area = r*r*r*4.0/3;
        System.out.println("此圆形的面积是: "+area);
    }
}
class Squre extends Shape{
    private int length;
    //重写抽象方法
    @Override
    public void getArea() {
        double area = length*length;
        System.out.println("此正方形的面积是: "+area);
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
}
  • 抽象类的特性
  • 抽象类中使用abstract修饰类和抽象方法,这个方法没有具体的实现,抽象类中可以包含普通类所能包含的成员,抽象类所存在的最大意义就是被继承。
  • 抽象类方法不能是私有的,如果一个普通类继承了抽象类,那么必须重写抽象类中的抽象方法,不能被static和final修饰,因为抽象方法要被子类继承。
  • 抽象类中不一定包含抽象方法,但是包含抽象方法的一定是抽象类,抽象类之间的相互继承不需要重写抽象方法。
二、接口
  • 接口的定义

接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。

  • 接口的使用
//接口的定义
interface USB {
    void openDevice();
    void closeDevice();
}
//实现接口
class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    public void click(){
        System.out.println("鼠标点击");
    }
}
//实现接口
class KeyBoard implements USB{
//实现接口中的抽象类
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
    public void inPut(){
        System.out.println("键盘输入");
    }
}
  • 注意事项
  • ❗ 接口不能够直接使用,必须有一个类来实现接口,并实现接口中的所有抽象方法

【Java】你真的了解抽象类和接口?_后端

  • ❗ 子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系
  • 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错。

【Java】你真的了解抽象类和接口?_后端_02

  • ❗ 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现 ,JDK1.8 开始允许有可以实现的方法,但这个方法只能是default 修饰的,类在实现该接口时,不需要重写该默认方法。

具体作用: 当我们进行业务扩展时,需要在接口中新增方法。如果新增的这个方法写成普通方法的话,那么需要在该接口所有的实现类中都重写这个方法。如果新增的方法定义为default类型,就不需要在所有的实现类中全部重写该default方法,哪个实现类需要新增该方法,就在哪个类中进行实现

【Java】你真的了解抽象类和接口?_后端_03

  • 重写接口中方法时,不能使用default访问权限修饰
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
  • 接口中不能有静态代码块和构造方法
  • 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

【Java】你真的了解抽象类和接口?_Java_04

  • 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

【Java】你真的了解抽象类和接口?_抽象类_05

  • 实现多个接口
  • 一个类实现多个接口
interface USB { 
    void openDevice();
    void closeDevice();
}
interface ULine{
    void lineInsert();
}
class Mouse implements USB,ULine{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    @Override
    public void lineInsert() {
        System.out.println("插入鼠标线");
    }
}

一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类

  • 一个类继承一个父类,同时实现多个接口
public class TestDemo3 {
    public static void main(String[] args) {
        Duck duck = new Duck("yaya");
        walk(duck);
        Brid brid = new Brid("gugu");
        walk(brid);
    }
    public static void walk(IRunning running) {
        System.out.println("去散步");
        running.run();
    }
}
 class Animal {
        protected String name;
        public Animal(String name) {
            this.name = name;
       }
}
interface IFlying {
        void fly();
}
interface IRunning {
      void run();
}
interface ISwimming {
        void swim();
}
class Duck extends Animal implements IFlying,IRunning,ISwimming{
    public Duck(String name) {
        super(name);
    }
    @Override
    public void fly() {
        System.out.println("飞飞飞");
    }
    @Override
    public void run() {
        System.out.println("鸭子嘎嘎跑");
    }
    @Override
    public void swim() {
        System.out.println("游游游");
    }
}
class Brid extends Animal implements IRunning,ISwimming,IFlying{
    public Brid(String name) {
        super(name);
    }
    @Override
    public void  fly() {
        System.out.println("鸟儿飞");
    }

    @Override
    public void run() {
        System.out.println("鸟儿跑");
    }

    @Override
    public void swim() {
        System.out.println("鸟儿游");
    }
}
  • 接口中的多态
public class TestDemo3 {
    public static void main(String[] args) {
        Duck duck = new Duck("yaya");
        walk(duck);
        Brid brid = new Brid("gugu");
        walk(brid);
    }
    public static void walk(IRunning running) {
        System.out.println("去散步");
        running.run();
    }
}

有了接口之后, 类的使用者就不必关注具体类型,而只关注某个类是否具备某种能力.

  • 接口之间的继承

一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的。接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字

interface IRing {
    void run();
} 
interface ISing {
    void swim();
} 
interface IAmphibious extends IRunning, ISwimming {}
class Frog implements IAmphibious {
    @Override
    public void run() {
        System.out.println("跑啊跑");
    }
    @Override
    public void swim() {
        System.out.println("游啊游");
    }
}

接口间的继承相当于把多个接口合并在一起.

✅抽象类和接口的区别??


区别

抽象类(abstract)

接口(interface)

1

结构组成

普通类+抽象方法

抽象方法+全局变量

2

权限

各种权限

public

3

子类使用

使用extends关键字继承抽象类

使用implements关键字实现接口

4

关系

一个抽象类可以实现若干接口

接口不能继承抽象类,但是可以使用extends关键字继承多个接口

5

子类限制

一个子类只能继承一个抽象类

一个子类可以实现多个接口

三、Object类

Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用进行接收。

public class TestDemo5 {
    public static void main(String[] args) {
        function(new Person());
        function(new Student());
    }
    public static void function(Object obj){
        System.out.println(obj);
    }
}
class Person{
    private int age;
    private String name;
}
class Student{
    private int grade;
    private String sno;
}

Object类中提供的一些默认方法

3.1 toString()方法
//Object类中的toString()方法实现:
public String toString() {
     return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

toString()方法一般需要通过重写之后进行使用。

3.2 hashcode()方法
  • 返回对象的hash代码值

源码:

public native int hashCode();

【Java】你真的了解抽象类和接口?_抽象类_06

重写hashCode() 方法

class Per{
    public String name;
    public int age;
    public Per(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class TestDemo6 {
    public static void main(String[] args) {
        Per per1 = new Per("gaobo",20);
        Per per2 = new Per("gaobo", 20);
        System.out.println(per1.hashCode());
       /* 
        注意事项:哈希值一样。
        结论:
        1、hashcode方法用来确定对象在内存中存储的位置是否相同
        2、事实上hashCode() 在散列表中才有用,在其它情况下没用。
        在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
        */
        System.out.println(per2.hashCode());
    }
}

【Java】你真的了解抽象类和接口?_Java_07

3.3 equals()方法
  • 比较的是地址
// Object类中的equals方法

public boolean equals(Object obj){

     return (this == obj);
   // 使用引用中的地址直接来进行比较
   
}

【Java】你真的了解抽象类和接口?_后端_08

如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的

重写equals()方法

@Override
 public boolean equals(Object obj) {
     //判断是否为空
        if (obj == null) {
            return false ;
        } if(this == obj) {
            return true ;
        }
        // 不是Person类对象
        if (!(obj instanceof Per)) {
            return false ;
        }
        Per per = (Per) obj ; // 向下转型,比较属性值
        return this.name.equals(per.name) && this.age==per.age ;
    }
    
/*  @Override
    public boolean equals(Object obj) {
        Per per = (Per)obj;
        //String类调用的是自身的equals,
        // s1跟s2两者比较的规则则是按照String类重写后的equals方法来比较,
        //很显然,String类的比较规则是按照值来比较的,因此结果会输出true。
        if(this.name.equals(per.name)&&this.age == per.age){
                return true;
        }
        return false;

    }
}
*/

【Java】你真的了解抽象类和接口?_抽象类_09

编译器自动生成重写的hashcode()和equals()方法

@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Per per = (Per) o;
        return age == per.age &&
                Objects.equals(name, per.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
   }

在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,**如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了.**但是hashcode() 相同时,equals()不一定相同

✅✅重写equals方法时,也必须重写hashcode()方法吗?

答:必须,hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,当重写equals方法后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值”的约定。

✅✅ == 和 equals 的区别是什么?

答:

对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  • 基本类型:比较的是值是否相同;
  • 引用类型:比较的是引用是否相同

String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true

对于equals() 方法,根据源码可以得知 : equals() 的本质上就是true

public boolean equals(Object obj) { return (this == obj); }

所以equals()方法 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

四、常用接口
4.1 Comparable接口(比较)

在学习数组时,Arrays类中的sort方法可以对对象数组进行排序 , 那下面的对象数组能不能用Arrays.sort排序呢?

class Student {  
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override  
    public String toString() { 
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[] { 
              new Student("zhangsan", 13),
              new Student("lisi", 23),
              new Student("able", 17),
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
       }
}

【Java】你真的了解抽象类和接口?_Java_10

此时编译器并不知道到底是按姓名还是年龄进行排序,当sort方法对对象所属的类进行排序时,对象所属的类必须实现Comparable接口,通过参考文档可知,Comparable接口中仅有一个抽象方法。

【Java】你真的了解抽象类和接口?_后端_11

【Java】你真的了解抽象类和接口?_Java_12

那么我们就可以实现Comparable接口,并实现和重写compareTo方法

class Student implements Comparable<Student>{
    public int age;
    public String name;
    
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    //重写compareTo方法
    @Override
    public int compareTo(Student o) {
        if (this.age - o.age > 0)
            return 1;
        else
        if (this.age - o.age < 0)
            return -1;
        else
            return 0;
    }
     public static void main1(String[] args) {
        Student student = new Student(16, "liba");
        Student student1 = new Student(13, "zhangsan");
        System.out.println(student.toString());
        System.out.println(student1.toString());
        if (student.compareTo(student1) > 0) {
            System.out.println("student > student1");
        } else {
            System.out.println("student < student1");
        }
    }

}

此时可以得到按年龄进行排序的结果:

【Java】你真的了解抽象类和接口?_抽象类_13

我们知道在Arrays.sort(students); 中是传了一个学生对象数组,在调用Arrays对对象数组排序的时候,其实就调用了我们的Comparable接口中的compareTo方法对数组的每个元素进行了排序和比较,在Java中对于引用数据类型的比较或者排序,一般都要用到使用Comparable接口中的compareTo() 方法

按姓名排序时,重写的compareTo方法

@Override 
 public int compareTo(Student o) {   // this.代表对当前对象的引用,o.代表对参数对的引用
        if (this.name.compareTo(o.name) > 0)//String类中重写了compareTo方法,可直接使用
             return 1;  
        else if (this.name.compareTo(o.name) < 0) 
             return -1;
        else 
             return 0;
    }
    //如果当前对象应排在参数对象之前, 返回小于 0 的数字;
    //如果当前对象应排在参数对象之后, 返回大于 0 的数字;
    //如果当前对象和参数对象不分先后, 返回 0;

标签:Java,name,age,接口,Student,抽象类,public,String
From: https://blog.51cto.com/u_15866929/6373958

相关文章

  • Javaweb中在SQL语句中使用未知数进行多表查询
    这个问题主要是匹配好引号和单引号即可。如果是varchar型,那么变量要带单引号('),如果是int型就不用带。同时要注意用+号进行String的拼接。示例:publicList<Student>huizong_bujige(Stringkemu1){List<Student>list=newArrayList<>();Connectionconn......
  • Java-Day-25( 字节输入流 + FileInputStream 和 FileOutputStream + FileReader 和 Fi
    Java-Day-25InputStream(字节输入流)InputStream抽象类是所有类字节输入流的超类InputStream常用的子类FileInputStream:文件输入流BufferedInputStream:缓冲字节输入流ObjectInputStream:对象字节输入流FileInputStream和FileOutputStreamFileInputStream(文......
  • IDEA-Maven项目中:java程序包org
    IDEA-Maven项目中:java:程序包org.apache.hadoop.conf.fs等众多Hadoop包不存在的问题问题描述在IDEA中创建Maven项目,乱修改xml文件,导致错误解决办法打开右侧导航栏:Maven输入:mvmidea:idea......
  • Java中多个pdf合并为一个pdf文件工具类
    Java中多个pdf合并为一个pdf文件工具类方案一:引入依赖<dependency><groupId>com.lowagie</groupId><artifactId>itext</artifactId><version>2.1.7</version></dependency>工具类importcom.lowagie.text.Document;impo......
  • java.lang.UnsupportedOperationException
    错误的查询返回格式//dao层Listquery_T_JS_DHGL_XMLGJ(Map<String,String>queryParams);正确的的查询返回格式ArrayList<Map>query_T_JS_DHGL_XMLGJ(Map<String,String>queryParams);知识点:使用asList方法继承的父类的add和remove,只会抛出UnsupportedOper......
  • 为什么我们需要API接口?API接口的核心又是什么?
    ​    API(ApplicationProgrammingInterface)是一种连接不同软件之间的标准化的接口,可以让不同软件间进行数据交互和通信。API接口的作用很多,以下是几个主要的原因:1.提高软件系统的灵活性和可扩展性。API接口可以将不同的模块分离开来,使得系统更加模块化,便于后续的扩展......
  • JavaWeb 解决乱码问题
    自写过滤器解决文件结构代码配置EncondingFilerpackagefilter;importjavax.servlet.*;importjava.io.IOException;publicclassEncondingFilterimplementsFilter{@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{......
  • java基础
    一、java关键字二、数据类型详情参考百度百科:https://baike.baidu.com/item/java关键字/5808816......
  • 十、JUC-Java对象内存布局和对象头
    零、问题Objectobject=newObject()谈谈你对这句话的理解?一般而言JDK8按照默认情况下,new一个对象占多少内存空间?位置所在:JVM里堆→新生区→伊甸园区一、对象的内存布局在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头、实例数据、对齐填充(保证8......
  • Java学习必备截图工具Snipaste下载使用教程
    截图功能已经成了现在学习及工作中的必备需求,分享给大家一款好用而且还免费的截图神器——SnipasteSnipaste功能非常强大,不需要安装,解压即可使用。这篇文章详细介绍一下Snipaste的下载安装及使用。这也是入门学习Java最实用的截图工具,也可直接观看视频讲解,b站上动力节点老杜最......