【迷人的爪哇】——抽象类和接口

目录

 一、抽象类

 1.1 概念语法

1.2 抽象类的特性

二、接口

2.1 概念

2.2 接口的使用

2.3 实现多个接口

2.4 接口之间的继承(功能的拓展)

2.5 自定义类型排序

2.6 Clonable接口和深拷贝

 2.7 抽象类和接口的区别

 三、Object类

3.1 对象比较equals方法

3.2 hashcode方法

 一、抽象类

 1.1 概念语法

  • 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
  • 一个类被abstract修饰,称为抽象类,被abstract修饰的方法叫做抽象方法。

abstract class Shape{

    //抽象方法
    public abstract void draw();
}

1.2 抽象类的特性

  • 在抽象类当中,可以有和普通类一样的方法、成员。最突出的区别就是抽象类不能实例化对象。
    abstract class Shape{
        public int a;
        public static int b;
        public void fun(){
    
        }
    
        //抽象方法
        public abstract void draw();
    }
    
    
  • 抽象类虽然不能实例化,但是可以被继承(抽象类就是要被继承的)。
  • 当一个普通类继承了抽象类,并且这个抽象类当中含有抽象方法,那么就要重写这个抽象方法,否则编译器不能通过编译。
    abstract class Shape{
    
        //抽象方法
        public abstract void draw();
    }
    
    class React extends Shape{
        @Override
        public void draw() {
            
        }
    }
    public class Test1 {
        public static void main(String[] args) {
    
    
        }
    }
    
  • 如果一个抽象类A继承另一个抽象类B,那么此时抽象类A可以不重写B中的抽象方法。
  • 抽象方法不能被private、static、final的关键字修饰的,因为抽象方法是要被继承的。

抽象类的作用 

  • 抽象类的作用就是相当于多了一层编译器的校验,在实际开发中是非常有意义的。

二、接口

2.1 概念

在生活中接口非常常见,例如:电脑上USB接口,所有USB都可以插入这个接口,不管是鼠标、键盘、U盘都可以插入。

在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型

2.2 接口的使用

  • 语法规则:

public interface 接口名称{

           // 抽象方法
           public abstract void method1(); // public abstract 是固定搭配,可以不写

}

  • 接口的使用 (接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。 

public class 类名称 implements 接口名称{
   // ...
}

注:接口名称一般以大写的  I  开头

  •  接口的特性:
public  interface IShape {
    public int a = 1;
    int b = 2;
    final int c = 3;
    default void test(){

    }

    public void fun();
}

class React implements IShape{
    @Override
    public void fun() {
        
    }
}
  1. 接口中的成员变量,默认都是由 public static final 修饰的。
  2. 接口当中的成员方法,默认都是抽象方法,由  public abstract  修饰的
  3. 接口中的普通成员方法,是不能有具体的实现的,如果要有具体的实现,必须加上default 修饰。
  4. 接口当中可以有静态成员方法,,但无论是静态方法还是 default方法,都是由public修饰的。
  5. 接口是不能实例化的
  6. 一个接口可以引用具体实现类的,向上转型。
  7. 接口当中不能有静态代码块、实例代码块、构造方法
  8. 如果一个抽象类实现一个接口,那这个抽象类就可以不重写抽象方法,但是还有其他类继承这个抽象类,那么还是要重写抽象方法的。

2.3 实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接口。

例如:

我们先创建一个动物类:

class Animal{
    public String name;

    public Animal(String name) {
        this.name = name;
    }
}

再创建几个动物行为的接口:

interface fly{
    void fly();
}

interface running{
    void running();
}
interface ISwimming{
    void swim();
}

然后创建具体的动物;

狗是用四条腿跑的:

class Dog extends Animal implements IRunning{
    public Dog(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(name + "正在用四条腿跑!");
    }
}

小鸟是用翅膀飞的:

class Bird extends Animal implements IFly{
    public Bird(String name) {
        super(name);
    }

    @Override
    public void fly() {
        System.out.println(name+"正在用翅膀飞");
    }
}

鱼是用尾巴在水里游的:

class Fish extends Animal implements ISwimming{
    public Fish(String name) {
        super(name);
    }

    @Override
    public void swim() {
        System.out.println(name + "正在水里用尾巴游");
    }
}

而鸭子既可以跑又可以飞还可以游泳:

class Duck extends Animal implements ISwimming,IFly,IRunning{
    public Duck(String name) {
        super(name);
    }

    @Override
    public void fly() {
        System.out.println(name+"正在用翅膀飞");
    }

    @Override
    public void run() {
        System.out.println(name +"正在用鸭掌跑");
    }

    @Override
    public void swim() {
        System.out.println(name+"正在用鸭掌游泳");
    }
}
public class Test2 {
    public static void fly(IFly iFly){
        iFly.fly();
    }
    public static void swim(ISwimming iSwimming){
        iSwimming.swim();
    }
    public static void run(IRunning iRunning){
        iRunning.run();
    }
    public static void main(String[] args) {
        fly(new Duck("唐老鸭"));
        run(new Duck("唐老鸭"));
        swim(new Duck("唐老鸭"));
    }
}

注:

  1.  一个类实现多个接口时,每个接口的抽象方法都要重写,除非是抽象类可以不用重写。
  2. 接口表达的含义是具有xxx特性。

2.4 接口之间的继承(功能的拓展)

接口和接口之间可以达到多继承:

interface IFly{
    void fly();
}

interface IRunning{
    void run();
}
interface ISwimming{
    void swim();
}
interface IAnimal extends IRunning,IFly,ISwimming{
    
}

2.5 自定义类型排序

Comparable接口可以用来排序我们自定义类型的排序:

class Student implements Comparable<Student>{

    public String name;
    public int age;
    public double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }

}

public class Test {
    public static void main(String[] args) {
        Student student = new Student("小明",10,100);
        Student student1 = new Student("小红",13,99);
        if (student.compareTo(student1) > 0){
            System.out.println("student > student1");
        }else if(student.compareTo(student1) == 0){
            System.out.println("student = student1");
        }else{
            System.out.println("student < student2");
        }
    }
}

注:

自定义数据牵扯到比较大小,需要指明比较大小的数据类型,在我们重写的compareTo方法中实现的。

上面这种情况我们就只能比较年龄,如果还想比较其他数据的话就必须进行修改,其实我们实现一个比较器:

年龄比较器:

class AgeComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}
public class Test {

    public static void main(String[] args) {
        Student student = new Student("小明",10,100);
        Student student1 = new Student("小红",13,99);
        AgeComparator ageComparator = new AgeComparator();
        int ret = ageComparator.compare(student,student1);

        if (ret > 0){
            System.out.println("student > student1");
        }else if(ret == 0){
            System.out.println("student = student1");
        }else{
            System.out.println("student < student2");
        }
}

分数比较器:

class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int) (o1.score - o2.score);
    }
}

对于自定义类型排序我们还可以使用Array.sort排序:

class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int) (o2.score - o1.score);
    }
}

public class Test {

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("小明",10,100);
        students[1] = new Student("小红",12,50);
        students[2] = new Student("小花",13,76);

        ScoreComparator scoreComparator = new ScoreComparator();

        Arrays.sort(students,scoreComparator);
        System.out.println(Arrays.toString(students));
    }
}

2.6 Clonable接口和深拷贝

Clonable接口克隆一个对象就是产生这个对象的副本:

class Person implements Cloneable{
    public int age = 10;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person = new Person();
        Person person1 = (Person) person.clone();
        System.out.println(person1);
    }
}


 当我们修改这个副本的值时,主体不会受到影响:

 其内存布局如下:


但是当我们再定义一个钱类,在人类里面对它实例化后,并且将克隆副本的钱的值修改,再打印就会发现主体和副本钱的值都修改:

class Money{
    public int money = 20;
}

class Person implements Cloneable{
    public int age = 10;
    public Money m = new Money();
}

 它的内存分布如下:

 这个就是浅拷贝,只是拷贝了Money的地址,并没有创建一个新的副本。我们可以给Money也实现一个接口,从而实现深拷贝:

 2.7 抽象类和接口的区别

  1. 抽象类是被abstract修饰,其方法为抽象方法且不用具体实现,与普通类最大的区别就是不能实例化;接口也不能实例化,其成员方法默认为抽象方法。
  2. 抽象类被继承后要重写抽象方法(extends),接口被实现后也要重写抽象方法(interface);
  3. 一个子类只能继承一个抽象类,一个子类可以实现多个接口;
  4. 一个抽象类可以实现多个接口,接口不能继承抽象类,但是接口可以使用extends关键字继承多个接口。
  5. 子类继承抽象类,重写抽象方法时其限定修饰符权限必须大于抽象方法的修饰符;而接口就是public;

 三、Object类

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

class Person{
 
}
class Student{

}
public class Test {
    public static void main(String[] args) {
        Object o = new Person();
        Object o1 = new Student();

    }
}

也可以方法传参接收:

class Person{
   public String name = "hello";

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student{

}
public class Test {
    public static void func(Object o){
        String str = o.toString();
        System.out.println(str);
    }

    public static void main(String[] args) {
        func(new Student());
        func(new Person());
    }
    public static void main1(String[] args) {
        Object o = new Person();
        Object o1 = new Student();

    }
}

3.1 对象比较equals方法

class Person{
    public int age;

    public Person(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age;
    }

}
public class Test {

    public static void main(String[] args) {
        Person person = new Person(10);
        Person person1 = new Person(10);
        System.out.println(person.equals(person1));
    }

注:比较对象中内容是否相同的时候,一定要重写equals方法。

3.2 hashcode方法

hashcode()这个方法帮我们算出一个具体对象的地址,也可以称为内存地址,然后将其打印出来。

class Person{
    public int age;

    public Person(int age) {
        this.age = age;
    }
    @Override
    public int hashCode() {
        return Objects.hash(age);
    }
}

public class Test {

    public static void main(String[] args) {
        Person person = new Person(10);
        Person person1 = new Person(10);
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
    }

  • 我们可以重写hashcode()方法,来实现对相同年龄位置定位相同的位置,所以运行结果是相同的数值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中整合STOMP,需要使用Spring Websocket模块。Spring Websocket提供了在Web应用程序中使用WebSocket的支持,并且它还包括对STOMP的支持。STOMP是一种简单的文本协议,用于在客户端和服务器之间进行实时通信。 在Spring Boot中使用STOMP需要进行以下步骤: 1. 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建一个WebSocket配置,用于配置WebSocket和STOMP的相关信息。 ``` @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket").withSockJS(); } } ``` 在上面的代码中,我们使用@EnableWebSocketMessageBroker注解来启用WebSocket和STOMP消息代理。configureMessageBroker()方法用于配置消息代理,其中我们使用@EnableSimpleBroker注解来启用简单的消息代理,将消息发送到以“/topic”开头的目的地。setApplicationDestinationPrefixes()方法用于设置应用程序的目的地前缀,这里我们将应用程序的目的地前缀设置为“/app”。registerStompEndpoints()方法用于注册STOMP端点,这里我们将STOMP端点设置为“/websocket”,并启用SockJS支持。 3. 创建一个STOMP监听,用于监听STOMP消息。 ``` @Component public class StompListener { @MessageMapping("/hello") @SendTo("/topic/greetings") public String greet(String name) { return "Hello, " + name + "!"; } } ``` 在上面的代码中,我们使用@MessageMapping注解来指定处理STOMP消息的目的地。在这个例子中,我们使用“/hello”作为目的地。@SendTo注解用于指定将处理结果发送到的目的地,这里我们将处理结果发送到以“/topic/greetings”开头的目的地。 以上就是Spring Boot整合STOMP的基本步骤。当客户端发送一个STOMP消息到“/app/hello”目的地时,StompListener中的greet()方法将会被调用,然后将处理结果发送到“/topic/greetings”目的地,客户端就可以接收到这个消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值