(翻译)《二》语言基础(1)--变量

原文链接:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

前言

变量

你已经学习了对象在域中保存自己的状态。但是java中用变量表达相同的意思。本节讨论他们之间的关系,还有变量命名规则和习惯,基础数据类型、字符串、数组,默认值和常量。

操作符

本节介绍java中的操作符,包括最常用的操作符,然后是不那么常用的,还有可以编译、运行的代码示例。

表达式、语句、块

块是由语句组成,语句的核心是表达式,表达式中会运用操作符来计算,本节讨论表达式、语句和块,并提供代码示例。

控制流语句

 本节介绍java提供的控制流语句,包括决策判断、循环、分支语句,能让你的程序有条件地执行特定的代码块。

 正文 

1,变量

像你之前学的,对象在域中保存状态。

int cadence = 0;
int speed = 0;
int gear = 1;

在什么是对象中介绍了域,但是你也许还有一些疑问,比如命名这些域的规则和习惯有哪些?除了int,还有哪些数据类型?域在声明时必须初始化吗?域如果没有明确地初始化会有默认值吗?在本节中我们会探索这些问题,但首先我们还要注意一些技术上的特质。在java中,域和变量的说法都会使用,并且看起来是同一个东西,这常常困扰新手。

java中,变量有下面一些类型:

a.实例的变量(非静态的域):技术上来说,对象在非静态的域中保存自己的各种状态,也就是说,声明域时没有使用static关键字。非静态域也被当作实例变量因为对于类的每个实例来说他们的值都是唯一的。好比每个自行车实例的当前速度都与其他自行车实例的当前速度不一样。

b.类的变量(静态的域):类的变量就是所有用static关键字声明的域,它会告诉编译器这个变量只存在一份不管这个类有多少个实例。同一类型的自行车挡位数可以用static关键字声明域,因为对于这个类型所有的自行车实例,挡位数都是一样的。static int gear = 6;会创建这样一个静态的域。此外增加关键字final表示这个挡位数不会改变。

c.局部变量:类似于对象在域中保存状态,一个方法通常在局部变量中保存临时状态。声明局部变量的语法和声明域类似(比如:int count = 0;)。没有专门的关键字声明局部变量,因为局部变量声明的位置--在一个方法的花括号之中。因此局部变量只对这个方法可见,不能被类的其他部分访问。

d.参数:你已经在Bicycle类和main方法中见过参数的例子,回想main方法的签名:public static void main(String args[]),这个args变量就是方法的参数。这里的重点是需要记住参数通常归类为变量还不是域。这同样适用于接受参数的构造函数、异常处理等等,你将在后面会学到。

就像我们说的,后面的教程讨论域和变量时,使用下面通用规则:类的变量和对象的变量,我们通常用域表示;如果是以上所有,我们通常用变量来表示;如果上下文需要区分,我们通常使用专门的说法(比如:静态域、局部变量等等)。你也会偶尔看到成员的说法。域、方法、嵌套类型都可以统称成员。

 命名

 每一种语言都有一套自己的命名规范和习惯,java也不例外。命名变量的规范和习惯可以总结如下:

  • 变量名称是大小写敏感的。变量的名称可以是任何合法的标识符--不限长度的unicode编码的字母和数字,可以以字母、$、_开头。但通常名称由字母打头,而不是$和_。此外,我们一般也不使用$。$会出现在自动生成的代码中,但是你的变量命名中应该避免使用它。同样,变量命名用下划线打头虽是合法的,但是不鼓励这样做。空格是不允许出现的。
  • 变量名称可以由字母、数字、点、下划线组成。尽量使用全称,避免使用缩写。这样使你的代码易于阅读和理解。通常这样做可以让你的代码自描述,比如域:cadence、speed、gear比使用缩写c、s、g更清晰。注意不要使用关键字和保留字命名。
  •  如果变量名称由一个单词组成,首字母小写。如果有多个单词,除首个单词首字母小写,其他单词首字母大写。比如:gearRatio和currentSpeed。如果你的变量保存了一个常量,习惯稍微改变,比如:static final int NUM_GEARS = 6;每个单词大写,并用下划线连接。通常下划线并没有用在别的地方。

 1.1,基础数据类型

