首页 > 编程语言 >java基础6—抽象类、接口、枚举

java基础6—抽象类、接口、枚举

时间:2024-08-01 21:53:54浏览次数:15  
标签:java name int void age 枚举 抽象类 public String

1.抽象类

1.1 简介

        由于继承这个显著特点,我们可以将子类设计的更加具体,而父类更加一般化,通用化。父类可以封装不同子类的共同特征或者共同行为。而有的时候,父类中封装的方法无法具体完成子类中需要的逻辑,因此我们可以将此方法设计成抽象方法,即使用关键字abstract进行修饰。而有抽象方法的类,也必须使用abstract关键字进行修饰,因此我们称之为抽象类。

1.2 特点

 abstract方法
1.方法不提供花括号{},那就必须使用abstract修饰,必须以分号结尾。
2.有抽象方法的类,必须是抽象类。需要使用abstract修饰类
3.子类需要实现抽象父类里的所有抽象方法除非子类也声明为抽象类
4.抽象类就是用来被继承的,所以不能使用final修饰。(final修饰的类不能被继承)
5.抽象类里面可以没有抽象方法(就如Duck类)
6.抽象类不能实例化,因此不能使用new关键字调用构造器,虽然可以提供构造器。

 1.3 意义

  1. 为其子类提供一个公共的父类型

  2. 封装子类中重复的内容,如成员变量和方法

  3. 定义抽象方法,子类虽然有不同的实现逻辑,但该方法的定义却是一致的。

测试代码(类):

public abstract class Animal {
    private String name;
    private int age;
    private String color;
    public Animal(){}

    public Animal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    //抽象方法
    public abstract void noise();

}
class Dog extends Animal {

    public Dog() {}
    public Dog(String name, int age, String color) {
        super(name, age, color);
    }


    public void noise(){
        System.out.println("汪汪汪汪");
    }

    public void lookHouse(){
        System.out.println("看家");
    }
}

class Cat extends Animal{
    public Cat() {}

    public Cat(String name, int age, String color) {
        super(name, age, color);

    }
    public void noise(){
        System.out.println("喵喵喵喵");
    }

    public void getMouse(){
        System.out.println("抓老鼠。");
    }
}

//如果不想实现抽象类里的抽象方法,该类需要使用abstract修饰。
abstract class Duck extends Animal{
    public Duck(){};
    public Duck(String name, int age, String color) {
        super(name, age, color);
    }

    public void swim(){
        System.out.println("游泳。");
    }
}

测试代码(测试类): 

public class AnimalTest {
    public static void main(String[] args) {
        //直接定义一个Cat类型,调用Cat里的功能
        Cat cat = new Cat();
        cat.noise();
        cat.getMouse();
        //使用多态的向上造型
        Animal a = new Dog();
        a.noise();
//        a.lookHouse();//报错,父类没有该方法。

        //下面代码编译错误,因为抽象类不能使用new关键字实例化。
//        Animal b = new Animal();

    }
}

2.接口 

        有的时候,我们需要从几个不相关的类中派生出一个子类,继承他们的所有成员变量和方法,但是java不支持多继承。此时,我们可以使用接口,来达到多继承的效果

 2.1 概念

概念:
        java没有多继承的语法,而有些时候需要使用这种形式,比如一个类想要(需要)两个类的属性或者方法时,可以使用另一个知识点来达到这个目的,就是接口。接口也可以理解为是一个特殊的抽象类,也可以理解为是一种规范。

2.2 类调用接口的特点

  • 接口的关键字:interface
  • 接口里可以提供成员属性,默认使用public static final 修饰的,即常量。
  • 接口里不能提供构造器,更不能使用new实例化,没有意义。
  • 接口里可以提供成员方法,默认使用public abstract修饰
  • 与类的继承不同,一个类可以实现多个接口。接口间使用逗号分开。
  • 一个类实现接口,需要使用关键字implements调用。
  • 一个类实现接口时,需要实现里面的所有抽象方法否则需要使用abstract修饰class。 

 代码测试:

接口代码:

public interface InterfaceA {
    double PI = 3.14159265358979323846;
    double NIM = 0.618;

//    public InterfaceA() {}//不允许构造

    void showInfo();
    public abstract int sum(int a, int b);
}

类调用接口:

class A implements InterfaceA {
    @Override
    public void showInfo() {}
    public int sum(int a, int b) {
        return a + b;
    }
}

