美文网首页
Java的static关键字

Java的static关键字

作者: Atomic | 来源:发表于2023-08-10 11:43 被阅读0次

Java关键字是什么?

摘自百度百科

Java关键字是电脑语言里事先定义的,有特别意义的标识符,有时又叫保留字,还有特别意义的变量。Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名、方法名、类名、包名和参数。

常用的关键字如下图


Java关键字.png

针对于上述关键字,我们抽出几个比较重要的来唠唠

修饰字符类型关键字

static

在Java中,static表示“静态的”,它也是一种修饰符,可以修饰属性、方法、代码块和内部类。
一般情况下,static修饰的变量,方法,代码块。都跟随类的生命周期,它们所属的JVM内存也都是处于共享内存

变量:

静态变量(或称为类变量),指被 static 修饰的成员变量;类的静态变量在内存中只有一个,Java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名被访问。静态变量的生命周期取决于类的生命周期,当加载类的时候,静态变量被创建并分配内存,当卸载类的时候,静态变量被销毁并撤销内存。
实例变量,指没有被 static 修饰的成员变量;类的每个实例都有相应的实例变量。每创建一个类的实例,Java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中。实例变量的生命周期取决于实例的生命周期,当创建实例的时候,实例变量被创建并分配内存,当销毁实例的时候,实例变量被销毁并撤销内存。
局部变量,指的是在一个方法的内部或者方法的一个代码块中声明的变量,前者的作用域就是整个方法,后者的作用域则是这个代码块(代码块就是{}以内的代码)

class Person() {
  private String name; // 实例变量
  private Integer age; // 实例变量
  private static String country = "China"; // 静态变量

  public person(String name, Integer age) {
    this.name = name;
    this.age = age;
  }
}

当我们使用这个类创建实例的时候

  public static void main(String[] args) {
    Person p1 = new Person("zhangfei", 30);
    Person p2 = new Person("guanyu", 35);
    
    System.out.println(p1.name);
    System.out.println(Person.country);
  }

内存分配如下:


Java_static内存分配.jpg
方法:
  • 静态方法是使用 static 关键字修饰的成员方法,它属于类,而不是类的实例。
  • 静态方法可以直接通过类名来调用,也可以通过类的对象来调用,但一般推荐使用类名来调用。
  • 静态方法只能访问类的静态变量和静态方法,不能访问类的实例变量和实例方法,也不能使用 this 关键字。
  • 静态方法通常是一些工具方法,不需要依赖于对象的状态,例如 Collections 类、Math 类等都包含了很多静态方法。
# 接上面的Person类
class Person() {
  ……

  public String printName() {
    System.out.println(this.name);
  }

  public static printCountry() {
    System.out.println(Person.country);
  }
  
}

实际调用

  public static void main(String[] args) {
    Person p1 = new Person("zhangfei", 30);
    Person p2 = new Person("guanyu", 35);
    
    p1.printName();
    Person.printCountry(); // 使用类名调用
    p1.printName(); // 使用对象调用,推荐使用类名调用
  }
代码块:

静态代码块,在Java类中,使用一对大括号包围起来的若干行代码被称为一个代码块,用static关键字修饰的代码块称为静态代码块。
当类被加载时,静态代码块会执行,由于类只加载一次,所以静态代码块只会执行一次。在程序中,通常会使用静态代码块来对类的成员变量进行初始化

# 接上面的Person类
class Person() {
  static{
    System.out.println("开始加载类,执行静态代码块");
  }
}

构造代码块
java类中使用{}声明的代码块(和静态代码块的区别是少了static关键字)

# 接上面的Person类
class Person() {
  {
    System.out.println("开始加载类,执行构造代码块");
  }
}

这里要梳理清楚执行顺序

静态代码块>构造代码块>构造函数>普通代码块

我们可以实际模拟运行一下

public class codeBlock {
    static {
        System.out.println("静态代码块");
    }
    {
        System.out.println("构造代码块");
    }
    public codeBlock(){
        System.out.println("无参构造函数");
    }
    public void sayHello(){
        System.out.println("普通代码块");
    }

    public static void main(String[] args) {
        System.out.println("执行了main方法");
        new codeBlock().sayHello();
        System.out.println("---------------------------");
    }
}

执行结果如下:

静态代码块
执行了main方法
构造代码块
无参构造函数
普通代码块
---------------------------

嵌套类

嵌套类又成为内部类,内部类就是一个定义在一个类里面的类,里面的类可以理解为(寄生),外部类可以理解成(宿主)
分为静态内部类和非静态内部类;

  • 静态内部类是指被声明为static的内部类,
  • 非静态内部类是指没有被声明为static的内部类

