Day13 static-静态变量

一、static

1.关于JavaBean类中的成员变量

public class Student {
    private String name;
    private int age;
    private String gender;

    //新增老师姓名
    public static String teacherName;
}

==public static String teacherName;==表示Student类中的所有对象都共享teacherName。
关于调用:

Student.teacherName = "王一博";

2.概述

static表示静态,时Java中的一个修饰符,可以修饰成员方法,成员变量

(1)静态变量

被static修饰的成员变量,叫做静态变量
特点:被该类的所有对象共享
调用方式:类名调用(推荐),对象名调用

<1>static内存图
String name;
int age;
String gender;

    //新增老师姓名
public static String teacherName;
public void show(){
  System.out.println(name + ", " + age + ", " + gender
  									 + ", " + teacherName);
    }
public class studentTest {
    public static void main(String[] args) {
        Student.teacherName = "肖战";
        Student s1 = new Student();
        s1.name = "王一博";
        s1.age = 23;
        s1.show();

        Student s2 = new Student();
        s2.show();
    }
}

分析:
1)main()进栈, Student.teacherName = “肖战”;把Student类的字节码文件(.class文件)加载到方法区,然后堆内存中单独创建一个静态存储位置(静态区)(JDK8以后),默认初始化值null(目前再内存中没有对象—>静态变量时随着类的加载而加载的,优先于对象的出现);
2)Student s1 = new Student();栈内存定义s1,在堆内存中开辟空间,存储所有的非静态变量,返回地址值赋给s1;
3)s1.show();show方法进栈,通过s1,找到堆内存里的name,age,再去静态区找到teacherName;
4)创建s2(在堆内存里另开辟一段空间),通过s2,也可以找到静态区里的teacherName。

(2)静态方法

被static修饰的成员方法,叫做静态方法
特点:多用在测试类和工具类中,在JavaBean类中很少会用
调用方式:类名调用(推荐),对象名调用

<1>三种类

1)JavaBean类:用来描述一类事物的类,如:Student,Teacher等
2)测试类:用来检查其他的类是否书写正确,带有main方法的类,是程序的入口
3)工具类:帮助我们做一些事情,但不描述任何事物的类

<2>工具类遵循规则

1)见名知意
2)私有化构造方法
目的:不让外界创建它的对象

public class ArrUtil{
	private ArrUtil(){}
}

使用:定义学生工具类,获取集合中最大学生年龄

public class StudentUtil {
    private StudentUtil() {
    }

    //静态方法
    public static int getStudentAgeMax(ArrayList<Student> list) {
        //定义索引参照物
        int max = 0;
        //遍历集合
        for (int i = 1; i < list.size(); i++) {
            int tempAge = list.get(i).getAge();
            if (list.get(max).getAge() < tempAge) {
                max = i;
            }
        }
        return max;
    }
}

调用工具类:

//调用工具类中的方法
        int max = StudentUtil.getStudentAgeMax(list);

在工具类中的方法里,几个注意点:
—>使用索引参照,也可以直接默认集合中的第一个元素为初始最大值
—>使用tempAge,提高代码的复用性
—>循环从1开始,尽可能减少循环次数

3)方法都定义为静态

3.static的注意事项

(1)静态方法只能访问静态变量和静态方法
(2)非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法
(3)静态方法中没有this关键字
分析:

<1>代码角度

