转载

【译】Java8官方教程:语言基础—变量

正如我们上一节中所学,对象将它的状态存储在"字段(fields)"中

int cadence = 0;
int speed = 0;
int gear = 1;
复制代码

"何为对象?"中向您介绍了“字段(fields)”,但是您可能会存在一些疑问,例如:命名"字段(fields)"的规则和约定是什么?除了int,还有一些什么数据类型?字段声明时必须初始化吗?如果没有显示初始化,它们具有默认的值吗?本节课我们将探索这些问题的答案,但是在这之前,下面是您必须首先注意的一些技术区别。在Java编程语言中,术语“字段(fields)”和“变量(Variables)”都被采用,对于新开发人员来说,这是一个常见的困惑源,它们通常指代的似乎是同一个事物。

Java编程语言定义了以下几种变量:

  • 实例变量(非静态字段):技术上来说,对象将各自的状态存储在“非静态字段”中,也就是说,声明字段时没有指定static关键字。非静态字段也称为实例变量,因为他们的值在每个类的实例中(或者说:在每个对象中)都是不一样的。一辆自行车的当前速度与另一辆自行车的当前速度无关。

  • 类变量(静态字段):使用静态修饰符(static)声明的任何字段称为类变量;这告诉编译器,不管这个类实例化了多少次,该变量都仅存在一个副本。对于特定类型自行车齿轮数的字段可以声明为static,这将赋予所有实例相同的齿轮数。代码段:static int numGears = 6;将创建一个静态字段,此外,可以添加关键字final来表示齿轮的数量永远不会改变。

  • 局部变量:与对象将状态存储在字段中相似,方法经常将其暂时的状态存在局部变量中。声明局部变量的语法类似于声明字段(int count = 0;)。没有特殊的关键字指定其为局部变量;这完全取决于变量声明的位置——方法的开括号和闭括号之间;因此,局部变量只对声明它们的方法可见;其他类无法访问它们。

  • 参数: 在自行车类和“Hello world!”应用中您已经看到过参数的示例。回想一下main方法:public static void main(String[] args),这里,args是这个方法的参数。重要的是要记住参数总是被分类为“变量”而不是“字段”。这也适用于其他接受参数的构造方法(如构造函数和异常处理器),您将在本教程的后面学习这些

话虽如此,如果我们谈论的是“一般的字段”(不包括局部变量和参数),我们可以简单地说“字段”。如果讨论适用于“以上所有”,我们可以简单地说“变量”。如果上下文需要区别,我们将使用特定的术语(静态字段、局部变量等)。你可能会经常看到"成员"这个术语。字段、方法和嵌套类型统称为其成员。

命名

每种编程语言对于允许使用的命名方式都有自己的一套规则和约定,Java编程语言也不例外,变量命名的规则和约定可以总结如下:

  • 变量名区分大小写。变量的名称可以是任何合法的标识符——不限长度的Unicode字母和数字序列,以字母,“$”符,或下划线“_”开头。然而,习惯上,变量名总是以字母开头,而不是“$”或“_”。此外,根据惯例,美元符号字符从未使用过。您可能会发现在某些情况下,自动生成的名称将包含美元符号,但是变量命名时应该避免使用。下划线字符也有类似的约定;虽然从技术上讲,以“_”作为变量名的开头是合法的,但是不鼓励这样做。空格是不被允许使用的。

  • 后续字符可以是字母、数字、美元符号或下划线字符。当为变量选择名称时,使用完整的单词而不是模糊的缩写。这样做将使您的代码更容易阅读和理解。在许多情况下,它还会使您的代码更直观;例如,名为cadence、speed和gear的字段比缩写版本(如s、c和g)更直观。还要记住,您选择的名称不能是关键字或保留字

  • 如果您选择的名称只包含一个单词,请将该单词全部用小写字母拼写。如果由一个以上的单词组成,则将后面每个单词的第一个字母大写。如:gearRatio、currentGear。对于static final int NUM_GEARS = 6,约定有少许变化,将每个字母大写,然后用下划线分隔后面的单词。按照惯例,下划线字符永远不会在其他地方使用

基本数据类型

Java编程语言是静态类型语言,这意味着所有的变量在使用前必须先声明。包括声明变量的类型和名称,正如你已经见过的:

int gear = 1;
复制代码

