当前位置:   article > 正文

Java学习笔记系列-基础篇-变量与常量_方法是一种能力的抽象,那变量和常量是什么

方法是一种能力的抽象,那变量和常量是什么

Java学习笔记

Java学习笔记是一个持续更新的系列,工作多年,抽个空对自身知识做一个梳理和总结归纳,温故而知新,同时也希望能帮助到更多正在学习Java 的同学们。

本系列目录

入门篇

基础篇


变量

变量是内存中的一个存储区域,用于在内存中保存数据,该区域的数据可以在一类型范围内不断变化,是Java程序中最基本的存储单元,包含变量类型,变量名,变量的值。

变量来源于数学,是计算机语言中能储存计算结果或能表示值的抽象概念。

使用IDEA,打开HelloWrod.java文件,我们把输出的字符串替换成一个字符串类型的变量试试

	public static void main(String[] args) {
        String value="Hello Word!";
        System.out.println(value);
    }
  • 1
  • 2
  • 3
  • 4

如何声明(定义)变量

变量的声明就是申请内存来存储值,需要根据它的数据类型为变量分配存储空间,在Java语言中,变量的声明必须遵守以下规则

  • 必须指定变量的数据类型
    由于Java中不同的数据类型,分配的内存空间不同,所以定义的变量必须指定数据类型。
    例如:String value;

  • 必须为变量指定一个标识符
    为了方便的引用变量的值,需要给变量起一个名字,遵守标识符的命名规则即可。
    例如:在班级里,需要统计本班学生的数学分数,则需要学生的姓名,分数

    String name; //姓名
    double score=0;//分数
    
    • 1
    • 2
  • 先声明,后使用
    变量必须先定义才能使用,如果未定义则无法通过编译。
    错误示范:

     		System.out.println(value);
            String value="Hello Word!";
    
    • 1
    • 2

    注意:如果是先声明,后使用,那么引用类型的变量在使用时需要进行空指针判断,可增加程序的容错性。

  • 只在作用域内生效
    变量只在定义的{}内生效
    错误示范:

     	public static void main(String[] args) {
            System.out.println(value);//调用value
        }
    	public void test(){
            String value="Hello Word!";//声明value
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:{{}}嵌套的情况下,最外层的变量可以作用在内层{}中,但是对变量的访问修饰符具有一定要求。

变量的作用域

变量的作用域由声明它的位置决定,根据声明的位置,可以概述为以下三种:

  • 成员变量
    成员变量是指定维度的成员变量,用于标识某个维度成员,通常定义在类里,方法外面,在方法中通过对象调用。
  • 局部变量
    是方法内部或复合语句内部定义的变量,通常用于方法中或方法的形参,需要先定义,赋值后才能使用 。
  • 静态变量
    是在程序执行前使用static关键字定义好的一类变量,通常在静态类中,方法外面,通过类名调用,有默认初始值。

变量的生存期

生存期即生命周期,是指变量的内存分配与回收的过程,通常根据变量的作用域决定自身的生命周期。

我们已经知道Java语言编译的程序都必须运行在JVM虚拟机中,而JVM虚拟机运行时的数据区如下
JVM内存数据分布区
可以看出来不同作用域的变量,所处的JVM区域也不同

  • 成员变量
    属于实例对象,生命周期与实例对象一致,即与实例对象共存亡,处于JVM堆区。
  • 局部变量
    属于方法,Java中的方法都在栈区中,所以局部变量也在栈区,它随着方法的调用生成,调用完成之后消亡。
  • 静态变量
    静态变量在Java方法区,随着虚拟机编译之后就一直存在。

常量

Java中的常量指在程序的整个运行过程中值保持不变的量。

在实际的程序中,可以根据数据在程序运行中是否发生改变,来选择应该是使用变量还是常量。

常量在程序运行过程中主要有2个作用

  1. 代表常数,便于程序的修改(例如:圆周率的值)
  2. 增强程序的可读性(例如:常量UP、DOWN分别代表上下,其数值分别是1和2)

常量的语法格式和变量类型
只需要在变量的语法格式前面添加关键字final即可。

常量的语法格式如下
final 数据类型 常量名称 = 值;
final 数据类型 常量名称1 = 值1, 常量名称2 = 值2,……常量名称n = 值n;

例如:

final double PI = 3.14final char MALE=‘M’,FEMALE=‘F’;
  • 1
  • 2

在Java语法中,常量也可以首先声明,然后再进行赋值,但是只能赋值一次。

 final int UP;
 	UP = 1
  • 1
  • 2

关于final详解

final 用于声明属性(常量),方法和类,分别表示属性一旦被分配内存空间就必须初始化

不会有默认初始化,局部变量也是如此,默认初始化只有普通的非final成员属性,对于static(无final修饰)类变量,类连接时候有默认初始化,对于像private int a;在类实例化时,构造函数默认初始为0,总之,变量必须初始化后方可用,这是java的安全之一。

final这个关键字的含义是“这是无法改变的”或者“最终态的”。
那么为什么要阻止改变呢?
Java语言的发明者可能由于两个目的而阻止改变:

  1. 效率问题:
    JDK中的某些类的某些方法,是不允许被用户覆盖的,设计者可能认为,所用方法已经是最好的方法,用户私自覆盖,或是由于疏忽而覆盖,就会影响JVM或是系统的系能;
  2. 设计所需:
    众所周知,有些情况必须使用final关键字,比如方法中的匿名内部类的参数传递

    修饰变量:
    final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
    修饰方法:
    final方法不能被子类方法覆盖,但可以被继承。
    修饰类:
    final类不能被继承,没有子类,final类中所有方法都是final的。(如String类)

被final修饰而没有被static修饰的类的属性变量只能在两种情况下初始化(必须初始化):

  • 在它被声明的时候赋值
  • 在构造函数里初始化

解释

当这个属性被修饰为final,而非static的时候,它属于类的实例对象的资源(实例常量),当类被加载进内存的时候这个属性并没有给其分配内存空间,而只是 定义了一个变量a,只有当类被实例化的时候这个属性才被分配内存空间。
而实例化的时候同时执行了构造函数,所以属性被初始化了,也就符合了当它被分配内存空间的时候就需要初始化,以后不再改变的条件。

被static修饰而没有被final修饰的类的属性变量只能在两种情况下初始化(可以不初始化):

  • 在它被声明的时候赋值
  • 在静态或非静态快里初始化

解释

当类的属性被同时被修饰为static时候,他属于类的资源(类变量),在类加载后,进行连接时候,分三步:

  1. 先验证;然后准备,准备时,先分配内存。
  2. 接着默认初始化;可以进行解析。
  3. 最后,进行类初始化,类初始化前,必须保证它的父类已经初始化了,所以最先初始化的是超类,对于接口,不必初始其父接口。

类初始化时,它把类变量初始化语句及静态初始化语句放到类初始化方法中,所以,如果无此两种语句,也就没类初始化方法,而构造函数是在当类被实例化的时候才会执行,所以用构造函数,这时候这个属性没有被初始化,程序就会报错,而static块是类被加载的时候执行,且只执行这一次,所以在 static块中可以被初始化。

同时被final和static修饰的类的属性变量只能在两种情况下初始化(必须初始化):

  • 在它被定义的时候
  • 在类的静态块里初始化
  • 特别对于初始化时候调用抛出异常的构造函数,初始时候注意,特别是在实现单例模式时(只能这么初始化)
    如:
    class A{ 
    	private final static A a;
    	static{
    		try{
    			a=new A();
    		}catch(Exception e){
    			throws new RuntimeException(e);          //必须有,不然不能完成常量的正确初始化
    		}
    	}
    	private A() throws Exception{}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

解释

当类的属性被同时被修饰为static和final的时候,他属于类的资源(类常量),那么就是类在被加载进内存的时候(也就是应用程 序启动的时候)就要已经为此属性分配了内存。
所以此时属性已经存在,它又被final修饰,所以必须在属性定义了以后就给其初始化值。
而构造函数是在当类被实例化的时候才会执行,所以用构造函数,这时候这个属性没有被初始化,程序就会报错。
而static块是类被加载的时候执行,且只执行这一次,所以在static块中可以被初始化。

final变量的变与不变
final表示变量的值或引用不变

有人说final变量在赋值后就不可变,此变量可以是基本数据类型+String或者是对象
那么这个不变到底指的是什么呢?
这个不变指的是引用,是地址,而所引用的对象的内容仍然是可变的。
注:如果是对象,注意此时类初始化条件
就是说,这个final变量永远指向某个对象,是一个常量指针,而不是指向常量的指针。

final关键字的具体应用
final+变量:

在实际应用中,这种形式是非常少见的。
比如logger是可以的,但是貌似并不是非常实用,或许用户仍然希望通过setter来改变logger变量。

static+final+变量:

常量,经常使用。

final+方法:

JDK中常用,但是自己并未常用。

final+类:

helper类经常使用。

final用于匿名内部类的参数传递:

在多线程测试时,经常使用

final用于方法的参数:

并不常用。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号