java是静态类型的语言,所有变量必须首先声明再使用。声明时规定变量的类型和名称。比如:int gear = 1;这是告诉你的程序有一个叫做gear的域,持有整数数据,并有一个初始值1。一个变量的数据类型决定了这个变量包含的值和这个变量可以做的操作。除了int,java还有7种基础数据类型。基础数据类型是java预定义的,并以保留关键字命名。基础数据值之间不会共享状态。以下是8个基础数据类型:

  • 字节:8位有符号的整数。最小值-128,最大值127。字节类型在使用大数组时对节省内存很有益,当节省内存确实是一个问题的时候。字节也可以在用到整型的地方使用,来帮助你理清代码;事实上,一个变量的范围限制可以当作文档的一种形式。
  • 短整型:16位有符号的整数。最小值-32768,最大值32767。和字节一样,你可以在大数组中使用短整型来节省内存,当节省内存确实是一个问题的时候。
  • 整型:默认是32位有符号的整数。最小值-231,最大值231-1。在java8及之后,你可以用int表示无符号的32位整型,最小值0,最大值232-1。使用Integer类定义无符号整型。后面会介绍更多信息。Integer类中新增的方法compareUnsigned、divideUnsigned被用来支持无符号的整型计算。
  • 长整型:64位整数。有符号的长整型最小值-263,最大值263-1。在java8及之后,你可以用long表示无符号的64位长整型,最小值0,最大值264-1。当你需要的整数超过了整型范围,你就可以使用长整型。Long类也提供了compareUnsigned和divideUnsigned等方法支持无符号长整型的计算。
  • 单精度浮点:单精度32位IEEE754标准浮点数,它的范围参考java协议。好像字节和短整型,使用单精度浮点数代替双精度浮点数能帮助你在使用大数组时节省内存。浮点数不能用于表示精确数值,好像货币。所以,你需要使用java.math.BigDecimal类代替。Number and Strings 涵盖了java平台提供的BigDecimal和其他有用的类。
  • 双精度双浮点:双精度64位IEEE754标准浮点数,它的范围参考java协议。对于包含小数的值,双精度浮点数是默认的选择。像上面提到的,此类型不能用于表示精确值,比如货币。
  • 布尔型:只有两个值,true和false。把布尔型当作一个简单的标志位来监测条件。布尔型表示一位的信息,但是它的大小却没有明确定义。
  • 字符:16位unicode编码字符。最小值是\u0000,最大值是\uffff。

除了上面8个基础数据类型,java通过java.lang.String类为字符串提供了专门的支持。为你的字符串打上双引号会自动创建一个新的String对象;比如,String s = "this is a string";。String对象是不可改变的,这表示一旦创建,String对象的值不能被修改。Sring类不是一个基础数据类型,但是考虑到java给它的特有的支持,你也许可以把它当作一个基础数据类型。在后面你好学到更多String类的知识。

默认值

 当声明一个域时,并不一定要给它赋值。域被声明但是没有被初始化,则被编译器设置一个合适的默认值。通常,这个值是0或null,这要看域的类型。依赖默认值赋值通常是一个坏的编程习惯。

下面给出各个数据类型的默认值:

byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String(any object) null
boolean false

局部变量会有一些不同,编译器不会给未初始化的局部变量赋默认值。如果你在声明局部变量时不能初始化,那么在使用它之前一定要给它赋值。否则访问一个未赋值的局部变量会造成编译错误。

常量

 你也许注意到,初始化一个基础类型的变量并不使用new关键字。基础数据类型是java内建的数据类型;它们不是java类创建的对象。一个常量是代码中的固定值。这些常量在你的代码直接表示,是不需要计算的。就像下面,给基础数据类型赋值常量。

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

整数常量

 以L或l结尾的整数常量是长整型;否则它就是整型。推荐使用大些L,因为小写l和数字1容易混淆。

 整数类型byte、short、int、long的值可以使用int常量创建。long类型的超过int类型的值可以使用long常量创建。整数常量有下面三种表达方式:

10进制

16进制

2进制

通常编程中,10进制好像就可以作为你唯一使用的表达方式。当然,如果你需要使用别的表达方式,下面的例子给出正确的语法。前缀0x表示16进制,0b表示2进制。

int decVal = 26;

int hexVal = 0x1a;

int binVal = 0b11010;

