⭐三个修饰符
♦一、abstract(抽象的)
1. abstract可以用于修饰类
(1) 被abstract修饰的类称为抽象类
语法:abstract class 类名{}
(2) 抽象类编译之后生成独立的.class文件
(3) 抽象类不能单独创建对象,但是可以声明引用
(4) 抽象类中可以定义成员变量和成员方法
(5) 抽象类中有构造方法,抽象类中构造方法供子类创建对象,先去完成父类对象的创建时应用。
2. abstract可以用于修饰方法
(1) 被abstract修饰的方法称为抽象方法
(2) 抽象方法只有方法的声明部分,没有方法的实现部分(连{}都没有)
语法:访问修饰符 abstract 返回值类型 方法名(形参列表);
注意:访问修饰符和 abstract 之间没有位置的先后顺序。
(3) 抽象方法只能定义在抽象类中;但是抽象类中既可以有抽象方法,也可以有非抽象方法。
(4) 注意:如果子类继承抽象类,子类不想成为抽象类,则需要覆盖父类(抽象类)中所有的抽象方法,否则子类也必须定义为抽象类。
3. 抽象类的作用:强制使用多态。
—
♦二、static(静态的)
1. static可以用于修饰属性【开发应用重点】
(1) 被static修饰的属性称为静态属性、静态变量、类变量
(2) 语法:访问修饰符 static 数据类型 属性名;
访问修饰符 static 数据类型 属性名 = 值;
注意:访问修饰符和 static 没有先后位置的要求。
(3) 特点:静态属性是全类共有的属性,与创建多少对象没有关系。
(4) 应用:
a. 对象名.静态属性名 // 不建议使用
b. 类名.静态属性名 // 建议使用

