首页 > java > basic > 5.Java变量

5.Java变量

所有的程序都使用变量临时存储各种数据, 在Java语言中变量必须在程序中被定义(或声明)后才能使用, 必须为每个变量确定一个具体类型.Java中变量分为基础类型变量和引用类型变量.Java有八种基础类型变量.分为数字类型(四个整数型,两个浮点型), 布尔型和字符类型.

1 数字类型变量

1.1 数字类型变量类型

  • byte

字节型变量,表示整数,取值范围(-2^8到2^8-1),不支持小数.

byte b0 = 88;
byte b1 = -10;
  • short 短整型变量,表示整数,取值范围(-2^16到2^16-1),不支持小数.
short s0 = 99;
short s1 = -1;
  • int 整型变量,表示整数,取值范围(-2^32到2^32-1),不支持小数.整形常量,范围可以粗略即为正负21亿之间,超过这个范围需要采用long类型.
int i0 = 100000;
int i1 = -2;
  • long 长整型变量,表示整数,取值范围(-2^64到2^64-1),不支持小数.
long l0 = 100000L;
long l1 = -3L;
  • float 浮点数类型,表示小数,取值范围(到).浮点数有舍入误差.定义变量时,需要在数字后边加个字符"f"或者"F",表示该数字为float类型.
float f0 = 3.14f;
float f1 = 2.73F;
  • double 浮点数类型,表示小数,取值范围(到).浮点数有舍入误差.定义变量时,需要在数字后边加个字符"d"或者"D",表示该数字为double类型.
double d0 = 123.4d;
double d1 = 1.4D;
  • char 字符型,用英文单引号""定义.可以储存任何字符.也可以当整数来用,但一般情况不建议这么用.
char c0 = 'a';
char c1 = '人';

1.2 数字类型变量选择

写代码时,根据变量的数据类型和数字大小范围选择对应的数字类型.超过类型的最大值或者小于最小值的数据会出错.比如int最大值20亿左右,需要定义一个100亿的数字需要采用long类型定义.如果采用int类型定义会产生数字溢出变为一个负数.

  • java数字类型的最大值和最小值 计算机存储整形数据是以二进制方式存储,有符号数据类型(byte, short, int, long, float)最小值为"-2^n",最大值为"2^-1","n"为占用字节数.无符号类型(char)最小值为0,最大值为2^16(65535).存储浮点类型数据表示范围太大,采用科学计数法方式存储,所以范围会整数型大很多.

图5-3

1.3 数字类型变量默认值和取值范围

在java里面定义一个变量,如果不主动给它赋值,系统会自动给它赋一个初始值值,这个值叫做"默认值".这一点比c/c++要只能一些.下面的表格中列出了Java数字类型变量默认值和取值范围.

类型 默认值 位数 最小值 最大值
byte 0 8 -128 127
short 0 16 -2^16 2^16-1
int 0 32 -2^32 2^32-1
long 0 64 -2^64 2^64-1
float 0f 32 -3.4 - 10^38 3.4 - 10^38
double 0d 64 -1.7 - 10^308 1.7 - 10^308
char 0 16 0 2^16
boolean false 1

浮点数不是精确值

浮点数值不适合用于禁止出现舍入误差的金融计算中. 例如:System.out.println(2.0-1.1); 将打印0.899999999999999,而不是0.9.因为浮点数值采用二进制系统表示,而二进制无法精确表示分数1/10,就像十进制无法精确表示1/3一样.如果需要在数值计算中不含有舍入误差,应该使用BigDecimal类.

2 布尔(boolean)变量

boolean(布尔类型),只有两个取值:true(是)和false(否).java程序中boolean默认值为false.

boolean bo0 = true;
boolean bo1 = false;

示例代码:

package com.dashidan.lesson5;

/**
 - 大屎蛋教程网-dashidan.com
 - <p>
 - Java教程基础篇: 5. Java变量
 - 基础类型变量
 */