这样做会告诉程序存在一个名为“gear”的字段,该字段保存数值数据,初始值为“1”。 变量的数据类型决定了它可能包含的值,以及可能对其执行的操作。除了int,Java程序语言还支持其他7种基本数据类型。基本类型由语言预定义,并由保留关键字命名。不同基本数据类型之间的值并不共享。Java支持的8种基本数据类型分别为:

  • byte:byte数据类型是8-bit补码表示的有符号整数。最小值为-128,最大值为127(含)。byte数据类型在大数组中节省内存时显得十分有用,在大数组中,内存的节省实际上非常重要。范围限制有助于阐明代码时可以用其代替int;变量的范围有限这一事实可以作为文档的一种形式。

  • short:short数据类型是16-bit补码表示的有符号整数。最小值为-32768,最大值为32767(含)。与byte一样,同样的指导原则也适用:在实际需要节省内存的情况下,您可以使用short来在大数组中节省内存。

  • int:默认情况下,int数据类型是一个32-bit补码表示的有符号整数,最小值为-2^31,最大值为2^31-1。在Java SE 8及更高版本中,可以使用int数据类型表示范围为0到2^32-1的无符号32-bit整数。使用Integer类将int数据类型用作无符号整数,更多信息见The Number Classes一节,在Integer类中添加了compareUnsigned、divideUnsigned等静态方法来支持无符号整数的算术运算。

  • long:long数据类型是一个64-bit补码表示的有符号整数,最小值为-2^64,最大值为2^64-1。在Java SE 8及更高版本中,您可以使用long数据类型来表示范围为0到2^64-1的无符号64-bit整数。当您需要比int提供的值范围更大的值时,可以使用这种数据类型。Long类还包含compareUnsigned、divideUnsigned等方法来支持无符号long的算术操作

  • float:float数据类型是一个单精度的32位IEEE 754浮点数,它的取值区间超出了我们的讨论范围,但是在 Floating-Point Types, Formats, and Values 一节中有详细说明。与byte和short的建议一样,如果需要在浮点数的大数组中节省内存,请使用float(而不是double)。这种数据类型不应该用于存储精确的值,比如货币。为此,您需要使用java.math.BigDecimal类。Numbers and Strings中涵盖了BigDecimal和其它Java平台提供的有用的类。

  • double:double数据类型是一个双精度的64位IEEE 754浮点数,它的取值区间超出了我们的讨论范围,但是在 Floating-Point Types, Formats, and Values 一节中有详细说明。对于包含小数的值,这种数据类型通常是默认选择。如上所述,这种数据类型永远不应该用于精确的值,比如货币。

  • boolean:boolean数据类型只有两个可能的值:true和false。使用此数据类型存储"真/假"条件。这个数据类型表示1-bit的信息,但是它实际占用内存的“大小”并不是精确定义的。

  • char: char数据类型是一个16位Unicode字符。 最小值为 '/u0000' (0),最大值为 '/uffff' (65535)

除了上面列出的八种基本数据类型之外,Java编程语言还通过Java .lang.String提供了对字符串的特殊支持。将字符串括在双引号内将自动创建一个新的字符串对象;例如: String s = "this is a string";String对象是不可变的,这意味着一旦创建,它们的值就不能更改。String类在技术上不是原始数据类型,但是考虑到该语言对它的特殊支持,您可能会这样认为。您将在 Numbers and Strings 中了解关于String类的更多信息

默认值

声明字段时并不总是需要赋值,编译器将为已经声明但未初始化的字段设置合理的默认值。一般来说,根据数据类型的不同,这个默认值将是零或null。然而,依赖这些默认值通常被认为是糟糕的编程风格

下表总结了上述数据类型的默认值:

【译】Java8官方教程:语言基础—变量

局部变量略有不同;编译器从不将默认值分配给未初始化的局部变量。如果无法在声明局部变量的地方初始化该变量,请确保在尝试使用它之前为其赋值。访问未初始化的局部变量将导致编译时错误。

字面量(Literals)

您可能已经注意到,在初始化基本类型的变量时不使用new关键字。基本类型是构建在语言中的特殊数据类型;它们不是通过类创建的对象。字面量是值的源代码表示,直接在代码中表示,不需要计算。如下所示,可以将字面量赋值给基本类型的变量:

boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;
复制代码

整数字面量