public class Student {
    String name;
    int age;
    //新增老师姓名
    public static String teacherName;
    public void show(){
        System.out.println(name + ", " + age + ", " + teacherName);
    }
    public static void methond(){
    	System.out.println("静态方法");
  }
public class studentTest {
    public static void main(String[] args) {
        Student.teacherName = "王一博";
        Student s1 = new Student();
        s1.name = "王二博";
        s1.age = 23;
        s1.show();

        Student s2 = new Student();
        s1.name = "王三博";
        s1.age = 22;
        s2.show();
    }
}

—>非静态方法中有this关键字,public void show(Student this)。在调用该方法时,不是手动赋值,由虚拟机进行赋值,this表示的是当前调用者的地址值第一次s1调用,把s1赋值给this,第二次调用,把s2赋值给this,起到区分成员变量的作用(this.name中的this省略不写)。在静态方法中没有this
非静态一般与对象有关,静态方法一般都是共享的,与某一对象没关系
—>静态不能访问非静态(成员变量,成员方法),成员变量和成员方法与对象相关
—>非静态访问所有,静态访问是可以用对象访问的,所以与对象相关的非静态是可以访问静态的

<2>内存角度

—>静态数据与非静态内存加载到内存的时机是不一样的,静态是随着类的加载而加载的,非静态是和对象有关的。当静态数据加载到内存中,而没有创建对象,此时是没有非静态的数据。静态之间是可以调用的,静态无法调用非静态。

public class studentTest {
    public static void main(String[] args) {
        Student.teacherName = "王一博";
        Student.method();
    }
}
public class Student {
    String name;
    int age;
    //新增老师姓名
    public static String teacherName;
     public void show(){
        show();//实际上报错
    }
    public static void method(){
        System.out.println(name + ", " + teacherName);//实际这里会报错
    }
  }

分析:
—>main方法进栈,Student.teacherName = “王一博”;Student类字节码文件加载到方法区,jdk7以后,静态区中存储静态变量。Student.method();找到方法区中的method()字节码文件,加载到栈内存中,获取两个变量name和teacherName,去静态区找这两个变量。而在静态区没有name(没有创建对象)。因为静态方法不能调用非静态变量
—>show()进栈,没有调用show的对象。

4.main方法

public:被JVM调用,访问权限足够大
static:被JVM调用,不用创建对象,直接类名访问。因为main方法是静态的,所以测试类中其他方法也需要是静态的
void:被JVM调用,不需要给JVM返回值
main:一个通用名称,不是关键字,但能被JVM识别
String[] args:以前用于接收键盘录入数据,现在没用。不是在控制台接收数据,在Run/Debug Configurations中Test里的Build and run里的数据

二、继承

封装—>对象
当JavaBean类越来越多,重复的成员变量,成员方法越来越多
例如:两个类Student和Teacher,他们都有成员变量name,age等,可以把这些重复的成员变量拿出来,封装成一个新的类Person

1.概述

Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系。

public class Student extends Person {};

Student成为子类(派生类),Person成为父类(基类或超类)

好处

1)可以把多个子类中重复的代码抽取到父类中,提高代码的复用性
2)子类可以在父类的基础上增加其他功能,使子类更加强大
什么时候用到继承
当类与类之间,存在相同的内容并满足子类是父类的一种,就可以考虑使用继承

2.特点

Java只支持单继承,不支持多继承,但支持多层继承
(1)单继承:一个子类只能继承一个父类
(2)多继承:一个子类不能继承多个父类
(3)多层继承:子类A可以继承父类B,父类B可以继承父类C(祖孙关系),C是A的间接父类
每一个类都直接或间接的继承于Object
分析共性和异性
画图:从下往上,下面是子类,上面是父类,把共性内容抽取到父类中
代码:从上往下
(4)子类只能继承父类中非私有的成员

3.子类到底能继承父类中的哪些内容

(1)两个误区

1)父类私有的东西,子类就无法继承
2)父类中非私有的成员,就被子类继承下来了

(2)内存图

能不能被子类继承(能继承,不一定能调用)

构造方法非私有 (不能)private(不能)
成员变量非私有(能)private(能)
成员方法非私有(能)private(不能)

所有成员变量都能继承下来,但不一定能用

1)构造方法

假设父类的构造方法能被继承,继承过去后,发现构造方法的名字与类的名字不一致,违背了构造方法名与类名一致的原则

2)成员变量

父类的private成员变量不能直接被子类使用
子类的对象在给变量赋值时,先查找堆内存中子类的地址空间,当找不到对应的成员变量时,再查找父类的。