实例化:静态内部类的实例化不依赖于外部类的实例,可以直接通过类名访问;而非静态内部类的实例化必须依赖于外部类的实例,只能在外部类的实例方法中创建。
关系:静态内部类与外部类没有任何联系,只是被包含在外部类中;而非静态内部类可以访问外部类的成员和方法,并且可以使用外部类的引用来访问外部类的成员。

静态内部类不需要依赖外部类的实例而可以被实例化。静态内部类通常用于封装与外部类紧密相关的一组静态方法或常量

public class OuterClass {
    public static class InnerClass {
        // 静态内部类中可以定义一组静态方法或常量
        public static final int MAX_VALUE = 100;
        public static int add(int x, int y) {
            return x + y;
        }
    }
}
public class OuterClass {
    private int outerVar;
    
    public OuterClass(int outerVar) {
        this.outerVar = outerVar;
    }
    
    public void outerMethod() {
        int localVar = 10;
        // 非静态内部类
        class InnerClass {
            public void innerMethod() {
                System.out.println(outerVar); // 访问外部类的实例变量
                System.out.println(localVar); // 访问局部变量
            }
        }
        
        InnerClass inner = new InnerClass();
        inner.innerMethod();
        
        // 静态内部类
        static class StaticInnerClass {
            public static final int MAX_VALUE = 100;
            public static void staticInnerMethod() {
                System.out.println("This is a static inner class.");
            }
        }
        
        StaticInnerClass staticInner = new StaticInnerClass();
        staticInner.staticInnerMethod();
    }
}

非静态内部类:InnerClass可以访问外部类的实例变量outerVar和局部变量localVar,因此适合在需要访问外部类实例的情况下使用**,例如实现一个事件监听器。

Outer.Inner in = new Outer().new.Inner()

静态内部类:StaticInnerClass没有访问外部类实例的需求,只需要实现一些独立的功能,因此适合在不需要访问外部类实例的情况下使用,例如实现一个工具类。同时,静态内部类的实例化不依赖于外部类的实例,可以直接通过类名访问,使用起来更加方便。和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已

Outer.Inner in = new Outer.Inner();

一道有意思的面试题

class People() {
  private int heartbeat = 150;
  public class Heart {
    private int heartbeat = 110;
    public void show() {
      int heartbeat = 80;
      System.out.println(heartbeat);//80
      System.out.println(this.heartbeat);//110
      System.out.println(People.this.heartbeat);//150
    }
  }

  public static void main(String[] args) {
    new People().new Heart().show();
  }
}

输出结果

80
110
150

匿名内部类(重要)
匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,那么你就可以使用匿名内部类
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口

匿名类是不能有名字的类,它们不能被引用,只能在创建时用New语句来声明它们。
匿名类的声明是在编译时进行的,实例化在运行时进行,这意味着for循环中的一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。

为什么在Java中需要内部类?
我们先看一下不使用匿名内部类来实现抽象方法的时候

abstract class Person {
    public abstract void eat();
}
 
class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用
但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类

引入匿名内部类之后

abstract class Person {
    public abstract void eat();
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

可以看到,我们直接将抽象类Person中的方法在大括号中实现了
这样便可以省略一个类的书写,并且,匿名内部类还能用于接口上

interface Person {
    public void eat();
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现
最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口

Thread类的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

Runnable接口的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

这篇文章介绍匿名内部类使用场景,比较通俗易懂。java匿名内部类总结

匿名内部类总结:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

相关文章

  • Java基础系列-static关键字

    原创文章,转载请标注出处:《Java基础系列-static关键字》 一、概述 static关键字是Java诸多关键...

  • Static关键字

    C语言中的static关键字和Java的static关键字意义不一样。 1 用static修饰函数 static用...

  • 1.3 static 关键字

    static 关键字 《Java编程思想》 中:static方法就是没有this的方法 static 修饰的方法或...

  • Java 面向对象2

    Java 面向对象 1. static 和 final static关键字---修饰成员变量 用static修饰的...

  • Java static关键字

    声明static属性 static是Java中定义的一个关键字,主要是描述全局的概念,所以利用static关键字可...

  • 代码查错

    Something1.java 5。 static关键字 static修饰成员变量 用static修饰的成员变量不...

  • java面试问题总结与分享,很乱

    java中static关键字的作用 在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员...

  • Java static关键字

    Java之美[从菜鸟到高手演变]之Java中static关键字

  • Java Static 用法

    Java中的Static关键字用的很多,但是总结起来,大概有:Static member、Static Block...

  • 《九》、static关键字及代码块

    一、static关键字    static关键字在Java程序开发过程之中主要进行属性和方法的定义。 1、stat...

网友评论

      本文标题:Java的static关键字

      本文链接:https://www.haomeiwen.com/subject/zloopdtx.html