public class Demo1 {
    public static void main(String[] args) {
        /** byte 变量*/
        byte b0 = 88;
        byte b1 = -10;
        System.out.println(b0);
        System.out.println(b1);
        /** short 变量*/
        short s0 = 99;
        short s1 = -1;
        System.out.println(s0);
        System.out.println(s1);
        /** int 变量*/
        int i0 = 100000;
        int i1 = -2;
        System.out.println(i0);
        System.out.println(i1);
        /** long 变量*/
        long l0 = 100000L;
        long l1 = -3L;
        System.out.println(l0);
        System.out.println(l1);
        /** float 变量*/
        float f0 = 3.14f;
        float f1 = 2.73F;
        System.out.println(f0);
        System.out.println(f1);
        /** double 变量*/
        double d0 = 123.4d;
        double d1 = 1.4D;
        System.out.println(d0);
        System.out.println(d1);
        boolean bo0 = true;
        boolean bo1 = false;
        System.out.println(bo0);
        System.out.println(bo1);
        /** char 变量*/
        char c0 = 'a';
        char c1 = '人';
        System.out.println(c0);
        System.out.println(c1);
        System.out.println(c0 + c1);
    }
}

输出:

88
-10
99
-1
100000
-2
100000
-3
3.14
2.73
123.4
1.4
true
false
a
人
20251

3 字符串类型变量

字符串类型是对象类型,不属于基础类型.赋值的时候属于值传递.在Java语言中,字符串String是不可变(final)的.Java在运行时保存了一个字符串池(String pool),这使String成为了一个特别的类.

3.1 中字符串为什么是不可变的

只有当字符串是不可变的,字符串池才有可能实现.字符串池的实现可以在运行时节约很多内存(heap)空间,因为不同的字符串变量都指向池中的同一个字符串.但如果字符串是可变的,那么字符串池技术将不能实现.因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变.

图5-4

3.2 中字符串不可变有什么优点

  • 由于字符串的值是不可变的, 无改变字符串指向的对象的值,避免安全漏洞.
  • 多线程安全, 同一个字符串实例可以被多个线程共享. 这样便不用因为线程安全问题而使用同步.字符串自己便是线程安全的.
  • 类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载. 譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏.
  • 在它创建的时候hashcode就被缓存了,不需要重新计算. 这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象.这就是HashMap中的键往往都使用字符串.

3.3 字符串变量赋值

java字符串变量赋值常用有2种方式:

  • 直接通过=赋值.
  • 通过new String()的方式创建字符串对象赋值.

java字符串变量赋值示例代码:

String s1 = "test0";
String s2 = new String("test1");
String s3 = new String(s2);

3.4 获取字符串长度

通过String对象自带的length()方法可以获取字符串长度.

String s0 = "test0";
int size = s0.length();

3.5 字符串相加

java语言中通过"+"操作可以将2个字符串组合.这个操作比起c/c++简化了很多.

String s0 = "test0";
String s1 = "test1";
String s2 = s0 + s1;

3.6 字符串比较

在java语言种字符串比较内容是否相同,需要通过equals()方法.双等于号(==)用来判断数字类型是否相等,对于引用类型的变量来说是判断内存地址是否相同.

双等于号(==)对于字符串类型判断是否相同很特殊, Java虚拟机独有的"字符串池"技术对字符串类型进行了优化,自动判断上下文中是否有相同的字符串,如果有相同的字符串,则直接把原有的字符串对象拿来使用,不重新创建字符串对象. 如果字符串发生改变则自动创建一个新的字符串对象.通过new关键字"new String()"创建字符串是重新创建而不是采用已有的相同字符串.

字符串类型采用equal()和==的区别示例代码:

package com.dashidan.lesson5;

/**
 - 大屎蛋教程网-dashidan.com
 -
 - Java教程基础篇: 5. Java变量
 - 字符串变量
 */
public class Demo2 {
    public static void main(String[] args) {
        /** 注意这里 s0 s1采用的字符串池技术, 而通过new创建的s2是新创建了一个字符串对象,没有采用字符串池技术*/
        String s0 = "大屎蛋教程网";
        String s1 = "大屎蛋教程网";
        String s2 = new String("大屎蛋教程网");
        /** equal比较字符串内容*/
        boolean isSame = s0.equals(s1);
        System.out.println("1 equals isSame : " + isSame);
        isSame = s0.equals(s1);
        System.out.println("2 equals isSame : " + isSame);
        isSame = s0.equals(s2);
        System.out.println("3 equals isSame : " + isSame);
        /** s2 是通过new的方式从新创建的字符串对象,s0 s2 指向不同的内存地址*/
        isSame = (s0 == s2);
        System.out.println("4 == isSame : " + isSame);
        isSame = (s0 == s1);
        /** 这里里的赋值,java虚拟机做了处理,自动指向了同一个字符串*/
        System.out.println("5 == isSame : " + isSame);
        /** 改变字符串 s0*/
        s0 += "aaa";
        /** s0 发生变化*/
        System.out.println("s0 " + s0);
        /** s1 没有发生变化*/
        System.out.println("s1 " + s1);
        /** 字符串s0 发生改变,虚拟机自动新建了一个字符串对象,s0 s1不再指向同一个字符串*/
        isSame = (s0 == s1);
        System.out.println("6 == isSame : " + isSame);
    }
}