abstract class B implements InterfaceA {
    @Override
    public void showInfo() {

    }
}

 2.3接口调用接口的特点

接口与接口之间:
    1.接口可以继承多个接口,使用extends,多继承使用逗号隔开。
    2.子接口拥有了父接口里的所有抽象方法。
    3.子接口可以提供自己独有的抽象方法
    4.类实现子接口时,要重写里面所有的抽象方法

代码测试:(C,D接口调用InterfeceB,ClassT继承接口D)

public interface InterfaceB {
    void methodB();
}

interface C{
    void methodC();
}
interface D extends C,InterfaceB{

    void methodD();
}

class ClassT implements D{

    @Override
    public void methodD() {

    }

    @Override
    public void methodC() {

    }

    @Override
    public void methodB() {

    }
}

 2.4 接口在1.8之后的新特性(default 、 static)

JDK1.8以后的接口新特性
1.提供了默认方法:使用default 修饰词修饰的具有方法体的方法。
    --1)该方法,默认使用public修饰。
    --2)该方法,逻辑不能满足子类时,子类可以重写。
2.提供了静态方法:使用static修饰的具有方法体的方法。
    --1)该方法,默认使用public修饰

    --2) 该方法不可重写。

测试代码: 

public interface InterfaceM {
     default void print(){
         System.out.println("--欢迎来到中国,我的家--");
     }
     static void print2(){
         System.out.println("--地球只有一个,人人有责---");
     }
}
class classU implements InterfaceM{
    //重写接口里的默认方法
    @Override
    public void print(){
        System.out.println("--欢迎来到长春,我的家--");
    }

    //@Override   添加注解报错,因此print2方法不能重写,此时是自己独有的静态方法。
    static void print2(){
        System.out.println("--地球只有一个,人人有责---");
    }
}

 2.5 常用接口

1)Serializable序列化接口

        系统类库提供好的一个接口。当涉及到数据传输时,比如将内存的对象保存到磁盘,磁盘上的文件变成内存中的对象,或者对象在两台电脑之间传输。那么该对象的类必须实现序列化接口。否则传输失败。

该接口就是一个规范,里面没有任何东西,源码如下:

public interface Serializable {
   
}

 比如Person类的对象想要进行传输:

public class Person implements Serializable {
   //.....person的代码
}

2) Comparable接口

汉语翻译成: 可比的,可比较的,是一个形容词。 当一个类的多个对象之间想要进行比较时,比如排序等操作,那么类必须实现该接口,然后自定义比较规则。否则不能比较,会报如下错误:

Exception in thread "main" 
java.lang.ClassCastException: xxx.类型名 cannot be cast to java.lang.Comparable

源码如下:

public interface Comparable<T> {
   public int compareTo(T o);
}

如何自定义比较规则? 即重写接口里提供好的compareTo方法。 总结下来,比较无非就是升序或者降序。

升序:  就使用this的相关属性-传入的对象o的相关属性
降序:  -(就使用this的相关属性-传入的对象o的相关属性)   拆开括号  :传入的对象o的相关属性-this的相关属性

测试代码(类):

 

package com.oop.day03.eInterface;

public class Person implements Comparable<Person> {
    private String name;
    private int age;
    private int height;
    private int weight;

    public Person(String name, int age, int height) {}
    public Person(String name, int age, int height, int weight) {
     this.name = name;
     this.age = age;
     this.height = height;
     this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                '}';
    }
/*
如果想要进行比较,那么除了要是实现comparable接口,还要实现里面的比较方法compareTo
升序:this的相关属性-传入的o的相关属性
降序:传入的o的相关属性-this的相关属性
 */
    @Override
    public int compareTo(Person o) {
        //按照年龄比较:升序  返回负数,证明this小,返回0,证明相等,返回整数,证明this大
//        return this.age - o.age;
        //按照身高比较,降序:
//        return o.height - this.height;
        int r = this.age - o.age;
        if (r == 0) {
            r = o.height - this.height;
        }
        return r;
//        if(this.age == o.age){
//            return o.height - this.height;
//        }
//        return this.age-o.age;
//
    }
}

测试代码:(测试类)

package com.oop.day03.eInterface;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;