如果以字母L或l结尾,整数字面量的类型为long;否则它是int类型的。建议使用大写字母L,因为小写字母l很难与数字1区分.整数类型byte、short、int和long的值可以从int字面量创建。long类型的值超出int的范围,可以从long字面量创建。整数字面值可以由这些数字系统表示:

  • 十进制:以10为基数,由数字0到9组成;这是你每天使用的数字系统
  • 16进制:以16为基数,由数字0到9和字母A到F组成
  • 二进制:以2为基数,由数字0和1组成(您可以在Java SE 7和更高版本中创建二进制字面量)

对于一般编程,十进制系统可能是您将使用的唯一数字系统。但是,如果需要使用另一个数字系统,下面的示例显示了正确的语法。前缀0x表示十六进制,0b表示二进制:

// The number 26, in decimal
int decVal = 26;
//  The number 26, in hexadecimal
int hexVal = 0x1a;
// The number 26, in binary
int binVal = 0b11010;
复制代码

浮点数字面量

如果以字母F或f结尾,浮点字面量的类型为float;否则,它的类型是double,并且可以选择以字母D或d结尾。浮点类型(float和double)也可以使用E或e(用于科学表示法)、F或f(32位float字面量)和D或d(64位double字面量;这是默认值,按惯例可省略)来表示。

double d1 = 123.4;
// same value as d1, but in scientific notation
double d2 = 1.234e2;
float f1  = 123.4f;
复制代码

字符和字符串字面量

字符和字符串类型的字面量可以包含任何Unicode (UTF-16)字符。如果编辑器和文件系统允许,可以在代码中直接使用这些字符。如果不允许,您可以使用“Unicode转义”,比如“/u0108”(大写的C)或"S/u00ED Se/u00F1or"(西班牙语中的Sí Señor)。对于char字面量,请始终使用'单引号';对于String字面量,请使用“双引号”。Unicode转义序列可以在程序的其他地方使用(例如在字段名中),而不仅仅是在字符或字符串字面量中。Java编程语言还支持一些用于字符和字符串字面量的特殊转义序列:/b(退格)、/t(制表符)、/n(换行)、/f(表格换行)、/r(回车)、/"(双引号)、/'(单引号)和//(反斜杠)

还有一个特殊的null字面量,可以用作任何引用类型的值。除基本类型的变量外,可以将null赋给任何变量。除了测试null值的存在性之外,您对null值几乎无能为力。因此,在程序中经常使用null作为标记来指示某些对象不可用。

最后,还有一种特殊的字面量,叫做类字面量,它是由一个类型名加上“.class”组成的;例如String.class。这表示对象本身的类型(类的类型)。

在数字字面量中使用下划线字符

在Java SE 7和更高版本中,任何下划线字符(_)都可以出现在数字字面量中数字之间的任何位置。这个特性支持您将数字字面量进行分隔,以提高代码的可读性。 例如,如果您的代码包含很多位数字,您可以使用下划线将数字分成三组,类似于使用逗号或空格等标点符号作为分隔符。 下面的示例展示了在数字字面量中使用下划线的方法:

long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi =  3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
复制代码

只能在数字之间放置下划线;不能在以下位置放置下划线:

  • 在数字的开头或结尾
  • 在浮点数的小数点相邻位置
  • 在F或L后缀之前
  • 在需要一串数字的位置(原文:In positions where a string of digits is expected)

下面的例子演示了数字字面量中有效和无效的下划线位置:

// Invalid: cannot put underscores
// 小数点相邻位置
float pi1 = 3_.1415F;
// Invalid: cannot put underscores 
// 小数点相邻位置
float pi2 = 3._1415F;
// Invalid: cannot put underscores 
// 在L后缀之前
long socialSecurityNumber1 = 999_99_9999_L;

// OK (decimal literal)
int x1 = 5_2;
// Invalid: cannot put underscores
// 字面量的开头或结尾
int x2 = 52_;
// OK (decimal literal)
int x3 = 5_______2;

// Invalid: cannot put underscores
// 在0x前缀中
int x4 = 0_x52;
// Invalid: cannot put underscores
// 在数字的开头
int x5 = 0x_52;
// OK (hexadecimal literal)
int x6 = 0x5_2; 
// Invalid: cannot put underscores
// 数字的结尾
int x7 = 0x52_;
复制代码

