Java抽象类和接口

发布时间:2026/5/28 8:58:22

Java抽象类和接口 1抽象类所谓抽象就是不是特指某个对象是个很宽泛的概念。如果一个类中没有包含足够的信息来描绘一个具体的对象这样的类就是抽象类。1.1 抽象类语法在 Java 中一个类如果被 abstract 修饰称为抽象类抽象类中被 abstract 修饰的方法称为抽象方法。抽象方法不能给具体的实现体如果有抽象方法的类一定是抽象类但抽象类里面不一定有抽象方法。// 抽象类被abstract修饰的类 public abstract class Shape { // 抽象⽅法被abstract修饰的⽅法没有⽅法体 abstract public void draw(); abstract void calcArea(); // 抽象类也是类也可以增加普通⽅法和属性 public double getArea(){ return area; } protected double area;// ⾯积 }抽象类也是类内部可以包含普通方法和属性甚至构造方法1.2 抽象类的特性抽象类无法实例化抽象类可以帮助构建对象。抽象方法不能被 private,final,static修饰因为抽象方法要被子类重写abstract class Shape { abstract private void draw(); } public abstract class Shape { abstract final void methodA(); abstract public static void methodB(); } // 编译出错抽象类必须被继承并且继承后子类要重写父类的抽象方法子类也是抽象类就不用重写但是后续有非抽象类继承需要把所有的抽象方法都重写。package demo1; public abstract class Animal { abstract void birth(); } package demo1; //哺乳类 public abstract class Mammals extends Animal { abstract void viviparity();//胎生 } package demo1; public class Dog extends Mammals{ //重写两个抽象方法 Override void viviparity() { System.out.println(胎生); } Override void birth() { System.out.println(出生); } }抽象类中可以有构造方法供子类创建对象时初始化父类的成员变量就和继承的子类创建必须先构造父类一样1.3 抽象类的作用抽象类不能实例化只能继承给其他类帮助其他类创建对象如果实例化了抽象类就会报错。2接口2.1 接口接口就是公共的行为规范标准大家在实现时只要符合规范标准就可以通用。在Java中接口可以看成是多个类的公共规范是一种引用数据类型2.2 语法规则接口的定义格式与定义类的格式相同将class关键字换成 interface 关键字就定义了一个接口public interface 接⼝名称{ // 抽象⽅法 public abstract void method1(); // public abstract 是固定搭配可以不写 public void method2(); abstract void method3(); void method4(); // 注意在接⼝中上述写法都是抽象⽅法跟推荐⽅式4代码更简洁 }创建接口时接口的命名一般以大写字母 i 开头接口的命名一般使用“形容词”词性的单词阿里编码规范中约定接口中的方法和属性不要加任何修饰符号接口当中的成员变量默认是public static final2.3 接口的使用接口不能直接使用必须要有一个“实现类”来“实现”该接口实现接口中的所有抽象方法。类比抽象类public class 类名称 implements 接⼝名称{ // ... }类和类是继承 extends 的关系类和接口是 implements 实现的关系实现笔记本电脑使⽤ USB ⿏标、 USB 键盘的例子1. USB 接⼝包含打开设备、关闭设备功能2. 笔记本类包含开机功能、关机功能、使⽤ USB 设备功能3. ⿏标类实现 USB 接⼝并具备点击功能4. 键盘类实现 USB 接⼝并具备输⼊功能// USB接⼝ public interface USB { void openDevice(); void closeDevice(); } // ⿏标类实现USB接⼝ 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(⿏标点击); } } // 键盘类实现USB接⼝ 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(键盘输⼊); } } // 笔记本类使⽤USB设备 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(); }else if(usb instanceof KeyBoard){ KeyBoard keyBoard (KeyBoard)usb; keyBoard.inPut(); } usb.closeDevice(); } } // 测试类 public class TestUSB { public static void main(String[] args) { Computer computer new Computer(); computer.powerOn(); // 使⽤⿏标设备 computer.useDevice(new Mouse()); // 使⽤键盘设备 computer.useDevice(new KeyBoard()); computer.powerOff(); } }2.4 接口特性1.接口是一种引用类型但是不能直接new接口的对象public class TestUSB { public static void main(String[] args) { USB usb new USB(); } } // Error:(10, 19) java: day20210915.USB //是抽象的; ⽆法实例化2.接口中每一个方法都是public的抽象方法隐式类型为 public abstract (只能是 public abstract,其他修饰符都会报错public interface USB { // Error:(4, 18) java: 此处不允许使⽤修饰符private private void openDevice(); void closeDevice(); }3.接口中的方法不能有主体因为是抽象方法jdk8中接⼝中还可以包含default⽅法public interface IUSB { default void closeDevice(){ System.out.println(关闭USB设备); } }4.重写接口中方法时不能使用默认的访问权限要带publicpublic interface USB { void openDevice(); // 默认是public的 void closeDevice(); // 默认是public的 } public class Mouse implements USB { Override void openDevice() { System.out.println(打开⿏标); } // ... } // 编译报错重写USB中openDevice⽅法时不能使⽤默认修饰符 // 正在尝试分配更低的访问权限; 以前为public5.接口中的成员变量默认是 public static final 修饰public interface USB { double brand 3.0; // 默认被final public static修饰 void openDevice(); void closeDevice(); } public class TestUSB { public static void main(String[] args) { System.out.println(USB.brand); // 可以直接通过接⼝名访问说明是静态的 // 编译报错Error:(12, 12) java: ⽆法为最终变量brand分配值 USB.brand 2.0; // 说明brand具有final属性 } }6.接口中不能有静态代码块和构造方法public interface USB { // 编译失败 public USB(){ } {} // 编译失败 void openDevice(); void closeDevice(); }7.接口虽然不是类但是接口编译完成后字节码文件的后缀格式也是 .class8.如果类没有实现接口中的所有的抽象方法则类必须设置为抽象类2.5 实现多接口我们都知道 Java没有多继承但是可以用接口实现多继承的效果interface IRunning { void run(); } interface ISwimming { void swim(); } 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 正在蹬腿游泳); } }实现多个接口时每个接口的抽象方法都要实现IDEA使用 ctrl i 快速实现接口2.6 接口与接口的继承interface IRunning { void run(); } interface ISwimming { void swim(); } // 两栖的动物, 既能跑, 也能游 interface IAmphibious extends IRunning, ISwimming { } class Frog implements IAmphibious { ... }接口间的继承相当于把多个接口合并在一起2.7 接口使用例子对象之间进行大小关系比较使用 Comparable 接口让我们的Student类实现Comparable接口,并实现其中的compareTo⽅法class Student implements Comparable { private String name; private int score; public Student(String name, int score) { this.name name; this.score score; } Override public String toString() { return [ this.name : this.score ]; } Override public int compareTo(Object o) { Student s (Student)o; if (this.score s.score) { return -1; } else if (this.score s.score) { return 1; } else { return 0; } } }public class Test { public static void main(String[] args) { Student s1 new Student(zhangsan,10); Student s2 new Student(lisi,20); System.out.println(s1.compareTo(s2) ); } }如果s1⼤于s2那么返回⼤于0的数字如果相同返回0否则返回小于0的数字这种方法写了之后就很难改变了。使用Comparator接口class Student { public String name; public int score; public Student(String name, int score) { this.name name; this.score score; } Override public String toString() { return [ this.name : this.score ]; } } class ScoreComparator implements ComparatorStudent { Override public int compare(Student o1, Student o2) { return o1.score-o2.score; } } class NameComparator implements ComparatorStudent { Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } }public class Test { public static void main(String[] args) { Student s1 new Student(zhangsan,10); Student s2 new Student(lisi,20); //根据分数进⾏⽐较 ScoreComparator scoreComparator new ScoreComparator(); System.out.println(scoreComparator.compare(s1, s2)); //根据姓名进⾏⽐较 NameComparator nameComparator new NameComparator(); System.out.println(nameComparator.compare(s1, s2)); } }2.8 Clonable 接口和深拷贝Object类中存在⼀个clone⽅法,调⽤这个⽅法可以创建⼀个对象的拷⻉.但是要想合法调⽤clone ⽅法,必须要先实现Clonable接⼝,否则就会抛出CloneNotSupportedException异常class Animal implements Cloneable { private String name; Override public Animal clone() { Animal o null; //异常捕获的知识 try { o (Animal)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } } public class Test { public static void main(String[] args) { Animal animal new Animal(); Animal animal2 animal.clone(); System.out.println(animal animal2); } } // 输出结果 // false浅拷贝class Money { public double m 99.99; } class Person implements Cloneable{ public Money money new Money(); Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class TestDemo3 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 new Person(); Person person2 (Person) person1.clone(); System.out.println(通过person2修改前的结果); System.out.println(person1.money.m); System.out.println(person2.money.m); person2.money.m 13.6; System.out.println(通过person2修改后的结果); System.out.println(person1.money.m); System.out.println(person2.money.m); } } // 执⾏结果 通过person2修改前的结果 99.99 99.99 通过person2修改后的结果 13.6 13.6深拷贝class Money implements Cloneable{ public double m 99.99; Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ public Money money new Money(); Override protected Object clone() throws CloneNotSupportedException { Person tmp (Person) super.clone(); tmp.money (Money) this.money.clone(); return tmp; } } public class TestDemo3 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 new Person(); Person person2 (Person) person1.clone(); System.out.println(通过person2修改前的结果); System.out.println(person1.money.m); System.out.println(person2.money.m); person2.money.m 13.6; System.out.println(通过person2修改后的结果); System.out.println(person1.money.m); System.out.println(person2.money.m); } }2.9 抽象类和接口的区别相同点都不能实例化不同点结构组成抽象类普通类抽象方法。接口抽象方法全局常量权限抽象类各种权限。接口public子类使用抽象类extends继承。接口implements实现关系抽象类可以实现多个接口。接口可以继承多个父类接口子类限制抽象类只能继承一个子类。接口可以继承多个接口3.内部类将一个类定义在另一个类或者方法的内部叫做内部类public class OutClass { class InnerClass{ } } // OutClass是外部类 // InnerClass是内部类内部类和外部类共用一个Java源文件但是经过编译之后内部类会形成单独的字节码文件3.1 内部类的分类静态内部类实例内部类局部内部类匿名内部类静态内部类被 static 修饰的内部成员类称为静态内部类public class OutClass { public int a; public static int b; // 静态内部类被static修饰的成员内部类 static class InnerClass{ public void methodInner(){ // 在内部类中只能访问外部类的静态成员 // a 100; // 编译失败因为a不是类成员变量 b 200; } } public static void main(String[] args) { // 静态内部类对象创建 成员访问 OutClass.InnerClass innerClass new OutClass.InnerClass(); innerClass.methodInner(); } }在静态内部类中只能访问外部类中的静态成员创建静态内部对象时不需要先创建外部类对象实例内部类未被 strtic 修饰的成员内部类public class OutClass { public int a; public static int b; public int c; // 实例内部类未被static修饰 class InnerClass{ int c; public void methodInner(){ // 在实例内部类中可以直接访问外部类中任意访问限定符修饰的成员 a 100; b 200; // 如果外部类和实例内部类中具有相同名称成员时优先访问的是内部类⾃⼰的 c 300; System.out.println(c); // 如果要访问外部类同名成员时候必须外部类名称.this.同名成员名字 OutClass.this.c 400; System.out.println(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); System.out.println(实例内部类的访问); // 要访问实例内部类中成员必须要创建实例内部类的对象 // ⽽普通内部类定义与外部类成员定义位置相同 //因此创建实例内部类对象时必须借助外部类 // 创建实例内部类对象 OutClass.InnerClass innerClass1 new OutClass().new InnerClass(); // 上述语法⽐较怪异也可以先将外部类对象先创建出来然后再创建实例内部类对象 OutClass.InnerClass innerClass2 outClass.new InnerClass(); innerClass2.methodInner(); } }外部类中的任何成员都可以在实例内部类方法中直接访问实例内部类所处的位置与外部类成员位置相同因此也受publicprivate等访问限定符的约束在实例内部类方法中访问同名的成员时优先访问自己的如果要访问外部类同名的成员必须使用外部类名称.this.同名成员 来访问实例内部类对象必须在先有外部对象的前提下才能创建实例内部类的非静态方法中包含了一个指向外部类对象的引用外部类中不能直接访问实例内部类中的成员如果要访问必须先要创建内部类的对象。局部内部类定义在外部类的方法体或者{}中该种内部类只能在其定义的位置使⽤⼀般使用的⾮常少public class OutClass { int a 10; public void method(){ int b 10; // 局部内部类定义在⽅法体内部 // 不能被public、static等访问限定符修饰 class InnerClass{ public void methodInnerClass(){ System.out.println(a); System.out.println(b); } } // 只能在该⽅法体内部使⽤其他位置都不能⽤ InnerClass innerClass new InnerClass(); innerClass.methodInnerClass(); } public static void main(String[] args) { // OutClass.InnerClass innerClass null; 编译失败 } }局部内部类只能在所定义的方法体内部使用不能被publicstatic等修饰编译器也有自己独立的字节码文件命名格式外部类$数字内部类名字.class几乎不会使用匿名内部类没有类名的内部类new SuperType(constructor-arguments) { //类体 };SuperType可以是接口抽象类或具体类interface Greeting { void greet(); } public class Test { public static void main(String[] args) { Greeting greeting new Greeting() { Override public void greet() { System.out.println(Hello!); } }; greeting.greet(); } }匿名内部类当中可以定义和正常类一样的成员变量但是和正常类一样都不能直接包含执行语句4.Object类object是祖先类一般不写继承的都继承object类使用Object接受所有类的对象class Person{} class Student{} public class Test { public static void main(String[] args) { function(new Person()); function(new Student()); } public static void function(Object obj) { System.out.println(obj); } } //执⾏结果 Person1b6d3586 Student4554617c发生了向上转型4.1 获取对象信息如果要打印对象中的内容就可以直接重写Object中的toString()方法// Object类中的toString()⽅法实现 public String toString() { return getClass().getName() Integer.toHexString(hashCode()); }4.2 对象比较equals方法比较相同或者不同Java中比较相同如果左右两侧是基本类型变量比较的是变量中值是否相同如果左右两侧是引用类型变量比较的是引用变量地址是否相同要比较就要重写Object中的equals方法因为equals方法默认也是按照地址比较的// Object类中的equals⽅法 public boolean equals(Object obj) { return (this obj); // 使⽤引⽤中的地址直接来进⾏⽐较 }class Person{ private String name; private int age; public Person(String name, int age) { this.age age; this.name name; } } public class Test { public static void main(String[] args) { Person p1 new Person(cyy, 20); Person p2 new Person(cyy, 20); int a 10; int b 10; System.out.println(a b); // 输出true System.out.println(p1 p2); // 输出false System.out.println(p1.equals(p2)); // 输出false } }重写equals方法class Person{ ... Override public boolean equals(Object obj) { if (obj null) { return false ; } if(this obj) { return true ; } // 不是Person类对象 if (!(obj instanceof Person)) { return false ; } Person person (Person) obj ; // 向下转型⽐较属性值 return this.name.equals(person.name) this.ageperson.age ; } }4.3 hashcode方法hashcode方法源码public native int hashCode();该方法是一个native方法底层是由C/C代码写的看不到。我们认为两个名字相同年龄相同的对象将存储在同⼀个位置如果不重写hashcode()方法我们求出的hash值不一样重写hashcode()方法class Person { public String name; public int age; public Person(String name, int age) { this.name name; this.age age; } Override public int hashCode() { return Objects.hash(name, age); } } public class TestDemo4 { public static void main(String[] args) { Person per1 new Person(cyy, 20) ; Person per2 new Person(cyy, 20) ; System.out.println(per1.hashCode()); System.out.println(per2.hashCode()); } } //执⾏结果 //3070322 //3070322hashcode方法用来确定对象在内存中存储的位置是否相同

相关新闻