public class PersonTest {
    public static void main(String[] args) {
        Person[] ps =new Person[3];
        ps[0] = new Person("小明",19,166,70);
        ps[1] = new Person("小黑",18,176,65);
        ps[2] = new Person("小张",19,186,64);
        Arrays.sort(ps);
        System.out.println(Arrays.toString(ps));

        //现在想要修改比较规则,按照体重进行升序排序。不能修改源代码,因为Person类可能有人已经使用了,并不是自己一个人在用。
        //此时,就可以使用Comparator比较器进行重新自定义比较规则。
        //使用匿名内部类创建一个比较器对象,
        Comparator c1 = new Comparator<Person>(){
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getWeight()-o2.getWeight();
            }
        };
        //数组工具类sort方法,重载了很多个方法,包含一个sort(Object[] a,Comparator c);
        Arrays.sort(ps,c1);
        System.out.println(Arrays.toString(ps));
    }
}
3) Comparator接口

 汉语翻译成:比较器,比较仪。用于在compareble的基础上去修改比较规则。

 3.枚举

3.1 简介

在Java中,枚举是一种特殊的引用数据类型,是一个被命名的整型常数的集合用于声明一组带标识符的常数,枚举在日常生活中很常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。

背景:枚举是在JDK1.5以后引入的。

主要用途是:将一组常量,也可以说成是一组离散值组织起来。

3.2 枚举的定义 

1)自定义类实现枚举 的规则:
  • 类内部创建一组对象,通常使用public static final关键字共同修饰,对外进行暴露

  • 枚举对象名通常全部都会大写,这是常量的命名规范

  • 可以提供属性,属性应使用private final共同修饰

  • 构造器私有化

  • 属性,可以提供getXXX方法,但是不需要提供setXxx方法,属性应该是只读的。

测试代码:

 

public class Season {
    public static final Season SPRING =new Season("春天","春暖花开");
    public static final Season SUMMER =new Season("夏天","烈日炎炎");
    public static final Season AUTUMN =new Season("秋天","秋高气爽");
    public static final Season WINTER =new Season("冬天","银装素裹");

    private final String desc;
    private final String name;
    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
    public String getName() {
        return name;
    }
    public String toString() {
        return name+","+desc;
    }

}
 2) enum关键字实现枚举

enum关键字实现枚举的规则

  • 使用enum关键字定义一个枚举,默认会继承java.lang.Enum类,而且是一个final类,因此不能再继承其他类

  • 必须在枚举类的第一行声明枚举类对象有多个枚举对象时,使用逗号隔开,最后一个用分号结尾

  • 可以提供私有的属性

  • 可以提供构造器必须是私有的,如果构造器有形参,定义对象时必须显式调用构造器

  • 如果使用无参构造器创建枚举对象,则定义对象时,小括号可以省略

/**
 * 案例1:简单定义一个枚举
 * 注意:
 * 1. 第一行,必须是枚举类的对象.  名称自定义,应该符合常量的命名规则。
 * 2. 内部系统提供了一个无参构造器,因为创建枚举对象时,调用的是无参构造器,因此
 *    对象后面的小括号是可以省略的。
 *    注意:构造器是私有的。
 */
public enum Week {
    //MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
    周一,周二,周三,周四,周五,周六,周日;

    public static void main(String[] args) {
        System.out.println(Week.周五);
    }
}
  • 使用enum关键字后,就不能再继承其它类,因为enum会隐式继承Enum,而Java是单继承机制

  • 枚举类和普通类一样,可以实现接口

/*
方向的枚举
 */
public enum Direction implements interA{
    BEFORE("前"){
        @Override
        public void showInfo() {
            System.out.println("向前进,如箭离弦,永不回头");
        }
    },
    AFTER("后"){
        public void showInfo() {
            System.out.println("向后退");
        }
    },
    LEFT("左"){
        public void showInfo() {
            System.out.println("left");
        }
    },
    RIGHT("right"){
        public void showInfo() {
            System.out.println("right");
        }
    };


    private String name;
    private Direction(String name){
        this.name = name;
    }


    public void showInfo(){
        System.out.println("方向");
    }

    public static void main(String[] args) {
        Direction direction = Direction.BEFORE;
        System.out.println(direction);
        direction.showInfo();

    }

}
interface interA{
    void showInfo();
}

 3.3 enum的常用方法

说明:使用关键字enum时,会隐式继承Enum类,这样我们就可以使用Enum类相关的方法

