一、abstract(抽象的)
1、abstract可以用于修饰类
- 被abstract修饰的类称为抽象类。
语法:abstract class 类名{}
- 抽象类编译之后会生成独立的 .class 文件
package day28;
class TestAbstract{
public static void main(String[] args){
}
}
//抽象类
abstract class MyClass{}
- 抽象类不能单独创建对象(即不能 new 对象),但是可以声明抽象类类型的引用 (简称:可以声明引用)
//MyClass mc = new MyClass();
//报错:MyClass 是抽象的; 无法对其进行实例化
MyClass mc;
- 抽象中可以定义 成员变量 和 成员方法
- 抽象类中有构造方法,但是抽象类中构造方法不再是用于new 对象,而是供子类创建对象时,JVM默认创建一个父类对象时应用。
2、abstract可以用于修饰方法
- 被 abstract 修饰的方法称为抽象方法
- 抽象方法不能有主体,只有声明部分,没有方法实现部分(连 {}都没有),以分号结尾
语法: 访问修饰符 abstract 返回值类型 方法名(形参列表);
例子:
public abstract void m2();
abstract public void m3();
注意:访问修饰符 和 abstract 没有先后位置。
- 抽象方法只能定义在抽象类中;但是抽象类中既可以定义抽象方法,也可以定义非抽象方法。
3、抽象的子类
- 如果一个类继承抽象类,此类为抽象类的子类
- 如果子类不想定义为抽象类,必须覆盖父类中所有的抽象方法,否则子类必须定义抽象类。
- 抽象类类名 引用名 = new 子类类名(形参);
- 抽象类强制使用多态。
class TestAbstract{
public static void main(String[] args){
//MyClass mc = new MyClass();//报错:MyClass 是抽象的;无法对其进行实例化
//MyClass mc;
//mc = new Sub2();//强制使用多态
MyClass mc = new Sub2();
mc.m1();
mc.m2();
mc.m3();
}
}
//抽象类
abstract class MyClass{
int a;//可以定义属性
public void m1(){
System.out.println("m1()实现...");
}//可以定义成员方法
public abstract void m2();//抽象方法不能有主体,没有{},有;
abstract public void m3();
}
abstract class Sub1 extends MyClass{}
class Sub2 extends MyClass{
public void m2(){
System.out.println("m2()实现...");
}
public void m3(){
System.out.println("m3()实现......");
}
}
- 抽象类强制使用多态。
- 抽象类的应用场景:
1、通常将一些父类定义为抽象类:具有某一类事物的特性和行为,但是不具有具体的执行功能(实现)。例如:动物类、图形类等。
2、**依赖倒转原则:**当一个类和另外一个类建立关联时,尽可能避开直接和子类建立关系,而是与其父类建立联系。
a. 降低程序之间的耦合度,从而实现弱耦合。
b. 提高代码的可维护性
abstract:能修饰类和方法
二、static(静态的)
1、static可以修饰属性
- 被static修饰的属性称为静态属性,静态变量,类变量
语法:访问修饰符 static 数据变量 变量名;
访问修饰符 static 数据变量 变量名 = 值;
注意:访问修饰符 和 static 没有位置先后。
-
特点:静态变量/静态属性/类变量 是依赖于类的变量,和创建多少对象没有关系,被每一个对象共享
注意:实例变量(非静态变量)每一个对象独有一份
静态变量让每一个对象共享。 -
使用:
a.引用名.静态属性名
b.类名.静态属性名 -
内存分析如下:
-
案例:
class TestMyClass{
public static void main(String[] args){
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
mc1.value = 20;
mc1.m =3;
System.out.println("mc1.value = "+mc1.value);//20
System.out.println("mc1.m = "+mc1.m);//3
System.out.println("mc2.value = "+mc2.value);//10
System.out.println("mc2.m = "+mc2.m);//3
MyClass mc3 = new MyClass();
System.out.println("mc3.m = "+mc3.m);//3
mc3.m=100;
System.out.println("mc3.m = "+mc3.m);//100
System.out.println("mc2.m = "+mc2.m);//100
System.out.println(MyClass.m);
MyClass.m = 20;
MyClass mc = new MyClass();
System.out.println(mc.m);//20
MyClass.m = 30;
System.out.println(mc.m);//30
}
}
class MyClass{
int value = 10;
static int m;//静态属性,静态变量,类变量
static int n;
}
2、static可以修饰成员方法
- 被static修饰的方法称为静态方法
语法:
访问修饰符 static 返回值类型 方法名(形参列表){}
注意:访问修饰符 和 static 没有位置上的先后顺序。
-
使用:
a.类名.静态方法名(实参)
b.对象名.静态方法名(实参) -
注意:
a.静态方法中不能直接访问本类的非静态成员(实例变量+成员方法)
b.静态方法中可以直接访问本类的静态成员(静态变量+静态方法)
c.非静态方法中既可以直接访问 本类非静态的成员,也可以直接访问本类的静态成员。
d. 静态方法中不能使用 this 和 super 关键字
e.父类中的静态方法可以被子类继承
语法:子类类名.父类静态方法名(实参);
f. 如果子类覆盖父类中的静态方法,则子类覆盖的方法也必须是静态的(静态方法只能被静态方法覆盖);以父类型的引用调用静态方法,直接访问父类中静态方法,没有体现多态的覆盖结果。 -
应用场景:为了方便调用,通常将工具类中方法定义为静态方法。
例如:java.util.Arrays.sort(数组名);
java.util:包名
Array:类名
sort:方法名
System.out.println();实现原理
System:类名(位于java.util中的);
out:System类中被static修饰的静态属性,引用;
println:out数据类型中方法。
3、static可以修饰初始代码块
- 初始化代码:也称为动态代码块
(1) 定义在 类以内,方法以外的 {}
(2) 作用:创建对象时,按照和属性(实例变量)定义的先后顺序完成对属性初始化工作。 - 静态初始化代码块(重点)
(1) 定义在类以内,方法以外,被 static 修饰的 {}
static{}
(2) 作用:在类加载的时候,按照静态属性定义的先后顺序完成静态属性的初始化工作。
(3) 类加载:
① 类加载:JVM第一次使用一个类的时候,通过classPath(类路径)找到所需要的类对应的 .class 文件,读取并获取类对应信息(包名、类名、属性、构造方法、成员方法、父类等信息),将类的信息保存到JVM内存中,一个类类加载进行一次。
② 第一次使用一个类:
a. 第一次调用类中静态成员(静态属性和静态方法)
b. 第一次创建一个类的对象:先进行类加载,再完成对象的创建
c. 子类类加载会先导致其父类进行类加载
**注意:**只是声明引用,不会导致类加载(MyClass mc;)
class Test3{
public static void main(String[] args){
Sub sub = new Sub();//142356
/*
先类加载:(静态初始化)static{}
加载父类 --1
加载子类 --4
创建对象:
new : 分配空间
执行子类构造方法
super()--》执行父类构造方法
(1)初始化内容(属性初始化语句+初始代码块/动态代码块) --2
(2)执行父类构造方法中其它语句 --3
继续执行子类构造方法中其它内容:
(1)属性初始化内容(属性初始化语句+初始代码块/动态代码块)--5
(2)执行子类构造方法中其它语句 --6
*/
//System.out.println(Sub.n);//149(这是第一句时)
}
}
class MyClass{
static int m = 8;
static{
System.out.println("父类静态类加载...");//1
}
{
System.out.println("父类动态类加载...");//2
}
public MyClass(){
System.out.println("父类构造方法加载...");//3
}
}
class Sub extends MyClass{
static int n = 9;
static{
System.out.println("子类静态类加载...");//4
}
{
System.out.println("子类动态类加载...");//5
}
public Sub(){
System.out.println("子类构造方法加载...");//6
}
}
三、final(最终的、最后的)
int a;//实例变量
static int b;//静态变量、静态属性、类变量
这些都是成员变量
1、final可以修饰变量(局部变量,实例变量,静态变量)
-
final修饰的变量是作用范围内的常量,只允许一次赋值,不允许更改
注意:final修饰的变量通常以全大写字母作为名字 -
final 修饰 实例变量,JVM不再分配默认值
final修饰 实例变量 的位置:
a.在声明的同时 初始化;
b.可以在构造方法中对其初始化,但是必须保证每一个构造方法中都有对其初始化的语句。 -
final 修饰 静态变量,JVM不再分配默认值
final修饰 静态变量 的位置:
a.在声明的同时 初始化;
b.可以在静态代码块中完成对其初始化 -
如果引用被final修饰,代表引用中的存储地址不可以改变,但是可以通过引用对象的属性进行修改
font size=4>1、final可以修饰方法
- 被final修饰的方法被子类继承,但不允许覆盖
System 、String、Math等一些工具类通常会定义为final类。
总结:
三个修饰符(abstract、static、final)的内容:
abstract:可以修饰类、方法
static:可以修饰属性、方法、静态代码块
final:可以修饰类变量(局部变量,静态变量,实例变量)、方法、、类
abstract、static、final都不能用于修饰构造方法
1.abstract:抽象方法只有方法的声明,没有方法的实现,实现部分让子类完成;但是构造方法是不能被子类继承,如果构造方法被abstract修饰,则子类无法完成构造方法的实现内容。
2.static:static和对象没有关系,但是构造方法是用于创建对象的,相互矛盾;同时static修饰的方法可以直接通过类名.静态方法名(实参);调用,但是构造方法不允许手动调用。
final:final方法是约束子类不能覆盖,但是构造方法本身不允许子类继承。谈不上覆盖,所以没必要用final修饰。
private、abstract、static、final是否能联合修饰成员方法?
a.private 和 abstract :private修饰的方法不能被子类继承,abstract修饰的方法需要通过子类覆盖与方法的实现部分,联合修饰一个成员,二者矛盾;
b.static 和 abstract :static方法可以直接通过类名.方法名(实参);进行调用,如果通过类名调用一个抽象方法(半成品),JVM无法执行,二者不能联合修饰一个成员方法;
c.final 和 abstract :final修饰的方法可以被子类继承,但是不允许被覆盖,而abstract修饰的方法的实现需要通过子类覆盖时给与实现,二者不能联合使用。
private、static、final可以联合使用
一个方法中必须而且只能有一个访问修饰符
private、default、protected、public(4个访问修饰符)