使用变量表示信息,熟悉原始数据类型、引用数据类型的变量表示信息的方式,了解数组引用数据类型以及类的引用数据类型之内存结构以及各种运算符组合的表达式情景。
                 爱校码使用变量表示信息,熟悉原始数据类型、引用数据类型的变量表示信息的方式,了解数组引用数据类型以及类的引用数据类型之内存结构以及各种运算符组合的表达式情景。
声明:本系列博文为"爱校码.中国"原创博文,版权所有,未经授权,不得转载或抄袭,若发现将依法追责
对于学习者来说,编写程序时需要存储数据,而变量是一种存储数据的载体,在程序运行过程中变量存储的数据可以根据需要进行改变。学习者在编写Java程序时,通过标识符来定义原始数据类型或引用数据类型的变量,使用该标识符表示信息并对其进行修改。
1. 变量与常量
在本情景的任务1的相关知识点3之词法规范中,对变量和常量进行过描述,在此再简单的回顾一下。在Java程序设计中,实体通过对象来表示,而实体的属性或对象的属性用数据来表达,变量是一种存储数据的载体或者容器。如何使用一个变量呢?首先需要创建变量,而且需要了解变量的四个要素:分别为名字、类型、地址和值。
变量名根据词法规范要求采用标识符命名,程序通过变量名访问变量的值;变量类型需要显示地声明,编译器根据类型解释变量地址所指向的内存空间中的字节单元数;变量地址指的是内存地址,表明某一个变量与内存中某一个区域相关联;变量的值即为变量的地址所指向的内存单元中存放的数据。
变量须遵循“先声明、后使用”原则,即在第一次使用变量之前就必须对变量的数据类型进行声明,格式如下:
数据类型 变量名;
数据类型 变量名 = 数值或表达式;
常量是变量的特例,即变量的值不允许改变,也就是说变量不能被重新赋值,格式如下:
final 数据类型 常量名 = 常量值;
为了便于识别,通常使用大写字母表示常量名。
2. 数据类型
类型是一种类属标志,定义了表达式和变量的行为方式。在面向对象的语言中,各种类型的数据都可以当作对象。在Java中,将数据类型分为两个类别,一种是表示不可分割的单值表达式,例如,整型、浮点数、字符和布尔值,它们很像非面向对象语言中的简单类型,称之为原始数据类型;另一种是引用(reference)数据类型,由于Java中没有明确定义指针类型,存储在引用类型变量中的值可以被认为就是指向该变量所表示的实际值的指针,即地址,JVM从不直接对对象寻址而是操作对象的引用。引用数据类型有类(class)、接口(interface)和数组(array)三种,它们的默认值是null。
⑴ 原始数据类型
Java有八个原始数据类型,即byte、short、int、long、char、float、double和boolean,它们被分成四组:
Java是一种强类型语言,每个变量、每个表达式都有类型,每个类型都有严格的限定,没有某些语言中的自动匹配或冲突类型的转换,要求将表达式赋给变量或者在方法调用时传递参数,都要求类型相互匹配,如果不匹配,在编译时提示错误信息而不是警告。原始数据类型一次存储一个值,以下列出了原始数据类型的大小和范围。
数据类型      大小          范围                                 说明
byte         8 位         -128 ~ +127 有符号(-27~27-1)   字节型,用于存储以字节为单位的数据,处理网络或文件的数据流。
                           0 ~ 255    无符号
short       16 位         -32768 ~ +32768(-215~215-1)    短整型,用于存储较小的整数,通常针对条目编号。
int         32 位         -2的31次方 ~ 2的31次方-1        整型,用于存储较大的整数。
long        64 位         -2的63次方 ~ 2的63次方-1        长整型,用于存储非常大的整数。
float       32 位         -2的31次方 ~ 2的31次方-1        浮点型,用于存储带有小数位的数字。
double      64 位         -2的63次方 ~ 2的63次方-1        双精型,用于存储带有小数位的大型数据值。
char        16 位         ‘\u0000’~’\uFFFF’ 单个字符      字符型,用于存储数字表示和字符数据。
boolean     1  位         true或false 布尔值              布尔型,用于存储真值或假值,用于条件判断语句中。
⑵ 引用数据类型
Java的引用数据类型有类、接口和数组,在后续情景任务中将会进一步详细描述,在此进行简单的说明。Java的引用数据类型有类、接口和数组,在后续情景任务中将会进一步详细描述,在此进行简单的说明。如下所示。
数据类型                          说明
  类                  定义方法和变量的数据类型,表示方法和变量的集合,
                      通过引用类的实例(对象)或null实现的,例如,
                      MyClass myObject=new MyClass();或MyClass object=null;
  接口                表示一个抽象类模版,定义了对象必须实现的方法,由于
                      接口不能被实例化,而实现了接口方法的对象可以作为接
                      口实例被引用。一个类可以实现多个接口,从而体现Java
                      中的多重继承。接口变量只能引用实现该接口的类的实例(对象),
                      例如,一个接口为MyInterface,实现该接口的类为MyClass,
                      则接口变量定义为: MyInterface objectInterface=new MyClass();
  数组                数组是动态创建的引用对象,是具有相同数据类型的变量的集合。
                     同样,数组只能引用数组的实例或null。例如,
                     int myIntArray[]=new int[10]; 或 int myIntArray[]=null;
