7.类(静态)变量与类(静态)方法

类变量(静态变量)

1.类变量(静态变量)

1.快速理解:就是一个变量被多个类共同使用
2.Static变量在类加载的时候就已经生成了
定义语法:

访问修饰符 static 数据类型,变量名

如何访问静态变量:

1.类名.类变量名(推荐)
2.对象名.类变量名

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class VisitStatic{
public static void main(String[]args){
//类型.类变量名
//说明:类变量是随着类的加载而创建的,所以没有实例也能访问。
System.out.println(A.name);
A a = new A();
System.out.println(a.name);
}
}
class A{
//静态变量
//静态变量的访问权限仍然要遵循相关的访问权限
public static String name = "haozi";
}

3.类变量细节:
当我们让每个类都共享使用一个变量时,就可以考虑使用类变量。
类变量是共享的,实例变量是独有的
类变量的生命周期是随着类的加载开始的,随着类的消亡而销毁

2.类方法(静态方法)

1.定义格式:访问修饰符 static 数据返回类型 方法名(){ }
2.调用方式:类名.类方法名或对象名.类方法名
3.案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Stu{
private String name;
private static double fee = 0;
public Stu(String name){
this.name=name;
}
//当方法使用了static修饰,那么它就是静态方法
//静态方法就可以访问静态属性/变量
public static void payFee(double fee){
Stu.fee+=fee;
}
public static void showFee(){
System.out.println(Stu.fee);
}
}

4.类方法使用细节:
1.类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区,类方法中无this的参数,普通方法中隐含着this的参数
2.类方法(静态方法)可以通过类名调用,也可以通过对象名调用
3.类方法中不允许使用对象有关的关键字,比如this和super……
5.类方法中只能访问静态变量或静态方法
6.普通成员方法既可以访问普通变量/方法,也可以访问静态变量/方法
小结:静态方法只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员必须遵守访问权限

3.代码块

1.理解:相当于对构造器的补充机制,可以做初始化操作
2.使用场景:多个构造器中都有重复的语句,可以放到构造器中
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Movie{
private String name;
private double price;
private String director;
}
//代码块
//1.下面的若干构造器都有相同的语句
//2.我们把相同的语句放到代码块中
//3.不管调用哪个构造器,创建对象,都会先调用代码块的内容
{
System.out.println("电影屏幕打开……");
System.out.println("广告开始……");
System.out.println("电影正式开始……");
}
public Movie(String name){
this.name=name;
}
public Movie(String name,double price){
......
}

注意事项:
1.static代码块也叫静态代码块,而且随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行。
2.类在什么时候被加载

1.创建对象实例时(new)
2.创建子类对象实例,父类也会被加载
3.使用类的静态成员时(静态属性,静态方法)
4.static代码块是类加载时,执行的,只会执行一次
5.普通代码块是在创建对象时调用的,创建一次,调用一次

调用顺序注意事项:

1.调用静态代码块和静态属性初始化(静态代码块和静态属性初始化调用的优先级一样,吐过有多个,则按照它们的定义顺序调用)
2.调用普通代码块和普通属性的初始化(优先级一样,按照定义顺序调用)
3.最后调用构造方法
4.构造器的前面隐含了super()和普通代码块,调用顺序为super()、普通代码块、构造器

子类继承关系代码块调用顺序:

1.父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
2.子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
3.父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
4.父类的构造方法
5.子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
6.子类的构造方法

4.final关键字

使用场景:

1.当不希望被继承时,可以用final修饰
2.当不希望父类的某个方法被子类覆盖/重写
3.当不希望类的某个属性值被修改可以用final修饰
4.当不希望某个局部变量被修改,可以用final修饰

赋值方式:

1.可以在定义时赋值
2.可以在构造器中赋值
3.可以在代码块中赋值

如果final修饰的属性是静态的,则初始化的位置只能是:

1.定义时
2.在静态代码块中,不能在构造器中赋值

5.抽象类

定义:当父类的某些方法,需要声明,但是有不确定如何实现,可以声明为抽象方法,那么这个类就是抽象类。所谓抽象方法就是没有实现的方法体,实现就是指,没有方法体
案例:

1
2
3
4
5
6
7
8
9
10
11
12
//关键字abstract修饰的类称为抽象类
abstract class A {
……
}
//例如:
public abstract class A{
String color;
String getColor(){//成员方法
return this.color;
}
public abstract double getArea();//抽象方法
}