浮点数常量

 浮点数常量如果以字母F或f结尾就是单精度浮点类型,否者就是双精度浮点类型,也可选用D或d结尾。浮点数类型可以用E或e表示(科学记数法)、F或f(32位浮点数常量)、D或d(64位浮点数常量,这是默认的,可不加D或d,习惯是不加)。

double d1 = 123.14;//默认

double d2 = 1.2314e2;//科学记数法

fload f1 = 123.1f;//单精度浮点数

字符、字符串常量

 char类型和字符串类型的字面常量可以包含任意unicode编码字符。如果你的编译器和文件系统允许,你可以在代码中直接使用这些字符。如果不支持,你可以用unicode转义字符,比如'\u0108'(c大调)、"S\u00ED Se\u00F1or"(西班牙语)。记住,字符常量使用单引号,字符串常量使用双引号。除了字符、字符串常量,unicode转义符也可能用在程序里(比如一个域的名称)。

java还为字符、字符串常量提供了一些转义符,\b(回退),\t(制表),\n(换行),\f(换页),\r(回车),\"(双引号),\'(单引号),\\(反斜杠)。

还有特殊的null常量可以作为所有引用类型的值。null可以赋给除了基础数据类型外的所有变量。除了测试null的存在,我们对null做不了别的事情。因此,null在程序中通常作为标记表示一个对象不可访问。

最后,还有一种常量称为类常量,由类型名称和".classs"组成。比如String.class。这是指这个对象(class类型)代表了类型本身。

数字常量中使用下划线

 在java7及之后,任意数量的下划线可以出现在数字常量之中的任意位置。这样通过下划线将数字常量分组,可以提供代码可读性。

比如,你的数包含很多位数,你可以使用下划线将数字分成几组,就像你使用标点符号作为分隔符。

下面展示下划线分隔的例子:

long creditCardNumber = 1234_4567_7890_0123L;

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;

byte bytes = 0b11010010_01101001_10010100_10010010;

下划线只能放在数字之间,你不能放在:

数字的开头或结尾;

浮点数常量中不能和小数点在一起;

不能在F或f后缀之前;

不能放在应该放字符的位置上;

下面展示一些合法和非法使用下划线的例子:

// Invalid: cannot put underscores
// adjacent to a decimal point
float pi1 = 3_.1415F;
// Invalid: cannot put underscores 
// adjacent to a decimal point
float pi2 = 3._1415F;
// Invalid: cannot put underscores 
// prior to an L suffix
long socialSecurityNumber1 = 999_99_9999_L;

// OK (decimal literal)
int x1 = 5_2;
// Invalid: cannot put underscores
// At the end of a literal
int x2 = 52_;
// OK (decimal literal)
int x3 = 5_______2;

// Invalid: cannot put underscores
// in the 0x radix prefix
int x4 = 0_x52;
// Invalid: cannot put underscores
// at the beginning of a number
int x5 = 0x_52;
// OK (hexadecimal literal)
int x6 = 0x5_2; 
// Invalid: cannot put underscores
// at the end of a number
int x7 = 0x52_;

1.2,数组
一个数组是一个容器对象,它持有固定数量的值,并且这些值都是同一类型。当创建一个数组时,数组的长度就确定下来。创建之后,长度是不能更改的。你已经看过之前例子中的数组。本节介绍更多细节部分。