3. 数组
数组是引用数据类型,用于将相同数据类型的数据存储在连续的存储单元中,可以使用数字索引引用存储在数组中的单独数据项目。
数组需要声明来指定其名称和大小。数组中的数据既可以是原始数据类型,也可以是对象。在Java中,数组本身是真实的对象,这是因为可以使用new运算符创建实例并给数组分配内存。创建数组时,可以初始化为数组赋值,如果没有赋值,Java将根据数据类型为数组元素赋默认值。访问数组时需要检验以确保索引在数组的下界和上界范围内,数组的下界为0,数组元素的索引号从零开始。
⑴ 一维数组
语法:
<data_type>[] <array_name>;
<data_type> <array_name>[];
在Java中的惯例是使用上面的第一种语法,在声明数组之后,必须为其分配内存。数组的长度存储在变量length中,而变量length是所有数组的成员变量,例如,array_name.length指明数组array_name的长度。在以下列出了创建一维数组的三种方式。
语法                       方法              说明                              示例
datatype[] array_name;   声明数组           只是表示了数组的声明     int[] data;声明整型数组

语法                            方法              说明                                示例
datatype[] array_name=new  声明并创建数组    使用关键字new给声明的数组实例化并分配    int[] data=new int[3];
   datatype[size];                           内存空间,以datatype默认值初始化。       声明为整型数组并分配了三个
                                                                                      整数空间,初始化默认值为0

 语法                            方法                   说明                              示例
datatype[] array_name=     声明、创建并初始化数组,     使用大括号括起的一串由逗号     int[] data={7,8,9};
{value1,value2,…valueN};  也称为静态初始化。            分隔的表达式来给声明的数组     声明为整型数组,分配了三
                                                        实例化、分配内存并对其元素     个整数空间,并给三个数组
                                                        赋初始值。                     单元赋初值。

通过举例说明一维数组的应用,代码如清单2-1所示:
清单 2-1:
1:/*
2: * 爱校码
3: * 版权所有
4: * /
5:/**
6: * 学生类演示一维数组的用法
7: * @version 1.0 2023年3月18日
8: * @author zcj
9: */
10: public class Student{
11:    String[] course;            //声明课程数组
12:    int[] marks={85,60,80,70};  //声明、创建并初始化成绩数组
13:    /**
14:    * 构造方法Student
15:     */
16:    public Student() {
17:        course=new String[4];    //创建一个具有四个元素的字符串型的数组对象,开辟引用空间
18:       course[0]=new String("英语");  //为第一个数组元素开辟空间 
19:       course[1]=new String("C语言程序设计");  //为第二个数组元素开辟空间
20:       course[2]=new String("数据库原理及应用");  //为第三个数组元素开辟空间
21:       course[3]=new String("Java语言程序设计");  //为第四个数组元素开辟空间
22:   }
23:    /**
24:    * main方法
25:    * @param args 传递给main方法的参数
26:     */
27:   public static void main(String[] args){
28:        Student student=new Student();//创建学生类的对象
29:        /* 输出数组元素 */
30:        for(int i=0;i<4;i++){
31:           System.out.println(student.course[i]+"的成绩是"+student.marks[i]);
32:         }
33:    }
34: }
Java中对使用的数组进行严格的检查,以确保所有索引不超出数组的范围。
⑵ 多维数组
Java中的数组可以是多维的,可以有多个数字索引,以下是二维数组的语法:
<data_type>[][] <array_name>;
<data_type> <array_name>[][];
Java语言中并没有真正的多维数组,可以看作是数组的数组,数组空间不是连续分配的,不要求多维数组每一维的大小相同。在以下列出了创建二维数组的三种方式。
语法                             方法             说明                               示例
data_type array_name[][];    声明二维数组        只是表示了二维数组的声明         int intArray[][];
                                                                              声明整型二维数组

