文章目录
static关键字
2024/8/21记
2024/8/21下午课
1.static关键字
static修饰符修饰的代码属于类代码
(对所有对象共享)
没有用static修饰符修饰的代码属于对象
public class Person {
private int age;
private String name;
private char sex;
public void run(){
System.out.println("人走路");
}
public void fly(){
System.out.println("人不会飞");
}
public static void main(String[] args) {
}
}
你可能会觉得:run(),fly()这样的方法也都是在类里面的,为什么说它是属于对象。
它们也属于类,但严格来说,他们是对象所拥有的。
2.代码举例(好例子,易错,便于理解)——static修饰变量
static修饰变量
Person类
public class Person {
public String name="张三";
public static String address="保定";
public String toString(){
return "Person{"+"name='"+name+'\''+
"address='"+address+'\''+
'}';
}
}
Test类(测试类,无实际意义,测试用)
public class Test{
public static void main(String[]args){
Person p1=new Person();
Person p2=new Person();
p1.name = "李四";
p1.address="北京";
p2.name = "王五";
p2.address="上海";
System.out.println(p1.toString());
System.out.println(p2.toString());
}
}
你可能想到的结果:
Person{name='李四’address=‘北京’}
Person{name='王五’address=‘上海’}
实际上:
Person{name='李四’address=‘上海’}
Person{name='王五’address=‘上海’}
3.画图解释
用代码流程图解释(堆栈图):
类信息存储在方法区里面。
方法区里面有个专门的区域叫:静态常量池。静态常量池里面存储的是static所修饰的代码。
步骤一
步骤二
步骤三
所以,最后输出结果是:
Person{name='李四’address=‘上海’}
Person{name='王五’address=‘上海’}
由此也可以看出,static修饰的变量被所有类共享的
4.代码举例:加深理解——static修饰方法
static修饰方法
Person类
public class Person {
public String name="张三";
public static String address="保定";
public String toString(){
return "Person{"+"name='"+name+'\''+
"address='"+address+'\''+
'}';
}
public static void run(String num){
System.out.println("跑了"+num+"米");
}
}
Test类(测试类,无实际意义,测试用)
public class Test{
public static void main(String[]args){
Person p1=new Person();
Person p2=new Person();
p1.name = "李四";
p1.address="北京";
p2.name = "王五";
p2.address="上海";
System.out.println(p1.toString());
System.out.println(p2.toString());
p1.run("100");
p2.run("200");
}
}
实际上结果:
Person{name='李四’address=‘上海’}
Person{name='王五’address=‘上海’}
跑了100米
跑了200米
5.画图解释
1、p1调用run()方法
2、run()方法入栈
3、 执行函数:跑了100米 (因为传参就是传的100)
4、 run()方法出栈
同理:
1、p2调用run()方法
2、run()方法入栈
3、 执行函数:跑了200米 (因为传参就是传的200)
4、 run()方法出栈
静态变量是类共享的,静态方法也是类共享的
都是共享的。
但是对于变量来说,它相当于一块内存空间。只要一变,就都变了。
对于方法来说,谁调用就是谁的。相当于工具。会进行入栈出栈的使用。
6.总结
static修饰的代码块是属于类的。
属于类的东西是被所有对象共享的。
为什么是共享的?
因为类是创建对象的模板。
类可以生成很多对象。
类里面的东西是被对象共享的。
1.static修饰变量
static修饰符修饰的变量叫做类变量。
被 所有 该类所产生的对象 所共享。
2. static修饰方法
方法分为静态方法和非静态方法。
static修饰的方法属于静态方法。
静态方法能直接被main方法使用
非静态方法不能直接被静态方法所使用
静态方法只能被静态方法所调用
main方法本身属于静态方法。
static修饰的方法才能调用static修饰的方法
3. static修饰代码块
static修饰的代码块在main方法之前运行。
作用是:优化程序
程序执行第一步:main方法入栈
main方法入栈之前:static修饰的代码块在main方法之前运行,其目的是优化程序。(无论static修饰的代码块放在哪里)
复习一:由此引出复习static修饰代码块相关知识点:static在main方法入栈之前执行的过程
(很全面,知识点+代码+顺一遍流程,不用翻看前面笔记,直接在这里回顾就行)
步骤一
public class Test extends Base{
static {
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
程序执行先去找main()方法启动程序
先扫描再编译
1.首先 先去扫描Test类,发现Test类有父类Base类,先去扫描父类,发现Base类没有父类
2.将Base.class加载进方法区,此时Base类当中的static代码块执行
3.将Test.class加载进方法区(只有.class文件才能进方法区),此时Test类当中的static代码块执行
(static在main方法入栈之前执行)
4.main方法入栈——》执行new Test();去创建Test类的对象
5.创建子类对象之前先创建父类对象,所以先执行Base()构造器,再执行Test()构造器
步骤二,变形,加深理解。
public class Test extends Base{
static {
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
public static void main(String[] args) {
new Test();
}
}
程序执行先去找main()方法启动程序
先扫描再编译
1.首先 先去扫描Base类,发现Base类没有父类
2.将Base.class加载进方法区,此时Base类当中的static代码块执行(输出1)
3.main方法入栈——》执行new Test();去创建Test类的对象
4.扫描Test类时,发现Test类有父类Base。但Base类已经加载过了,不会重复加载。
5.将Test.class加载进方法区,此时Test类当中的static代码块执行(输出二)
6.创建子类对象之前先创建父类对象,所以先执行Base()构造器,再执行Test()构造器
(static在main方法入栈之前执行)
步骤三,复习的时候:自己一边顺一遍,一边大致画一下流程图+看笔记。自己画一遍!然后别放到笔记里了。反复画就行。如图:
①
②
复习二:方法的重写
用流程图理解大致的流程就行。复习的时候自己画。
步骤一
A类
public class A {
public void run(){
System.out.println("跑得快");
}
public void fly(){
System.out.println("飞得高");
}
}
B类
public class B extends A{
}
}
测试类1
public class Test {
public static void main(String[] args) {
B b=new B();
b.run();
b.fly();
}
}
结果:
跑得快
飞得高
流程图
一、
main方法入栈
创建B对象——》在创建B对象的时候,优先创建父类A的对象
堆用来存储对象
对象是堆里面的一块空间
因为继承关系,所以B可以使用A中的代码
a对象里面有run(),fly()方法。
所以b对象也可以调用run(),fly()方法。
步骤二
A类
public class A {
public void run(){
System.out.println("跑得快");
}
public void fly(){
System.out.println("飞得高");
}
}
B类2
public class B extends A{
public void run(){
System.out.println("B跑得快");
}
}
测试类2
public class Test {
public static void main(String[] args) {
B b=new B();
b.run();
b.fly();
}
}
流程图
二、
当子类重写父类的方法时:
由于继承关系,b可以使用a的代码,
当b有了自己的run()方法后,
父类对象当中的方法被覆盖,
也就是不再能访问到。
步骤三
A类
public class A {
public void run(){
System.out.println("跑得快");
}
public void fly(){
System.out.println("飞得高");
}
}
B类
public class B extends A{
public void run(){
System.out.println("B跑得快");
}
}
测试类3
public class Test {
public static void main(String[] args) {
B b=new B();
b.run();
b.fly();
A a =new A();
a.run();
}
}
流程图
三、
此时执行的是A中的run()
new关键字:在堆里面开辟新的内存空间
新的空间里面有A的run(),A的fly()方法。
类是构建对象的方法,类里面有什么,对象里面就有什么。
没有子类,所以没有重写,所以就是自己类里面的方法。
需要反复强调的知识点(记住)
- 类:类是创建对象的模板
- 栈:调用方法时,方法的入栈出栈
- 堆:new对象和数组时,在堆中开辟空间,分配内存空间
- 方法区:存储类的信息
- 构造方法作用:在创建对象时,给对象初始化
- 构造方法特点:
1.构造方法名与类名相同
2.无返回值类型
3.系统编译器提供一个默认的无参构造器
4.一旦定义了至少一个构造方法,java编译器不会再提供默认的构造器
5.在创建对象时,提供new自动调用
6.可以有参数,参数可以是任何类型