抽象类细节:
1.抽象类不能实例化
2.抽象类不一定要包含abstract方法
3.一但包含了abstract方法,那么这个类必须声明为抽象类
4.abstract只能修饰类和方法
5.如果一个类继承了抽象类则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
6.抽象方法不能使用private final static 修饰,因为这些关键字都是和重写相违背的
例子2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
abstract class  VolumeArea{
abstract double volume(double r);
abstract double area(double r);
}
class VolumeAndArea extends VolumeArea {
double volume(double r) {
return 4/3*3.14*r*r*r;
}
double area (double r) {
return 3.14*r*r;
}
}
public class ktlx {
public static void main(String[]args) {
VolumeAndArea x = new VolumeAndArea();
System.out.println(x.area(2.5));
System.out.println(x.volume(2.5));
}
}

6.接口

定义:接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。
语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface 接口名{
//属性
public static final x = 0;
//方法
//在接口中,抽象方法可以省略abstract关键字
//方法体可以有实现方式,需要default关键字修饰
default public void ok(){
System.out.println("OKK");
}
//静态方法
public static void cry(){
System.out.println("cry....");
}
}
class 类名 implements 接口{
自己属性;
自己方法;
必须实现接口的抽象方法;
}

小结:Jdk8.0后接口类可以有静态方法、默认方法、也就是说接口中可以有方法的具体实现。
接口细节:
1.接口不能被实例化
2.接口中所有的方法是public方法
3.抽象类实现接口,可以不用实现接口的方法
4.一个类可以继承多个接口
5.接口中的属性只能是final的而且是public static final修饰符
6.接口中属性的访问形式:接口名.属性名
7.接口的修饰符只能是public和默认
8.当子类继承了父类,就自动拥有了父类的功能,如果子类需要扩展功能,可以通过实现接口的方式来扩展

7.接口的多态特性

1.多态参数
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
interface Usb{
public void start();
public void stop();
}
class Camera implements Usb{
public void start(){
System.out.println("我是相机,我开始工作");
}
public void stop(){
System.out.println("我是相机,我停止工作");
}
class Phone implements Usb{
public void start(){
System.out.println("我是手机,我开始工作");
}
public void stop(){
System.out.println("我是手机,我停止工作");
}
class Computer{
public void working(Usb usb){
usb.start();
usb.stop();
}
}
public class test{
public static void main(String[]args){
Camera c = new Camera();
Phone p = new Phone();
Computer c1 = new Computer();
c1.working(Phone);
}
}
}
}
//Usb usb形参是接口类型usb
//看到接收实现了usb接口的类的对象实例

2.多态数组
3.接口的多态传递

8.内部类

基本介绍:一个类的内部又完整的嵌套了另一个类结构,被嵌套的称为内部类,是我们类的五大成员(属性、方法、构造方法、代码块、内部类)
特点:可以直接访问私有属性并且可以体现类与类之间的包含关系
语法:

1
2
3
4
5
6
7
8
class Outer{  //外部类
class Inner{ //内部类

}
}
class Other{ //外部其他类

}

内部类的分类:
定义在外部类局部位置上(比如方法内):
1.局部内部类(有类名)
2.匿名内部类(没有类名,重点)
定义在外部类的成员位置上:
1.成员内部类(没用static修饰)
2.静态内部类(使用static修饰)

局部内部类的使用:
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
1.可以直接访问外部类的所有成员,包含私有的
2.不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰(加了就不能被继承)
3.作用域:仅仅在定义它的方法或代码块中
4.局部内部类访问外部类的成员访问方式是直接访问
5.外部类访问局部内部类的成员访问方式是:创建对象,再访问(注意,必须在作用域内)
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package jbnbl;

public class Test1 {
public static void main(String[]args) {
Other01 o1 = new Other01();
o1.say();
}
}
class Other01{ //外部类
private int i = 10;
private void m2() {
System.out.println("m2的私有方法");
}
public void say() { //方法
System.out.println("Say");
class inner01{ //内部类
public void f1() {
System.out.println(i);
m2();
}
}
//外部类访问内部类需要实例化对象再调用方法
inner01 i1 = new inner01();
i1.f1();
}
}

6.外部其他类不能访问局部内部类
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类型.this.成员)去访问

9.匿名内部类

说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
1.语法:

1
2
3
4
5
6
7
new 类或接口(参数列表){
类体
};
//1.本质是类
//2.内部类
//3.该类没有名字
//4.同时还是一个对象

2.实现案例(基于接口的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class test{
public static void main(String[]args){
Outher04 outher04 = new Outher04();
outher04.method();
}
}
class Outher04{
private int n1 = 10;
public void method(){
//需求:使用IA接口,并创建对象
//传统方式:写一个类,实现接口,并创建对象
//新需求:Tiger类只是使用一次,后面不再使用
//解决:可以使用匿名内部类来简化开发
//new 实现的接口名
IA tiger = new IA(){
public void cry(){
System.out.println("老虎叫唤");
}
};
tiger.cry();
}
}
interface IA{
public void cry();
}

3.实现案例(基于类的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class test2{
public static void main(String[]args){
Outher04 outher04 = new Outher04();
outher04.method();
}
}
class Outher04{
private int n1 = 10;
public void method(){
//演示基于类的匿名内部类
//1.father的编译类型为father
//2.father的运行类型为匿名内部类
Father father = new Father("jack"){
//匿名内部类可以直接访问外部类的所有成员,包含私有的
//外部其他类不能访问匿名内部类
//如果外部类和匿名内部类的成员重名时,内部类访问的话,默认遵守就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
//注意:jack参数列表会传递给构造器
//class 匿名内部类 extends father
public void test(){
System.out.println("匿名内部类重写了test方法");
}
};
father.test();
}
}
class Father{
public Father(String name){

}
public void test(){

}
}

匿名内部类实践:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
1.有一个铃声接口Bell,里面有一个ring方法
2.有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型
3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4.过匿名内部类(对象)作为参数,打印:小伙伴们上课了
*/
public class test3{
public static void main(String[]args){
Cellphone cellphone = new Cellphone();
cellphone.alarmclock(new Bell(){
public void ring(){
System.out.println("懒猪起床了");
}
});
cellphone.alarmclock(new Bell(){
public void ring(){
System.out.println("小伙伴们上课了");
}
});
}
}
interface Bell{
void ring();
}
class Cellphone{
public void alarmclock(Bell bell){
bell.ring();
}
}

10.成员内部类

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。

  1. 可以直接访问外部类的所有成员包含所有的
  2. 可以添加任意的访问修饰符因为它的地位就是一个成员
    例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class test3{
    public static void main(String[]args){
    Outher05 o5 = new Outher05();
    o5.t1();
    }
    }
    class Outher05{//外部类
    private int n = 10;
    public String name = "张三";
    //注意:成员内部类是定义在外部类的成员位置上
    class Innter05{//成员内部类
    public void say(){
    System.out.println{n+name};
    }
    }
    public void t1(){
    //使用成员内部类方法:
    Innter05 i5 = new Innter05();
    i5.say();
    }
    }
    细节:
  3. 作用域:和外部类的其他成员一样,为整个类体,比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。
  4. 成员内部类访问外部类是直接访问
  5. 外部类访问成员内部类访问方式是创建对象再访问
  6. 外部其他类使用成员内部类的三种方式
    案例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class test3{
    public static void main(String[]args){
    Outher05 o5 = new Outher05();
    o5.t1();
    //第一种方式:
    Outher05.Innter05 innter05 = Outer05.new Innter05();
    innter05.say();
    }
    }
    class Outher05{//外部类
    private int n = 10;
    public String name = "张三";
    class Innter05{//成员内部类
    public void say(){
    System.out.println{n+name};
    }
    }
    public void t1(){
    Innter05 i5 = new Innter05();
    i5.say();
    }
    }
  7. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类型.this.成员)去访问

    11.静态内部类

    说明:静态内部类是定义在外部类的成员位置,并且有static修饰
  8. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  9. 可以添加任意访问修饰符,因为它的地位就是一个成员
  10. 作用域:同其他的成员,为整个类体
  11. 外部类访问静态内部类访问方式为创建对象再访问
  12. 外部其他类访问静态内部类
    实现方法:
    1
    2
    Outher10.Inner10 inner10 = new Outher10.Inner10();
    inner10.say();
  13. 如果外部类和静态内部类的成员重名时,静态内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问。

7.类(静态)变量与类(静态)方法
http://example.com/2022/10/25/java/7.类变量与类方法/
作者
haozi0o0
发布于
2022年10月25日
许可协议