语法                             方法                       说明                             示例
data_type array_name[][]=new    声明并直接创       使用关键字new给声明的二维          double matrix[][]=new 
   data_type[size1][size2];     建二维数组。       数组实例化并分配内存空间,             double[3][3];声明
                                                  以datatype默认值初始化。           双精度型数组,并分配了三
                                                                                   行三列的双精度型数单元空间,
                                                                                   默认值为0.0D。
data_type array_name[][]= new   声明并从最高维      使用关键字new给声明的二维          dhouble matrix[][]=new
         data_type[size1][];    开始,分别为每一    数组从最高维开始逐一为每一               double[3][];
array_name[0]=new               维分配空间。        维分配内存空间,以datatype         matrix[0]=new double[3];
         datatype[size2];                           默认值初始化。                    matrix[1]=new double[3];
array_name[1]=new                                                                     matrix[2]=new double[3];
         datatype[size2];
array_name[1]=new 
         datatype[size2];
…
array_name[size-1]=new 
         datatype[size2];


语法                             方法             说明                               示例
datatype array_name[][]=      声明、创建并        使用嵌套的大括号括起         int iarr[][] = {
 {{value11,…,value1N },       初始化二维数        的一串由逗号分隔的表                 {1},
 {value21,…,value2N},         组,也称为静        达式来给声明的二维数                 {1,2},
    …,                        态初始化。          组实例化、分配内存并                 {1,2,3}
 {valueM1,…,valueMN}}                            对其元素赋初始值,由               };
                                                 于把二维数组看作是数
                                                  组的数组,数组空间不
                                                  是连续分配的,所以不
                                                  要求二维数组每一维的
                                                  大小相同。

通过举例说明二维数组的应用,将清单2-1中的一维数组改造为二维数组,代码如清单2-2所示:
清单 2-2:
1:/*
2: * 爱校码
3: * 版权所有
4: * /
5:/**
6: * 学生类演示二维数组的用法
7: * @version 1.0 2023年3月19日
8: * @author zcj
9: */
10: public class Student{
11:    String course[][];            //声明课程二维数组
12:    int marks[][]={{85,60,80,70},{76,89,90,95}};  //声明、创建并初始化成绩二维数组
13:    /**
14:     * 构造方法Student
15:      */
16:    public Student() {
17:      course=new String[2][];     
18:     course[0]=new String[4];      //为最高维分配引用空间
19:     course[1]=new String[4];      //为最高维分配引用空间
20:     course[0][0]=new String("学生A主修英语");            //为每个数组元素单独分配空间
21:     course[0][1]=new String("学生A主修C语言程序设计");  //为每个数组元素单独分配空间
22:     course[0][2]=new String("学生A主修数据库原理及应用"); //为每个数组元素单独分配空间
23:     course[0][3]=new String("学生A主修Java语言程序设计"); //为每个数组元素单独分配空间
24:     course[1][0]=new String("学生B主修英语");             //为每个数组元素单独分配空间
25:     course[1][1]=new String("学生B主修C语言程序设计");   //为每个数组元素单独分配空间
26:     course[1][2]=new String("学生B主修数据库原理及应用"); //为每个数组元素单独分配空间
27:     course[1][3]=new String("学生B主修Java语言程序设计"); //为每个数组元素单独分配空间
28:   }
29:    /**
30:    * main方法
31:    * @param args 传递给main方法的参数
32:     */
33:   public static void main(String []args){
34:       Student student=new Student();//创建学生类的对象
35:       /* 输出数组元素 */
36:      for(int i=0;i<2;i++){
37:         for(int j=0;j<4;j++){
38:           System.out.println(student.course[i][j]+"的成绩是"+student.marks[i][j]);
39:         }
40:      }
41:    }
42: }
对于二维引用数据类型的数组,必须首先给最高维分配索引空间,然后依次为低维分配索引空间,并且必须给每个数组元素单独分配空间。
4. 表达式与运算符
表达式是由操作数和运算符组成的符号序列,它们是按照语法规则组织起来的。最简单的表达式是用一个变量或常量来表示。一个表达式的结果往往是操作数与运算符经过运算而得,其值为表达式的值,表达式的类型为该值的类型。本知识点主要介绍表达式中运算符。
Java`运算符`是一种特殊字符,用来操作一个或多个操作数,然后生成结果。操作数是由变量、表达式或常量值组成,而操作指令是由运算符表示的。
Java中的运算符根据操作数的不同可划分为一元、二元和三元运算符。如果运算符只需一个操作数,则该运算符被称为一元运算符,运算符在操作数的前面,称之为前置一元运算符,而运算符在操作数的后面,则称之为后置一元运算符;需要有两个操作数,运算符在它们之间,该运算符被称为二元运算符;需要三个操作数的运算符被称为三元运算符。
Java内部提供了多种运算符,每个运算符代表一种算术或逻辑运算,将其分为算术操作、位操作、关系操作和逻辑操作四种类型。
⑴ 算术运算符
算术运算符使用数值操作数,用于算术运算,它和代数中的运算方法完全一致。操作数规定必须是数字类型,不能对布尔类型使用算术运算符,但字符(char)类型是个例外,因Java中char类型int类型的子集。以下列出了各种算术运算符。
运算符        结果
  +        相加,返回操作数的和。
  -        相减,返回操作数的差。
  *        相乘,返回操作数的积。
  /        相除,返回操作数的商。
  %        取模,返回操作数除法的余数。
  ++       递增,返回操作数的值加一。
  --       递减,返回操作数的值减一。
  +=       相加赋值,返回左右两边操作数的和,赋给左边操作数。
  -=       相减赋值,返回左右两边操作数的差,赋给左边操作数。
  *=       相乘赋值,返回左右两边操作数的积,赋给左边操作数。
  /=       相除赋值,返回左右两边操作数的商,赋给左边操作数。
  %=       取模赋值,返回左边操作数除以右边操作数所得的余数,赋给左边操作数。