数组中的每一项被称为元素,每个元素是通过数组的下标访问。下标从0开始,因此第九个元素的下标是8。
下面程序创建一个整型数组,放入一些值,并打印每个值到标准输出。
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
在现实编程中,你可能会用一个循环结构体来遍历数组中的每个元素,而不是一行处理一个元素。当然,上面的例子清晰的说明了数组的语法。你在后面将会学到各种循环结构体。
声明一个变量指向一个数组
下面的代码声明了一个数组:
int[] anArray;
就像其他类型的变量声明,一个数组声明有两个部分:数组的类型和名称。数组类型写法:type[],type就是数组包含的元素的数据类型;中括号表示声明的变量持有一个数组。数组的大小不是它类型的一部分(所以中括号里没有内容)。数组的名称可以是符合之前命名规范的任意名称。就像其他类型的变量,这个声明并不会实际创建一个数组,它只是告诉编译器这个变量将会持有某个类型的数组。
类似的,你可以声明其他类型的数组:
byte[] anArrayOfByte;
short[] anArrayOfShort;
int[] anArrayOfInt;
long[] anArrayOfLong;
float[] anArrayOfFloat;
double[] anArrayOfDouble;
boolean[] anArrayOfBoolean;
char[] anArrayOfChar;
String[] anArrayOfString;
你也可以把中括号放在名称的后面,比如byte anArrayOfByte[];但是不鼓励这样做。中括号表示变量是一个数组,应该和类型放在一起。
创建、初始化、访问数组
一个创建数组的方法是使用new操作符。下面代码为数组分配足够的内存来放置10个整型元素,并把数组指向anArray变量。
anArray = new int[10];
如果没有这个创建,编译器就会报错:变量anArray没有被初始化。
下面几行是为数组中的元素赋值。
anArray[0] = 100;
anArray[1] = 200;
每个元素可以通过数组下标访问。
System.out.println(anArray[0]);
另外,你还可以用下面简洁方法创建和初始化一个数组。
int[] anArray = {100,200,300,400,500,600};
这里,数组的长度是由花括号中值的个数决定的。
你也可以声明一个数组类型的数组(多维数组),通过使用多个中括号,像String[][]。数组中的元素,需要根据对应的下标访问。
在java中,一个多维数组就是数组中的元素也是数组。这不像c语言。这导致每一行的元素个数可以不一样。如下:
class MultiDimArray{
  public static void main(String[] args[]){
    String[][] names = {
      {"Mr. ","Mrs. ","Ms. "};
      {"zhang","wang"}
    };
    System.out.println(names[0][0] + names[1][0]);
    System.out.println(names[0][2] + names[1][1]);
  }
}
输出:
Mr. zhang
Ms. wang
最后,你可以使用数组内建的length属性得到数组长度。下面打印数组长度。
System.out.println(anArray.length);

数组拷贝
System类有一个arraycopy方法,你可以高效地拷贝数据,从一个数组到另一个数组。
public static void arraycopy(Object src, int srcPos, Object des, int desPos, int length)
其中两个对象参数分别是被拷贝数组和拷贝数组。三个整型参数指被拷贝数组的开始位置,拷贝数组的开始位置,要拷贝的元素个数。
下面程序声明了一个字符数组,可以拼成单词"decaffeinated"。使用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对数组提供了一些最常见的操作。比如,System类的arraycopy方法代替了手工遍历源数组中的元素并将每个元素放入目的数组中。这样隐藏了实现,让开发者用一行代码实现了拷贝的功能。
为了方便,java在java.util.Arrays类中提供了许多操作数组的方法(拷贝、排序、查找等)。比如,上面代码可以使用java.util.Arrays类中的copyOfRange方法代替System.arraycopy。两个方法的区别是使用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[] cppyTo = Arrays.copyOfRange(copyFrom, 2, 9);
    System.out.println(new String(copyTo));
  }
}

就像你看到,这个程序的输出也是caffein,只是需要更少的代码。注意,方法的第二个参数是拷贝的开始下标,是包含在内的,第三个参数是拷贝的结束下标,不包含在内。本例中,拷贝的元素不包含数组下标为9的元素。

java.util.Arrays提供的其他一些有用的操作有:
在数组中查询一个特定的值,返回这个值在数组中的下标。(binarySearch)
比较两个数字是否相等(equals)
用特定的值填充数组(fill)
数组排升序。Arrays提供了sort方法依次顺序排序,也提供了多线程排序的方法parallelSort。使用多核系统并行排序大数组要比顺序排序大数组要快。
变量总结
java技术术语包括域和变量。实例变量(非静态域)对于类的每个实例都是唯一的。类变量(静态域)是使用static声明的域,每个类变量都只有一份拷贝,不管这个类初始化了多少个实例。局部变量在方法中保存临时状态。参数是给方法提供额外信息的变量。局部变量和参数都称为变量,而不是域。给你的域或者变量命名时,需要遵守一些规则和习惯。
一共有8个基础数据类型:byte、short、int、long、float、double、char、boolean。java.lang.String代表字符串。编译器会给以上类型的域一个合适的默认值;对于局部变量,则没有默认值。字面常量在代码中表示一个固定值。数组是一个持有某个类型固定个数的值的容器对象。数组的长度是在数组创建时确定的。数组创建之后,长度是不可变的。


posted @ 2016-10-18 18:18  apple2016  阅读(248)  评论(0编辑  收藏  举报