方法名详细描述
toString得到当前枚举常量的名称。子类可以通过重写这个方法来使结果更易读
name返回当前对象名(常量名),子类中不能重写
ordinal返回当前对象的位置号(编号),默认从0开始
values返回当前枚举类中所有的常量
valueOf将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!
compareTo比较两个枚举常量,比较的就是位置号(编号)
hashCodeEnum实现了hashCode()来和equals()保持一致,它也是不可变的
getDeclaningClass得到枚举常量所属枚举类型的Class对象。可以用它来判断两个枚举常量是否属于同一个枚举类型
clone枚举类型不能被Clone。为了防止子类实现克隆方法Enum实现了一个仅抛出Clone Not Supported Exception异常的不变clone()

4.内部类 

4.1 成员内部类

定义在一个类的内部,与这个类的成员(属性、方法)平级,并且没有用static修饰的类。
1、访问权限可以是任意的权限,类似于一个类中的成员。
2、实例化的过程,需要先实例化外部类对象,再使用外部类对象进行内部类的实例化
3、内部类编译后,也会生成.class字节码文件。格式:外部类$内部类 .class

/*
成员内部类:
1.定义在一个类的里面,与类的其他成员是平级关系。没有static修饰
2.该内部类的访问权限可以是private,默认的,protected,public

 */
public class Outer {
    private String name;
    private int age;
    public Outer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void showInfo(){
        System.out.println(name+","+age);
    }
    //定义一个成员内部类
    class Inner{
        private int age;
        private String name;
        public Inner(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public void showInfo(){
            System.out.println(name+","+age);
            System.out.println(Outer.this.name);
        }
    }

    public static void main(String[] args) {
//        先创建一个外部类对象
        Outer outer = new Outer("妈妈",29);
        //然后通过外部类对象,来实例化一个内部类对象。
        Inner inner =outer.new Inner("儿子",0);
        inner.showInfo();
    }
}

4.2 静态内部类

定义在一个类的内部,与这个类的成员(属性、方法)平级,并且使用static修饰的类。
1、访问权限可以是任意的权限,类似于一个类中的成员。
2、实例化的过程中,直接使用 new实例化一个外部类 .内部类对象即可。
3、内部类编译后,也会生成.class字节码文件。格式:外部类$内部类 .class 

 

/*

1、访问权限可以是任意的权限,类似于一个类中的成员。
2、实例化的过程中,直接使用 new实例化一个外部类.内部类对象即可
3、内部类编译后,也会生成.class字节码文件。格式:外部类$内部类.class

 */
public class Outer {
    private String name;
    public Outer() {

    }
    public Outer(String name) {
        this.name = name;
    }
    public void showInfo(){
        System.out.println(name);
    }
    static class Inner{
        private String name;
        public Inner(String name) {
            this.name = name;
        }

        public void showInfo(){
            System.out.println("Inner showInfo");
            //不能直接访问外部类的成员
//            System.out.println(Outer.this.name);
        }
    }
    public static void main(String[] args) {
        //创建内部类的对象:new 外部类名.内部类构造器。
        Inner inner = new Outer.Inner("Inner showInfo");
    }
}

4.3局部内部类

定义在某一个代码段中的中。
1、没有访问权限修饰符。
2、在当前方法中,直接实例化即可
3、内部类编译后,也会生成.class字节码文件。格式:外部类$序号内部类 .class 

4、 出了作用域就失效了。

代码:

/*
局部内部类:
    再方法中定义的内部类,和局部变量用法一样。出了作用域就失效了。
 */
public class Outer {
    public static void main(String[] args) {
        int a = 10;
        System.out.println(a);

        class Inner {
            private int a;
            public Inner(int a) {
                this.a = a;
            }
            public int getA() {
                return a;
            }
        }

        Inner inner = new Inner(10);
        System.out.println(inner.getA());
    }
}

 4.4匿名内部类(重点)

没有名字的内部类,匿名内部类,通常是需要配合其他的类或者接口一块使用的。

用法:

接口名|抽象类名|父类名 变量=new 接口名|抽象类名|父类名(){
        方法的重写;
    };

代码:

/*
匿名内部类:
    就是没有名字的子类型对象
    
     接口名|抽象类名|父类名 变量=new 接口名|抽象类名|父类名(){
        方法的重写
    };
 */
public class Outer {
    public static void main(String[] args) {
        A a = new A(){
            //匿名内部类提供成员属性
            public String name ="asdasad";
            //重写接口A里的抽象方法
            @Override
            public void showInfo(){
                System.out.println("Hello World");
            }
            //子类提供了独有的getXXX方法
            public String getName(){
                return name;
            }

        };
        //编译期间,看变量类型,因此能调用到showInfo
        a.showInfo();
//        a.getName();//编译期间,a里根本没有getName方法。
    }
}

interface A{
    public void showInfo();
}
//一般A的子类写法
//class B implements A{
//    public void showInfo() {
//        System.out.println("B");
//    }
//}

在匿名内部类中,一般情况下不去添加新的成员(属性、方法),因为即便进行了添加,得到的对象也是向上转型后的对象,不能访问子类中的成员。在匿名内部类中,一般是用来做方法的重写实现的
匿名内部类也会生成 .class字节码文件,命名格式 : 外部类$序号 .class

标签:java,name,int,void,age,枚举,抽象类,public,String
From: https://blog.csdn.net/zhaogodzero/article/details/140832457

相关文章