清单2-3说明了算术运算符的用法。
清单2-3:
 1: /**
 2:  * @author zcj
 3:  * 这个类演示算术运算符的用法
 4:  */
 5:  public class MyArithmeticOperation {
 6:       /**
 7:        * 这是 main 方法
 8:        * @param args 传递至 main 方法的参数
 9 :       */
10:       public static void main(String[] args) {
11:           /* 变量声明 */
12:          int numberA = 5;
13:          int numberB = numberA*3;
14:          int numberC = numberB/4;
15:          int numberD = numberB-numberA;
16:          int numberE = -numberD;
17:          int result;
18:          System.out.println("numberA的值:"+numberA);
19:          System.out.println("numberB的值:"+numberB);
20:          System.out.println("numberC的值:"+numberC);
21:          System.out.println("numberD的值:"+numberD);
22:          System.out.println("numberE的值:"+numberE);
23:          result = numberA+numberB;
24:          System.out.println("numberA与numberB之和:"+result);
25:          result = numberA%numberC;
26:          System.out.println("numberA 对numberB取模:"+result);
27:          result *= numberC;
28:          System.out.println("result与numberC的积:"+result);
29:          numberE++;
30:          System.out.println("numberE累加后的值:"+numberE);
31:          numberD--;
32:          System.out.println("numberD累减后的值:"+numberD);
33:      }
34:  }
程序执行结果:
numberA的值:5
numberB的值:15
numberC的值:3
numberD的值:10
numberE的值:-10
numberA与numberB之和:20
numberA 对numberB取模:2
result与numberC的积:6
numberE累加后的值:-9
numberD累减后的值:9
⑵ 位运算符
位运算符关心值的内部表示,处理值中的每一位,所有的整数类型都可以用二进制值表示,通过位运算符,可以实现不同的目标要求。以下列出了各种位运算符。
运算符          结果
 ~           单元非
 &            位与
 |            位或
 ^            位异或
 >>           右移
 >>>          右移,0填充高位
 <<           左移
 &=           位与赋值
 |=           位或赋值
 ^=           位异或赋值
 >>=          右移赋值
 >>>=         右移填0赋值
 <<=          左移赋值
⑶ 关系运算符
比较两个操作数的值,表示它们之间的关系时使用关系运算符,其结果为布尔类型值true或false。以下列出了各种关系运算符。
运算符           结果
  ==            相等
  !=            不相等
  >             大于
  <             小于
  >=            大于等于
  <=            小于等于