public class Fu{
	private String name;
	private int age;
}
public class Zi extends FU{
	String game;
public class Demo03 {
    public static void main(String[] args) {
        Zi z = new Zi();
        System.out.println(z);
        z.name = "王一博";//实际上报错
        z.age = 23;//实际上报错
        z.game = "王者荣耀";
    }
}

分析:
<1>Zi z = new Zi();在堆内存中开辟空间并以分为二,分别存储父类成员变量和子类成员变量;返回地址值给z
<2>z.name = “王一博”;在堆内存找到z地址,先在子类成员变量中查找,是否有name。没找到,再从父类成员变量中找,发现name是一个私有变量,赋值失败。age同理

3)成员方法

A类—>B类—>C类
A怎么调用C的成员方法?
在顶级父类C里设计了一个虚方法表,把可能经常要用的方法,放在里面
虚方法表(满足:非private,非static,非final),C把虚方法表交给自己的子类B,B也有自己的虚方法表,它在C的虚方法表基础上加上自己类中的虚方法,A再继承B,同理A也有虚方法表,再B类基础上加上自己的。

A类先检查是不是虚方法,如果是,直接调用,如果不是,检查自己的成员方法,找到调用,否则回去父类的成员方法,确定是否为私有方法。

4.继承中的成员变量

特点

就近原则

public class Fu {
    String name = "Fu";
}
public class Zi extends Fu{
    String name = "Zi";
    public void ziShow(){
        String name = "ziShow";
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }

1)name—>局部位置找到name,输出 ziShow
2)this.name—>本类成员位置的name,既String name = “Zi”;故输出 Zi
3)super.name—>super表示父类,String name = “Fu”;输出 Fu
在子类中只能调用一次super

5.继承中的成员方法

(1)特点

直接调用满足就近原则
super调用,直接访问父类

(2)方法的重写

当父类的方法不能满足子类现在的需求,需要进行方法重写
1)书写格式:
在继承体系中,子类出现了和父类中一模一样的方法声明,就称子类这个
方法是重写的方法。
2)@override重写注解
<1>@override是放在重写后的方法上,校验子类重写时语法是否正确。

(3)方法重写的本质

在虚方法表进行添加时,在子类中发生了方法重写,子类中的方法会父类里面继承过来的方法覆盖

(4)方法重写注意事项和要求

1)重写方法的名称、形参列表必须与父类一致
2)子类重写父类方法时,访问权限子类必须大于等于父类
3)子类重写父类方法时,返回值类型子类必须小于等于父类
4)建议:重写方法尽量和父类保持一致
5)私有方法不能被重写
6)只有被添加到虚方法表里的方法才能被重写

6.继承中的构造方法

(1)特点

1)父类中的构造方法不会被子类继承
2)子类中所有构造方法默认先访问父类中的无参构造,再执行自己
为什么?
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类数据
子类在初始化之前,一定要先调用父类构造方法先完成父类数据空间的初始化

(2)怎么调用父类构造方法

1)子类构造方法的第一行语句默认都是:super()(调用父类的无参构造),不写也存在,且必须在第一行
2)如果想要调用父类的有参构造,必须手动写super进行调用
eg:super(name,age);直接传递变量

在这里插入图片描述

7.this,super总结

this:理解为一个变量,表示当前方法调用着的地址值
super:代表父类存储空间
关于使用
this(…) – 调用本类的其他构造方法
eg:需求:默认对象是王一博
可以在空参构造里写:

public Studnt(){//空参构造
	this(null,0,"王一博");//如果有其他有效语句,必须写在this()的下面
}//细节:虚拟机不会添加super()

8.继承父类后

public class Buyer extends AdminStaff{
    public Buyer() {
    }

    public Buyer(String name, String id) {
        super(name, id);
    }

    @Override
    public void work(){
        System.out.println("采购专员正在采购!");
    }
}

(1)子类私有成员变量
(2)空参构造方法
(3)带参构造方法(super)
(4)方法重写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Heliotrope&G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值