  • dbnet crnn java中文ocr识别
    TableofContentsAboutGettingStartedResultContactAbout完整项目:https://github.com/jiangnanboy/dbnet_crnn_java本项目利用java,javacv,onnx以及djl矩阵计算等技术加载文本检测模型dbnet与文本识别模型crnn,完成ocr的识别推理。包含模型的完整项目请从右侧relea......
  • java的诞生
    java的诞生C语言C语言(1972诞生)优点:贴近硬件,运行极快,效率极高操作系统,编译器,数据库,网络系统等都使用C语言开发缺点:指针和内存管理C++C++(1982诞生)面向对象兼容C图形领域、游戏等javajava(1995诞生)简单性面向对象可移植性(writeonce,runanywhe)高性能(即时编译)分......
  • 枚举知识点(完结)
    枚举文章目录枚举枚举定义枚举类的实现枚举类的属性枚举类的创建创建代码常用方法枚举定义Java枚举是一个特殊类,一边表示一组常量,比如一年的4个季节,一年的12个月份,一个星期的七天,方向有东南西北等类的对象只有有限个,确定的性别:男,女枚举类的实现JDK1.5之前需要......
  • Java面试题合集(持续更新)
    1、redis缓存穿透,缓存击穿以及缓存雪崩问题和对应的解决方案缓存穿透:当客户端访问一个不存在的数据,这个数据在缓存和数据库中都不能命中,如果有大量的这种穿过缓存直接访问数据库的请求,就会给数据库带来很大压力。解决思路:缓存空对象:当发现数据库中也没有该数据时,我们把这......
  • 全网最强Java面试题 很详细了!!!
    一、缓存面试官:什么是缓存穿透 ?怎么解决?候选人:(穿透无中生有Key,布隆过滤NULL隔离)嗯~~,我想一下缓存穿透是指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,可能导致DB挂掉。这种情况大概率是遭到了攻......
  • Java/SpringCloud/RabbitMq/无感实现消息携带用户信息 --- 逻辑讲解、代码实现、图形
    一、需求:依据黑马商城hmall为例,用户下单创建订单后,交易服务trade-service向交换机topic发送消息,交换机topic路由到队列,购物车服务cart-service监听此队列,实现自动清空购物车。改造下单功能,将基于OpenFeign的清理购物车同步调用,改为基于RabbitMQ的异步通知:定义t......
  • Java基础知识分享(二)相关练习题
    写在前面大家前面的方法和数组学的怎么样了,快来看看这些题你能不能快速地说出答案,数组和方法在Java学习中还是非常重要的,快来检测你的薄弱点在哪,及时查漏补缺!填空题1.数组会在内存中开辟一块连续固定大小的空间,每个空间相当于之前的一个变量,称为数组的元素。数组的长度一经确定......
  • Socket网络编程:Java中的实现与应用
    Socket网络编程:Java中的实现与应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Socket网络编程是实现网络通信的基础,通过它可以在不同的计算机之间传输数据。Java的java.net包提供了强大的网络编程功能,支持各种网络协议。本文将深入探讨Java中Socket编......
  • Java多线程编程详解:从基础到高级
    Java多线程编程详解:从基础到高级大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Java的多线程编程允许程序同时执行多个任务,提高了应用的性能和响应能力。本文将从基础到高级,全面介绍Java中的多线程编程,包括线程的创建、线程池、同步机制及并发工具的使用......
  • Java串口编程:与硬件通信的实现
    Java串口编程:与硬件通信的实现大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!串口编程在与硬件设备通信时扮演着重要角色,尤其是在工业自动化、嵌入式系统和其他硬件设备的控制中。Java虽然在串口编程上并不直接支持,但通过第三方库(如JavaSerialPortAPI......