输出结果:

1 equals isSame : true
2 equals isSame : true
3 equals isSame : true
4 == isSame : false
5 == isSame : true
s0 大屎蛋教程网aaa
s1 大屎蛋教程网
6 == isSame : false

注意代码中的字符串变量s0,s1采用的字符串池技术, 而通过new创建的字符串s2是新创建了一个字符串对象,没有采用字符串池技术.

  • equal方法和==判断字符串是否相同的区别 采用equal方法是判断字符串内容是否相同,采用==判断字符差是否相同时比较的内存地址是否相同.

3 引用类型变量

引用类型(reference type)指向对象在内存空间的地址.

3.1 什么是引用

把对象数据比喻为一座房子,引用就是门牌号. 一个对象在内存中会请求一块内存空间来保存数据,根据对象的大小, 需要占用的空间大小也不等. 访问对象数据时, 不直接访问对象在内存中的数据, 而是通过引用去访问. 如果我们定义了不止一个引用指向同一个对象, 那么这些引用是不相同的, 因为引用也是一种数据类型, 需要一定的内存空间(栈空间stack)来保存. 但是它们的指向的对象数据是相同的, 都指示同一个对象在内存(堆空间heap)的中位置.例:

String a="This is a Text!";
String b=a;

a和b是不同的两个引用,我们使用了两个定义语句来定义它们. 但它们的值是一样的, 都指向同一个对象 "This is a Text!".如图:

图5-1

String对象的值本身是不可更改的

像`b = "World";` `b = a;`这种情况不是改变了"World" 这一对象的值, 而是改变了它的引用b的值使之指向了另一个String对象a.

图5-2

3.2 引用类型

java3种引用类型

3.3 引用类型要点

  • 引用是一种数据类型(保存在stack,栈空间), 保存了对象在内存(heap,堆空间)中的地址.不是简单数据类型也不是类实例(对象).
  • 不同的引用可能指向同一个对象,换句话说, 一个对象可以有多个引用, 即该类类型的变量.

3.4 引用传递

引用传递也称为传地址.方法调用时,实际参数的引用(地址)被传递给方法中相对应的形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象.

4 变量作用域

Java变量从影响范围划分,分为成员变量和局部变量.

4.1 成员变量

java类内部定义的变量叫做成员变量,如果没有设定初始值,系统会自动赋值为默认值.作用范围是整个类.成员变量在所在类被实例化后,存在堆内存中.

4.2 局部变量

java方法内定义的变量被称为局部变量,局部变量没有默认值,声明变量时必须设定初始值.作用范围从声明开始,直到包含它的块(对应的大括号})结束.局部变量在所在方法调用时,存在栈内存中.方法参数是局部变量,范围涵盖整个方法.

4.3 变量作用域示例代码

package com.dashidan.lesson5;

/**
 - 大屎蛋教程网-dashidan.com
 - <p>
 - Java教程基础篇: 5. Java变量
 - 变量作用域
 */
public class Demo3 {
    /**
     - a,b 是成员变量,整个方法都可以调用.
     */
    public static int a;
    public static float b = 3.0f;

    public static void main(String args[]) {
        /**  在方法中调用成员变量, a为默认值, b为设定值*/
        System.out.println(a);
        System.out.println(b);

        testVar();
        /** 这里输出变量m, n,编译代码时,会报错,提示没有定义变量m,n*/
        //System.out.println(m);
        //System.out.println(n);
    }

    public static void testVar() {
        /**m,n 是成员变量,必须初始化赋值.作用域是在这个方法中. */
        int m = 0;
        int n = 1;
        System.out.println(m);
        System.out.println(n);
    }

}

输出:

0
3.0
0
1

示例代码需要注意的部分:

  • a,b 是成员变量,整个方法都可以调用.
  • 在方法中调用成员变量, a为默认值, b为设定值.
  • 输出变量m, n,编译代码时,会报错,提示没有定义变量m,n.
  • m,n 是局部变量,必须初始化赋值.作用域是在这个方法中.
转载请保留原文链接.