Java中的相等比较使用两个等号而不是一个等号,单个等号代表赋值。整数、浮点数、字符等操作数都可以比较大小,其返回结果是布尔类型的true或false。
清单2-4:
1: /**
2:  * @author zcj
3:  * 关系运算符的用法
4:  */
5:  public class MyRelationalOpration {
6:        /**
7:         * 这是 main 方法
8:         * @param args 传递至 main 方法的参数
9:         */
10:        public static void main(String[] args) {
11:               // 变量声明 
12:             float number1 = 34.00f;
13:             double number2 = 34.00;
14:             //判断是否相等,因为数据类型不匹配,将会发生自动类型转换
15:             if(number1 == number2){
16:                 System.out.println("数值相等");         
17:             }else{
18:                 System.out.println("数值不相等");        
19:             }
20:        }
21:  }
⑷ 逻辑运算符
逻辑运算符将两个布尔值进行逻辑运算并返回相应的布尔结果。以下列出了各种逻辑运算符。
 运算符          结果
  &            逻辑与
  |            逻辑或
  ^            逻辑异或
  ||           快速逻辑或
  &&           快速逻辑与
  !            逻辑单元非
  &=           与赋值
  |=           或赋值
  ^=           异或赋值
  ?:           if-then-else缩写形式
||和&&表示的快速逻辑或和快速逻辑与,其含义是在整个逻辑表达式中,只要运算符左侧已经得出整个表达式的值,则不再计算右运算符。即在使用||时,运算符的左侧计算为true,将不再计算运算符的右侧,整个表达式取值为true;在使用&&时,运算符的左侧计算为false, 将不再计算运算符的右侧,整个表达式取值为false。
例如:
if(number1!=0 && number2/number1>10)
当number1=0时,&&的左侧表达式计算为false,则不再计算&&的右侧表达式,整个表达式取值为false。
在所有的布尔逻辑中,使用到与和或的操作最好使用快速逻辑与和快速逻辑或。
清单2-5:
 1:  /**
 2:   * @author zcj
 3:   * 逻辑运算符的用法
 4:   */
 5:   public class BooleanLogic {
 6:        /**
 7:         * 这是 main 方法
 8:         * @param args 传递至 main 方法的参数
 9:         */
10:         public static void main(String[] args) {
11:             //变量声明 
12:             boolean booleanA = true;
13:             boolean booleanB = false;
14:             boolean booleanC = booleanA | booleanB;
15:             boolean booleanD = booleanA & booleanB;
16:             boolean booleanE = booleanA ^ booleanB;
17:             boolean booleanF = (!booleanA & booleanB)|
18:                                    (booleanA & !booleanB);
19:             boolean booleanG = !booleanA;
20:             //输出结果 
21:             System.out.println("booleanA = " + booleanA);
22:             System.out.println("booleanB = " + booleanB);
23:             System.out.println("booleanA | booleanB = " + booleanC);
24:             System.out.println("booleanA & booleanB = " + booleanD);
25:             System.out.println("booleanA ^ booleanB = " + booleanE);
26:             System.out.println("(!booleanA & booleanB)|
27:                                   (booleanA & !booleanB)=" + booleanF);
28:             System.out.println("!booleanA = " + booleanG);
29:        }
30:   }
以上程序的输出结果为:
  booleanA = true
  booleanB = false
  booleanA | booleanB = true
  booleanA & booleanB = false
  booleanA ^ booleanB = true
  (!booleanA & booleanB)|(booleanA & !booleanB)=true
  !booleanA = false
在上面的一个运算符? :是一种三元运算符,它的基本格式是:
expression ? statement1 : statement2
其中expression是一个布尔条件的表达式,其结果为true或false。如果返回值为true,则执行statement1,否则执行statement2。statement1和 statement2必须有返回值,并且具有相同的数据类型。例如:
int result=(number1 == 0) ? 0 : (number2/number1);
在Java中计算这个赋值表达式时,首先检查?号左边的表达式,若number1等于0,则返回0给result变量;若number1不等于0,则返回number2/number1表达式的值给result变量。
⑸ 运算符优先级
在表达式中,由多个操作数和多个运算符构成,存在着计算的先后顺序,以下从高优先级到低优先级列出了Java中的所有操作的顺序:
从高到低顺序               运算符                      说明
      1                 ()  []  .              括号()标明表达式;[]用于数组;点号用于引用对象。
      2                  ++ --  ~   !             一元运算符
      3                  *   /   %              乘除和取余运算符
      4                  +  -                   加减运算符
      5                  >> >>> <<              位移运算符
      6                  >  >=  <   <=          关系运算符
      7                  == !=                  关系运算符
      8                   &                     逻辑与运算符
      9                   ^                     逻辑异或运算符
     10                   |                     逻辑或运算符
     11                  &&                     快速逻辑与运算符
     12                  ||                     快速逻辑或运算符
     13                  ?:                     条件运算符
     14                  =                      赋值运算符
算数运算的类名定义为ArithmeticOperation,通过main方法完成算数运算,并能将运算结果输出到Console,代码如下:
清单2-6:ArithmeticOperation.java
1: package cn.ischoolcode.scene2;
2: /*
3: * 爱校码
4: * 版权所有
5: */
6: /**
7:  * 这个类演示算术运算符的用法
8:  * @ version 1.0 版,2023 年 3 月 19 日
9:  * @ author zcj
10: */
11: public class ArithmeticOperation {
12:     /**
13:      * 这是 main 方法
14:      * @param args 传递至 main 方法的参数
15:      */
16:      public static void main(String[] args) {
17:           /* 变量声明 */
18:           int inum = 5, inum1 = 12, inum2 = 20, iresult;
19:           double dnum3 = 25.75;
20:           double dnum4 = 14.25;
21:           double dres; 
22:           
23:           iresult = inum + inum1;        // 相加
24:           System.out.println("inum 和 inum1 的和(inum + inum1)为:  "
25:                 + iresult);
26:           iresult = inum % inum1;        // 取模
27:           System.out.println("inum 对 inum1 取模(inum % inum1)的结果为:" 
28:                    + iresult);
29:           iresult *= inum2;              // 相乘并赋值
30:           System.out.println("iresult 与 inum2 的积(iresult *= inum2)为: " 
31:                    + iresult);
32:           System.out.println("在 ++ 运算之前 inum 的值为: " + inum);
33:           inum++;                          // 递增
34:           System.out.println("在 ++ 运算之后 inum的值为: " +inum);
35:           dres = dnum3 - dnum4;         // 相减
36:           System.out.println("dnum3 – dnum4  相减后的值为 : " + dres);
37:           dres -= 2.50;                  // 相减并赋值
38:           System.out.println("dres -= 2.50 相减并赋值后的值为:" + dres);
39:           System.out.println("在 -- 运算之前dres 的值为: " + dres);
40:           dres--;                        // 递减
41:           System.out.println("在 -- 运算之后 dres 的值为: " + dres);  
42:      }
43:  }
在聊天系统中,用于交互的不同类型的信息,通过定义一个类来实现,类名为ChatMessage,该类的对象用于信息的传递,代码如下:
清单2-7:ChatMessage.java
1:package cn.ischoolcode.chatcui;
2:import java.io.*;
3:/**
4: * 这个类定义用于客户端与服务器之间交换的不同类型的信息 
5: *  @ author zcj
6: */
7:public class ChatMessage implements Serializable {
8:    public static final int WHOISIN = 0, MESSAGE = 1, LOGOUT = 2;
9:     private int type;//0:已连接的用户列表,1:普通信息,2:表示断开连接
10:   private String message;
11:   // 构造方法
12:   public ChatMessage(int type, String message) {
13:     this.type = type;
14:     this.message = message;
15:   }
16:   // get方法
17:   public int getType() {
18:     return type;
19:   }
20:   public String getMessage() {
21:     return message;
22:   }
23:}
通过客户端类Client调用ChatMessage类的对象,代码如下:
清单2-8:Client.java
1: package cn.ischoolcode.scene2;
2: import cn.ischoolcode. chatcui.ChatMessage;
3: import java.text.SimpleDateFormat;
4: import java.util.Date;
5: public class Client {    
6:    public static void main(String[] args) {
7:      ChatMessage chatMessage = new ChatMessage(1,"你好");
8:      SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
9:      String time = sdf.format(new Date());
10:     String messageLf = time + " " + chatMessage.getMessage() + "\n";
11:     System.out.print(messageLf);
12:   }
13:}
在聊天系统的服务端程序中,通过对象数组存放不同用户的登录情况,代码如下:
清单2-9:Server.java
1: package cn.ischoolcode.scene2;
2: import java.net.*;
3: public class Server {
4:   ServerSocket sSocket;
5:   Socket cSocket;
6:   // 用于存放不同用户登陆的SOCKET
7:   public static Object[] totalUser = new Object[200]; 
8:   public static int allUser = -1; // 用于确定当前有多少用户
9:   public static void main(String[] args) {
10:     Server server = new Server();
11:     try {
12:         int port = 1111;
13:         server.sSocket = new ServerSocket(port);
14:         System.out.println("正在侦听...");
15:         while (true) {
16:             server.cSocket = server.sSocket.accept();
17:             if (server.cSocket != null) {
18:                 // 当侦听到后就把侦听到的SOCKET放到OBJECT对象数组中
19:                 totalUser[++allUser] = server.cSocket;
20:                 System.out.println("当前在线用户:");
21:                 for (int i = 0; i <= allUser; i++) {
22:                     System.out.println(totalUser[i].toString());
23:                 }
24:             }
25:         }
26:     } catch (Exception e) {
27:         e.printStackTrace();
28:     }
29:   }
30: }
以上代码中涉及的ServerSocket类、Socket类以及try、catch异常处理将会在后面情景任务中详细介绍。
1. 变量的初始化原则
JVM内存区域组成分为四种:
① 栈区:由编译器自动分配释放,存放原始数据类型的数据和对象的引用,但对象本身不存放在栈区中,而是存放在堆区中。存放对象方法的参数值,方法内局部变量的值等,当方法执行结束之后,系统自动释放JVM内存资源。
② 堆区:存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象时,该对象就被回收。
③ 静态区:存放静态变量和常量,不释放。
④ 代码区:也称为方法区,也称为元数据空间。用于存储JVM加载的类信息,即编译器编译后的代码等数据。在后续版本中,将静态区规划为方法区的一部分。
在Java编程中,使用变量前必须进行初始化。如果代码给一个堆栈变量赋值,编译器很容易检查该变量,当开始执行方法时,已经为this引用和方法参数赋了值。只能通过查看方法代码来检查在方法代码内定义的局部变量。因此,编译器强调在给变量赋值之前,方法代码不能读取变量值。
对于堆的对象属性,执行这一检查不容易,解决这一问题最合理的方式就是强行为构造器赋一个初始值。如果程序员在声明变量时没有提供缺省值,那么编译器将会为其赋缺省值。原始数据类型的变量和引用数据类型的变量将初始化为以下所示的缺省值。
  变量          值
  byte          0
  short         0
  int           0
  long          0L
  float         0.0F
  double        0.0D
  char         ‘\u0000’
  boolean       false
  所有引用类型   null
值为null的引用不指向任何对象。企图使用null引用的对象会引发异常。异常是运行时发生的错误,将在以后的情景任务中说明。
方法外定义的变量(类的成员变量)自动被初始化,但方法内局部变量必须在使用前手工初始化。如果编译器发现变量未经初始化即被使用,将标识出错。
2. 类型转换
在Java编译器内部只执行两个数据类型相同的操作数的二元运算,当二元运算的两个操作数的数据类型不同时,编译器会转换其中一个操作数的类型,以保证两个操作数的类型一致,然后才进行运算,这种由编译器自动完成的数据类型转换,称为隐式数据类型转换或者自动类型转换。隐式转换时,编译器创建被转换数据类型操作数变量的副本,参与运算的实际是被转换变量的副本,该变量本身并未受到影响。
Java中算术运算、关系运算以及逻辑运算的隐式类型转换,是按照取值范围小的类型向取值范围大的类型转换,例如,int类型的操作数和float类型的操作数一起参与运算,其结果将会是float类型的数据。当将一种类型的变量赋给另一种类型的变量时,只要满足以下条件,就会发生隐式类型转换:
当赋值运算的左(目标)、右(源)操作数类型不一致时,右操作数首先转换为左操作数的类型,然后将转换结果赋值给左操作数,隐式自动转换是发生在左操作数(目标)类型的取值范围大于右操作数(源)类型的取值范围。但是,当左操作数(目标)类型的取值范围小于右操作数(源)类型的取值范围,则编译器会报告错误并拒绝转换。如果确实需要用到这样的赋值运算,就必须使用显示或强制类型转换。如果被转换的值的数据类型大于其目标类型,就会丢失部分信息。
示例:
float fnum = 34.89675f;
int inum = (int) fnum + 10;       // 将fnum转换为整型
强制类型转换的形式是在表达式前面加上由圆括号括住的类型名称。
博文最后更新时间: