Java——三个关键字 static this final

 static关键字

在Java中,static是一个关键字,用于修饰类的成员(变量、方法等)。静态成员属于类本身而不是类的实例,这意味着每个类都有唯一的静态变量副本,所有该类的对象共享这个副本,而不论创建了多少个对象。

有static修饰的代码和没有static修饰的代码的区别:

有static修饰的代码属于类,没有static修饰的代码属于对象

属于类的东西是被所有对象所共享的

初始static关键字

e88bf2c53540440e8fd0c23748237c00.png

代码:

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类

public class Person {
    public String name ="张三";
    public static string address ="保定";
    public static void run(string num){
        System.out.println("跑了====》"+num+"米");
     }
 }

拿上面的图片来举例子:

右侧代码写入了一个Person类,而该类中的adress是static类型的,所以adress和其他的存储变量在存储空间上是有所区别的。

对象的创建:

下图是对象创建的时候,流程图是一个怎样的过程。因为有static修饰的adress是属于类的,所以在方法区中有一个静态常量池,这里面是专门存储静态内容的。随着对象的创建,编译器会分配空间并初始化变量。但因为adress是属于类的,所以无论是实例化对象p1或是p2中的哪一个,他们都是静态常量池中的那个adress,所以上面那个代码最终两个对象的adress都是上海。

dbf470527f1f46d6baa9f575741e2452.png

这里还需要注意的是,代码是按照顺序执行的,如果将p1的打印放在生成p2之前,打印的结果是有所不同的。

static修饰不同的区别

修饰变量:

成为类变量,被所有该类产生的对象所共享的

修饰方法:

成为静态方法

静态方法和非静态方法

静态方法能够直接被类使用,非静态方法不能被main方法所使用

static修饰的方法才能够调用static方法,而main方法是一种静态方法

修饰代码块:

static修饰的代码块在程序运行之前执行,其目的是优化

6694882f8efc4f88be23437b0b2c60de.png

e5565629484f4e4fbb1ce919d2d0c1f7.png

执行顺序

拿一个案例来举例:

public class Test extends Base {
    public Test() {
        System.out.println("test constructor");
    }
 
    public static void main(String[] args) {
        new Test();
    }
 
    //static修饰的代码块在ma1n方法执行之前执行,其目的是修饰main方法.
    static {
        System.out.println("test static");
    }
}
class Base {
    static {
        System.out.println("base static");
    }
 
    public Base() {
        System.out.println("base constructor");
    }
}

运行结果:

原理:

 在程序运行过程中,先是扫描.java文件并生成.class,此时main函数提供入口,从这里进入,但当所要进入放入的类有父类的时候,程序先是去扫描父类并生成对应的.class文件,所以在该程序中,先运行父类代码块,输出base static。

        父类完毕后接着是子类,运行子类代码块,输出test static。

        随后在编译完毕后,进入main函数,new Test();提供构造器,运行构造函数,同样也是按照先父类后子类的顺序所以先后输出base constructor和 test constructor。

流程图如下:

易错点:

static不能修饰局部变量

例题:1.如何代码输出的结果是什么?(D )
   

 public class Test {
        public int aMethod( ) {
            static int i = 0;
            i++;
            return i;
        }
        public static void main (String args[]) {
            Test test = new Test();
            test.aMethod();
            int j = test.aMethod();
            System.out.println(j);
        }
    }


A. 0 B. 1 C. 2 D.编译失败
 

static不能用于直接声明类

static class MyClass { // 注意:这是错误的,static不能用于直接声明类  
    int myVariable = 10;  
    void myMethod() {  
        System.out.println("Hello");  
    }  
}


 

static代码块只能执行一次,下面再new对象的时候就和这个代码块没有关系,不会执行了

特性

static修饰符具有如下特性:

● 被static修饰的属性(成员变量)称为静态变量,也叫做类变量;

● 被static修饰的常量称为静态常量;

● 被static修饰的方法称为静态方法,也叫做类方法;

● 被static修饰的代码块叫做静态代码块;

● 被static修饰符的内部类,叫做静态内部类。

紧接上文对static做出小结

static关键字小结:

是什么?

static所修饰的代码属于类,所定义的变量存储在静态常量池中

为什么?

static之所以被设置,是为了方便类能够直接去使用自己的方法和变量

对象:对象是堆里面的一块内存空间

类中的代码以信息的形式存储在方法区当中

对于static方法,建议最好是用类去调用。对象是可以使用类的信息的,所以也可以用对象去调用

举例分析:
1.

A类:
public class A {
    public static String name = "admin";

    public static void run() {
        System.out.println("跑的很快");
    }

    public static void flay() {
        System.out.println("飞的很高");
    }

}
Test类:
public class Test {
    public static void main(String[] args) {
        A a=new A();
        a.run();
        a.flay();
        a.name="ss";
        
        A.name="xx";
        A.run();
        A.flay();
    }
}
运行结果:

2.
A类
public class A {

    public static String name="admin";
    public String address="保定";

    public String toString(){
        return  "A{"+
                "address='"+address+'\'' +
                "address='"+address+'\'' +
                '}'
                ;
    }

}
 Test类
public class Test {
    public static void main(String[] args) {
        A a1=new A();
        A a2=new A();
        a1.address="北京";
        a1.name="aaaaaaaaaa";
        a2.address="上海";
        a2.name="cccccccccc";
        System.out.println(a1.toString());
        System.out.println(a2.toString());
    }
}
运行结果:

 

方法

非静态方法可以调用静态方法,静态方法不可以调用非静态方法。

问题:

如何解决非静态方法不能被静态方法调用的问题?

1.将非静态方法改为静态方法

2.用创建对象的方式去调用

public class A {

    public static String name="admin";
    public String address="保定";
    
    public String toString(){
        return  "A{"+
                "address='"+address+'\'' +
                "name='"+name+'\'' +
                '}'
                ;
    }
    
    public static void aaa(){
        
    }
    public void bbb(){

    }
    public static void main(String[] args) {
        //将非静态的aaa方法修改成静态的
        aaa();
        //生成对象,用对象区调用
        A p=new A();
        p.bbb();
    }
    

}
为什么非静态方法可以调用静态方法?

非静态方法的使用必须要创建对象,而有对象一定是有类的

运行分析(难点):

代码1

public class Demo {
    public Demo(String aa) {
        System.out.println("====" + aa);
    }

    static {
        System.out.println("11");
    }

    public static Demo demo = new Demo("+++");

    static {
        System.out.println("22");
    }
}
class Test{
    public static void main(String[] args){
        Demo demo = new Demo( "----");
    }
}

运行分析:

1.main方法在哪里我们就先去扫描那个类----》首先去扫描Test类,发现没有父类,也没有static修饰的代码,那么编译Test类,并且将main方法入栈

2.执行new Demo("----");在执行之前扫描Demo类,发现没有父类,所以编译Demo类,在编译的过程中static代码块按顺序优先执行 

3.首先输出的是11

4.执行 public static Demo demo = new Demo("+++");此时会涉及到调用Demo构造方法,所以输出 ===+++

5.输出 22

6.编译完毕,回到main方法当中继续执行new Demo("----");现在可以创建对象了!!也就是进行到了运行阶段

7.通过调佣构造器创建对象:===

运行结果:

 关键字this

一、基本概念

在 Java 中,“this” 是一个关键字,它代表当前对象的引用。可以在类的方法中使用 “this” 来引用当前正在调用该方法的对象。

 二、为什么可以代表当前对象的引用?

this.属性

class Person {
    public String name;

    public void run(int name) {
        this.name= name;//this.变量
    }
}

我们在主方法中这样写道:

Person p1 = new Person();
p1.run("aaa");


Person p2 = new Person();
p2.run("bbb");

 这里的this.name相当于指向了实例对象中的变量name,和在局部函数中的参数是两回事。

this.方法

易错点:

static修饰的方法中不能出现this关键字,因为类是构建对象的模板,有类不一定有对象

static修饰的代码被所有的对象共享,所以this可以调用static方法

this()  //了解

①thisO)不能在普通方法中使用,只能在构造方法中使用

②this()在构造方法中使用必须是第一条语句

③在一个类下两个构造方法中不能通过this()相互调用

④不能与super()同时使用

二、主要用途

1.区分成员变量和局部变量

当方法的参数或局部变量与类的成员变量同名时,可以使用 “this” 来明确引用成员变量。例如:

class Person {
    private int age;

    public void setAge(int age) {
        this.age = age;
    }
}

  • 在上述例子中,参数 “age” 与成员变量 “age” 同名,“this.age” 明确表示引用的是成员变量,而不是局部变量。

2.调用构造方法

在一个构造方法中可以使用 “this” 来调用同一类中的其他构造方法,以实现代码的复用和减少重复。例如:

class Person {
    private int age;
    private String name;

