
目录
[第一部分 抽象类 abstract](#第一部分 抽象类 abstract)
[1.1 抽象类概念](#1.1 抽象类概念)
[1.2 抽象类语法](#1.2 抽象类语法)
[1.3 抽象类全部特性(高频考点)](#1.3 抽象类全部特性(高频考点))
[1.4 抽象类的作用](#1.4 抽象类的作用)
[第二部分 接口 interface](#第二部分 接口 interface)
[2.1 接口概念](#2.1 接口概念)
[2.2 接口定义语法](#2.2 接口定义语法)
[2.3 接口实现 implements](#2.3 接口实现 implements)
[2.4 接口重要语法约束(必背)](#2.4 接口重要语法约束(必背))
[2.5 一个类实现多个接口(弥补 Java 单继承)](#2.5 一个类实现多个接口(弥补 Java 单继承))
[2.6 接口和接口之间可以多继承](#2.6 接口和接口之间可以多继承)
[2.7 抽象类 vs 接口(面试高频)](#2.7 抽象类 vs 接口(面试高频))
[第三部分 内部类](#第三部分 内部类)
[3.1 静态内部类 static class](#3.1 静态内部类 static class)
[3.2 实例内部类(普通成员内部类,没有 static)](#3.2 实例内部类(普通成员内部类,没有 static))
[3.3 局部内部类](#3.3 局部内部类)
[3.4 匿名内部类(高频)](#3.4 匿名内部类(高频))
[第四部分 Object 根类](#第四部分 Object 根类)
[4.1 toString()](#4.1 toString())
[4.2 equals () 方法](#4.2 equals () 方法)
[4.3 hashCode()](#4.3 hashCode())
[4.4 Cloneable 克隆接口与浅拷贝](#4.4 Cloneable 克隆接口与浅拷贝)
本节学习目标
- 掌握抽象类、抽象方法的语法、全部特性,理解抽象类存在的意义
- 掌握
interface接口语法、接口成员规则、implements实现接口 - 掌握多实现、接口之间多继承,理解接口表达 "具备某种能力"
- 理解四种内部类:实例内部类、静态内部类、局部内部类、匿名内部类
- 吃透
Object根类:toString()、equals()、hashCode(),区分==和equals - 了解
Cloneable克隆接口、浅拷贝概念
第一部分 抽象类 abstract
1.1 抽象类概念

并不是所有的类都可以用来实例化对象。 有些父类只用来描述通用行为,行为没有办法写出具体实现 ,比如动物bark()叫:动物都会叫,但是普通动物不知道怎么叫,狗、猫这些具体子类才知道怎么叫。
抽象方法 :只有方法声明,没有方法体,没有具体实现。 抽象类 :包含抽象方法的类,被
abstract修饰。

示例图形场景:Shape图形父类,draw()画图形,不同图形绘制逻辑完全不一样,父类写不出通用实现,可以把draw()定义为抽象方法。
1.2 抽象类语法
java
// abstract修饰抽象类
public abstract class Shape {
//抽象方法:abstract修饰,没有{}方法体,直接分号结束
abstract public void draw();
abstract void calcArea();
//抽象类也是普通类,可以拥有普通成员变量、普通成员方法
protected double area;
public double getArea(){
return area;
}
}
✔抽象类可以包含:普通成员变量、普通方法、构造方法、抽象方法。
1.3 抽象类全部特性(高频考点)
- 抽象类不能直接 new 实例化对象
java
Shape shape = new Shape();
//编译报错:Shape是抽象的; 无法实例化
- 抽象方法不能用
private修饰 抽象方法目的就是让子类重写,private 子类看不到,矛盾。
java
abstract private void draw(); //编译报错:非法修饰符组合 abstract和private
- 抽象方法不能使用
final、static修饰
final方法不能被重写,抽象方法必须被子类重写,冲突。static属于类,静态方法不能被子类重写。
java
abstract final void methodA(); //报错
abstract public static void methodB(); //报错
- 子类继承抽象类,必须重写全部抽象方法;如果不全部实现,子类也必须是 abstract 抽象类
java
//矩形子类,实现全部抽象方法,可以是普通类
public class Rect extends Shape {
private double length;
private double width;
Rect(double length, double width){
this.length = length;
this.width = width;
}
@Override
public void draw(){
System.out.println("矩形: length= "+length+" width= " + width);
}
@Override
public void calcArea(){
area = length * width;
}
}
//圆子类
public class Circle extends Shape{
private double r;
final private static double PI = 3.14;
public Circle(double r){
this.r = r;
}
@Override
public void draw(){
System.out.println("圆:r = "+r);
}
@Override
public void calcArea(){
area = PI * r * r;
}
}
//三角形:没有实现calcArea抽象方法,自己必须也是抽象类
public abstract class Triangle extends Shape {
private double a;
private double b;
private double c;
@Override
public void draw() {
System.out.println("三角形:a = "+a + " b = "+b+" c = "+c);
}
//没有重写calcArea,本类必须abstract
}
- 抽象类不一定包含抽象方法;但是只要有抽象方法,这个类一定是抽象类。
可以写一个没有抽象方法的 abstract 类,目的:禁止直接 new 这个类。
- 抽象类存在构造方法!
抽象类不能 new 对象,但是构造方法提供给子类
super()调用,用来初始化父类继承的成员变量。
1.4 抽象类的作用
核心作用:利用编译器做语法校验,防止错误实例化父类。
普通父类,程序员不小心直接 new 父类对象,编译器不会报错,运行才发现逻辑不对。 抽象类直接禁止实例化,编译阶段就拦截错误。
很多语法设计目的:提前在编译期发现 bug,而不是等到运行时。
第二部分 接口 interface
2.1 接口概念


现实类比:USB 接口、电源插座。 接口是一套公共行为规范、标准。设备只要遵守 USB 接口规范,就可以插到 USB 口使用。
Java 中接口是引用类型,代表一组行为规范。
2.2 接口定义语法
使用interface关键字,代替class。
java
public interface USB {
// public abstract 可以省略,接口里面抽象方法默认 public abstract
void openDevice();
void closeDevice();
}
编码小提示:
- 接口命名习惯:一般大写
I开头,例如IRunning;多用形容词。- 阿里规范:接口方法不要手写修饰符,保持简洁。
2.3 接口实现 implements
类和接口不是继承
extends,是实现implements。
java
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("键盘输入");
}
}
笔记本使用 USB 设备示例:
java
public class Computer {
public void powerOn(){
System.out.println("打开笔记本电脑");
}
public void powerOff(){
System.out.println("关闭笔记本电脑");
}
//接口引用接收任意实现了USB规范的对象
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();
}
}
2.4 接口重要语法约束(必背)
- JDK8 之前,接口中方法默认
public abstract抽象方法,不能写方法体。
java
public interface USB {
void openDevice();
// void closeDevice(){ System.out.println(); } //编译报错,不能有方法体
}
- 实现接口重写方法,访问权限必须是 public,不能缩小权限。
java
//接口方法默认public
public interface USB {
void openDevice();
}
class Mouse implements USB{
@Override
void openDevice(){
//编译报错!重写不能使用默认包访问,权限降低
}
}
- 接口里面定义的变量,会被编译器隐式加上
public static final,是常量,不能修改。
java
public interface USB {
double brand = 3.0; //等价 public static final double brand =3.0;
}
public class TestUSB {
public static void main(String[] args) {
System.out.println(USB.brand);
// USB.brand = 2.0; //编译报错 final常量不能赋值
}
}
- 接口不能包含构造方法、静态代码块。
java
public interface USB {
// public USB(){} //构造方法,编译报错
// {} //实例代码块,编译报错
}
- 接口虽然不是类,编译之后同样生成
.class字节码文件。 - 如果实现类没有实现接口全部抽象方法 ,这个类必须定义为
abstract抽象类。 - ✨JDK8 新特性:接口中可以写
default默认方法,带方法体;还可以有 static 静态方法。
2.5 一个类实现多个接口(弥补 Java 单继承)
Java 类和类只能单继承
extends;但是一个类可以implements多个接口,逗号隔开。
java
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 Cat extends Animal implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + "正在用四条腿跑");
}
}
//青蛙:继承动物,同时实现跑、游泳两个接口
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 + "正在蹬腿游泳");
}
}
//鸭子,同时实现三个接口
class Duck extends Animal implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() { System.out.println(this.name + "正在用翅膀飞"); }
@Override
public void run() { System.out.println(this.name + "正在用两条腿跑"); }
@Override
public void swim() { System.out.println(this.name + "正在漂在水上"); }
}
语义区分:
extends继承:is‑a 是一个;猫是动物implements接口:has‑ability 具备某种能力;猫具备跑的能力
多态用法示例,只关心能力,不关心具体是什么类:
java
//只要实现IRunning接口,具备跑的能力,就可以传入,不管是动物还是机器人
public static void walk(IRunning running) {
System.out.println("我带着伙伴去散步");
running.run();
}
//机器人不是Animal,但是实现IRunning接口,也可以传进去
class Robot implements IRunning {
private String name;
public Robot(String name) { this.name = name; }
@Override
public void run() {
System.out.println(this.name + "正在用轮子跑");
}
}
2.6 接口和接口之间可以多继承
接口使用extends可以同时继承多个其他接口,实现接口合并。
java
interface IRunning { void run(); }
interface ISwimming { void swim(); }
//两栖接口,同时继承跑和游泳两个接口
interface IAmphibious extends IRunning, ISwimming{
}
//实现IAmphibious,就必须实现run()和swim()两个方法
class Frog implements IAmphibious{
@Override
public void run() {}
@Override
public void swim() {}
}
2.7 抽象类 vs 接口(面试高频)
表格
| 对比项 | 抽象类 abstract class | 接口 interface |
|---|---|---|
| 关键字 | abstract class | interface |
| 成员变量 | 普通成员变量,可以有各种修饰符 | 默认public static final常量,不能普通变量 |
| 方法 | 可以普通方法、抽象方法、构造方法 | JDK8 前只能抽象方法;JDK8 支持 default、static 方法;没有构造方法 |
| 继承 / 实现 | extends,类只能单继承 |
implements,类可以多实现;接口可以多继承接口 |
| 语义 | is‑a 是一个事物 | 具备某一种能力、规范 |
开发经验:优先用接口定义能力;有一部分通用成员逻辑复用,再考虑抽象类。
第三部分 内部类
把一个类写在另外一个类的内部,叫内部类。 分类:
- 实例内部类(成员内部类,无 static)
- 静态内部类(static 修饰成员内部类)
- 局部内部类(写在方法里面,极少用)
- 匿名内部类(重点,经常使用)
3.1 静态内部类 static class
被 static 修饰,属于外部类,不属于外部类的对象。
java
public class OutClass {
public int a; //实例成员
public static int b; //静态成员
//静态内部类
static class InnerClass{
public void methodInner(){
// a = 100; //❌不能直接访问外部类的实例成员a
b = 200; //✅可以访问外部类静态成员
}
}
public static void main(String[] args) {
//创建静态内部类对象,不需要外部类实例对象
OutClass.InnerClass inner = new OutClass.InnerClass();
inner.methodInner();
}
}
要点:
- 静态内部类只能直接访问外部类 static 静态成员;访问外部实例成员,必须传入外部类对象引用。
- 创建对象语法:
外部类.静态内部类 变量 = new 外部类.静态内部类();,不需要 new 外部类对象。
3.2 实例内部类(普通成员内部类,没有 static)
写在外部类的成员位置,不加 static。每一个外部类对象,对应一份内部类对象。
java
public class OutClass {
public int a;
public static int b;
public int c = 100;
//实例内部类
class InnerClass{
int c = 200;
public void methodInner(){
//可以直接访问外部类所有成员(private也可以)
System.out.println(a);
System.out.println(b);
System.out.println(c); //优先内部自己的c →200
//访问外部类同名成员:外部类名.this.成员
System.out.println(OutClass.this.c); //取外部类c →100
}
}
public static void main(String[] args) {
OutClass out = new OutClass();
//实例内部类必须依赖外部类对象才能创建
OutClass.InnerClass inner1 = out.new InnerClass();
inner1.methodInner();
//也可以一行写完
OutClass.InnerClass inner2 = new OutClass().new InnerClass();
}
}
重点规则:
- 实例内部类可以直接访问外部类全部成员,包含 private。
- 内外类成员重名:内部优先访问自己;访问外部同名成员:
外部类名.this.变量名。- 创建实例内部类对象,必须先有外部类对象。
- 外部类不能直接访问内部类成员,必须先 new 内部类对象。
3.3 局部内部类
定义在方法内部,只能当前方法里面使用,几乎不写业务代码,了解即可。
java
public class OutClass {
int a = 10;
public void method(){
//局部内部类,方法里面定义
class InnerClass{
public void func(){
System.out.println(a);
}
}
InnerClass inner = new InnerClass();
inner.func();
}
}
限制:不能使用
public static等修饰符;只在本方法作用域有效。
3.4 匿名内部类(高频)
没有类名字,定义类的同时直接 new 实例对象;经常用于接口、抽象类,只使用这一次。 语法:
java
new 父类/接口(){
//重写方法
};
示例,实现接口:
java
interface Greeting {
void greet();
}
public class Test {
public static void main(String[] args) {
//匿名内部类,没有类名,直接new接口并且重写方法
Greeting greeting = new Greeting() {
@Override
public void greet() {
System.out.println("Hello!");
}
};
greeting.greet();
}
}
适用场景:这个实现类只使用一次,不想单独写一个
.java文件。
第四部分 Object 根类
⚠️Java 中所有类,直接或者间接继承 Object 。任何对象,都可以用
Object引用接收。 Object 是所有类的祖先。

4.1 toString()
java
//Object原生toString实现
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
直接打印对象,默认调用 toString,输出类名@十六进制哈希码。 想要打印对象属性内容,需要重写 toString ()。
java
class Person{
String name;
int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name="+name+",age="+age+"}";
}
}
4.2 equals () 方法
==和equals()核心区分(面试必考题)
- 如果
==两边是基本数据类型 :比较值是否相等。 - 如果
==两边是引用类型 :比较两个引用保存的内存地址是否是同一个对象。
Object 原生 equals 源码:
java
public boolean equals(Object obj) {
return (this == obj); //原生equals也是比较地址!
}
如果业务需求是比较对象里面的内容属性是否相等 ,必须重写 equals ()。
示例:
java
class Person{
String name;
int age;
public Person(String name,int age){
this.name = name;
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 && name.equals(person.name);
}
}
4.3 hashCode()
返回对象 int 哈希码。
- 原生实现:根据对象内存地址生成哈希值。
- 如果重写了
equals,业务上认为两个对象内容相等,强烈建议同步重写 hashCode (),保证相等对象 hashCode 返回相同数值。
java
@Override
public int hashCode() {
return Objects.hash(name, age);
}
4.4 Cloneable 克隆接口与浅拷贝
Cloneable是标记接口,接口内部没有抽象方法。 实现Cloneable,才可以调用super.clone()做对象拷贝。
clone 默认做浅拷贝:拷贝出来新对象,引用类型成员还是指向原来的堆对象。
java
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();
//浅拷贝,两个person的money引用指向同一个Money对象
person2.money.m = 13.6;
System.out.println(person1.money.m); //输出13.6!person1也被修改
}
}
浅拷贝:基本类型直接复制值;引用类型复制地址,共用同一个子对象。 深拷贝:递归把引用指向的对象也完整复制一份,互不干扰,需要自己手写。
📔本篇核心考点总结
- 抽象类 abstract
- 有抽象方法一定是抽象类;抽象类不一定有抽象方法;不能 new。
- 子类继承抽象类,必须重写全部抽象方法,否则子类 abstract;抽象类有构造方法供子类 super 调用。
- 接口 interface
- 接口方法默认
public abstract;变量默认public static final常量;没有构造方法。 - 类
implements实现接口;一个类可以多实现;接口之间可以多继承。 - 语义:
extends is‑a;implements具备某种能力。
- 接口方法默认
- 内部类
- 静态内部类:只能直接访问外部 static 成员,创建不需要外部类实例。
- 实例内部类:依赖外部类对象,可以访问外部所有成员;同名成员使用
外部类名.this。 - 匿名内部类:接口 / 抽象类一次性使用,定义同时实例化。
- Object
- 所有类的父类。
==:基本类型比值,引用类型比地址;原生equals也是比地址;比较对象内容要重写equals,配套重写hashCode()。clone()默认浅拷贝。
面试简答 Q:抽象类和接口区别?
A:抽象类用 abstract class,可以有普通成员变量、构造方法;接口 interface 变量只能是常量,不能有构造;类单继承抽象类,类可以多实现接口;语义上抽象类代表 is‑a,接口代表具备某种能力。
Q:==和equals()区别?A:
==基本类型比较数值;引用类型比较对象地址。Object 原生 equals 等价于 ==;需要比较对象内部属性内容,要手动重写 equals 方法。
