static,this,静态代码块,实例代码块


static,this,静态代码块,实例代码块

static

1.static

  • static翻译为“静态的”

  • 所有static关键字修饰的都是类相关的,类级别的。

  • 所有static修饰的,都是采用“类名.”的方式访问。

  • static修饰的变量:静态变量

  • static修饰的方法:静态方法

 

2.变量的分类:

变量根据声明的位置进行划分:

  1. 在方法体中声明的变量叫做:局部变量。

  2. 在方法体外声明的变量叫做:成员变量。

其中成员变量又可以分为:

  1. 实例变量

  2. 静态变量

eg1.

以下实例的,都是对象相关的,访问时采用 “引用.” 的方式访问。需要先new对象。

实例相关的,必须先有对象,才能访问,否则可能会出现空指针异常。

 class Test{
  // 成员变量中的实例变量
  int i;
 ?
  // 实例方法
  public void m2(){
  // 局部变量
  int x = 200;
 }

 

eg2.

以下静态的,都是类相关的,访问时采用 “类名.” 的方式访问。不需要new对象。

不需要对象的参与即可访问。没有空指针异常的发生。

 class Test{
 ?
  // 成员变量中的静态变量
  static int k;
 ?
  // 静态方法
  public static void m1(){
  // 局部变量
  int m = 100;}
 }
 ?
 

 

3.什么时候变量声明为实例的,什么时候声明为静态的?

  • 如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费内存空间。

  • 建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。

 

  • 一个对象一份的是实例变量。

  • 所有对象一份的是静态变量。

eg.

 class Chinese{
  // 身份证号
  // 每一个人的身份证号不同,所以身份证号应该是实例变量,一个对象一份。
  String idCard;  
 ?
  // 姓名
  // 姓名也是一个人一个姓名,姓名也应该是实例变量。
  String name;
 ?
  // 国籍
  // 重点重点五颗星:加static的变量叫做静态变量
  static String country = "中国";
 ?
  // 无参数
  public Chinese(){
  }
 ?
  // 有参数
  public Chinese(String s1,String s2){
  idCard = s1;
  name = s2;
  }
 }

注意:

静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了。

静态变量存储在方法区。

4.重点

eg.

 public class StaticTest03{
 ?
  public static void main(String[] args){    
  // 通过"类名."的方式访问静态变量
  System.out.println(Chinese.country);
 ?
  // 创建对象
  Chinese c1 = new Chinese("1111111", "张三");
  System.out.println(c1.idCard); // 1111111
  System.out.println(c1.name); // 张三
  System.out.println(c1.country); // 中国
 ?
  // c1是空引用
  c1 = null;
  // 分析这里会不会出现空指针异常?
  // 不会出现空指针异常。
  // 因为静态变量不需要对象的存在。
  // 实际上以下的代码在运行的时候,还是:System.out.println(Chinese.country);
  System.out.println(c1.country);
 ?
  // 这个会出现空指针异常,因为name是实例变量。
  //System.out.println(c1.name);
  }
 }

 

 class Chinese{
  // 实例变量
  String idCard;
  String name;
 ?
  // 静态变量
  static String country = "中国";
 ?
  //构造方法
  public Chinese(String x, String y){
  idCard = x;
  name = y;
  }
 }
  • 实例的变量或方法:一定需要使用“引用.”来访问。

 Chinese c1 = new Chinese("1111111", "张三");
 System.out.println(c1.idCard); // 1111111
 System.out.println(c1.name); // 张三
 System.out.println(c1.country); // 中国
  • 静态的变量或方法:建议使用“类名.”来访问,但使用“引用.”也行(不建议使用"引用.")。静态的如果使用“引用.”来访问会让程序员产生困惑:程序员以为是实例的变量或方法。

 // 通过"类名."的方式访问静态变量
 System.out.println(Chinese.country);
 System.out.println(c1.country)//这样也行

注意:空引用访问静态变量不会出现空指针异常

 c1 = null;
 System.out.println(c1.country);

这里不会出现空指针异常。因为静态变量不需要对象的存在。

实际上以下的代码在运行的时候,还是:

 System.out.println(Chinese.country);

结论:空指针异常只有在只有在“空引用”访问“实例”相关的,都会出现空指针异常。

 

5.关于方法来说,什么时候定义为实例方法?什么时候定义为静态方法?

1.思想角度:

  • 如果说该行为必须由对象去触发。那么该方法定义为实例方法。

2.代码角度

  • 当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。

我们以后开发中,大部分情况下,如果是工具类的话,工具类当中的方法一般都是静态的。(静态方法有一个优点,是不需要new对象,直接采用类名调用,极其方便。工具类就是为了方便,所以工具类中的方法一般都是static的)

 

静态代码块

1、怎么定义静态代码块

使用static关键字可以定义:静态代码块

2、什么是静态代码块,语法是什么?

 static{
  java语句;
  java语句;
 }

3、static静态代码块在什么时候执行呢?

类加载时执行。并且只执行一次。

注意:静态代码块在类加载时执行,并且在main方法执行之前执行。

4、静态代码块执行顺序

静态代码块一般是按照自上而下的顺序执行。

5、静态代码块有啥作用,有什么用?

第一:静态代码块不是那么常用。(不是每一个类当中都要写的东西。)

第二:静态代码块这种语法机制实际上是SUN公司给我们java程序员的一个特殊的时刻/时机。这个时机叫做:类加载时机。

eg.具体的业务:

项目经理说了:大家注意了,所有我们编写的程序中,只要是类加载了,请记录一下类加载日志信息(在哪年哪月哪日几时几分几秒,哪个类加载到JVM当中了)。

这些记录日志的代码写到静态代码块当中。

eg.

 public class StaticTest06{
  // 静态代码块(特殊的时机:类加载时机。)
  static {
  System.out.println("A");
  }
  // 一个类当中可以编写多个静态代码块
  static {
  System.out.println("B");
  }
  // 入口
  public static void main(String[] args){
  System.out.println("Hello World!");
  }
  // 编写一个静态代码块
  static{
  System.out.println("C");
  }
 }
 /*A
  B
  C
  Hello World!
  */

6、静态代码块可以访问静态变量,不能访问实例变量。

因为:

静态代码块在类加载时执行。并且只执行一次。

 

静态变量在什么时候初始化?类加载时初始化。

静态变量存储在哪里?方法区。

 

实例变量在构造方法执行时内存空间才会开辟。

类加载时,实例变量的内存空间还没有被开辟出来。

 

注意:

静态代码块和静态变量都在类加载时候执行,时间相同,只能靠代码的顺序来决定谁先谁后。

如果静态代码块访问的静态变量声明的代码顺序在其之下,编译器报错。

 

总结:到目前为止,你遇到的所有java程序,有顺序要求的是哪些?

第一:对于一个方法来说,方法体中的代码是有顺序的,遵循自上而下的顺序执行。

第二:静态代码块1与静态代码块2是由先后顺序的。(不是静态方法)

第三:静态代码块和静态变量是有先后顺序的。

 

实例代码块

  1. 除了静态代码块之外,还有一种语句块叫做:实例语句块

  2. 实例语句在类加载时并没有执行。

实例语句语法?

 {
  java语句;
  java语句;
  java语句;
 }

实例语句块在什么时候执行?

只要是构造方法执行,必然在构造方法执行之前,自动执行“实例语句块”中的代码。实际上这也是SUN公司为java程序员准备一个特殊的时机,叫做对象构建时机。

实例语句块有什么用?

如果多个构造方法中有一样的语句,可以提取到实例语句块中。

 

this

1.this是一个关键字,是一个引用,保存内存地址指向自身。

一个对象一个this。

this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。

所以,严格意义上来说,this代表的就是“当前对象”

this存储在堆内存当中对象的内部。

 

2.this可以使用在实例方法中,也可以使用在构造方法中。

 

3.this出现在实例方法中其实代表的是当前对象。

谁调用这个实例方法,this就是谁。

eg.

 public class This{
    public static void main(String[] args){
        Customer c1 = new Customer("张三");
        c1.shopping();
 ?
        Customer c2 = new Customer("李四");
        c2.shopping();
   
    Customer.doSome();
    }
 }
 ?
 class Customer{
  // 属性
  // 实例变量(必须采用“引用.”的方式访问)
  String name;  
 ?
  //构造方法
  public Customer(){
  }
 ?
  public Customer(String s){
  name = s;
  }
 ?
  // 顾客购物的方法
  // 实例方法
  public void shopping(){
  // 这里的this是谁?this是当前对象。
  // c1调用shopping(),this是c1
  // c2调用shopping(),this是c2
  //System.out.println(this.name + "正在购物!");
 ?
  // this. 是可以省略的。
  // this. 省略的话,还是默认访问“当前对象”的name。
  System.out.println(name + "正在购物!");
    }
 ?
  // 静态方法
  public static void doSome(){
  // this代表的是当前对象,而静态方法的调用不需要对象。矛盾了。
  // 错误: 无法从静态上下文中引用非静态 变量 this
  //System.out.println(this);
  }
 }

4.this不能使用在静态方法中。

this代表当前对象,静态方法中不存在当前对象。

 class Student{
  // 实例变量,怎么访问?必须先new对象,通过“引用.”来访问。
  String name = "zhangsan";
 ?
  // 静态方法
  public static void m1(){
  //System.out.println(name);//错误
  // this代表的是当前对象。
  //System.out.println(this.name);//错误
 ?
  // 除非你这样---》main方法同理
  Student s = new Student();
  System.out.println(s.name);
  }
 }

5.this. 大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。

 class Student{
  //学号
  private int no;
 ?
  //姓名
  private String name;
 ?
  //构造方法无参
  public Student(){
  }
 ?
  //构造方法有参
  /*
  public Student(int i, String s){
  no = i;
  name = s;
  }
  */
 ?
  // 上面的构造方法也增强以下可读性
  public Student(int no, String name){
  this.no = no;
  this.name = name;
  }
 ?
  // setter and getter方法
  /*
  public void setNo(int i){
  no = i;
  }
  */
 ?
  /*
  public void setNo(int no){ // 就近原则。
  no = no; //这两个no都是局部变量no,和实例变量no没关系。
  }
  */
 ?
  public void setNo(int no){
  //no是局部变量
  //this.no 是指的实例变量。
  this.no = no; // this. 的作用是:区分局部变量和实例变量。
  }
 ?
  public int getNo(){
  return no;
  //return this.no;//---》这样也行,这里可以省略
  }
 ?
  /*
  public void setName(String s){
  name = s;
  }
  */
 ?
  /*
  public void setName(String name){ // 就近原则
  name = name; //这两个name都是局部变量name,和实例变量name没关系。
  }
  */
 ?
  public void setName(String name){
  this.name = name;
  }
 ?
  /*
  public String getName(){
  return name;
  }
  */
 ?
  public String getName(){ // getName实际上获取的是“当前对象”的名字。
  //return this.name; // 严格来说,这里是有一个 this. 的。只不过这个 this. 是可以省略的。
  return name;
  }
 }

6.this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的构造方法,目的是代码复用.

语法格式:

 this(实际参数列表);
 class Date{
  private int year;
  private int month;
  private int day;
 ?
  // 构造方法无参
  // 调用无参数构造方法,初始化的日期是固定值。
  public Date(){
        //错误: 对this的调用必须是构造器中的第一个语句
        //System.out.println(11);
        /*
        this.year = 1970;
        this.month = 1;
        this.day = 1;
        */
        //上三行代码,体现不出代码复用性,下面代码体现代码复用性
        this(1970, 1, 1);
  }
 ?
 ?
  // 构造方法有参数
  public Date(int year, int month, int day){
  this.year = year;
  this.month = month;
    this.day = day;
  }
 }

 

相关