    public Person() {
        this(0, "Unknown");
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

  • 在无参构造方法中,使用 “this (0, "Unknown")” 调用了有参构造方法,初始化了成员变量。

3.作为方法的返回值

“this” 可以作为方法的返回值,返回当前对象的引用,使得可以在方法调用链中连续调用多个方法。例如:

class Person {
    private int age;
    private String name;

    public Person setAge(int age) {
        this.age = age;
        return this;
    }

    public Person setName(String name) {
        this.name = name;
        return this;
    }
}
  • 可以这样使用:Person person = new Person().setAge(20).setName("Tom");

三、注意事项

  1. “this” 只能在非静态方法中使用,因为静态方法是属于类的,而不是属于特定的对象。
  2. 在构造方法中调用其他构造方法时,“this” 语句必须放在构造方法的第一行。

关键字 final

一、概述

在 Java 中,final关键字用于限制变量、方法和类的行为。它表示不可改变或最终的状态。

二、作用于变量

final所修饰的变量叫做常量(常量是只能赋值一次的变量)

public class Test01 {
    public static void main(String[] args) {
        final int NUM= 10;
        // NUM= 20; // 会报错,因为 final 变量不能被重新赋值。
        System.out.println("Final variable num: " + num);
    }
}

注意:常量的变量名要大写

按照作用域区分:

        1.全局变量:final修饰的全局变量必须赋值(因为final只能赋值一次

         2.局部变量:

按照类型区分:      

  1. 1基本类型变量
    • 当用final修饰基本类型变量时,该变量一旦被初始化,其值就不能再被改变。
    • 例如:final int num = 10;,之后任何试图改变num值的操作都会导致编译错误。
public class FinalPrimitiveExample {
    public static void main(String[] args) {
        final int num = 10;
        // num = 20; // 编译错误,不能重新赋值
        System.out.println("Final primitive variable: " + num);
    }
}
  1. 2.引用类型变量
    • 对于引用类型变量,final表示该引用不能再指向其他对象。但被引用的对象本身的内容是可以改变的。
    •  例如:final List<Integer> list = new ArrayList<>();,不能再将list指向另一个新的集合对象,但可以对list中的元素进行添加、删除或修改操作。



public class Test{
    public static void main(String[] args) {
        
        final int[] arr1 = new int[]{1,2,3};
        final int[] arr2 = new int[]{12,22,32};
        final int a = 10;
        public void fun(){
            a=11;//error
        }
        public void changge(){
            arr1=arr2;//error
        }


    }
}

三、作用于方法

class Test02 {
    final void finalMethod() {
        System.out.println("This is a final method and cannot be overridden.");
    }
}

class SubClass extends Test02 {
    // 不能重写父类的 final 方法
    // void finalMethod() {}
}

  1. 当一个方法被声明为final时,这个方法不能在子类中被重写。
    • 这可以确保该方法在继承体系中的行为是固定的,不会被意外修改。
    • 例如:class Parent { final void method() { // 方法体 } },如果有一个子类Child试图重写method方法,会导致编译错误。

四、作用于类

final class Test03{
    public void display() {
        System.out.println("This is a final class.");
    }
}

// class SubFinalClass extends Test03{} // 会报错,因为 final 类不能被继承。

  1. 当一个类被声明为final时,这个类不能被继承。
    • 这可以确保该类的实现是完整的,不会被其他类修改或扩展。
    • 例如:final class FinalClass { // 类的成员 },任何尝试继承FinalClass的类都会导致编译错误。

五、优点

  1. 安全性
    • 确保变量的值或方法的行为不会被意外改变,增强了程序的安全性和稳定性。
  2. 性能优化
    • 在某些情况下,编译器可以进行优化,因为它知道被final修饰的内容是不可变的。

六、注意事项

  1. 谨慎使用
    • 过度使用final可能会导致代码灵活性降低,在设计时需要权衡可维护性和安全性。
  2. 理解引用类型的限制
    • 对于final引用类型变量,要清楚只是引用不能改变,而被引用对象的内容可能是可变的。

七、同样是不可修改,final关键字和private看似有些相似,他们又有什么区别?

一、作用对象不同

  1. final

    • 可以修饰变量、方法和类。
    • 修饰变量时表示变量的值不可改变;修饰方法时表示该方法不能被重写;修饰类时表示该类不能被继承。
  2. private

    • 主要用于修饰成员变量、成员方法和内部类。
    • 表示被修饰的成员只能在当前类中被访问,对其他类不可见。

二、限制范围不同

  1. final

    • 限制的是可变性和可继承性等方面的行为。
    • 对于变量,限制了其值的更改;对于方法,限制了其在子类中的重写;对于类,限制了其被继承。
  2. private

    • 主要限制的是访问权限。
    • 确保被修饰的成员只能在定义它们的类内部使用,外部类无法直接访问。

三、继承和重写方面

  1. final

    • 阻止方法被重写和类被继承。
    • 如果一个方法被声明为final,子类不能重写该方法;如果一个类被声明为final,则不能有子类。
  2. private

    • private方法不能被重写,因为它们在子类中不可见。但是,这并不是因为明确禁止重写,而是由于访问限制导致的。同时,private修饰的类成员不会影响类的继承关系,子类可以继承父类中private修饰的成员变量和方法,只是不能直接访问。

四、使用场景不同

  1. final

    • 当你希望确保某个变量的值在初始化后不再改变,或者某个方法的行为在子类中不被修改,或者一个类不应该有子类时,可以使用final
    • 例如,在定义常量时可以使用final修饰变量。
  2. private

    • 当你希望隐藏类的实现细节,只暴露必要的公共接口时,可以使用private修饰成员变量和方法。
    • 比如,一些内部的辅助方法或者不希望被外部类直接访问的变量可以使用private修饰。

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值