public class TestStatic{
public static void main(String[] args){
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
mc1.value = 50;
mc1.b = 48;
System.out.println("mc1.value="+mc1.value); // 50
System.out.println("mc1.b="+mc1.b);
System.out.println("mc2.value="+mc2.value); // 10
System.out.println("mc2.b="+mc2.b);
}
}
class MyClass{
int value = 10; // 实例变量
static int b = 30; // 静态变量、类变量、静态属性
}
2. static 可以用于修饰方法【开发应用重点】
(1) 被 static 修饰的方法称为静态方法。
(2) 语法:访问修饰符 static 返回值类型 方法名(形参列表) { // 方法的实现 }
注意:访问修饰符和 static 没有位置先后要求。
(3) 使用:类名.静态方法名(实参);
对象名.静态方法名(实参); // 不建议使用
(4) 注意:
a. 静态方法中只能直接访问本类的静态成员(静态属性和静态方法)
b. 静态方法中不能直接访问本类的非静态的成员(非静态的属性和方法)
c. 非静态方法中既可以访问本类的非静态成员(实例变量和成员方法),也可以直接访问本类的静态成员(静态属性和方法)
d. 静态方法中不能使用 this/super 关键字
e. 静态方法允许被子类继承,静态方法只能被静态方法覆盖,但是没有多态的应用
注意:如果在静态方法中访问非静态成员,则可以利用创建对象,用对象名调用非静态的成员。
思考:System.out.println(); 实现原理

static 可以用于修饰初始化代码块
(1) 初始化代码块也被称为动态代码块【了解】
a. 位置:定义在类以内,方法以外
b. 作用:在创建对象时,按照和属性定义先后顺序,完成对属性的初始化工作。
对象创建的过程:
分配空间:为属性赋默认值
初始化属性:为属性第一次赋值的机会
执行构造方法:为属性第二次赋值的机会
(2) 被 static 修饰的初始化代码块称为静态初始化代码块,简称静态代码块。【开发应用重点】
a. 位置:定义在类以内,方法以外,同时被 static 修饰
b. 作用:在类加载时,按照和静态属性定义先后顺序,完成对静态属性的初始化工作。
c. 类加载:
I. 概念:当 JVM 第一次使用一个类的时候,通过 ClassPath(类路径)找到对应的 class 文件,从 class 文件中读取类的信息(包、类名、父类、属性、成员方法、构造方法等),读取之后将信息存储在 JVM 内存中,一个类只进行一次类加载。
II. 类加载时机:
① 第一次使用该类的静态成员(静态属性和静态方法):会进行类加载
② 子类的类加载会导致其父类先进行类加载:先加载其父类,再加载子类
– 第一次调用子类中的静态成员:先加载其父类,再加载子类
– 第一次创建子类对象:先加载,再完成对象的创建带有类加载创建对象的过程:
先加载:先加载其父类,再加载子类
先加载父类:为父类的静态属性分配空间并完成父类静态属性的初始化
——> 父类的静态代码块被执行
再加载子类:为子类的静态属性分配空间并完成子类静态属性的初始化
——> 子类的静态代码块被执行
再完成对象的创建:先创建父类对象,再创建子类对象
先完成父类对象的创建:
初始化父类的属性:——> 父类的动态代码块被执行
执行父类的构造方法
再完成子类对象的创建:
初始化子类的属性:——> 子类的动态代码块被执行
执行子类的构造方法
注意:只声明引用不会导致类加载。
4. static 可以用于修饰内部类
♦三、final(最终的、最后的)
1. 变量(局部变量、实例变量、静态变量)
(1) final修饰的变量是作用范围内的常量,只允许一次赋值,不允许更改,可以多次被使用。
(2) final的实例变量不再分配默认值,为其初始化的时机:
a. 声明的同时对其初始化
b. 在构造方法中对其初始化,但是必须保证每一个构造方法都对其进行初始化
c. 借助动态代码块对其初始化
(3) final修饰的静态属性不再分配默认值,为其初始化的时机:
a. 声明的同时对其初始化
b. 借助静态初始化代码块对其初始化
注意:final修饰的引用,代表引用中存储对象的地址不能改变。
2. final可以用于修饰方法:可以被子类继承,但是不允许被覆盖。
3. final可以用于修饰类:被final修饰的类不能被继承,即没有子类。
例如:String / System / Math 等。
⭐接口
♦一、概念
1. 接口:是一种标准、规范,是接口的实现者和接口的使用者都必须遵循的约定。【理解】
2. 接口的语法:
(1) 接口的关键字: interface
interface 接口名{}
(2) 接口编译之后会生成独立的.class文件
(3) 接口不能创建对象,但是可以声明引用
(4) 接口中的属性都是公开、静态、常量(默认被 public static final 修饰)
(5) 接口中的方法都是公开、抽象方法(默认被 public abstract 修饰)
(6) 接口中没有构造方法
注意:接口不是类。
—
♦二、实现类【开发重点】
1. 语法:class 类名 implements 接口名{}
2. 注意:实现类实现接口,如果实现类不想成为抽象类,则需要实现(覆盖)接口中所有的方法;
实现类实现接口中的方法时,方法的访问修饰符必须是 public 的访问权限。
3. 应用:接口名 引用名 = new 实现类类名(实参);
注意:接口类型的引用指向实现类的对象,多态的应用。——> 强制使用多态
public class TestInter2{
public static void main(String[] args){
MyInter mi = new MyClass(); // 多态
mi.m1();
int n = mi.m2();
System.out.println(n);
}
}
// 接口
interface MyInter{
int n = 3; // public static final
void m1();
int m2(); // public abstract
}
// 实现类
class MyClass implements MyInter{
public void m1(){
System.out.println("m1的方法…");
}
public int m2(){
System.out.println("m2的方法…");
return 0;
}
}
—
♦三、接口的继承性【基础重点】
1. Java中的接口之间的继承关系是多继承,一个接口可以有多个父接口
2. 类和接口之间是多实现的关系:一个类可以同时实现多个接口
(1) 语法:class 类名 implements 接口名1,接口名2{}
(2) 注意:一个类同时实现多个接口,如果这个类不想成为抽象类,则必须实现所有接口中所有方法;
而且每一个方法的访问修饰符都是 public
3. 一个类继承一个父类的同时可以实现多个接口
(1) 语法:class 类名 extends 父类名 implements 接口名1,接口名2{}
(2) 注意:必须是先继承后实现。(单继承多实现)
—
♦四、接口多继承的影响【了解】
1. 如果引用之间相互强制类型转换,转换的一方为接口类型的引用,则编译一定通过,但是运行时仍会出现以下两种情况:
(1) 实际存储的对象类型和要转换的类型一致 -> 成功
(2) 实际存储的对象类型和要转换的类型不一致 -> 运行报错 java.lang.ClassCastException
(3) 通常将主要功能定义在父类中,次要的功能(扩展的功能)定义在接口中。
♦五、接口的作用[【理解+开发应用】
1.可以扩充子类的能力
(1)由于Java中类之间是单继承,当子类从父类中继承功能方法不足以满足子类功能需求时,可以借助接口扩
充子类的能力
(2)通常将主要功能定义在父类中,次要的功能(扩展的功能)定义在接口中。2. 降低程序中的耦合度
接口定义好之后,将接口的实现者和接口的使用者分离,借助多态,降低各模块之间的耦合度。
♦六、接口的回调【理解】
1. 接口回调:接口定义之后,先有接口的使用者,再有接口的实现者。
2. 注意:遇到接口回调的应用,开发人员需要关注的是根据接口规范,给予接口的实现部分。
总结:接口和抽象类的区别?【面试重点】
特性 接口 抽象类
关键字 interface abstract class
属性 公开、静态、常量 没有要求(实例变量+静态变量+对final没有要求)
方法 公开、抽象方法 抽象方法+非抽象方法
构造方法 没有 有构造方法
继承关系 多继承 单继承
⭐内部类
♦一、概念
1. 内部类:定义在一个类内部的类。
```
// 外部类
class Outer{
// 内部类
class Inner{}
}
```
2. 内部类编译之后生成独立的 .class 文件,命名:外部类类名$内部类类名.class
3. 内部类可以直接使用外部类私有成员,从而不破坏外部类的封装性。
4. 内部类的分类:成员内部类、静态内部类、局部内部类、匿名内部类。
♦二、内部类的分类
1. 成员内部类:类比于实例变量【了解】
(1) 位置:定义在类以内,方法以外。
(2) 成员内部类对象的创建,必须依赖于外部类的对象而创建:
```java
Outer o = new Outer(); // 外部类的对象
Outer.Inner i = o.new Inner(); // 内部类的对象
```
(3) 访问外部类的当前对象:外部类类名.this
```
外部类类名.this.属性名 – 访问外部类的属性
外部类类名.this.成员方法名(参数) – 调用外部类的成员方法
```
(4) 成员内部类中不能定义静态成员(静态属性和静态方法)
2. 静态内部类:类比于静态变量【了解】
(1) 位置:定义在类以内,方法以外,同时被 static 修饰
(2) 静态内部类中可以定义实例变量,也可以定义静态变量
(3) 创建静态内部类的对象,只需要依赖于外部类的类名即可:
```java
Outer.Inner i = new Outer.Inner();
```
(4) 访问静态内部类的静态成员时,可以直接通过 外部类类名.静态内部类类名 进行访问:
```
外部类类名.静态内部类类名.静态方法名(实参);
```
(5) 静态内部类只能访问外部类的静态成员(静态属性和静态方法)
3. 局部内部类:类比于局部变量
(1) 位置:定义在方法内部
(2) 局部内部类对象的创建,必须在定义它的方法内部创建,并且在类的定义位置后面完成对象的创建
(3) 局部内部类的方法中可以访问定义它的方法内部的局部变量,但是要求局部变量必须被 final 修饰。
注意:JDK8.0及以上版本,编译器编译时,如果检测到局部变量被局部内部类中方法访问,则默认为此局部变量前面加 final,这种技术被称为语法糖。
4. 匿名内部类:是一个特殊的局部内部类
(1) 匿名内部类的定义必须继承一个类或是实现一个接口
(2) 基于一个匿名内部类只能创建该类的一个对象,并且匿名内部类的定义和对象的创建一起完成。
(3) 语法:
```
接口名 引用名 = new 接口名() {
// 接口中需要实现的方法
};
```
(4) 匿名内部类的优缺点:
a. 优点:减少代码量,让编程思路连贯。
b. 缺点:可读性低。
案例:
```java
interface IA{
void m1();
}
public class Test{
public static void main(String[] args){
IA ia = new IA() {
public void m1(){
System.out.println("匿名内部类实现的方法…");
}
};
ia.m1();
}
}
```
```java
public class Test {
public static void main(String[] args) {
MyClass mc = new MyClass() {
public void method(){
System.out.println("子类覆盖后的方法…");
}
};
mc.method();
}
}
class MyClass {
public void method(){
System.out.println("父类中method方法…");
}
}
```