数组

数组是一个容器对象,它存储固定数量的单一类型值。数组的长度是在创建数组时确定的。创建之后,它的长度就是固定的。您已经在“Hello World!”应用程序的主方法中看到了一个数组示例(main(String[] args))。本节更详细地讨论数组:

【译】Java8官方教程:语言基础—变量

数组中的每一项都称为一个元素,每个元素都由其数值索引访问。如上图所示,编号从0开始。例如,第9个元素将在索引8处访问。

下面的程序ArrayDemo创建一个整数数组,在数组中放入一些值,并将每个值打印到标准输出:

class ArrayDemo {
    public static void main(String[] args) {
        // declares an array of integers
        int[] anArray;

        // allocates memory for 10 integers
        anArray = new int[10];
           
        // initialize first element
        anArray[0] = 100;
        // initialize second element
        anArray[1] = 200;
        // and so forth
        anArray[2] = 300;
        anArray[3] = 400;
        anArray[4] = 500;
        anArray[5] = 600;
        anArray[6] = 700;
        anArray[7] = 800;
        anArray[8] = 900;
        anArray[9] = 1000;

        System.out.println("Element at index 0: "
                           + anArray[0]);
        System.out.println("Element at index 1: "
                           + anArray[1]);
        System.out.println("Element at index 2: "
                           + anArray[2]);
        System.out.println("Element at index 3: "
                           + anArray[3]);
        System.out.println("Element at index 4: "
                           + anArray[4]);
        System.out.println("Element at index 5: "
                           + anArray[5]);
        System.out.println("Element at index 6: "
                           + anArray[6]);
        System.out.println("Element at index 7: "
                           + anArray[7]);
        System.out.println("Element at index 8: "
                           + anArray[8]);
        System.out.println("Element at index 9: "
                           + anArray[9]);
    }
} 
复制代码

程序输出:

Element at index 0: 100
Element at index 1: 200
Element at index 2: 300
Element at index 3: 400
Element at index 4: 500
Element at index 5: 600
Element at index 6: 700
Element at index 7: 800
Element at index 8: 900
Element at index 9: 1000
复制代码

在实际的编程环境中,您可能会使用受支持的循环结构来遍历数组的每个元素,而不是像前面的示例那样单独地编写每一行。然而,这个例子清楚地说明了数组语法。在 "控制流(Control Flow)"一节中您将了解各种循环结构(for、while和do-while)。

声明引用数组的变量

前面的程序使用以下代码行声明一个数组(名为anArray):

// declares an array of integers
int[] anArray;
复制代码

与其他类型变量的声明一样,数组声明有两个组件:数组的类型和数组的名称。数组的类型被写成type[],其中type是所包含元素的数据类型;[]是一些特殊的符号,表示这个变量包含一个数组。数组的大小不是其类型的一部分(这就是为什么[]是空的)。数组的名称可以是任何您想要的名称,只要它遵循前面在命名部分中讨论的规则和约定即可。与其他类型的变量一样,声明实际上并不创建数组;它只是告诉编译器该变量将保存指定类型的数组。

类似地,您可以声明其他类型的数组:

byte[] anArrayOfBytes;
short[] anArrayOfShorts;
long[] anArrayOfLongs;
float[] anArrayOfFloats;
double[] anArrayOfDoubles;
boolean[] anArrayOfBooleans;
char[] anArrayOfChars;
String[] anArrayOfStrings;
复制代码

你也可以把括号放在数组的名字后面:

// this form is discouraged
float anArrayOfFloats[];
复制代码

然而,惯例不鼓励这种形式;方括号标识数组类型,并应与类型指定一起出现。

创建、初始化和访问数组

创建数组的一种方法是使用new操作符。下面ArrayDemo程序中的语句申请一个足够容纳10个整数的数组,并将数组分配给anArray变量:

// create an array of integers
anArray = new int[10];
复制代码

如果缺少该语句,编译器将打印如下错误,编译失败:

ArrayDemo.java:4: Variable anArray may not have been initialized.
复制代码

接下来的几行代码为数组的每个元素赋值:

anArray[0] = 100; // initialize first element
anArray[1] = 200; // initialize second element
anArray[2] = 300; // and so forth
复制代码

每个数组元素都由其数值索引访问:

System.out.println("Element 1 at index 0: " + anArray[0]);
System.out.println("Element 2 at index 1: " + anArray[1]);
System.out.println("Element 3 at index 2: " + anArray[2]);
复制代码

或者,您可以使用快捷语法创建和初始化数组:

int[] anArray = { 
    100, 200, 300,
    400, 500, 600, 
    700, 800, 900, 1000
};
复制代码

数组的长度由大括号中逗号分隔的值的数量决定。

您还可以使用两个或多个括号(如String[][]名称)声明数组的数组(也称为多维数组)。因此,每个元素必须由相应数量的索引值访问。

在Java编程语言中,多维数组是一个数组,其组件本身就是数组。这与C或Fortran中的数组不同。其结果是允许行长度变化,如下面的MultiDimArrayDemo程序所示:

class MultiDimArrayDemo {
    public static void main(String[] args) {
        String[][] names = {
            {"Mr. ", "Mrs. ", "Ms. "},
            {"Smith", "Jones"}
        };
        // Mr. Smith
        System.out.println(names[0][0] + names[1][0]);
        // Ms. Jones
        System.out.println(names[0][2] + names[1][1]);
    }
}
复制代码

程序输出为:

Mr. Smith
Ms. Jones
复制代码

最后,您可以使用内置的length属性来确定任何数组的大小。以下代码将数组的大小打印到标准输出:

System.out.println(anArray.length);
复制代码

复制数组

System类有一个arraycopy方法,您可以使用它来有效地将数据从一个数组复制到另一个数组:

public static void arraycopy(Object src, int srcPos,
                             Object dest, int destPos, int length)
复制代码

这两个Object参数指定源数组和要目的数组,三个int参数指定源数组中的起始位置、目标数组中的起始位置和要复制的数组元素的数量。

下面的程序ArrayCopyDemo声明了一个char元素数组,存储单词“decaffeated”。它使用System.arraycopy方法将源数组的子串复制到第二个数组中:

class ArrayCopyDemo {
    public static void main(String[] args) {
        char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
			    'i', 'n', 'a', 't', 'e', 'd' };
        char[] copyTo = new char[7];

        System.arraycopy(copyFrom, 2, copyTo, 0, 7);
        System.out.println(new String(copyTo));
    }
}
复制代码

这个程序的输出是:

caffein
复制代码

操纵数组

数组是编程中使用的一个强大而有用的概念。Java SE提供了一些方法来执行与数组相关的一些最常见的操作。例如,ArrayCopyDemo示例使用系统类的arraycopy方法,而不是手动遍历源数组的元素并将每个元素放入目标数组。这是在后台执行的,允许开发人员只使用一行代码来调用方法。

为了方便起见,Java SE在java.util.Arrays 类中提供了几种执行数组操作的方法(常见的任务:如复制、排序和搜索)。例如,可以修改前面的示例,使用java.util.Arrays类的copyOfRange方法。正如您在ArrayCopyOfDemo示例中所看到的。不同之处在于,使用copyOfRange方法不需要在调用该方法之前创建目标数组,因为该方法返回目标数组。

class ArrayCopyOfDemo {
    public static void main(String[] args) {
        
        char[] copyFrom = {'d', 'e', 'c', 'a', 'f', 'f', 'e',
            'i', 'n', 'a', 't', 'e', 'd'};
            
        char[] copyTo = java.util.Arrays.copyOfRange(copyFrom, 2, 9);
        
        System.out.println(new String(copyTo));
    }
}
复制代码

正如您所看到的,尽管这个程序的代码更少,但是输出却是相同的(caffein)。注意,copyOfRange方法的第二个参数是要复制的范围的初始索引,而第三个参数是要复制的范围的最终索引。在本例中,要复制的范围不包括索引9处的数组元素('a')。

下面例举java.util.Arrays类中提供的一些其他有用的方法:

  • 在数组中搜索特定值,以获得它所在的索引(binarySearch方法)
  • 比较两个数组以确定它们是否相等(equals方法)
  • 在每个索引处放置特定值(fill方法)
  • 按升序排列数组。可以使用sort方法顺序执行,也可以使用Java SE 8中引入的parallelSort方法并发执行。在多处理器系统上对大数组进行并行排序要比顺序数组排序快。
原文  https://juejin.im/post/5cd55c2af265da0359488eed
正文到此结束
Loading...