JavaSE->抽象类和接口

目录

一、抽象类

1.概念

2.抽象类语法

3.抽象类的特性

二、接口

1.概念

2.语法规则

3.接口的使用

4.接口特性

5.实现多个接口

6.接口间的继承

7.接口的使用实例

8.Clonable接口深度拷贝

8.1Clonable

8.2深度拷贝

9.抽象类和接口的区别

三、Object类

1.获取对象的信息

2.对象的比较

3.hashcode方法 

四、内部类

1.内部类

1.1实例内部类

1.2静态内部类

2.局部内部类

3.匿名内部类


一、抽象类

1.概念

如果一个类没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

2.抽象类语法

一个类被abstract修饰称为抽象类,抽象方法不用给出具体的实现

public abstract class Shape {
    //抽象方法:被abstract修饰的方法,没有方法体
    abstract public void methodA();
    abstract void methodB();

    //抽象类也是类,也可以有普通方法和属性
    public double area;
    public Shape(double area) {
        this.area = area;
    }
    public double getArea() {
        return area;
    }
}

抽象类也是类,内部可以包含普通方法和属性,甚至构造方法 

3.抽象类的特性

抽象类不能直接实例化对象,只能创建抽象类的子类,然后重写抽象类中的抽象方法

抽象方法不能是private的

抽象方法不能被final和static修饰,因此抽象方法要被子类重写

抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用abstract修饰

抽象类不一定包含抽象方法,但是有抽象方法的类一定是抽象类

抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

二、接口

1.概念

多个类的公共规范,是一种引用数据类型

2.语法规则

与类差不多,将class关键字换成interface关键字,就定义了一个接口

public interface USB {
    //抽象方法
    public abstract void method1(); // public abstract是固定搭配,可以不写
    public void method2();
    abstract void method3();
    void method4();
}

3.接口的使用

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

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

子类和父类之间是extends继承关系,类与接口之间是implements实现关系

简单的实现一个电脑系统:

public interface USB {
    void openDevice();
    void closeDevice();
}

public class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标~~");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标~~");
    }

    public void click() {
        System.out.println("鼠标点击~~");
    }
}

public class KeyBoard implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开键盘~~");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭键盘~~");
    }

    public void inPut() {
        System.out.println("键盘输入~~");
    }
}

public class Computer {
    public void powerOn() {
        System.out.println("打开笔记本电脑~~");
    }
    public void powerOff() {
        System.out.println("关闭笔记本电脑~~");
    }
    public void useDevice(USB usb) {
        usb.openDevice();
        if(usb instanceof Mouse) {
            Mouse mouse = (Mouse) usb;
            mouse.click();
        }
        if(usb instanceof KeyBoard) {
            KeyBoard keyBoard = (KeyBoard) usb;
            keyBoard.inPut();
        }
        usb.closeDevice();
    }
}

public class Text {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.powerOn();
        computer.useDevice(new Mouse());
        computer.useDevice(new KeyBoard());
        computer.powerOff();
    }
}
//打开笔记本电脑~~
//打开鼠标~~
//鼠标点击~~
//关闭鼠标~~
//打开键盘~~
//键盘输入~~
//关闭键盘~~
//关闭笔记本电脑~~

4.接口特性

接口是一种引用类型,但是不能直接new接口对象

接口中的每一种方法都是public的抽象方法,即接口中的方法都会被隐式的指定为public abstract

接口中的方法是不能在接口中实现的,只能由实现接口的类来实现

重写接口时,不能用默认的访问权限(默认是public)

接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final变量

接口中不能有静态代码块和构造方法

接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

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

5.实现多个接口

Java中不支持多继承,但一个类可以实现多个接口

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

ctrl + i:快速实现接口

Java面对对象最常见的用法 : 一个类继承一个父类,同时实现多种接口

继承表达 : is-a

接口表达 : 具有xxx特性

猫是一种动物,具有会跑的特性

public class Animal {
    protected String name;

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

public class Cat extends Animal
        implements IRunning {
    public Cat(String name) {
        super(name);
    }
    @Override
    public void run() {
        System.out.println(this.name + "正在跑步~~~");
    }

}

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

    @Override
    public void run() {
        System.out.println(this.name + "正在跳~~~");
    }

    @Override
    public void swim() {
        System.out.println(this.name + "正在蛙游~~~");
    }
}

public interface ISwimming {
    void swim();
}

interface IRunning {
    void run();
}

public class Robot implements IRunning {
    private String name;

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

    @Override
    public void run() {
        System.out.println(this.name + "正在跑步~~~");
    }
}

public class Text {
    public static void walk(IRunning running) {
        running.run();
    }
    public static void swim(ISwimming swimming) {
        swimming.swim();
    }
    public static void main(String[] args) {
        Cat cat = new Cat("小猫");
        walk(cat);
        Frog frog = new Frog("小青蛙");
        swim(frog);
        Robot robot = new Robot("机器人");
        //机器人不是动物,一样可以跑步
        walk(robot);
    }
}
//小猫正在跑步~~~
//小青蛙正在蛙游~~~
//机器人正在跑步~~~

在walk方法下,不用关注到底是那种动物,只要参数(甚至不用是动物)会跑的就行

6.接口间的继承

接口可以继承一个接口,达到复用的效果,使用extends关键字。

接口之间可以多继承 

interface IRunning {
    void run();
}

interface ISwimming {
    void swim();
}

//两栖动物,既能跑又能游泳
interface IAmphiibious extends IRunning,ISwimming {
     //
}

7.接口的使用实例

给对象数组排序

public class Student implements Comparable{
    private String name;
    private double score;

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

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

    @Override
    public int compareTo(Object o) {
            Student student = (Student) o;
            if(this.score > student.score) {
                return 1;
            }else if(this.score <student.score) {
                return -1;
            }else {
                return 0;
        }
    }
}

import java.util.Arrays;

public class Text {
    public static void main(String[] args) {
        Student[] students = {
                new Student("小明",95.4),
                new Student("小红",86.4),
                new Student("小亮",76.4)
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}
//[Student{name='小亮', score=76.4}, Student{name='小红', score=86.4}, Student{name='小
//明', score=95.4}]

让Student类实现Comparable,并实现compareTo方法

在sort方法中会自动调用compareTo方法

如果当前对象应排在参数对象之前,返回小于零的数字

如果当前对象应排在参数对象之后,返回大于零的数字

如果当前对象与参数对象不分前后,返回零

对于sort方法来说,需要传入的数组的每个对象都是可比较的,需具备compareTo这样的能力,通常通过重写compareTo方法的方式,就可以定义比较规则。

8.Clonable接口深度拷贝

8.1Clonable

Object类存在一个clone方法,调用这个方法可以创建一个对象的拷贝,但想要合法调用clone方法,必须要先实现Clonable接口,否则就会抛出CloneNotSupportedException异常Clonable是浅拷贝

public class Animal implements Cloneable {//证明当前类是可以被克隆的
    private String name;

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

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

//    @Override
//    public String toString() {
//        return "Animal{" +
//                "name='" + name + '\'' +
//                '}';
//    }
}

public class Text {
    public static void main(String[] args) throws CloneNotSupportedException {
        Animal animal1 = new Animal("小猫");
        Animal animal2 = (Animal) animal1.clone();
        System.out.println(animal1);
        System.out.println(animal2);
    }
}
//dome2.Animal@2f4d3709
//dome2.Animal@4e50df2e
public class Money {
    public double m = 9.9;
    public Money() {
    }

    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }
}
public class Animal implements Cloneable {
    public String name;
    public Money money;
    public Animal(String name) {
        this.name = name;
        this.money = new Money();
    }

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

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
public class Text {
    public static void main(String[] args) throws CloneNotSupportedException {
        Animal animal1 = new Animal("小猫");
        Animal animal2 = (Animal) animal1.clone();
        //修改前
        System.out.println(animal1);
        System.out.println(animal2);
        animal1.money.m = 10.0;
        animal1.name = "小华";
        System.out.println("*****************");
        //修改后
        System.out.println(animal1);
        System.out.println(animal2);
    }
}
//Animal{name='小猫', money=Money{m=9.9}}
//Animal{name='小猫', money=Money{m=9.9}}
//*****************
//Animal{name='小华', money=Money{m=10.0}}
//Animal{name='小猫', money=Money{m=10.0}}

8.2深度拷贝
public class Money implements Cloneable {
    public double m = 9.9;

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

    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }
}
public class Animal implements Cloneable {
    public String name;
    public Money money;
    public Animal(String name) {
        this.name = name;
        this.money = new Money();
    }

    @Override
    protected Object clone()
            throws CloneNotSupportedException {
        //return super.clone();
        Animal tmp = (Animal) super.clone();
        tmp.money = (Money)this.money.clone();
        return tmp;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

9.抽象类和接口的区别

区别抽象类(abstract)接口(interface)
1结构组成普通类+抽象方法抽象方法+全局变量
2权限各种权限public
3子类使用使用extends关键字继承抽象类使用implements关键字实现接口
4关系一个抽象类可以实现若干接口接口不能继承抽象类,但是接口可以使用extends关键字继承多个接口
5子类限制一个子类只能继承一个抽象类一个子类可以实现多个接口

三、Object类

Java里面除了Object类,所有的类的是存在继承关系的,默认会继承Object父类

1.获取对象的信息

Object中的toString方法

2.对象的比较

Object中的equals方法

    public boolean equals(Object obj) {
        return (this == obj);//比较地址
    }

 重写equals方法,然后比较

public class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(this == obj) {
            return true;
        }
        if(!(obj instanceof Person)) {
            return false;
        }
        Person person = (Person) obj;//向下转型,比较属性值
        return this.name.equals(person.name) && this.age == person.age;
    }
}

public class Text {
    public static void main(String[] args) {
        Person person1 = new Person("小红",25);
        Person person2 = new Person("小化",25);
        System.out.println(person1.equals(person2));
    }
}
//false

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

3.hashcode方法 

用来确定对象在内存中存储的位置是否相同

没重写前:

public class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(this == obj) {
            return true;
        }
        if(!(obj instanceof Person)) {
            return false;
        }
        Person person = (Person) obj;//向下转型,比较属性值
        return this.name.equals(person.name) && this.age == person.age;
    }
}
public class Text {
    public static void main(String[] args) {
        Person person3 = new Person("小红",25);
        Person person4 = new Person("小红",25);
        System.out.println(person3.hashCode());
        System.out.println(person4.hashCode());
    }
}
//793589513
//1313922862

重写后:

public class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(this == obj) {
            return true;
        }
        if(!(obj instanceof Person)) {
            return false;
        }
        Person person = (Person) obj;//向下转型,比较属性值
        return this.name.equals(person.name) && this.age == person.age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name,age);
    }
}
public class Text {
    public static void main(String[] args) {
stem.out.println(person1.equals(person2));
        Person person3 = new Person("小红",25);
        Person person4 = new Person("小红",25);
        System.out.println(person3.hashCode());
        System.out.println(person4.hashCode());
    }
}
//23653831
//23653831

在散列表中hashcode()的作用值获取对象的散列码,进而确定该对象在散列表中的位置 

四、内部类

可以将一个类定义在另一个类的内部或者一个方法的内部,前一个类称为内部类,后一个类称为外部类。

内部类和外部类共用同一个java源文件,但经过编译之后,内部类会形成单独的字节码文件。

1.内部类

在外部类中,内部类定义的位置与外部类成员的位置相同

1.1实例内部类

未被static修饰的成员内部类

public class Outclass {
    private int a;
    static int b;
    int c = 30;
    public void methodA() {
        a = 10;
        System.out.println("a = " + a);
    }
    public static void methodB() {
        System.out.println("b = " + b);
    }

//实例内部类
    class innerClass {
        int c;
        public void methodInner() {
            //在实例内部类中可以直接访问外部类中:任意访问限定修饰符的成员
            a = 100;
            b = 200;
            methodA();
            methodB();
            //如果外部类和实例内部类有相同名称成员,优先访问内部类自己的
            c = 300;
            System.out.println("c = " + c);
            //若要访问外部类的同名成员时,必须:外部类名称.this.同名成员名名字
            System.out.println("c = " + Outclass.this.c);
        }
    }

    public static void main(String[] args) {
        //外部类:对象的创建以及成员访问
        Outclass outClass = new Outclass();
        System.out.println(outClass.a);
        System.out.println(outClass.b);
        System.out.println(outClass.c);
        outClass.methodA();;
        outClass.methodB();;
        System.out.println("*************实例内部类访问*************");
        //创建内部类对象
        Outclass.innerClass innerClass1 = outClass.new innerClass();
        innerClass1.methodInner();
        System.out.println();
        Outclass.innerClass innerclass2 = new Outclass().new innerClass();
        innerclass2.methodInner();
    }
}
//0
//0
//30
//a = 10
//b = 0
//*************实例内部类访问*************
//a = 10
//b = 200
//c = 300
//c = 30

//a = 10
//b = 200
//c = 300
//c = 30

 注意事项:

外部类中的任何成员都可以在实例内部类方法中直接访问

实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束

 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问

 实例内部类对象必须在先有外部类对象前提下才能创建

 实例内部类的非静态方法中包含了一个指向外部类对象的引用

 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象

1.2静态内部类

被static修饰的内部成员类

public class OutClass {
    private int a = 1;
    static int b = 2;

    static class InnerClass {
        //要想访问外部类属性,要先创建外部类对象
        OutClass out = new OutClass();
        public int c = 3;
        public void test() {
            System.out.println(out.a);
            System.out.println(b);
            System.out.println(c);
        }
    }
}
public class Text {
    public static void main(String[] args) {
        //创建内部类对象
        OutClass.InnerClass inner = new OutClass.InnerClass();
        inner.test();
    }
}
//1
//2
//3

2.局部内部类

定义在外部类的方法体或者{}中

public class Text {
    public void test() {
        class Inner {
            public int a = 1;
            public int b = 2;
            
            //~~~~
        }
        //只能在当前方法中使用
        Inner inner = new Inner();
        System.out.println(inner.a);
    }

    public static void main(String[] args) {
        //~~~~
    }
}

局部内部类只能在所定义的方法体内部使用

 不能被public、static等修饰符修饰

 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

3.匿名内部类

public interface IA {
    void testA();
}
public class Student {
    public void test() {
        System.out.println("Student::test()");
    }
}
public class Text {
    public static void func2() {
        //匿名内部类,相当于实现接口
        new IA() {
            @Override
            public void testA() {
                System.out.println("testA()~~~");
            }
        }.testA();
    }
    public static void func1() {
        //匿名内部类,相当于继承Student
        new Student() {
            @Override
            public void test() {
                System.out.println("重写test()方法~~~");
            }
        }.test();//调用test()
    }

    public static void main(String[] args) {
        func1();
        func2();
    }
}
//重写test()方法~~~
//testA()~~~
//匿名内部类
Student stu = new Student() {
  //~~~
   public void test() {
      //~~~
   } 
};
stu.test();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值